githits 0.5.0 → 0.5.2
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.plugin/plugin.json +1 -1
- package/dist/cli.js +43 -44
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-rfbq8swx.js → chunk-3ts4j2bz.js} +238 -23
- package/dist/shared/{chunk-zykgxy2b.js → chunk-5frt0jap.js} +1 -1
- package/dist/shared/{chunk-vgw103dk.js → chunk-gvvj0h4n.js} +1 -1
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/skills/githits-code/references/code-and-docs.md +1 -1
- package/skills/githits-package/SKILL.md +1 -1
- package/skills/githits-package/references/package.md +1 -1
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import{__require,version}from"./chunk-
|
|
1
|
+
import{__require,version}from"./chunk-gvvj0h4n.js";import{createHash,randomBytes}from"node:crypto";function generateCodeVerifier(){return randomBytes(32).toString("base64url")}function generateCodeChallenge(verifier){return createHash("sha256").update(verifier).digest("base64url")}function generateState(){return randomBytes(32).toString("hex")}var CLIENT_UPDATE_REQUIRED_REASON="Backend protocol changed";class ClientUpdateRequiredError extends Error{reason;currentVersion;constructor(message=`Update required: ${CLIENT_UPDATE_REQUIRED_REASON}`,reason=CLIENT_UPDATE_REQUIRED_REASON,currentVersion=undefined){super(message);this.reason=reason;this.currentVersion=currentVersion;this.name="ClientUpdateRequiredError"}}function isClientUpdateRequiredGraphQLError(input){return input.code==="CLIENT_UPDATE_REQUIRED"}function isGraphQLSchemaMismatchError(input){if(!isGraphQLSchemaMismatchMessage(input.message))return false;return!input.code||input.code==="GRAPHQL_VALIDATION_FAILED"||input.code==="BAD_USER_INPUT"}function isGraphQLSchemaMismatchMessage(message){return/Cannot query field|Field .* does not exist|Unknown argument|Unknown type|Unknown field/i.test(message)}import{z}from"zod";function debugLog(area,payload){if(!isAreaEnabled(area))return;const line={ts:new Date().toISOString(),area,...payload};let text;try{text=JSON.stringify(line)}catch{text=JSON.stringify({ts:line.ts,area,error:"debug-log payload not serialisable"})}process.stderr.write(`${text}
|
|
2
2
|
`)}function isDebugAreaEnabled(area){return isAreaEnabled(area)}function isAreaEnabled(area){const raw=process.env.GITHITS_DEBUG;if(!raw||raw==="")return false;const scopes=raw.split(",").map((s)=>s.trim()).filter(Boolean);if(scopes.includes(area))return true;if(isExplicitOnlyArea(area))return false;return scopes.includes("*")}function isExplicitOnlyArea(area){return area==="code-nav-wire"}var DEFAULT_FETCH_TIMEOUT_MS=120000;class FetchTimeoutError extends Error{timeoutMs;constructor(timeoutMs,options){super(`Request timed out after ${timeoutMs}ms.`,options);this.name="FetchTimeoutError";this.timeoutMs=timeoutMs}}async function fetchWithTimeout(input,init={},options={}){const timeoutMs=options.timeoutMs??DEFAULT_FETCH_TIMEOUT_MS;const timeoutSignal=AbortSignal.timeout(timeoutMs);const signal=init.signal?AbortSignal.any([init.signal,timeoutSignal]):timeoutSignal;const fetchFn=options.fetchFn??globalThis.fetch;let timeoutId;const timeout=new Promise((_,reject)=>{timeoutId=setTimeout(()=>{reject(new FetchTimeoutError(timeoutMs))},timeoutMs)});try{return await Promise.race([fetchFn(input,{...init,signal}),timeout])}catch(cause){if(cause instanceof FetchTimeoutError)throw cause;if(timeoutSignal.aborted&&!init.signal?.aborted){throw new FetchTimeoutError(timeoutMs,{cause})}throw cause}finally{if(timeoutId)clearTimeout(timeoutId)}}function isFetchTimeoutError(error){return error instanceof FetchTimeoutError}class PkgseerTransportError extends Error{constructor(message,options){super(message,options);this.name="PkgseerTransportError"}}function baseUrl(endpointUrl){return endpointUrl.replace(/\/+$/,"")}async function postPkgseerGraphql(request){const userAgent=request.userAgent??"githits-cli";const timeoutMs=request.timeoutMs??DEFAULT_FETCH_TIMEOUT_MS;let response;try{response=await fetchWithTimeout(`${baseUrl(request.endpointUrl)}/api/graphql`,{method:"POST",headers:{...request.clientHeaders?.(),Authorization:`Bearer ${request.token}`,"Content-Type":"application/json","User-Agent":userAgent},body:JSON.stringify({query:request.query,variables:request.variables})},{fetchFn:request.fetchFn,timeoutMs})}catch(cause){debugLog("pkg-graphql",{event:"transport-error",errorName:cause instanceof Error?cause.name:typeof cause,hasCause:true});throw new PkgseerTransportError("Network request failed before a response was received. Caller should re-wrap with a domain-specific message.",{cause})}const responseBody=await response.text().catch(()=>"");const parsedBody=parseJsonOrNull(responseBody);return{status:response.status,responseBody,parsedBody}}function parseJsonOrNull(body){if(!body)return null;try{return JSON.parse(body)}catch{return null}}import{writeSync}from"node:fs";var ENABLED_VALUES=new Set(["1","true","yes","on"]);function isTelemetryEnabled(env=process.env){const raw=env.GITHITS_TELEMETRY?.trim().toLowerCase();if(!raw)return false;return ENABLED_VALUES.has(raw)}class TelemetryCollector{enabled;now;write;sessionStartMs;spans=[];activeSpans=new Map;nextId=1;flushed=false;constructor(options={}){this.enabled=isTelemetryEnabled(options.env);this.now=options.now??(()=>globalThis.performance.now());this.write=options.write??((text)=>writeSync(process.stderr.fd,text));this.sessionStartMs=this.now()}isEnabled(){return this.enabled}startSpan(name,attributes){if(!this.enabled)return;const span={id:this.nextId++,name,startMs:this.now(),attributes:sanitiseAttributes(attributes)};this.spans.push(span);this.activeSpans.set(span.id,span);return{id:span.id}}endSpan(handle,attributes){if(!this.enabled||!handle)return;const span=this.activeSpans.get(handle.id);if(!span||span.endMs!==undefined)return;span.endMs=this.now();span.attributes=mergeAttributes(span.attributes,attributes);this.activeSpans.delete(handle.id)}flush(exitCode=0){if(!this.enabled||this.flushed)return;const nowMs=this.now();for(const span of this.activeSpans.values()){if(span.endMs!==undefined)continue;span.endMs=nowMs;span.endedAtExit=true}this.activeSpans.clear();this.write(formatTelemetryReport(this.spans,this.sessionStartMs,nowMs,exitCode));this.flushed=true}}async function withTelemetrySpan(name,operation,attributes){const handle=telemetryCollector.startSpan(name,attributes);try{const result=await operation();telemetryCollector.endSpan(handle);return result}catch(error){telemetryCollector.endSpan(handle,{error:true});throw error}}function startTelemetrySpan(name,attributes){return telemetryCollector.startSpan(name,attributes)}function endTelemetrySpan(handle,attributes){telemetryCollector.endSpan(handle,attributes)}function flushTelemetry(exitCode=0){telemetryCollector.flush(exitCode)}var telemetryCollector=new TelemetryCollector;function sanitiseAttributes(attributes){if(!attributes)return;const entries=Object.entries(attributes).filter(([,value])=>value!==undefined);if(entries.length===0)return;return Object.fromEntries(entries)}function mergeAttributes(initial,extra){if(!initial&&!extra)return;return sanitiseAttributes({...initial??{},...extra??{}})}function formatTelemetryReport(spans,sessionStartMs,sessionEndMs,exitCode){const lines=["[githits telemetry]",`exit: ${exitCode}`,`total: ${formatMs(sessionEndMs-sessionStartMs)}`];const orderedSpans=[...spans].sort((left,right)=>{if(left.startMs!==right.startMs){return left.startMs-right.startMs}return left.id-right.id});for(const span of orderedSpans){const endMs=span.endMs??sessionEndMs;const details=[`start +${formatMs(span.startMs-sessionStartMs)}`];if(span.endedAtExit){details.push("ended-at-exit")}const attrs=formatAttributes(span.attributes);if(attrs){details.push(attrs)}lines.push(`- ${span.name}: ${formatMs(endMs-span.startMs)} (${details.join(", ")})`)}return`${lines.join(`
|
|
3
3
|
`)}
|
|
4
|
-
`}function formatAttributes(attributes){if(!attributes)return"";return Object.entries(attributes).map(([key,value])=>`${key}=${String(value)}`).join(" ")}function formatMs(value){return`${value.toFixed(1)}ms`}var AUTHENTICATION_REQUIRED_MESSAGE="Authentication required.";var LOCAL_AUTHENTICATION_MISSING_MESSAGE="No local GitHits authentication token found.";var SERVER_AUTHENTICATION_REJECTED_MESSAGE="GitHits could not accept the authentication token.";class AuthenticationError extends Error{source;constructor(message=AUTHENTICATION_REQUIRED_MESSAGE,source="local"){super(message);this.name="AuthenticationError";this.source=source}}function parseDetail(body){if(!body)return;try{const parsed=JSON.parse(body);if(typeof parsed.detail==="string")return parsed.detail}catch{return body}return}class GitHitsServiceImpl{apiUrl;token;fetchFn;fetchTimeoutMs;runtime;constructor(apiUrl,token,fetchFn,fetchTimeoutMs=DEFAULT_FETCH_TIMEOUT_MS,runtime={}){this.apiUrl=apiUrl;this.token=token;this.fetchFn=fetchFn;this.fetchTimeoutMs=fetchTimeoutMs;this.runtime=runtime}async search(params){return withTelemetrySpan("githits.search.request",async()=>{const response=await fetchWithTimeout(`${this.apiUrl}/search`,{method:"POST",headers:this.headers(),body:JSON.stringify({query:params.query,language:params.language,license_mode:params.licenseMode??"strict",include_explanation:params.includeExplanation??false})},this.fetchOptions());if(!response.ok){throw await this.createError(response)}return response.text()})}async getLanguages(){return withTelemetrySpan("githits.languages.request",async()=>{const response=await fetchWithTimeout(`${this.apiUrl}/languages`,{headers:this.headers()},this.fetchOptions());if(!response.ok){throw await this.createError(response)}return response.json()})}async searchLanguages(query,limit=5){return withTelemetrySpan("githits.languages.search.request",async()=>{const params=new URLSearchParams({query,limit:String(limit)});const response=await fetchWithTimeout(`${this.apiUrl}/languages?${params.toString()}`,{headers:this.headers()},this.fetchOptions());if(!response.ok){throw await this.createError(response)}return response.json()})}async submitFeedback(params){return withTelemetrySpan("githits.feedback.request",async()=>{const response=await fetchWithTimeout(`${this.apiUrl}/feedbacks`,{method:"POST",headers:this.headers(),body:JSON.stringify({...params.exampleId!==undefined&&{example_id:params.exampleId},...params.solutionId!==undefined&&{solution_id:params.solutionId},accepted:params.accepted,feedback_text:params.feedbackText??null,...params.toolName!==undefined&&{tool_name:params.toolName}})},this.fetchOptions());if(!response.ok){throw await this.createError(response)}return{success:true,message:"Feedback submitted successfully"}})}headers(){return{...this.runtime.clientHeaders?.(),Authorization:`Bearer ${this.token}`,"Content-Type":"application/json","User-Agent":this.runtime.userAgent??"githits-cli"}}fetchOptions(){return{fetchFn:this.fetchFn,timeoutMs:this.fetchTimeoutMs}}async createError(response){const status=response.status;const body=await response.text().catch(()=>"");switch(status){case 401:return new AuthenticationError(SERVER_AUTHENTICATION_REJECTED_MESSAGE,"server");case 403:return new Error("Access denied.");case 404:return new Error(parseDetail(body)||"Resource not found.");default:{if(status>=500){const detail=body?`: ${body}`:"";return new Error(`Server error (${status})${detail}`)}return new Error(body||`Request failed with status ${status}`)}}}}async function executeWithTokenRefresh(options){const token=await options.getToken();if(!token){throw new AuthenticationError(LOCAL_AUTHENTICATION_MISSING_MESSAGE,"local")}try{return await options.executeWithToken(token)}catch(error){if(!options.shouldRefresh(error)){throw error}const refreshedToken=await options.forceRefresh();if(!refreshedToken){throw error}return options.executeWithToken(refreshedToken)}}class CodeNavigationAccessError extends Error{constructor(message){super(message);this.name="CodeNavigationAccessError"}}class CodeNavigationGraphQLError extends Error{code;constructor(message,code){super(message);this.code=code;this.name="CodeNavigationGraphQLError"}}class CodeNavigationIndexingError extends Error{indexingRef;availableVersions;availableRefs;targetResolution;constructor(message,indexingRef,availableVersions,availableRefs,targetResolution=undefined){super(message);this.indexingRef=indexingRef;this.availableVersions=availableVersions;this.availableRefs=availableRefs;this.targetResolution=targetResolution;this.name="CodeNavigationIndexingError"}}class CodeNavigationUnresolvableError extends Error{constructor(message){super(message);this.name="CodeNavigationUnresolvableError"}}class MalformedCodeNavigationResponseError extends Error{constructor(message){super(message);this.name="MalformedCodeNavigationResponseError"}}class CodeNavigationTargetNotFoundError extends Error{availableVersions;constructor(message,availableVersions){super(message);this.availableVersions=availableVersions;this.name="CodeNavigationTargetNotFoundError"}}class CodeNavigationFileNotFoundError extends Error{filePath;constructor(message,filePath){super(message);this.filePath=filePath;this.name="CodeNavigationFileNotFoundError"}}class CodeNavigationVersionNotFoundError extends Error{packageName;requestedVersion;latestIndexed;availableVersions;constructor(message,packageName,requestedVersion,latestIndexed,availableVersions){super(message);this.packageName=packageName;this.requestedVersion=requestedVersion;this.latestIndexed=latestIndexed;this.availableVersions=availableVersions;this.name="CodeNavigationVersionNotFoundError"}}class CodeNavigationValidationError extends Error{constructor(message){super(message);this.name="CodeNavigationValidationError"}}class CodeNavigationFeatureFlagRequiredError extends Error{constructor(message){super(message);this.name="CodeNavigationFeatureFlagRequiredError"}}class CodeNavigationNetworkError extends Error{constructor(message,options){super(message,options);this.name="CodeNavigationNetworkError"}}class CodeNavigationBackendError extends Error{status;graphqlCode;retryable;constructor(message,status,graphqlCode,retryable){super(message);this.status=status;this.graphqlCode=graphqlCode;this.retryable=retryable;this.name="CodeNavigationBackendError"}}var TARGET_RESOLUTION_AVAILABLE_REFS_SELECTION=`
|
|
4
|
+
`}function formatAttributes(attributes){if(!attributes)return"";return Object.entries(attributes).map(([key,value])=>`${key}=${String(value)}`).join(" ")}function formatMs(value){return`${value.toFixed(1)}ms`}var AUTHENTICATION_REQUIRED_MESSAGE="Authentication required.";var LOCAL_AUTHENTICATION_MISSING_MESSAGE="No local GitHits authentication token found.";var SERVER_AUTHENTICATION_REJECTED_MESSAGE="GitHits could not accept the authentication token.";class AuthenticationError extends Error{source;constructor(message=AUTHENTICATION_REQUIRED_MESSAGE,source="local"){super(message);this.name="AuthenticationError";this.source=source}}function parseDetail(body){if(!body)return;try{const parsed=JSON.parse(body);if(typeof parsed.detail==="string")return parsed.detail}catch{return body}return}class GitHitsServiceImpl{apiUrl;token;fetchFn;fetchTimeoutMs;runtime;constructor(apiUrl,token,fetchFn,fetchTimeoutMs=DEFAULT_FETCH_TIMEOUT_MS,runtime={}){this.apiUrl=apiUrl;this.token=token;this.fetchFn=fetchFn;this.fetchTimeoutMs=fetchTimeoutMs;this.runtime=runtime}async search(params){return withTelemetrySpan("githits.search.request",async()=>{const response=await fetchWithTimeout(`${this.apiUrl}/search`,{method:"POST",headers:this.headers(),body:JSON.stringify({query:params.query,language:params.language,license_mode:params.licenseMode??"strict",include_explanation:params.includeExplanation??false})},this.fetchOptions());if(!response.ok){throw await this.createError(response)}return response.text()})}async getLanguages(){return withTelemetrySpan("githits.languages.request",async()=>{const response=await fetchWithTimeout(`${this.apiUrl}/languages`,{headers:this.headers()},this.fetchOptions());if(!response.ok){throw await this.createError(response)}return response.json()})}async searchLanguages(query,limit=5){return withTelemetrySpan("githits.languages.search.request",async()=>{const params=new URLSearchParams({query,limit:String(limit)});const response=await fetchWithTimeout(`${this.apiUrl}/languages?${params.toString()}`,{headers:this.headers()},this.fetchOptions());if(!response.ok){throw await this.createError(response)}return response.json()})}async submitFeedback(params){return withTelemetrySpan("githits.feedback.request",async()=>{const response=await fetchWithTimeout(`${this.apiUrl}/feedbacks`,{method:"POST",headers:this.headers(),body:JSON.stringify({...params.exampleId!==undefined&&{example_id:params.exampleId},...params.solutionId!==undefined&&{solution_id:params.solutionId},accepted:params.accepted,feedback_text:params.feedbackText??null,...params.toolName!==undefined&&{tool_name:params.toolName}})},this.fetchOptions());if(!response.ok){throw await this.createError(response)}return{success:true,message:"Feedback submitted successfully"}})}headers(){return{...this.runtime.clientHeaders?.(),Authorization:`Bearer ${this.token}`,"Content-Type":"application/json","User-Agent":this.runtime.userAgent??"githits-cli"}}fetchOptions(){return{fetchFn:this.fetchFn,timeoutMs:this.fetchTimeoutMs}}async createError(response){const status=response.status;const body=await response.text().catch(()=>"");switch(status){case 401:return new AuthenticationError(SERVER_AUTHENTICATION_REJECTED_MESSAGE,"server");case 403:return new Error("Access denied.");case 404:return new Error(parseDetail(body)||"Resource not found.");default:{if(status>=500){const detail=body?`: ${body}`:"";return new Error(`Server error (${status})${detail}`)}return new Error(body||`Request failed with status ${status}`)}}}}async function executeWithTokenRefresh(options){const token=await options.getToken();if(!token){throw new AuthenticationError(LOCAL_AUTHENTICATION_MISSING_MESSAGE,"local")}try{return await options.executeWithToken(token)}catch(error){if(!options.shouldRefresh(error)){throw error}const refreshedToken=await options.forceRefresh();if(!refreshedToken){throw error}return options.executeWithToken(refreshedToken)}}class CodeNavigationAccessError extends Error{constructor(message){super(message);this.name="CodeNavigationAccessError"}}class CodeNavigationGraphQLError extends Error{code;constructor(message,code){super(message);this.code=code;this.name="CodeNavigationGraphQLError"}}class CodeNavigationIndexingError extends Error{indexingRef;availableVersions;availableRefs;targetResolution;constructor(message,indexingRef,availableVersions,availableRefs,targetResolution=undefined){super(message);this.indexingRef=indexingRef;this.availableVersions=availableVersions;this.availableRefs=availableRefs;this.targetResolution=targetResolution;this.name="CodeNavigationIndexingError"}}class CodeNavigationUnresolvableError extends Error{constructor(message){super(message);this.name="CodeNavigationUnresolvableError"}}class MalformedCodeNavigationResponseError extends Error{constructor(message){super(message);this.name="MalformedCodeNavigationResponseError"}}class CodeNavigationTargetNotFoundError extends Error{availableVersions;constructor(message,availableVersions){super(message);this.availableVersions=availableVersions;this.name="CodeNavigationTargetNotFoundError"}}class CodeNavigationFileNotFoundError extends Error{filePath;constructor(message,filePath){super(message);this.filePath=filePath;this.name="CodeNavigationFileNotFoundError"}}class CodeNavigationVersionNotFoundError extends Error{packageName;requestedVersion;latestIndexed;availableVersions;constructor(message,packageName,requestedVersion,latestIndexed,availableVersions){super(message);this.packageName=packageName;this.requestedVersion=requestedVersion;this.latestIndexed=latestIndexed;this.availableVersions=availableVersions;this.name="CodeNavigationVersionNotFoundError"}}class CodeNavigationRefNotFoundError extends Error{repoUrl;requestedRef;availableRefs;suggestedRefs;constructor(message,repoUrl,requestedRef,availableRefs,suggestedRefs){super(message);this.repoUrl=repoUrl;this.requestedRef=requestedRef;this.availableRefs=availableRefs;this.suggestedRefs=suggestedRefs;this.name="CodeNavigationRefNotFoundError"}}class CodeNavigationValidationError extends Error{constructor(message){super(message);this.name="CodeNavigationValidationError"}}class CodeNavigationFeatureFlagRequiredError extends Error{constructor(message){super(message);this.name="CodeNavigationFeatureFlagRequiredError"}}class CodeNavigationNetworkError extends Error{constructor(message,options){super(message,options);this.name="CodeNavigationNetworkError"}}class CodeNavigationBackendError extends Error{status;graphqlCode;retryable;constructor(message,status,graphqlCode,retryable){super(message);this.status=status;this.graphqlCode=graphqlCode;this.retryable=retryable;this.name="CodeNavigationBackendError"}}var TARGET_RESOLUTION_AVAILABLE_REFS_SELECTION=`
|
|
5
5
|
availableRefs {
|
|
6
6
|
version
|
|
7
7
|
ref
|
|
8
|
+
}`;var TARGET_RESOLUTION_SUGGESTED_REFS_SELECTION=`
|
|
9
|
+
suggestedRefs {
|
|
10
|
+
version
|
|
11
|
+
ref
|
|
12
|
+
}`;var DISCOVERY_TARGET_PROGRESS_SUGGESTED_REFS_SELECTION=`
|
|
13
|
+
suggestedRefs {
|
|
14
|
+
version
|
|
15
|
+
ref
|
|
8
16
|
}`;var TARGET_RESOLUTION_SELECTION=`
|
|
9
17
|
targetResolution {
|
|
10
18
|
requested {
|
|
@@ -42,6 +50,7 @@ targetResolution {
|
|
|
42
50
|
ref
|
|
43
51
|
}
|
|
44
52
|
${TARGET_RESOLUTION_AVAILABLE_REFS_SELECTION}
|
|
53
|
+
${TARGET_RESOLUTION_SUGGESTED_REFS_SELECTION}
|
|
45
54
|
}`;var CODE_CONTEXT_AVAILABLE_VERSIONS_SELECTION=`
|
|
46
55
|
availableVersions {
|
|
47
56
|
version
|
|
@@ -54,7 +63,8 @@ availableVersions {
|
|
|
54
63
|
availableRefs {
|
|
55
64
|
version
|
|
56
65
|
ref
|
|
57
|
-
}
|
|
66
|
+
}
|
|
67
|
+
${DISCOVERY_TARGET_PROGRESS_SUGGESTED_REFS_SELECTION}`;var UNIFIED_SEARCH_QUERY=`
|
|
58
68
|
query UnifiedSearch(
|
|
59
69
|
$targets: [SearchPackageInput!]!
|
|
60
70
|
$query: String!
|
|
@@ -290,7 +300,7 @@ query UnifiedSearchStatus($searchRef: String!, $includeResults: Boolean!) {
|
|
|
290
300
|
}
|
|
291
301
|
}
|
|
292
302
|
}
|
|
293
|
-
}`;function debugUnifiedSearchRequest(variables){if(!isDebugAreaEnabled("code-nav"))return;const serialised=serialiseForDebug(variables);const filters=asRecord(serialised.filters);debugLog("code-nav",{event:"request",operation:"search",targetCount:Array.isArray(serialised.targets)?serialised.targets.length:0,sources:Array.isArray(serialised.sources)?serialised.sources:[],hasFilters:filters!==undefined,filterKeys:filters?Object.keys(filters).sort():[],fileIntent:filters&&typeof filters.fileIntent==="string"?filters.fileIntent:"omitted",allowPartialResults:serialised.allowPartialResults===true,presentVariableKeys:Object.keys(serialised).sort(),hasLimit:typeof serialised.limit==="number",hasOffset:typeof serialised.offset==="number",waitTimeoutMs:typeof serialised.waitTimeoutMs==="number"?serialised.waitTimeoutMs:undefined})}function debugGraphqlWireRequest(operation,graphqlQuery,variables){if(!isDebugAreaEnabled("code-nav-wire"))return;debugLog("code-nav-wire",{event:"wire-request",operation,graphqlQuery,variables:serialiseForDebug(variables)})}function serialiseForDebug(value){try{const text=JSON.stringify(value);if(!text)return{};const parsed=JSON.parse(text);return asRecord(parsed)??{}}catch{return{}}}function asRecord(value){if(value&&typeof value==="object"&&!Array.isArray(value)){return value}return}var availableVersionSchema=z.object({version:z.string().nullable().optional(),ref:z.string()});var targetResolutionIdentitySchema=z.object({kind:z.string().nullable().optional(),registry:z.string().nullable().optional(),packageName:z.string().nullable().optional(),version:z.string().nullable().optional(),repoUrl:z.string().nullable().optional(),gitRef:z.string().nullable().optional(),commitSha:z.string().nullable().optional()}).nullable().optional();var targetResolutionSchema=z.object({requested:targetResolutionIdentitySchema,resolvedRequested:targetResolutionIdentitySchema,served:targetResolutionIdentitySchema,freshness:z.string().nullable().optional(),freshnessReason:z.string().nullable().optional(),indexingRef:z.string().nullable().optional(),availableVersions:z.array(availableVersionSchema).nullable().optional(),availableRefs:z.array(availableVersionSchema).nullable().optional()}).nullable().optional();var unifiedSearchSourceSchema=z.enum(["AUTO","DOCS","CODE","SYMBOL"]);var unifiedSearchResultTypeSchema=z.enum(["DOCUMENTATION_PAGE","REPOSITORY_SYMBOL","REPOSITORY_CODE","REPOSITORY_DOC"]);var unifiedSearchLocatorSchema=z.object({registry:z.string().nullable().optional(),packageName:z.string().nullable().optional(),version:z.string().nullable().optional(),pageId:z.string().nullable().optional(),sourceKind:z.string().nullable().optional(),sourceUrl:z.string().nullable().optional(),repoUrl:z.string().nullable().optional(),gitRef:z.string().nullable().optional(),requestedRef:z.string().nullable().optional(),filePath:z.string().nullable().optional(),startLine:z.number().int().nullable().optional(),endLine:z.number().int().nullable().optional(),fileContentHash:z.string().nullable().optional(),symbolRef:z.string().nullable().optional(),qualifiedPath:z.string().nullable().optional(),kind:z.string().nullable().optional(),category:z.string().nullable().optional(),language:z.string().nullable().optional()});var unifiedSearchHitSchema=z.object({id:z.string(),resultType:unifiedSearchResultTypeSchema,targetLabel:z.string(),requestedTargetLabel:z.string().nullable().optional(),freshTargetLabel:z.string().nullable().optional(),servedTargetLabel:z.string().nullable().optional(),freshness:z.string().nullable().optional(),title:z.string().nullable().optional(),summary:z.string().nullable().optional(),score:z.number().nullable().optional(),highlights:z.object({title:z.array(z.tuple([z.number().int(),z.number().int()])).nullable().optional(),summary:z.array(z.tuple([z.number().int(),z.number().int()])).nullable().optional()}).nullable().optional(),locator:unifiedSearchLocatorSchema});var unifiedSearchPageInfoSchema=z.object({offset:z.number().int(),limit:z.number().int(),returned:z.number().int(),hasMore:z.boolean()});var unifiedSearchSourceStatusSchema=z.object({source:unifiedSearchSourceSchema,targetLabel:z.string(),requestedTargetLabel:z.string().nullable().optional(),freshTargetLabel:z.string().nullable().optional(),servedTargetLabel:z.string().nullable().optional(),targetResolution:targetResolutionSchema,indexingStatus:z.string().nullable().optional(),codeIndexState:z.string().nullable().optional(),resultCount:z.number().int().nullable().optional(),appliedFilters:z.array(z.string()),ignoredFilters:z.array(z.string()),incompatibleFilters:z.array(z.string()),appliedQueryFeatures:z.array(z.string()),ignoredQueryFeatures:z.array(z.string()),incompatibleQueryFeatures:z.array(z.string()),note:z.string().nullable().optional()});var unifiedSearchResultSchema=z.object({query:z.string(),queryWarnings:z.array(z.string()),sources:z.array(unifiedSearchSourceSchema),results:z.array(unifiedSearchHitSchema),page:unifiedSearchPageInfoSchema,partialResults:z.boolean(),sourceStatus:z.array(unifiedSearchSourceStatusSchema)});var unifiedSearchSessionStatusSchema=z.enum(["PENDING","INDEXING","SEARCHING","COMPLETED","TIMEOUT","FAILED"]);var unifiedSearchFiltersSchema=z.object({fileIntent:z.string().nullable().optional(),kind:z.string().nullable().optional(),category:z.string().nullable().optional(),publicOnly:z.boolean().nullable().optional(),pathPrefix:z.string().nullable().optional()}).nullable().optional();var unifiedSearchProgressTargetSchema=z.object({requested:z.string().nullable().optional(),resolvedRequested:z.string().nullable().optional(),served:z.string().nullable().optional(),freshness:z.string().nullable().optional(),indexingRef:z.string().nullable().optional(),requestedRefKind:z.string().nullable().optional(),targetResolution:targetResolutionSchema,availableVersions:z.array(availableVersionSchema).nullable().optional(),availableRefs:z.array(availableVersionSchema).nullable().optional()});var unifiedSearchRequestedTargetSchema=z.object({registry:z.string().nullable().optional(),name:z.string().nullable().optional(),version:z.string().nullable().optional(),repoUrl:z.string().nullable().optional(),gitRef:z.string().nullable().optional()});var unifiedSearchProgressSchema=z.object({searchRef:z.string(),status:unifiedSearchSessionStatusSchema,targetsTotal:z.number().int(),targetsReady:z.number().int(),elapsedMs:z.number().int(),query:z.string(),queryWarnings:z.array(z.string()),sources:z.array(unifiedSearchSourceSchema),requestedSources:z.array(unifiedSearchSourceSchema).nullable().optional(),targetMode:z.string().nullable().optional(),requestedTargets:z.array(unifiedSearchRequestedTargetSchema).nullable().optional(),filters:unifiedSearchFiltersSchema,limit:z.number().int().nullable().optional(),offset:z.number().int().nullable().optional(),targets:z.array(unifiedSearchProgressTargetSchema).nullable().optional(),expiresAt:z.string().nullable().optional(),results:unifiedSearchResultSchema.nullable().optional()});var asyncUnifiedSearchResultSchema=z.object({completed:z.boolean(),searchRef:z.string().nullable().optional(),result:unifiedSearchResultSchema.nullable().optional(),progress:unifiedSearchProgressSchema.nullable().optional()});var graphQLErrorSchema=z.object({message:z.string(),extensions:z.record(z.string(),z.unknown()).optional()});var navigationResolutionSchema=z.object({requestedVersion:z.string().nullable().optional(),requestedRef:z.string().nullable().optional(),resolvedRef:z.string().nullable().optional(),commitSha:z.string().nullable().optional()}).nullable().optional();var navigationDiagnosticsSchema=z.object({hint:z.string().nullable().optional()}).nullable().optional();var repoFileEntrySchema=z.object({path:z.string(),name:z.string().nullable().optional(),language:z.string().nullable().optional(),fileType:z.string().nullable().optional(),byteSize:z.number().int().nullable().optional()});var listRepoFilesResponseSchema=z.object({files:z.array(repoFileEntrySchema),total:z.number().int(),hasMore:z.boolean(),indexedVersion:z.string().nullable().optional(),resolution:navigationResolutionSchema,targetResolution:targetResolutionSchema,diagnostics:navigationDiagnosticsSchema,codeIndexState:z.string(),indexingRef:z.string().nullable().optional(),availableVersions:z.array(availableVersionSchema).nullable().optional()});var listRepoFilesGraphQLResponseSchema=z.object({data:z.object({listRepoFiles:listRepoFilesResponseSchema.nullable().optional()}).nullable().optional(),errors:z.array(graphQLErrorSchema).optional()});var LIST_REPO_FILES_QUERY=`
|
|
303
|
+
}`;function debugUnifiedSearchRequest(variables){if(!isDebugAreaEnabled("code-nav"))return;const serialised=serialiseForDebug(variables);const filters=asRecord(serialised.filters);debugLog("code-nav",{event:"request",operation:"search",targetCount:Array.isArray(serialised.targets)?serialised.targets.length:0,sources:Array.isArray(serialised.sources)?serialised.sources:[],hasFilters:filters!==undefined,filterKeys:filters?Object.keys(filters).sort():[],fileIntent:filters&&typeof filters.fileIntent==="string"?filters.fileIntent:"omitted",allowPartialResults:serialised.allowPartialResults===true,presentVariableKeys:Object.keys(serialised).sort(),hasLimit:typeof serialised.limit==="number",hasOffset:typeof serialised.offset==="number",waitTimeoutMs:typeof serialised.waitTimeoutMs==="number"?serialised.waitTimeoutMs:undefined})}function debugGraphqlWireRequest(operation,graphqlQuery,variables){if(!isDebugAreaEnabled("code-nav-wire"))return;debugLog("code-nav-wire",{event:"wire-request",operation,graphqlQuery,variables:serialiseForDebug(variables)})}function serialiseForDebug(value){try{const text=JSON.stringify(value);if(!text)return{};const parsed=JSON.parse(text);return asRecord(parsed)??{}}catch{return{}}}function asRecord(value){if(value&&typeof value==="object"&&!Array.isArray(value)){return value}return}var availableVersionSchema=z.object({version:z.string().nullable().optional(),ref:z.string()});var targetResolutionIdentitySchema=z.object({kind:z.string().nullable().optional(),registry:z.string().nullable().optional(),packageName:z.string().nullable().optional(),version:z.string().nullable().optional(),repoUrl:z.string().nullable().optional(),gitRef:z.string().nullable().optional(),commitSha:z.string().nullable().optional()}).nullable().optional();var targetResolutionSchema=z.object({requested:targetResolutionIdentitySchema,resolvedRequested:targetResolutionIdentitySchema,served:targetResolutionIdentitySchema,freshness:z.string().nullable().optional(),freshnessReason:z.string().nullable().optional(),indexingRef:z.string().nullable().optional(),availableVersions:z.array(availableVersionSchema).nullable().optional(),availableRefs:z.array(availableVersionSchema).nullable().optional(),suggestedRefs:z.array(availableVersionSchema).nullable().optional()}).nullable().optional();var unifiedSearchSourceSchema=z.enum(["AUTO","DOCS","CODE","SYMBOL"]);var unifiedSearchResultTypeSchema=z.enum(["DOCUMENTATION_PAGE","REPOSITORY_SYMBOL","REPOSITORY_CODE","REPOSITORY_DOC"]);var unifiedSearchLocatorSchema=z.object({registry:z.string().nullable().optional(),packageName:z.string().nullable().optional(),version:z.string().nullable().optional(),pageId:z.string().nullable().optional(),sourceKind:z.string().nullable().optional(),sourceUrl:z.string().nullable().optional(),repoUrl:z.string().nullable().optional(),gitRef:z.string().nullable().optional(),requestedRef:z.string().nullable().optional(),filePath:z.string().nullable().optional(),startLine:z.number().int().nullable().optional(),endLine:z.number().int().nullable().optional(),fileContentHash:z.string().nullable().optional(),symbolRef:z.string().nullable().optional(),qualifiedPath:z.string().nullable().optional(),kind:z.string().nullable().optional(),category:z.string().nullable().optional(),language:z.string().nullable().optional()});var unifiedSearchHitSchema=z.object({id:z.string(),resultType:unifiedSearchResultTypeSchema,targetLabel:z.string(),requestedTargetLabel:z.string().nullable().optional(),freshTargetLabel:z.string().nullable().optional(),servedTargetLabel:z.string().nullable().optional(),freshness:z.string().nullable().optional(),title:z.string().nullable().optional(),summary:z.string().nullable().optional(),score:z.number().nullable().optional(),highlights:z.object({title:z.array(z.tuple([z.number().int(),z.number().int()])).nullable().optional(),summary:z.array(z.tuple([z.number().int(),z.number().int()])).nullable().optional()}).nullable().optional(),locator:unifiedSearchLocatorSchema});var unifiedSearchPageInfoSchema=z.object({offset:z.number().int(),limit:z.number().int(),returned:z.number().int(),hasMore:z.boolean()});var unifiedSearchSourceStatusSchema=z.object({source:unifiedSearchSourceSchema,targetLabel:z.string(),requestedTargetLabel:z.string().nullable().optional(),freshTargetLabel:z.string().nullable().optional(),servedTargetLabel:z.string().nullable().optional(),targetResolution:targetResolutionSchema,indexingStatus:z.string().nullable().optional(),codeIndexState:z.string().nullable().optional(),resultCount:z.number().int().nullable().optional(),appliedFilters:z.array(z.string()),ignoredFilters:z.array(z.string()),incompatibleFilters:z.array(z.string()),appliedQueryFeatures:z.array(z.string()),ignoredQueryFeatures:z.array(z.string()),incompatibleQueryFeatures:z.array(z.string()),note:z.string().nullable().optional()});var unifiedSearchResultSchema=z.object({query:z.string(),queryWarnings:z.array(z.string()),sources:z.array(unifiedSearchSourceSchema),results:z.array(unifiedSearchHitSchema),page:unifiedSearchPageInfoSchema,partialResults:z.boolean(),sourceStatus:z.array(unifiedSearchSourceStatusSchema)});var unifiedSearchSessionStatusSchema=z.enum(["PENDING","INDEXING","SEARCHING","COMPLETED","TIMEOUT","FAILED"]);var unifiedSearchFiltersSchema=z.object({fileIntent:z.string().nullable().optional(),kind:z.string().nullable().optional(),category:z.string().nullable().optional(),publicOnly:z.boolean().nullable().optional(),pathPrefix:z.string().nullable().optional()}).nullable().optional();var unifiedSearchProgressTargetSchema=z.object({requested:z.string().nullable().optional(),resolvedRequested:z.string().nullable().optional(),served:z.string().nullable().optional(),freshness:z.string().nullable().optional(),indexingRef:z.string().nullable().optional(),requestedRefKind:z.string().nullable().optional(),targetResolution:targetResolutionSchema,availableVersions:z.array(availableVersionSchema).nullable().optional(),availableRefs:z.array(availableVersionSchema).nullable().optional(),suggestedRefs:z.array(availableVersionSchema).nullable().optional()});var unifiedSearchRequestedTargetSchema=z.object({registry:z.string().nullable().optional(),name:z.string().nullable().optional(),version:z.string().nullable().optional(),repoUrl:z.string().nullable().optional(),gitRef:z.string().nullable().optional()});var unifiedSearchProgressSchema=z.object({searchRef:z.string(),status:unifiedSearchSessionStatusSchema,targetsTotal:z.number().int(),targetsReady:z.number().int(),elapsedMs:z.number().int(),query:z.string(),queryWarnings:z.array(z.string()),sources:z.array(unifiedSearchSourceSchema),requestedSources:z.array(unifiedSearchSourceSchema).nullable().optional(),targetMode:z.string().nullable().optional(),requestedTargets:z.array(unifiedSearchRequestedTargetSchema).nullable().optional(),filters:unifiedSearchFiltersSchema,limit:z.number().int().nullable().optional(),offset:z.number().int().nullable().optional(),targets:z.array(unifiedSearchProgressTargetSchema).nullable().optional(),expiresAt:z.string().nullable().optional(),results:unifiedSearchResultSchema.nullable().optional()});var asyncUnifiedSearchResultSchema=z.object({completed:z.boolean(),searchRef:z.string().nullable().optional(),result:unifiedSearchResultSchema.nullable().optional(),progress:unifiedSearchProgressSchema.nullable().optional()});var graphQLErrorSchema=z.object({message:z.string(),extensions:z.record(z.string(),z.unknown()).optional()});var navigationResolutionSchema=z.object({requestedVersion:z.string().nullable().optional(),requestedRef:z.string().nullable().optional(),resolvedRef:z.string().nullable().optional(),commitSha:z.string().nullable().optional()}).nullable().optional();var navigationDiagnosticsSchema=z.object({hint:z.string().nullable().optional()}).nullable().optional();var repoFileEntrySchema=z.object({path:z.string(),name:z.string().nullable().optional(),language:z.string().nullable().optional(),fileType:z.string().nullable().optional(),byteSize:z.number().int().nullable().optional()});var listRepoFilesResponseSchema=z.object({files:z.array(repoFileEntrySchema),total:z.number().int(),hasMore:z.boolean(),indexedVersion:z.string().nullable().optional(),resolution:navigationResolutionSchema,targetResolution:targetResolutionSchema,diagnostics:navigationDiagnosticsSchema,codeIndexState:z.string(),indexingRef:z.string().nullable().optional(),availableVersions:z.array(availableVersionSchema).nullable().optional()});var listRepoFilesGraphQLResponseSchema=z.object({data:z.object({listRepoFiles:listRepoFilesResponseSchema.nullable().optional()}).nullable().optional(),errors:z.array(graphQLErrorSchema).optional()});var LIST_REPO_FILES_QUERY=`
|
|
294
304
|
query ListRepoFiles(
|
|
295
305
|
$registry: Registry
|
|
296
306
|
$packageName: String
|
|
@@ -481,8 +491,12 @@ query GrepRepo(
|
|
|
481
491
|
ref
|
|
482
492
|
}
|
|
483
493
|
}
|
|
484
|
-
}`}var unifiedSearchGraphQLResponseSchema=z.object({data:z.object({search:asyncUnifiedSearchResultSchema.nullable().optional()}).nullable().optional(),errors:z.array(graphQLErrorSchema).optional()});var unifiedSearchStatusGraphQLResponseSchema=z.object({data:z.object({discoverySearchProgress:unifiedSearchProgressSchema.nullable().optional()}).nullable().optional(),errors:z.array(graphQLErrorSchema).optional()});class CodeNavigationServiceImpl{codeNavigationUrl;tokenProvider;fetchFn;runtime;constructor(codeNavigationUrl,tokenProvider,fetchFn=globalThis.fetch,runtime={}){this.codeNavigationUrl=codeNavigationUrl;this.tokenProvider=tokenProvider;this.fetchFn=fetchFn;this.runtime=runtime}async postGraphqlWithTargetResolutionFallback(input){const response=await postPkgseerGraphql({endpointUrl:this.codeNavigationUrl,token:input.token,query:input.query,variables:input.variables,fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent});if(response.status<200||response.status>=300)return response;if(!hasSchemaMismatchErrors(response.parsedBody))return response;for(const fallbackQuery of buildTargetResolutionFallbackQueries(input.query)){debugLog("code-nav",{event:"target-resolution-query-fallback"});const fallbackResponse=await postPkgseerGraphql({endpointUrl:this.codeNavigationUrl,token:input.token,query:fallbackQuery,variables:input.variables,fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent});if(!hasSchemaMismatchErrors(fallbackResponse.parsedBody)){return fallbackResponse}}return response}async search(params){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:(error)=>error instanceof AuthenticationError,executeWithToken:(token)=>this.executeUnifiedSearch(token,params)})}async searchStatus(searchRef){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:(error)=>error instanceof AuthenticationError,executeWithToken:(token)=>this.executeUnifiedSearchStatus(token,searchRef)})}async executeUnifiedSearch(token,params){if(params.targets.length===0){throw new CodeNavigationValidationError("At least one search target is required.")}let response;const variables={targets:params.targets.map((target)=>({registry:target.registry,name:target.packageName,version:target.version,repoUrl:target.repoUrl,gitRef:target.gitRef})),query:params.query,sources:params.sources,filters:params.filters,allowPartialResults:params.allowPartialResults??false,limit:params.limit,offset:params.offset,waitTimeoutMs:params.waitTimeoutMs};debugUnifiedSearchRequest(variables);debugGraphqlWireRequest("search",UNIFIED_SEARCH_QUERY,variables);try{response=await this.postGraphqlWithTargetResolutionFallback({token,query:UNIFIED_SEARCH_QUERY,variables})}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=unifiedSearchGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.search;if(!data){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}return this.normaliseUnifiedSearchOutcome(data)}async executeUnifiedSearchStatus(token,searchRef){let response;try{response=await this.postGraphqlWithTargetResolutionFallback({token,query:UNIFIED_SEARCH_STATUS_QUERY,variables:{searchRef,includeResults:true}})}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=unifiedSearchStatusGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.discoverySearchProgress;if(!data){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}const progress=this.normaliseUnifiedSearchProgress(data);const result=data.results?this.normaliseUnifiedSearchResult(data.results):undefined;if(result&&progress.status==="COMPLETED"){return{state:"completed",completed:true,searchRef:progress.searchRef,result,progress}}return{state:"incomplete",completed:false,searchRef:progress.searchRef,result,progress}}createHttpError(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 CodeNavigationAccessError(detail??"Code navigation access denied.")}if(status>=500){return new CodeNavigationBackendError(detail?`Server error (${status}): ${detail}`:`Server error (${status})`,status)}return new CodeNavigationBackendError(detail??`Request failed with status ${status}`,status)}createTransportError(error){if(isFetchTimeoutError(error.cause)){return new CodeNavigationBackendError("Code navigation request timed out.",undefined,"TIMEOUT",true)}return new CodeNavigationNetworkError("Could not reach the code navigation service. Check your connection or set GITHITS_CODE_NAV_URL.",{cause:error})}createGraphQLError(errors){const message=errors.map((error)=>error.message).join(", ");const extensions=getPrimaryExtensions(errors);const code=typeof extensions?.code==="string"?extensions.code:undefined;const retryable=typeof extensions?.retryable==="boolean"?extensions.retryable:undefined;const indexingRef=getGraphQLIndexingRef(errors);if(isClientUpdateRequiredGraphQLError({message,code})){return new ClientUpdateRequiredError(undefined,undefined,this.runtime.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=code-nav-wire to inspect GraphQL details during local development.";debugLog("code-nav",{event:"graphql-schema-mismatch",code:code??"omitted",message});return new CodeNavigationBackendError(isDebugAreaEnabled("code-nav-wire")?message:sanitized,undefined,code,retryable)}switch(code){case"PACKAGE_INDEXING":return new CodeNavigationIndexingError(this.createIndexingMessage(indexingRef),indexingRef,parseAvailableVersions(extensions),parseAvailableRefs(extensions),parseTargetResolution(extensions));case"GREP_PATTERN_TOO_SHORT":case"GREP_PATTERN_TOO_LONG":case"GREP_PATTERN_INVALID":case"GREP_INVALID_REGEX":case"GREP_UNSUPPORTED_PATTERN":case"GREP_PATTERN_TOO_UNSELECTIVE":case"GREP_SCOPE_REQUIRED":case"GREP_SELECTOR_INVALID":case"GREP_CURSOR_INVALID":case"GREP_CONTEXT_TOO_LARGE":case"GREP_CONTEXT_NEGATIVE":case"GREP_MAX_MATCHES_TOO_LARGE":case"GREP_MAX_MATCHES_INVALID":return new CodeNavigationValidationError(message);case"VERSION_NOT_FOUND":return new CodeNavigationVersionNotFoundError(message,typeof extensions?.package==="string"?extensions.package:undefined,typeof extensions?.requested_version==="string"?extensions.requested_version:undefined,typeof extensions?.latest_indexed==="string"?extensions.latest_indexed:undefined,parseAvailableVersions(extensions));case"NOT_FOUND":case"PACKAGE_NOT_FOUND":case"NO_REPOSITORY_URL":return new CodeNavigationTargetNotFoundError(message);case"FILE_NOT_FOUND":return new CodeNavigationFileNotFoundError(message,typeof extensions?.file_path==="string"?extensions.file_path:typeof extensions?.filePath==="string"?extensions.filePath:undefined);case"UNSUPPORTED_REGISTRY":case"VALIDATION_ERROR":return new CodeNavigationValidationError(message);case"FEATURE_FLAG_REQUIRED":return new CodeNavigationFeatureFlagRequiredError(message);case"UNAUTHORIZED":return new AuthenticationError(SERVER_AUTHENTICATION_REJECTED_MESSAGE,"server");case"FORBIDDEN":return new CodeNavigationAccessError("Code navigation access denied. This feature may not be enabled for your account.");case"UPSTREAM_ERROR":case"TIMEOUT":case"RATE_LIMITED":case"GREP_FILE_TOO_LARGE":case"GREP_TIMEOUT":case"GREP_SERVICE_UNAVAILABLE":case"GREP_FAILED":case"GREP_INDEX_NOT_AVAILABLE":case"INTERNAL_ERROR":case"UNKNOWN_ERROR":return new CodeNavigationBackendError(message,undefined,code,retryable);default:break}if(code===undefined){if(isAuthMessage(message)){return new CodeNavigationAccessError("Code navigation access denied. This feature may not be enabled for your account.")}if(isUnresolvableMessage(message)){return new CodeNavigationUnresolvableError(message)}if(isTargetNotFoundMessage(message)){return new CodeNavigationTargetNotFoundError(message)}}return new CodeNavigationBackendError(message,undefined,code,retryable)}createIndexingMessage(indexingRef){const base="Target is still indexing. Indexing usually completes within 30 seconds. Retry this request, or pass a longer wait timeout (CLI: `--wait 60000`, MCP: `wait_timeout_ms: 60000`) to block until ready.";if(indexingRef){return`${base} Indexing reference: ${indexingRef}.`}return base}normaliseUnifiedSearchOutcome(data){const progress=data.progress?this.normaliseUnifiedSearchProgress(data.progress):undefined;if(data.completed){if(!data.result){throw new MalformedCodeNavigationResponseError("Completed unified search response missing result payload.")}return{state:"completed",completed:true,searchRef:data.searchRef??undefined,result:this.normaliseUnifiedSearchResult(data.result),progress}}const searchRef=data.searchRef??progress?.searchRef;if(!searchRef){throw new MalformedCodeNavigationResponseError("Incomplete unified search response missing search reference.")}const result=data.result?this.normaliseUnifiedSearchResult(data.result):undefined;return{state:"incomplete",completed:false,searchRef,result,progress}}normaliseUnifiedSearchResult(result){return{query:result.query,queryWarnings:result.queryWarnings,sources:result.sources,results:result.results.map((entry)=>({id:entry.id,resultType:entry.resultType,targetLabel:entry.targetLabel,requestedTargetLabel:entry.requestedTargetLabel??undefined,freshTargetLabel:entry.freshTargetLabel??undefined,servedTargetLabel:entry.servedTargetLabel??undefined,freshness:entry.freshness??undefined,title:entry.title??undefined,summary:entry.summary??undefined,score:entry.score??undefined,highlights:entry.highlights?{title:entry.highlights.title??undefined,summary:entry.highlights.summary??undefined}:undefined,locator:{registry:entry.locator.registry??undefined,packageName:entry.locator.packageName??undefined,version:entry.locator.version??undefined,pageId:entry.locator.pageId??undefined,sourceKind:entry.locator.sourceKind??undefined,sourceUrl:entry.locator.sourceUrl??undefined,repoUrl:entry.locator.repoUrl??undefined,gitRef:entry.locator.gitRef??undefined,requestedRef:entry.locator.requestedRef??undefined,filePath:entry.locator.filePath??undefined,startLine:entry.locator.startLine??undefined,endLine:entry.locator.endLine??undefined,fileContentHash:entry.locator.fileContentHash??undefined,symbolRef:entry.locator.symbolRef??undefined,qualifiedPath:entry.locator.qualifiedPath??undefined,kind:entry.locator.kind??undefined,category:entry.locator.category??undefined,language:entry.locator.language??undefined}})),page:{offset:result.page.offset,limit:result.page.limit,returned:result.page.returned,hasMore:result.page.hasMore},partialResults:result.partialResults,sourceStatus:result.sourceStatus.map((entry)=>({source:entry.source,targetLabel:entry.targetLabel,requestedTargetLabel:entry.requestedTargetLabel??undefined,freshTargetLabel:entry.freshTargetLabel??undefined,servedTargetLabel:entry.servedTargetLabel??undefined,targetResolution:normaliseTargetResolution(entry.targetResolution),indexingStatus:entry.indexingStatus??undefined,codeIndexState:entry.codeIndexState??undefined,resultCount:entry.resultCount??undefined,appliedFilters:entry.appliedFilters,ignoredFilters:entry.ignoredFilters,incompatibleFilters:entry.incompatibleFilters,appliedQueryFeatures:entry.appliedQueryFeatures,ignoredQueryFeatures:entry.ignoredQueryFeatures,incompatibleQueryFeatures:entry.incompatibleQueryFeatures,note:entry.note??undefined}))}}normaliseUnifiedSearchProgress(progress){return{searchRef:progress.searchRef,status:progress.status,targetsTotal:progress.targetsTotal,targetsReady:progress.targetsReady,elapsedMs:progress.elapsedMs,query:progress.query,queryWarnings:progress.queryWarnings,sources:progress.sources,requestedSources:progress.requestedSources??undefined,targetMode:normaliseTargetMode(progress.targetMode),requestedTargets:progress.requestedTargets?.map((target)=>({registry:target.registry?target.registry:undefined,name:target.name??undefined,version:target.version??undefined,repoUrl:target.repoUrl??undefined,gitRef:target.gitRef??undefined})),filters:normaliseProgressFilters(progress.filters),limit:progress.limit??undefined,offset:progress.offset??undefined,targets:progress.targets?.map((target)=>({requested:target.requested??undefined,resolvedRequested:target.resolvedRequested??undefined,served:target.served??undefined,freshness:target.freshness??undefined,indexingRef:target.indexingRef??undefined,requestedRefKind:normaliseRequestedRefKind(target.requestedRefKind),targetResolution:normaliseTargetResolution(target.targetResolution),availableVersions:normaliseAvailableVersions(target.availableVersions),availableRefs:normaliseAvailableVersions(target.availableRefs)})),expiresAt:progress.expiresAt??undefined}}throwIfIndexing(data){if(data.codeIndexState==="INDEXING"){const targetResolution=normaliseTargetResolution(data.targetResolution);throw new CodeNavigationIndexingError(this.createIndexingMessage(data.indexingRef??targetResolution?.indexingRef),data.indexingRef??targetResolution?.indexingRef,normaliseAvailableVersions(data.availableVersions)??targetResolution?.availableVersions,targetResolution?.availableRefs,targetResolution)}}async listFiles(params){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:(error)=>error instanceof AuthenticationError,executeWithToken:(token)=>this.executeListFiles(token,params)})}async executeListFiles(token,params){let response;try{response=await this.postGraphqlWithTargetResolutionFallback({token,query:LIST_REPO_FILES_QUERY,variables:{registry:params.target.registry,packageName:params.target.packageName,repoUrl:params.target.repoUrl,gitRef:params.target.gitRef,version:params.target.version,pathPrefix:params.pathPrefix,pathSelectors:params.pathSelectors?.map((entry)=>({kind:entry.kind,value:entry.value})),extensions:params.extensions,fileTypes:params.fileTypes,languages:params.languages,fileIntent:params.fileIntent,fileIntents:params.fileIntents,excludeFileIntents:params.excludeFileIntents,excludeDocFiles:params.excludeDocFiles,excludeTestFiles:params.excludeTestFiles,includeHidden:params.includeHidden,limit:params.limit,waitTimeoutMs:params.waitTimeoutMs}})}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=listRepoFilesGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.listRepoFiles;if(!data){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}this.throwIfIndexing(data);return{files:data.files.map((entry)=>({path:entry.path,name:entry.name??undefined,language:entry.language??undefined,fileType:entry.fileType??undefined,byteSize:entry.byteSize??undefined})),total:data.total,hasMore:data.hasMore,indexedVersion:data.indexedVersion??undefined,resolution:data.resolution?{requestedVersion:data.resolution.requestedVersion??undefined,requestedRef:data.resolution.requestedRef??undefined,resolvedRef:data.resolution.resolvedRef??undefined,commitSha:data.resolution.commitSha??undefined}:undefined,targetResolution:normaliseTargetResolution(data.targetResolution),hint:data.diagnostics?.hint??undefined}}async readFile(params){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:(error)=>error instanceof AuthenticationError,executeWithToken:(token)=>this.executeReadFile(token,params)})}async executeReadFile(token,params){let response;try{response=await this.postGraphqlWithTargetResolutionFallback({token,query:FETCH_CODE_CONTEXT_QUERY,variables:{registry:params.target.registry,packageName:params.target.packageName,repoUrl:params.target.repoUrl,gitRef:params.target.gitRef,version:params.target.version,filePath:params.filePath,startLine:params.startLine,endLine:params.endLine,waitTimeoutMs:params.waitTimeoutMs}})}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=fetchCodeContextGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.fetchCodeContext;if(!data){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}this.throwIfIndexing(data);return{filePath:data.filePath??undefined,language:data.language??undefined,totalLines:data.totalLines??undefined,startLine:data.startLine??undefined,endLine:data.endLine??undefined,content:data.content??undefined,isBinary:data.isBinary??undefined,targetResolution:normaliseTargetResolution(data.targetResolution),availableVersions:normaliseAvailableVersions(data.availableVersions)}}async grepRepo(params){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:(error)=>error instanceof AuthenticationError,executeWithToken:(token)=>this.executeGrepRepo(token,params)})}async executeGrepRepo(token,params){let response;try{response=await this.postGraphqlWithTargetResolutionFallback({token,query:buildGrepRepoQuery(params.symbolFields),variables:{registry:params.target.registry,packageName:params.target.packageName,repoUrl:params.target.repoUrl,gitRef:params.target.gitRef,version:params.target.version,waitTimeoutMs:params.waitTimeoutMs,pattern:params.pattern,patternType:params.patternType,caseSensitive:params.caseSensitive,pathSelectors:params.pathSelectors?.map((entry)=>({kind:entry.kind,value:entry.value})),extensions:params.extensions,excludeDocFiles:params.excludeDocFiles,excludeTestFiles:params.excludeTestFiles,allowUnscoped:params.allowUnscoped,contextLinesBefore:params.contextLinesBefore,contextLinesAfter:params.contextLinesAfter,maxMatches:params.maxMatches,maxMatchesPerFile:params.maxMatchesPerFile,cursor:params.cursor,symbolFields:params.symbolFields}})}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=grepRepoGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.grepRepo;if(!data){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}this.throwIfIndexing(data);return{matches:data.matches.map((entry)=>({filePath:entry.filePath,line:entry.line,matchStartByte:entry.matchStartByte,matchEndByte:entry.matchEndByte,lineContent:entry.lineContent,contextBefore:entry.contextBefore??undefined,contextAfter:entry.contextAfter??undefined,fileContentHash:entry.fileContentHash??undefined,fileIntent:entry.fileIntent??undefined,symbolRowId:entry.symbolRowId??undefined,symbol:entry.symbol?{symbolRef:entry.symbol.symbolRef,name:entry.symbol.name,qualifiedPath:entry.symbol.qualifiedPath??undefined,kind:entry.symbol.kind??undefined,category:entry.symbol.category??undefined,arity:entry.symbol.arity??undefined,isPublic:entry.symbol.isPublic??undefined,filePath:entry.symbol.filePath??undefined,startLine:entry.symbol.startLine??undefined,endLine:entry.symbol.endLine??undefined,code:entry.symbol.code??undefined,callerCount:entry.symbol.callerCount??undefined,contentHash:entry.symbol.contentHash??undefined,parentSymbolRef:entry.symbol.parentSymbolRef??undefined,parentPath:entry.symbol.parentPath??undefined}:undefined})),nextCursor:data.nextCursor??undefined,hasMore:data.hasMore,truncatedReason:data.truncatedReason,routeTaken:data.routeTaken??undefined,filesScanned:data.filesScanned,filesInScope:data.filesInScope,binaryFilesSkipped:data.binaryFilesSkipped,filesTooLargeSkipped:data.filesTooLargeSkipped,totalMatches:data.totalMatches,uniqueFilesMatched:data.uniqueFilesMatched,indexedVersion:data.indexedVersion??undefined,resolution:data.resolution?{requestedVersion:data.resolution.requestedVersion??undefined,requestedRef:data.resolution.requestedRef??undefined,resolvedRef:data.resolution.resolvedRef??undefined,commitSha:data.resolution.commitSha??undefined}:undefined,targetResolution:normaliseTargetResolution(data.targetResolution)}}}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 buildTargetResolutionFallbackQueries(query){const candidates=[query.replaceAll(TARGET_RESOLUTION_AVAILABLE_REFS_SELECTION,""),query.replaceAll(DISCOVERY_TARGET_PROGRESS_RETRY_SELECTION,""),query.replaceAll(CODE_CONTEXT_AVAILABLE_VERSIONS_SELECTION,""),query.replaceAll(TARGET_RESOLUTION_SELECTION,"").replaceAll(DISCOVERY_TARGET_PROGRESS_RETRY_SELECTION,"").replaceAll(CODE_CONTEXT_AVAILABLE_VERSIONS_SELECTION,"")];return candidates.filter((candidate,index,all)=>candidate!==query&&all.indexOf(candidate)===index)}function hasSchemaMismatchErrors(parsedBody){if(!parsedBody||typeof parsedBody!=="object")return false;const errors=parsedBody.errors;if(!Array.isArray(errors))return false;return errors.some((entry)=>{if(!entry||typeof entry!=="object")return false;const error=entry;if(typeof error.message!=="string")return false;const code=typeof error.extensions?.code==="string"?error.extensions.code:undefined;return isGraphQLSchemaMismatchError({message:error.message,code})})}function getPrimaryExtensions(errors){for(const error of errors){if(error.extensions&&Object.keys(error.extensions).length>0){return error.extensions}}return}function getGraphQLIndexingRef(errors){for(const error of errors){const indexingRef=error.extensions?.indexing_ref??error.extensions?.indexingRef;if(typeof indexingRef==="string")return indexingRef}return}function parseAvailableVersions(extensions){const raw=extensions?.available_versions??extensions?.availableVersions;return parseAvailableArtifacts(raw)}function parseAvailableRefs(extensions){const raw=extensions?.available_refs??extensions?.availableRefs;return parseAvailableArtifacts(raw)}function parseTargetResolution(extensions){const raw=extensions?.target_resolution??extensions?.targetResolution;const parsed=targetResolutionSchema.safeParse(raw);if(!parsed.success)return;return normaliseTargetResolution(parsed.data)}function parseAvailableArtifacts(raw){if(!Array.isArray(raw))return;const parsed=[];for(const item of raw){if(item&&typeof item==="object"&&"ref"in item){const entry=item;if(typeof entry.ref==="string"){parsed.push({ref:entry.ref,version:typeof entry.version==="string"?entry.version:undefined})}}}return parsed.length>0?parsed:undefined}function normaliseAvailableVersions(entries){if(!entries||entries.length===0)return;return entries.map((entry)=>({version:entry.version??undefined,ref:entry.ref}))}function normaliseTargetResolution(resolution){if(!resolution)return;return{requested:normaliseTargetResolutionIdentity(resolution.requested),resolvedRequested:normaliseTargetResolutionIdentity(resolution.resolvedRequested),served:normaliseTargetResolutionIdentity(resolution.served),freshness:resolution.freshness??undefined,freshnessReason:resolution.freshnessReason??undefined,indexingRef:resolution.indexingRef??undefined,availableVersions:normaliseAvailableVersions(resolution.availableVersions)??[],availableRefs:normaliseAvailableVersions(resolution.availableRefs)??[]}}function normaliseTargetResolutionIdentity(identity){if(!identity)return;const out={};if(identity.kind)out.kind=identity.kind;if(identity.registry)out.registry=identity.registry;if(identity.packageName)out.packageName=identity.packageName;if(identity.version)out.version=identity.version;if(identity.repoUrl)out.repoUrl=identity.repoUrl;if(identity.gitRef)out.gitRef=identity.gitRef;if(identity.commitSha)out.commitSha=identity.commitSha;return Object.keys(out).length>0?out:undefined}function isAuthMessage(message){const lower=message.toLowerCase();return lower.includes("unauthorized")||lower.includes("forbidden")||lower.includes("permission")||lower.includes("authentication")}function normaliseTargetMode(value){if(value==="PACKAGES"||value==="REPO"||value==="MIXED"){return value}return}function normaliseRequestedRefKind(value){switch(value){case"OMITTED_VERSION":case"LATEST_VERSION":case"EXACT_VERSION":case"DEFAULT_BRANCH":case"HEAD":case"BRANCH":case"SHA":return value;default:return}}function normaliseProgressFilters(filters){if(!filters)return;const out={};if(filters.fileIntent)out.fileIntent=filters.fileIntent;if(filters.kind)out.kind=filters.kind;if(filters.category)out.category=filters.category;if(typeof filters.publicOnly==="boolean"){out.publicOnly=filters.publicOnly}if(filters.pathPrefix)out.pathPrefix=filters.pathPrefix;return Object.keys(out).length>0?out:undefined}function isTargetNotFoundMessage(message){const lower=message.toLowerCase();return lower.includes("not found")||lower.includes("unknown package")||lower.includes("no such package")||lower.includes("does not exist")}function isUnresolvableMessage(message){const lower=message.toLowerCase();return lower.includes("could not resolve")||lower.includes("cannot resolve")}var DEFAULT_MCP_URL="https://mcp.githits.com";var DEFAULT_API_URL="https://api.githits.com";var DEFAULT_CODE_NAV_URL="https://pkgseer.dev";function getMcpUrl(){return process.env.GITHITS_MCP_URL??DEFAULT_MCP_URL}function getApiUrl(){return process.env.GITHITS_API_URL??DEFAULT_API_URL}function getCodeNavigationUrl(){const explicitUrl=process.env.GITHITS_CODE_NAV_URL??process.env.PKGSEER_URL;if(explicitUrl){return explicitUrl}return DEFAULT_CODE_NAV_URL}function getEnvApiToken(){return process.env.GITHITS_API_TOKEN}import{z as z2}from"zod";function promoteGenericVersionNotFound(error,params){if(!(error instanceof PackageIntelligenceBackendError))return error;if(error.graphqlCode!==undefined)return error;const requestedVersion=pickRequestedVersion(params);if(!requestedVersion)return error;if(!/no matching version/i.test(error.message))return error;const qualifiedName=synthesizeQualifiedName(params);return new PackageIntelligenceVersionNotFoundError(error.message,qualifiedName,requestedVersion,undefined)}function pickRequestedVersion(params){if(params.version)return params.version;if(params.fromVersion)return params.fromVersion;if(params.toVersion)return params.toVersion;return}function synthesizeQualifiedName(params){if(!params.registry||!params.packageName)return;return`${params.registry.toLowerCase()}:${params.packageName}`}class PackageIntelligenceAccessError extends Error{constructor(message){super(message);this.name="PackageIntelligenceAccessError"}}class PackageIntelligenceFeatureFlagRequiredError extends Error{constructor(message){super(message);this.name="PackageIntelligenceFeatureFlagRequiredError"}}class PackageIntelligenceNetworkError extends Error{constructor(message,options){super(message,options);this.name="PackageIntelligenceNetworkError"}}class PackageIntelligenceBackendError extends Error{status;graphqlCode;retryable;constructor(message,status,graphqlCode,retryable){super(message);this.status=status;this.graphqlCode=graphqlCode;this.retryable=retryable;this.name="PackageIntelligenceBackendError"}}class PackageIntelligenceGraphQLError extends Error{code;constructor(message,code){super(message);this.code=code;this.name="PackageIntelligenceGraphQLError"}}class PackageIntelligenceTargetNotFoundError extends Error{constructor(message){super(message);this.name="PackageIntelligenceTargetNotFoundError"}}class PackageIntelligenceValidationError extends Error{constructor(message){super(message);this.name="PackageIntelligenceValidationError"}}class PackageIntelligenceVersionNotFoundError extends Error{packageName;requestedVersion;availableVersions;constructor(message,packageName,requestedVersion,availableVersions){super(message);this.packageName=packageName;this.requestedVersion=requestedVersion;this.availableVersions=availableVersions;this.name="PackageIntelligenceVersionNotFoundError"}}class MalformedPackageIntelligenceResponseError extends Error{constructor(message){super(message);this.name="MalformedPackageIntelligenceResponseError"}}class PackageIntelligenceChangelogSourceNotFoundError extends Error{constructor(message){super(message);this.name="PackageIntelligenceChangelogSourceNotFoundError"}}var githubRepositorySchema=z2.object({stargazersCount:z2.number().int().nullable().optional(),forksCount:z2.number().int().nullable().optional(),openIssuesCount:z2.number().int().nullable().optional(),archived:z2.boolean().nullable().optional(),language:z2.string().nullable().optional(),topics:z2.array(z2.string()).nullable().optional(),pushedAt:z2.string().nullable().optional()}).nullable().optional();var packageIdentitySchema=z2.object({name:z2.string().nullable().optional(),registry:z2.string().nullable().optional(),description:z2.string().nullable().optional(),latestVersion:z2.string().nullable().optional(),latestVersionPublishedAt:z2.string().nullable().optional(),homepage:z2.string().nullable().optional(),repositoryUrl:z2.string().nullable().optional(),license:z2.string().nullable().optional(),downloadsLastMonth:z2.number().int().nullable().optional(),downloadsTotal:z2.number().int().nullable().optional(),githubRepository:githubRepositorySchema});var vulnerabilityOverviewSchema=z2.object({osvId:z2.string().nullable().optional(),summary:z2.string().nullable().optional(),severityScore:z2.number().nullable().optional(),publishedAt:z2.string().nullable().optional()});var packageSecurityOverviewSchema=z2.object({vulnerabilityCount:z2.number().int().nullable().optional(),hasCurrentVulnerabilities:z2.boolean().nullable().optional(),recentVulnerabilities:z2.array(vulnerabilityOverviewSchema).nullable().optional()}).nullable().optional();var changelogEntrySchema=z2.object({version:z2.string().nullable().optional(),publishedAt:z2.string().nullable().optional(),body:z2.string().nullable().optional()});var packageSummaryResponseSchema=z2.object({package:packageIdentitySchema.nullable().optional(),security:packageSecurityOverviewSchema,latestChangelogs:z2.array(changelogEntrySchema).nullable().optional()});var graphQLErrorSchema2=z2.object({message:z2.string(),extensions:z2.record(z2.string(),z2.unknown()).optional()});var graphQLResponseSchema=z2.object({data:z2.object({packageSummary:packageSummaryResponseSchema.nullable().optional()}).nullable().optional(),errors:z2.array(graphQLErrorSchema2).optional()});var PACKAGE_SUMMARY_QUERY=`
|
|
485
|
-
query PackageSummary(
|
|
494
|
+
}`}var unifiedSearchGraphQLResponseSchema=z.object({data:z.object({search:asyncUnifiedSearchResultSchema.nullable().optional()}).nullable().optional(),errors:z.array(graphQLErrorSchema).optional()});var unifiedSearchStatusGraphQLResponseSchema=z.object({data:z.object({discoverySearchProgress:unifiedSearchProgressSchema.nullable().optional()}).nullable().optional(),errors:z.array(graphQLErrorSchema).optional()});class CodeNavigationServiceImpl{codeNavigationUrl;tokenProvider;fetchFn;runtime;constructor(codeNavigationUrl,tokenProvider,fetchFn=globalThis.fetch,runtime={}){this.codeNavigationUrl=codeNavigationUrl;this.tokenProvider=tokenProvider;this.fetchFn=fetchFn;this.runtime=runtime}async postGraphqlWithTargetResolutionFallback(input){const response=await postPkgseerGraphql({endpointUrl:this.codeNavigationUrl,token:input.token,query:input.query,variables:input.variables,fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent});if(response.status<200||response.status>=300)return response;if(!hasSchemaMismatchErrors(response.parsedBody))return response;for(const fallbackQuery of buildTargetResolutionFallbackQueries(input.query)){debugLog("code-nav",{event:"target-resolution-query-fallback"});const fallbackResponse=await postPkgseerGraphql({endpointUrl:this.codeNavigationUrl,token:input.token,query:fallbackQuery,variables:input.variables,fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent});if(!hasSchemaMismatchErrors(fallbackResponse.parsedBody)){return fallbackResponse}}return response}async search(params){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:(error)=>error instanceof AuthenticationError,executeWithToken:(token)=>this.executeUnifiedSearch(token,params)})}async searchStatus(searchRef){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:(error)=>error instanceof AuthenticationError,executeWithToken:(token)=>this.executeUnifiedSearchStatus(token,searchRef)})}async executeUnifiedSearch(token,params){if(params.targets.length===0){throw new CodeNavigationValidationError("At least one search target is required.")}let response;const variables={targets:params.targets.map((target)=>({registry:target.registry,name:target.packageName,version:target.version,repoUrl:target.repoUrl,gitRef:target.gitRef})),query:params.query,sources:params.sources,filters:params.filters,allowPartialResults:params.allowPartialResults??false,limit:params.limit,offset:params.offset,waitTimeoutMs:params.waitTimeoutMs};debugUnifiedSearchRequest(variables);debugGraphqlWireRequest("search",UNIFIED_SEARCH_QUERY,variables);try{response=await this.postGraphqlWithTargetResolutionFallback({token,query:UNIFIED_SEARCH_QUERY,variables})}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=unifiedSearchGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.search;if(!data){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}return this.normaliseUnifiedSearchOutcome(data)}async executeUnifiedSearchStatus(token,searchRef){let response;try{response=await this.postGraphqlWithTargetResolutionFallback({token,query:UNIFIED_SEARCH_STATUS_QUERY,variables:{searchRef,includeResults:true}})}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=unifiedSearchStatusGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.discoverySearchProgress;if(!data){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}const progress=this.normaliseUnifiedSearchProgress(data);const result=data.results?this.normaliseUnifiedSearchResult(data.results):undefined;if(result&&progress.status==="COMPLETED"){return{state:"completed",completed:true,searchRef:progress.searchRef,result,progress}}return{state:"incomplete",completed:false,searchRef:progress.searchRef,result,progress}}createHttpError(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 CodeNavigationAccessError(detail??"Code navigation access denied.")}if(status>=500){return new CodeNavigationBackendError(detail?`Server error (${status}): ${detail}`:`Server error (${status})`,status)}return new CodeNavigationBackendError(detail??`Request failed with status ${status}`,status)}createTransportError(error){if(isFetchTimeoutError(error.cause)){return new CodeNavigationBackendError("Code navigation request timed out.",undefined,"TIMEOUT",true)}return new CodeNavigationNetworkError("Could not reach the code navigation service. Check your connection or set GITHITS_CODE_NAV_URL.",{cause:error})}createGraphQLError(errors){const message=errors.map((error)=>error.message).join(", ");const extensions=getPrimaryExtensions(errors);const code=typeof extensions?.code==="string"?extensions.code:undefined;const retryable=typeof extensions?.retryable==="boolean"?extensions.retryable:undefined;const indexingRef=getGraphQLIndexingRef(errors);if(isClientUpdateRequiredGraphQLError({message,code})){return new ClientUpdateRequiredError(undefined,undefined,this.runtime.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=code-nav-wire to inspect GraphQL details during local development.";debugLog("code-nav",{event:"graphql-schema-mismatch",code:code??"omitted",message});return new CodeNavigationBackendError(isDebugAreaEnabled("code-nav-wire")?message:sanitized,undefined,code,retryable)}switch(code){case"PACKAGE_INDEXING":return new CodeNavigationIndexingError(this.createIndexingMessage(indexingRef),indexingRef,parseAvailableVersions(extensions),parseAvailableRefs(extensions),parseTargetResolution(extensions));case"GREP_PATTERN_TOO_SHORT":case"GREP_PATTERN_TOO_LONG":case"GREP_PATTERN_INVALID":case"GREP_INVALID_REGEX":case"GREP_UNSUPPORTED_PATTERN":case"GREP_PATTERN_TOO_UNSELECTIVE":case"GREP_SCOPE_REQUIRED":case"GREP_SELECTOR_INVALID":case"GREP_CURSOR_INVALID":case"GREP_CONTEXT_TOO_LARGE":case"GREP_CONTEXT_NEGATIVE":case"GREP_MAX_MATCHES_TOO_LARGE":case"GREP_MAX_MATCHES_INVALID":return new CodeNavigationValidationError(message);case"VERSION_NOT_FOUND":return new CodeNavigationVersionNotFoundError(message,typeof extensions?.package==="string"?extensions.package:undefined,typeof extensions?.requested_version==="string"?extensions.requested_version:undefined,typeof extensions?.latest_indexed==="string"?extensions.latest_indexed:undefined,parseAvailableVersions(extensions));case"REF_NOT_FOUND":return new CodeNavigationRefNotFoundError(message,typeof extensions?.repo_url==="string"?extensions.repo_url:typeof extensions?.repoUrl==="string"?extensions.repoUrl:undefined,typeof extensions?.git_ref==="string"?extensions.git_ref:typeof extensions?.gitRef==="string"?extensions.gitRef:undefined,parseAvailableRefs(extensions),parseSuggestedRefs(extensions));case"NOT_FOUND":case"PACKAGE_NOT_FOUND":case"NO_REPOSITORY_URL":return new CodeNavigationTargetNotFoundError(message);case"FILE_NOT_FOUND":return new CodeNavigationFileNotFoundError(message,typeof extensions?.file_path==="string"?extensions.file_path:typeof extensions?.filePath==="string"?extensions.filePath:undefined);case"UNSUPPORTED_REGISTRY":case"VALIDATION_ERROR":return new CodeNavigationValidationError(message);case"FEATURE_FLAG_REQUIRED":return new CodeNavigationFeatureFlagRequiredError(message);case"UNAUTHORIZED":return new AuthenticationError(SERVER_AUTHENTICATION_REJECTED_MESSAGE,"server");case"FORBIDDEN":return new CodeNavigationAccessError("Code navigation access denied. This feature may not be enabled for your account.");case"UPSTREAM_ERROR":case"TIMEOUT":case"RATE_LIMITED":case"GREP_FILE_TOO_LARGE":case"GREP_TIMEOUT":case"GREP_SERVICE_UNAVAILABLE":case"GREP_FAILED":case"GREP_INDEX_NOT_AVAILABLE":case"INTERNAL_ERROR":case"UNKNOWN_ERROR":return new CodeNavigationBackendError(message,undefined,code,retryable);default:break}if(code===undefined){if(isAuthMessage(message)){return new CodeNavigationAccessError("Code navigation access denied. This feature may not be enabled for your account.")}if(isUnresolvableMessage(message)){return new CodeNavigationUnresolvableError(message)}if(isTargetNotFoundMessage(message)){return new CodeNavigationTargetNotFoundError(message)}}return new CodeNavigationBackendError(message,undefined,code,retryable)}createIndexingMessage(indexingRef){const base="Target is still indexing. Indexing usually completes within 30 seconds. Retry this request, or pass a longer wait timeout (CLI: `--wait 60000`, MCP: `wait_timeout_ms: 60000`) to block until ready.";if(indexingRef){return`${base} Indexing reference: ${indexingRef}.`}return base}normaliseUnifiedSearchOutcome(data){const progress=data.progress?this.normaliseUnifiedSearchProgress(data.progress):undefined;if(data.completed){if(!data.result){throw new MalformedCodeNavigationResponseError("Completed unified search response missing result payload.")}return{state:"completed",completed:true,searchRef:data.searchRef??undefined,result:this.normaliseUnifiedSearchResult(data.result),progress}}const searchRef=data.searchRef??progress?.searchRef;if(!searchRef){throw new MalformedCodeNavigationResponseError("Incomplete unified search response missing search reference.")}const result=data.result?this.normaliseUnifiedSearchResult(data.result):undefined;return{state:"incomplete",completed:false,searchRef,result,progress}}normaliseUnifiedSearchResult(result){return{query:result.query,queryWarnings:result.queryWarnings,sources:result.sources,results:result.results.map((entry)=>({id:entry.id,resultType:entry.resultType,targetLabel:entry.targetLabel,requestedTargetLabel:entry.requestedTargetLabel??undefined,freshTargetLabel:entry.freshTargetLabel??undefined,servedTargetLabel:entry.servedTargetLabel??undefined,freshness:entry.freshness??undefined,title:entry.title??undefined,summary:entry.summary??undefined,score:entry.score??undefined,highlights:entry.highlights?{title:entry.highlights.title??undefined,summary:entry.highlights.summary??undefined}:undefined,locator:{registry:entry.locator.registry??undefined,packageName:entry.locator.packageName??undefined,version:entry.locator.version??undefined,pageId:entry.locator.pageId??undefined,sourceKind:entry.locator.sourceKind??undefined,sourceUrl:entry.locator.sourceUrl??undefined,repoUrl:entry.locator.repoUrl??undefined,gitRef:entry.locator.gitRef??undefined,requestedRef:entry.locator.requestedRef??undefined,filePath:entry.locator.filePath??undefined,startLine:entry.locator.startLine??undefined,endLine:entry.locator.endLine??undefined,fileContentHash:entry.locator.fileContentHash??undefined,symbolRef:entry.locator.symbolRef??undefined,qualifiedPath:entry.locator.qualifiedPath??undefined,kind:entry.locator.kind??undefined,category:entry.locator.category??undefined,language:entry.locator.language??undefined}})),page:{offset:result.page.offset,limit:result.page.limit,returned:result.page.returned,hasMore:result.page.hasMore},partialResults:result.partialResults,sourceStatus:result.sourceStatus.map((entry)=>({source:entry.source,targetLabel:entry.targetLabel,requestedTargetLabel:entry.requestedTargetLabel??undefined,freshTargetLabel:entry.freshTargetLabel??undefined,servedTargetLabel:entry.servedTargetLabel??undefined,targetResolution:normaliseTargetResolution(entry.targetResolution),indexingStatus:entry.indexingStatus??undefined,codeIndexState:entry.codeIndexState??undefined,resultCount:entry.resultCount??undefined,appliedFilters:entry.appliedFilters,ignoredFilters:entry.ignoredFilters,incompatibleFilters:entry.incompatibleFilters,appliedQueryFeatures:entry.appliedQueryFeatures,ignoredQueryFeatures:entry.ignoredQueryFeatures,incompatibleQueryFeatures:entry.incompatibleQueryFeatures,note:entry.note??undefined}))}}normaliseUnifiedSearchProgress(progress){return{searchRef:progress.searchRef,status:progress.status,targetsTotal:progress.targetsTotal,targetsReady:progress.targetsReady,elapsedMs:progress.elapsedMs,query:progress.query,queryWarnings:progress.queryWarnings,sources:progress.sources,requestedSources:progress.requestedSources??undefined,targetMode:normaliseTargetMode(progress.targetMode),requestedTargets:progress.requestedTargets?.map((target)=>({registry:target.registry?target.registry:undefined,name:target.name??undefined,version:target.version??undefined,repoUrl:target.repoUrl??undefined,gitRef:target.gitRef??undefined})),filters:normaliseProgressFilters(progress.filters),limit:progress.limit??undefined,offset:progress.offset??undefined,targets:progress.targets?.map((target)=>({requested:target.requested??undefined,resolvedRequested:target.resolvedRequested??undefined,served:target.served??undefined,freshness:target.freshness??undefined,indexingRef:target.indexingRef??undefined,requestedRefKind:normaliseRequestedRefKind(target.requestedRefKind),targetResolution:normaliseTargetResolution(target.targetResolution),availableVersions:normaliseAvailableVersions(target.availableVersions),availableRefs:normaliseAvailableVersions(target.availableRefs),suggestedRefs:normaliseAvailableVersions(target.suggestedRefs)})),expiresAt:progress.expiresAt??undefined}}throwIfIndexing(data){if(data.codeIndexState==="INDEXING"){const targetResolution=normaliseTargetResolution(data.targetResolution);throw new CodeNavigationIndexingError(this.createIndexingMessage(data.indexingRef??targetResolution?.indexingRef),data.indexingRef??targetResolution?.indexingRef,normaliseAvailableVersions(data.availableVersions)??targetResolution?.availableVersions,targetResolution?.availableRefs,targetResolution)}}async listFiles(params){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:(error)=>error instanceof AuthenticationError,executeWithToken:(token)=>this.executeListFiles(token,params)})}async executeListFiles(token,params){let response;try{response=await this.postGraphqlWithTargetResolutionFallback({token,query:LIST_REPO_FILES_QUERY,variables:{registry:params.target.registry,packageName:params.target.packageName,repoUrl:params.target.repoUrl,gitRef:params.target.gitRef,version:params.target.version,pathPrefix:params.pathPrefix,pathSelectors:params.pathSelectors?.map((entry)=>({kind:entry.kind,value:entry.value})),extensions:params.extensions,fileTypes:params.fileTypes,languages:params.languages,fileIntent:params.fileIntent,fileIntents:params.fileIntents,excludeFileIntents:params.excludeFileIntents,excludeDocFiles:params.excludeDocFiles,excludeTestFiles:params.excludeTestFiles,includeHidden:params.includeHidden,limit:params.limit,waitTimeoutMs:params.waitTimeoutMs}})}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=listRepoFilesGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.listRepoFiles;if(!data){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}this.throwIfIndexing(data);return{files:data.files.map((entry)=>({path:entry.path,name:entry.name??undefined,language:entry.language??undefined,fileType:entry.fileType??undefined,byteSize:entry.byteSize??undefined})),total:data.total,hasMore:data.hasMore,indexedVersion:data.indexedVersion??undefined,resolution:data.resolution?{requestedVersion:data.resolution.requestedVersion??undefined,requestedRef:data.resolution.requestedRef??undefined,resolvedRef:data.resolution.resolvedRef??undefined,commitSha:data.resolution.commitSha??undefined}:undefined,targetResolution:normaliseTargetResolution(data.targetResolution),hint:data.diagnostics?.hint??undefined}}async readFile(params){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:(error)=>error instanceof AuthenticationError,executeWithToken:(token)=>this.executeReadFile(token,params)})}async executeReadFile(token,params){let response;try{response=await this.postGraphqlWithTargetResolutionFallback({token,query:FETCH_CODE_CONTEXT_QUERY,variables:{registry:params.target.registry,packageName:params.target.packageName,repoUrl:params.target.repoUrl,gitRef:params.target.gitRef,version:params.target.version,filePath:params.filePath,startLine:params.startLine,endLine:params.endLine,waitTimeoutMs:params.waitTimeoutMs}})}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=fetchCodeContextGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.fetchCodeContext;if(!data){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}this.throwIfIndexing(data);return{filePath:data.filePath??undefined,language:data.language??undefined,totalLines:data.totalLines??undefined,startLine:data.startLine??undefined,endLine:data.endLine??undefined,content:data.content??undefined,isBinary:data.isBinary??undefined,targetResolution:normaliseTargetResolution(data.targetResolution),availableVersions:normaliseAvailableVersions(data.availableVersions)}}async grepRepo(params){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:(error)=>error instanceof AuthenticationError,executeWithToken:(token)=>this.executeGrepRepo(token,params)})}async executeGrepRepo(token,params){let response;try{response=await this.postGraphqlWithTargetResolutionFallback({token,query:buildGrepRepoQuery(params.symbolFields),variables:{registry:params.target.registry,packageName:params.target.packageName,repoUrl:params.target.repoUrl,gitRef:params.target.gitRef,version:params.target.version,waitTimeoutMs:params.waitTimeoutMs,pattern:params.pattern,patternType:params.patternType,caseSensitive:params.caseSensitive,pathSelectors:params.pathSelectors?.map((entry)=>({kind:entry.kind,value:entry.value})),extensions:params.extensions,excludeDocFiles:params.excludeDocFiles,excludeTestFiles:params.excludeTestFiles,allowUnscoped:params.allowUnscoped,contextLinesBefore:params.contextLinesBefore,contextLinesAfter:params.contextLinesAfter,maxMatches:params.maxMatches,maxMatchesPerFile:params.maxMatchesPerFile,cursor:params.cursor,symbolFields:params.symbolFields}})}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=grepRepoGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.grepRepo;if(!data){throw new MalformedCodeNavigationResponseError("Malformed response from code navigation service.")}this.throwIfIndexing(data);return{matches:data.matches.map((entry)=>({filePath:entry.filePath,line:entry.line,matchStartByte:entry.matchStartByte,matchEndByte:entry.matchEndByte,lineContent:entry.lineContent,contextBefore:entry.contextBefore??undefined,contextAfter:entry.contextAfter??undefined,fileContentHash:entry.fileContentHash??undefined,fileIntent:entry.fileIntent??undefined,symbolRowId:entry.symbolRowId??undefined,symbol:entry.symbol?{symbolRef:entry.symbol.symbolRef,name:entry.symbol.name,qualifiedPath:entry.symbol.qualifiedPath??undefined,kind:entry.symbol.kind??undefined,category:entry.symbol.category??undefined,arity:entry.symbol.arity??undefined,isPublic:entry.symbol.isPublic??undefined,filePath:entry.symbol.filePath??undefined,startLine:entry.symbol.startLine??undefined,endLine:entry.symbol.endLine??undefined,code:entry.symbol.code??undefined,callerCount:entry.symbol.callerCount??undefined,contentHash:entry.symbol.contentHash??undefined,parentSymbolRef:entry.symbol.parentSymbolRef??undefined,parentPath:entry.symbol.parentPath??undefined}:undefined})),nextCursor:data.nextCursor??undefined,hasMore:data.hasMore,truncatedReason:data.truncatedReason,routeTaken:data.routeTaken??undefined,filesScanned:data.filesScanned,filesInScope:data.filesInScope,binaryFilesSkipped:data.binaryFilesSkipped,filesTooLargeSkipped:data.filesTooLargeSkipped,totalMatches:data.totalMatches,uniqueFilesMatched:data.uniqueFilesMatched,indexedVersion:data.indexedVersion??undefined,resolution:data.resolution?{requestedVersion:data.resolution.requestedVersion??undefined,requestedRef:data.resolution.requestedRef??undefined,resolvedRef:data.resolution.resolvedRef??undefined,commitSha:data.resolution.commitSha??undefined}:undefined,targetResolution:normaliseTargetResolution(data.targetResolution)}}}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 buildTargetResolutionFallbackQueries(query){const withoutSuggestedRefs=query.replaceAll(TARGET_RESOLUTION_SUGGESTED_REFS_SELECTION,"").replaceAll(DISCOVERY_TARGET_PROGRESS_SUGGESTED_REFS_SELECTION,"");const candidates=[withoutSuggestedRefs,withoutSuggestedRefs.replaceAll(TARGET_RESOLUTION_AVAILABLE_REFS_SELECTION,""),withoutSuggestedRefs.replaceAll(DISCOVERY_TARGET_PROGRESS_RETRY_SELECTION,""),withoutSuggestedRefs.replaceAll(CODE_CONTEXT_AVAILABLE_VERSIONS_SELECTION,""),withoutSuggestedRefs.replaceAll(TARGET_RESOLUTION_SELECTION,"").replaceAll(DISCOVERY_TARGET_PROGRESS_RETRY_SELECTION,"").replaceAll(CODE_CONTEXT_AVAILABLE_VERSIONS_SELECTION,"")];return candidates.filter((candidate,index,all)=>candidate!==query&&all.indexOf(candidate)===index)}function hasSchemaMismatchErrors(parsedBody){if(!parsedBody||typeof parsedBody!=="object")return false;const errors=parsedBody.errors;if(!Array.isArray(errors))return false;return errors.some((entry)=>{if(!entry||typeof entry!=="object")return false;const error=entry;if(typeof error.message!=="string")return false;const code=typeof error.extensions?.code==="string"?error.extensions.code:undefined;return isGraphQLSchemaMismatchError({message:error.message,code})})}function getPrimaryExtensions(errors){for(const error of errors){if(error.extensions&&Object.keys(error.extensions).length>0){return error.extensions}}return}function getGraphQLIndexingRef(errors){for(const error of errors){const indexingRef=error.extensions?.indexing_ref??error.extensions?.indexingRef;if(typeof indexingRef==="string")return indexingRef}return}function parseAvailableVersions(extensions){const raw=extensions?.available_versions??extensions?.availableVersions;return parseAvailableArtifacts(raw)}function parseAvailableRefs(extensions){const raw=extensions?.available_refs??extensions?.availableRefs;return parseAvailableArtifacts(raw)}function parseSuggestedRefs(extensions){const raw=extensions?.suggested_refs??extensions?.suggestedRefs;return parseAvailableArtifacts(raw)}function parseTargetResolution(extensions){const raw=extensions?.target_resolution??extensions?.targetResolution;const parsed=targetResolutionSchema.safeParse(raw);if(!parsed.success)return;return normaliseTargetResolution(parsed.data)}function parseAvailableArtifacts(raw){if(!Array.isArray(raw))return;const parsed=[];for(const item of raw){if(item&&typeof item==="object"&&"ref"in item){const entry=item;if(typeof entry.ref==="string"){parsed.push({ref:entry.ref,version:typeof entry.version==="string"?entry.version:undefined})}}}return parsed.length>0?parsed:undefined}function normaliseAvailableVersions(entries){if(!entries||entries.length===0)return;return entries.map((entry)=>({version:entry.version??undefined,ref:entry.ref}))}function normaliseTargetResolution(resolution){if(!resolution)return;return{requested:normaliseTargetResolutionIdentity(resolution.requested),resolvedRequested:normaliseTargetResolutionIdentity(resolution.resolvedRequested),served:normaliseTargetResolutionIdentity(resolution.served),freshness:resolution.freshness??undefined,freshnessReason:resolution.freshnessReason??undefined,indexingRef:resolution.indexingRef??undefined,availableVersions:normaliseAvailableVersions(resolution.availableVersions)??[],availableRefs:normaliseAvailableVersions(resolution.availableRefs)??[],suggestedRefs:normaliseAvailableVersions(resolution.suggestedRefs)??[]}}function normaliseTargetResolutionIdentity(identity){if(!identity)return;const out={};if(identity.kind)out.kind=identity.kind;if(identity.registry)out.registry=identity.registry;if(identity.packageName)out.packageName=identity.packageName;if(identity.version)out.version=identity.version;if(identity.repoUrl)out.repoUrl=identity.repoUrl;if(identity.gitRef)out.gitRef=identity.gitRef;if(identity.commitSha)out.commitSha=identity.commitSha;return Object.keys(out).length>0?out:undefined}function isAuthMessage(message){const lower=message.toLowerCase();return lower.includes("unauthorized")||lower.includes("forbidden")||lower.includes("permission")||lower.includes("authentication")}function normaliseTargetMode(value){if(value==="PACKAGES"||value==="REPO"||value==="MIXED"){return value}return}function normaliseRequestedRefKind(value){switch(value){case"OMITTED_VERSION":case"LATEST_VERSION":case"EXACT_VERSION":case"DEFAULT_BRANCH":case"HEAD":case"BRANCH":case"SHA":return value;default:return}}function normaliseProgressFilters(filters){if(!filters)return;const out={};if(filters.fileIntent)out.fileIntent=filters.fileIntent;if(filters.kind)out.kind=filters.kind;if(filters.category)out.category=filters.category;if(typeof filters.publicOnly==="boolean"){out.publicOnly=filters.publicOnly}if(filters.pathPrefix)out.pathPrefix=filters.pathPrefix;return Object.keys(out).length>0?out:undefined}function isTargetNotFoundMessage(message){const lower=message.toLowerCase();return lower.includes("not found")||lower.includes("unknown package")||lower.includes("no such package")||lower.includes("does not exist")}function isUnresolvableMessage(message){const lower=message.toLowerCase();return lower.includes("could not resolve")||lower.includes("cannot resolve")}var DEFAULT_MCP_URL="https://mcp.githits.com";var DEFAULT_API_URL="https://api.githits.com";var DEFAULT_CODE_NAV_URL="https://pkgseer.dev";function getMcpUrl(){return process.env.GITHITS_MCP_URL??DEFAULT_MCP_URL}function getApiUrl(){return process.env.GITHITS_API_URL??DEFAULT_API_URL}function getCodeNavigationUrl(){const explicitUrl=process.env.GITHITS_CODE_NAV_URL??process.env.PKGSEER_URL;if(explicitUrl){return explicitUrl}return DEFAULT_CODE_NAV_URL}function getEnvApiToken(){return process.env.GITHITS_API_TOKEN}import{z as z2}from"zod";function promoteGenericVersionNotFound(error,params){if(!(error instanceof PackageIntelligenceBackendError))return error;if(error.graphqlCode!==undefined)return error;const requestedVersion=pickRequestedVersion(params);if(!requestedVersion)return error;if(!/no matching version/i.test(error.message))return error;const qualifiedName=synthesizeQualifiedName(params);return new PackageIntelligenceVersionNotFoundError(error.message,qualifiedName,requestedVersion,undefined)}function pickRequestedVersion(params){if(params.version)return params.version;if(params.fromVersion)return params.fromVersion;if(params.toVersion)return params.toVersion;return}function synthesizeQualifiedName(params){if(!params.registry||!params.packageName)return;return`${params.registry.toLowerCase()}:${params.packageName}`}class PackageIntelligenceAccessError extends Error{constructor(message){super(message);this.name="PackageIntelligenceAccessError"}}class PackageIntelligenceFeatureFlagRequiredError extends Error{constructor(message){super(message);this.name="PackageIntelligenceFeatureFlagRequiredError"}}class PackageIntelligenceNetworkError extends Error{constructor(message,options){super(message,options);this.name="PackageIntelligenceNetworkError"}}class PackageIntelligenceBackendError extends Error{status;graphqlCode;retryable;constructor(message,status,graphqlCode,retryable){super(message);this.status=status;this.graphqlCode=graphqlCode;this.retryable=retryable;this.name="PackageIntelligenceBackendError"}}class PackageIntelligenceGraphQLError extends Error{code;constructor(message,code){super(message);this.code=code;this.name="PackageIntelligenceGraphQLError"}}class PackageIntelligenceTargetNotFoundError extends Error{constructor(message){super(message);this.name="PackageIntelligenceTargetNotFoundError"}}class PackageIntelligenceValidationError extends Error{constructor(message){super(message);this.name="PackageIntelligenceValidationError"}}class PackageIntelligenceVersionNotFoundError extends Error{packageName;requestedVersion;availableVersions;constructor(message,packageName,requestedVersion,availableVersions){super(message);this.packageName=packageName;this.requestedVersion=requestedVersion;this.availableVersions=availableVersions;this.name="PackageIntelligenceVersionNotFoundError"}}class MalformedPackageIntelligenceResponseError extends Error{constructor(message){super(message);this.name="MalformedPackageIntelligenceResponseError"}}class PackageIntelligenceChangelogSourceNotFoundError extends Error{constructor(message){super(message);this.name="PackageIntelligenceChangelogSourceNotFoundError"}}var githubRepositorySchema=z2.object({stargazersCount:z2.number().int().nullable().optional(),forksCount:z2.number().int().nullable().optional(),openIssuesCount:z2.number().int().nullable().optional(),archived:z2.boolean().nullable().optional(),language:z2.string().nullable().optional(),topics:z2.array(z2.string()).nullable().optional(),pushedAt:z2.string().nullable().optional()}).nullable().optional();var packageIdentitySchema=z2.object({name:z2.string().nullable().optional(),registry:z2.string().nullable().optional(),description:z2.string().nullable().optional(),latestVersion:z2.string().nullable().optional(),latestVersionPublishedAt:z2.string().nullable().optional(),homepage:z2.string().nullable().optional(),repositoryUrl:z2.string().nullable().optional(),license:z2.string().nullable().optional(),downloadsLastMonth:z2.number().int().nullable().optional(),downloadsTotal:z2.number().int().nullable().optional(),githubRepository:githubRepositorySchema});var vulnerabilityOverviewSchema=z2.object({osvId:z2.string().nullable().optional(),summary:z2.string().nullable().optional(),severityScore:z2.number().nullable().optional(),publishedAt:z2.string().nullable().optional()});var packageSecurityOverviewSchema=z2.object({vulnerabilityCount:z2.number().int().nullable().optional(),hasCurrentVulnerabilities:z2.boolean().nullable().optional(),recentVulnerabilities:z2.array(vulnerabilityOverviewSchema).nullable().optional()}).nullable().optional();var changelogEntrySchema=z2.object({version:z2.string().nullable().optional(),publishedAt:z2.string().nullable().optional(),body:z2.string().nullable().optional()});var packageSummaryResponseSchema=z2.object({package:packageIdentitySchema.nullable().optional(),security:packageSecurityOverviewSchema,latestChangelogs:z2.array(changelogEntrySchema).nullable().optional()});var graphQLErrorSchema2=z2.object({message:z2.string(),extensions:z2.record(z2.string(),z2.unknown()).optional()});var graphQLResponseSchema=z2.object({data:z2.object({packageSummary:packageSummaryResponseSchema.nullable().optional()}).nullable().optional(),errors:z2.array(graphQLErrorSchema2).optional()});var PACKAGE_SUMMARY_QUERY=`
|
|
495
|
+
query PackageSummary(
|
|
496
|
+
$registry: Registry!
|
|
497
|
+
$name: String!
|
|
498
|
+
$includeVerboseFields: Boolean! = true
|
|
499
|
+
) {
|
|
486
500
|
packageSummary(registry: $registry, name: $name) {
|
|
487
501
|
package {
|
|
488
502
|
name
|
|
@@ -500,22 +514,22 @@ query PackageSummary($registry: Registry!, $name: String!) {
|
|
|
500
514
|
forksCount
|
|
501
515
|
openIssuesCount
|
|
502
516
|
archived
|
|
503
|
-
language
|
|
504
|
-
topics
|
|
505
|
-
pushedAt
|
|
517
|
+
language @include(if: $includeVerboseFields)
|
|
518
|
+
topics @include(if: $includeVerboseFields)
|
|
519
|
+
pushedAt @include(if: $includeVerboseFields)
|
|
506
520
|
}
|
|
507
521
|
}
|
|
508
522
|
security {
|
|
509
523
|
vulnerabilityCount
|
|
510
524
|
hasCurrentVulnerabilities
|
|
511
|
-
recentVulnerabilities {
|
|
525
|
+
recentVulnerabilities @include(if: $includeVerboseFields) {
|
|
512
526
|
osvId
|
|
513
527
|
summary
|
|
514
528
|
severityScore
|
|
515
529
|
publishedAt
|
|
516
530
|
}
|
|
517
531
|
}
|
|
518
|
-
latestChangelogs(limit: 3) {
|
|
532
|
+
latestChangelogs(limit: 3) @include(if: $includeVerboseFields) {
|
|
519
533
|
version
|
|
520
534
|
publishedAt
|
|
521
535
|
body
|
|
@@ -582,6 +596,9 @@ query PackageDependencies(
|
|
|
582
596
|
$name: String!
|
|
583
597
|
$version: String
|
|
584
598
|
$includeTransitive: Boolean
|
|
599
|
+
$includeTransitiveDetails: Boolean! = true
|
|
600
|
+
$includeDependencyGraph: Boolean! = true
|
|
601
|
+
$includeGroups: Boolean! = true
|
|
585
602
|
$maxDepth: Int
|
|
586
603
|
$lifecycle: [String!]
|
|
587
604
|
) {
|
|
@@ -609,10 +626,10 @@ query PackageDependencies(
|
|
|
609
626
|
type
|
|
610
627
|
}
|
|
611
628
|
transitive {
|
|
612
|
-
totalEdges
|
|
613
|
-
uniquePackagesCount
|
|
614
|
-
uniqueDependencies
|
|
615
|
-
dependencyConflicts {
|
|
629
|
+
totalEdges @include(if: $includeTransitiveDetails)
|
|
630
|
+
uniquePackagesCount @include(if: $includeTransitiveDetails)
|
|
631
|
+
uniqueDependencies @include(if: $includeTransitiveDetails)
|
|
632
|
+
dependencyConflicts @include(if: $includeTransitiveDetails) {
|
|
616
633
|
packageName
|
|
617
634
|
requiredVersions
|
|
618
635
|
conflictingEdges {
|
|
@@ -622,12 +639,12 @@ query PackageDependencies(
|
|
|
622
639
|
dependencyType
|
|
623
640
|
}
|
|
624
641
|
}
|
|
625
|
-
circularDependencyCycles {
|
|
642
|
+
circularDependencyCycles @include(if: $includeTransitiveDetails) {
|
|
626
643
|
cycleStart
|
|
627
644
|
circularPath
|
|
628
645
|
displayChain
|
|
629
646
|
}
|
|
630
|
-
dependencyGraph {
|
|
647
|
+
dependencyGraph @include(if: $includeDependencyGraph) {
|
|
631
648
|
formatVersion
|
|
632
649
|
nodes {
|
|
633
650
|
registry
|
|
@@ -643,7 +660,7 @@ query PackageDependencies(
|
|
|
643
660
|
}
|
|
644
661
|
}
|
|
645
662
|
}
|
|
646
|
-
dependencyGroups {
|
|
663
|
+
dependencyGroups @include(if: $includeGroups) {
|
|
647
664
|
primaryGroup
|
|
648
665
|
environmentMarkers {
|
|
649
666
|
type
|
|
@@ -863,7 +880,205 @@ query PackageUpgradeDependencyProbe(
|
|
|
863
880
|
}
|
|
864
881
|
}
|
|
865
882
|
}
|
|
866
|
-
}`;var
|
|
883
|
+
}`;var packageUpgradeAdvisorySchema=z2.object({id:z2.string().nullable().optional(),aliases:z2.array(z2.string()),summary:z2.string().nullable().optional(),severity:z2.number().nullable().optional(),severityLabel:z2.string().nullable().optional(),fixedIn:z2.array(z2.string()),isMalicious:z2.boolean().nullable().optional()});var packageUpgradeVersionVulnerabilitySummarySchema=z2.object({version:z2.string(),publishedAt:z2.string().nullable().optional(),deprecated:z2.boolean().nullable().optional(),deprecationReason:z2.string().nullable().optional(),affectedCount:z2.number().int(),nonAffectingCount:z2.number().int(),allCount:z2.number().int(),lastModifiedAt:z2.string().nullable().optional(),advisories:z2.array(packageUpgradeAdvisorySchema)}).nullable().optional();var packageUpgradeTransitivePackagePageSchema=z2.object({entries:z2.array(z2.object({id:z2.string(),registry:z2.string(),name:z2.string(),versions:z2.array(z2.string()),affectedCount:z2.number().int(),maxSeverityScore:z2.number().nullable().optional(),maxSeverityLabel:z2.string().nullable().optional(),advisoryIds:z2.array(z2.string())})),totalCount:z2.number().int(),truncated:z2.boolean()});var packageUpgradeTransitiveSecuritySchema=z2.object({currentAffected:z2.number().int(),targetAffected:z2.number().int(),introducedPackages:z2.array(z2.string()),fixedPackages:z2.array(z2.string()),introducedPackageDetails:packageUpgradeTransitivePackagePageSchema,fixedPackageDetails:packageUpgradeTransitivePackagePageSchema,stillAffectedPackageDetails:packageUpgradeTransitivePackagePageSchema}).nullable().optional();var packageUpgradeSecuritySchema=z2.object({current:packageUpgradeVersionVulnerabilitySummarySchema,target:packageUpgradeVersionVulnerabilitySummarySchema,added:z2.array(packageUpgradeAdvisorySchema),removed:z2.array(packageUpgradeAdvisorySchema),notAddressed:z2.array(packageUpgradeAdvisorySchema),fixed:z2.array(packageUpgradeAdvisorySchema),introduced:z2.array(packageUpgradeAdvisorySchema),unchanged:z2.array(packageUpgradeAdvisorySchema),transitive:packageUpgradeTransitiveSecuritySchema});var packageUpgradeChangelogEntrySchema=z2.object({version:z2.string().nullable().optional(),publishedAt:z2.string().nullable().optional(),htmlUrl:z2.string().nullable().optional(),body:z2.string().nullable().optional(),bodyPreview:z2.string().nullable().optional(),headline:z2.string().nullable().optional(),signals:z2.array(z2.string())});var packageUpgradeChangelogSchema=z2.object({source:z2.string().nullable().optional(),fallback:z2.string().nullable().optional(),entries:z2.array(packageUpgradeChangelogEntrySchema),sampledEntries:z2.array(packageUpgradeChangelogEntrySchema),keywordEntries:z2.array(packageUpgradeChangelogEntrySchema),totalKeywordEntries:z2.number().int(),totalEntries:z2.number().int(),totalEntriesWithBodies:z2.number().int(),truncated:z2.boolean(),hasReleaseNoteBodies:z2.boolean(),breakingSignals:z2.array(z2.string()),migrationSignals:z2.array(z2.string())});var packageUpgradeCompatibilitySchema=z2.object({peerDependencyChanges:z2.array(z2.string()),notes:z2.array(z2.string())}).nullable().optional();var packageUpgradeDependencyChangeItemSchema=z2.object({name:z2.string(),registry:z2.string().nullable().optional(),version:z2.string().nullable().optional(),fromVersions:z2.array(z2.string()),toVersions:z2.array(z2.string()),constraint:z2.string().nullable().optional(),type:z2.string().nullable().optional()});var packageUpgradeDependencyChangeGroupSchema=z2.object({added:z2.array(packageUpgradeDependencyChangeItemSchema),removed:z2.array(packageUpgradeDependencyChangeItemSchema),changed:z2.array(packageUpgradeDependencyChangeItemSchema)});var packageUpgradeDependencyChangesSchema=z2.object({direct:packageUpgradeDependencyChangeGroupSchema,transitive:packageUpgradeDependencyChangeGroupSchema}).nullable().optional();var packageUpgradeDependencyIssuesSchema=z2.object({currentTotal:z2.number().int(),targetTotal:z2.number().int(),introducedDeprecated:z2.array(z2.string()),introducedDuplicates:z2.array(z2.string()),introducedConflicts:z2.array(z2.string()),introducedOutdated:z2.array(z2.string())}).nullable().optional();var packageUpgradeReviewSchema=z2.object({registry:z2.string(),name:z2.string(),currentVersion:z2.string(),targetVersion:z2.string(),latestVersion:z2.string().nullable().optional(),versionDelta:z2.string(),security:packageUpgradeSecuritySchema,changelog:packageUpgradeChangelogSchema,compatibility:packageUpgradeCompatibilitySchema,dependencyChanges:packageUpgradeDependencyChangesSchema,dependencyIssues:packageUpgradeDependencyIssuesSchema,unknowns:z2.array(z2.string())});var packageUpgradeReviewResponseSchema=z2.object({summary:z2.object({total:z2.number().int(),withUnknowns:z2.number().int(),withAddedAdvisories:z2.number().int(),withBreakingSignals:z2.number().int(),withDirectDependencyChanges:z2.number().int(),withTransitiveVulnerabilityAdditions:z2.number().int()}),reviews:z2.array(packageUpgradeReviewSchema)});var packageUpgradeReviewGraphQLResponseSchema=z2.object({data:z2.object({packageUpgradeReview:packageUpgradeReviewResponseSchema.nullable().optional()}).nullable().optional(),errors:z2.array(graphQLErrorSchema2).optional()});var PACKAGE_UPGRADE_REVIEW_QUERY=`
|
|
884
|
+
query PackageUpgradeReview(
|
|
885
|
+
$packages: [PackageUpgradeReviewPackageInput!]!
|
|
886
|
+
$includeTransitiveSecurity: Boolean!
|
|
887
|
+
$includeDependencyIssues: Boolean!
|
|
888
|
+
$minSeverity: Float
|
|
889
|
+
$changelogLimit: Int!
|
|
890
|
+
) {
|
|
891
|
+
packageUpgradeReview(
|
|
892
|
+
packages: $packages
|
|
893
|
+
includeTransitiveSecurity: $includeTransitiveSecurity
|
|
894
|
+
minSeverity: $minSeverity
|
|
895
|
+
changelogLimit: $changelogLimit
|
|
896
|
+
) {
|
|
897
|
+
summary {
|
|
898
|
+
total
|
|
899
|
+
withUnknowns
|
|
900
|
+
withAddedAdvisories
|
|
901
|
+
withBreakingSignals
|
|
902
|
+
withDirectDependencyChanges
|
|
903
|
+
withTransitiveVulnerabilityAdditions
|
|
904
|
+
}
|
|
905
|
+
reviews {
|
|
906
|
+
registry
|
|
907
|
+
name
|
|
908
|
+
currentVersion
|
|
909
|
+
targetVersion
|
|
910
|
+
latestVersion
|
|
911
|
+
versionDelta
|
|
912
|
+
security {
|
|
913
|
+
current {
|
|
914
|
+
version
|
|
915
|
+
publishedAt
|
|
916
|
+
deprecated
|
|
917
|
+
deprecationReason
|
|
918
|
+
affectedCount
|
|
919
|
+
nonAffectingCount
|
|
920
|
+
allCount
|
|
921
|
+
lastModifiedAt
|
|
922
|
+
advisories {
|
|
923
|
+
...PackageUpgradeAdvisoryFields
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
target {
|
|
927
|
+
version
|
|
928
|
+
publishedAt
|
|
929
|
+
deprecated
|
|
930
|
+
deprecationReason
|
|
931
|
+
affectedCount
|
|
932
|
+
nonAffectingCount
|
|
933
|
+
allCount
|
|
934
|
+
lastModifiedAt
|
|
935
|
+
advisories {
|
|
936
|
+
...PackageUpgradeAdvisoryFields
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
added {
|
|
940
|
+
...PackageUpgradeAdvisoryFields
|
|
941
|
+
}
|
|
942
|
+
removed {
|
|
943
|
+
...PackageUpgradeAdvisoryFields
|
|
944
|
+
}
|
|
945
|
+
notAddressed {
|
|
946
|
+
...PackageUpgradeAdvisoryFields
|
|
947
|
+
}
|
|
948
|
+
fixed {
|
|
949
|
+
...PackageUpgradeAdvisoryFields
|
|
950
|
+
}
|
|
951
|
+
introduced {
|
|
952
|
+
...PackageUpgradeAdvisoryFields
|
|
953
|
+
}
|
|
954
|
+
unchanged {
|
|
955
|
+
...PackageUpgradeAdvisoryFields
|
|
956
|
+
}
|
|
957
|
+
transitive @include(if: $includeTransitiveSecurity) {
|
|
958
|
+
currentAffected
|
|
959
|
+
targetAffected
|
|
960
|
+
introducedPackages
|
|
961
|
+
fixedPackages
|
|
962
|
+
introducedPackageDetails(first: 50) {
|
|
963
|
+
...PackageUpgradeTransitivePackagePageFields
|
|
964
|
+
}
|
|
965
|
+
fixedPackageDetails(first: 50) {
|
|
966
|
+
...PackageUpgradeTransitivePackagePageFields
|
|
967
|
+
}
|
|
968
|
+
stillAffectedPackageDetails(first: 50) {
|
|
969
|
+
...PackageUpgradeTransitivePackagePageFields
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
changelog {
|
|
974
|
+
source
|
|
975
|
+
fallback
|
|
976
|
+
entries {
|
|
977
|
+
...PackageUpgradeChangelogEntryFields
|
|
978
|
+
}
|
|
979
|
+
sampledEntries {
|
|
980
|
+
...PackageUpgradeChangelogEntryFields
|
|
981
|
+
}
|
|
982
|
+
keywordEntries {
|
|
983
|
+
...PackageUpgradeChangelogEntryFields
|
|
984
|
+
}
|
|
985
|
+
totalKeywordEntries
|
|
986
|
+
totalEntries
|
|
987
|
+
totalEntriesWithBodies
|
|
988
|
+
truncated
|
|
989
|
+
hasReleaseNoteBodies
|
|
990
|
+
breakingSignals
|
|
991
|
+
migrationSignals
|
|
992
|
+
}
|
|
993
|
+
compatibility {
|
|
994
|
+
peerDependencyChanges
|
|
995
|
+
notes
|
|
996
|
+
}
|
|
997
|
+
dependencyChanges {
|
|
998
|
+
direct {
|
|
999
|
+
...PackageUpgradeDependencyChangeGroupFields
|
|
1000
|
+
}
|
|
1001
|
+
transitive {
|
|
1002
|
+
...PackageUpgradeDependencyChangeGroupFields
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
dependencyIssues @include(if: $includeDependencyIssues) {
|
|
1006
|
+
currentTotal
|
|
1007
|
+
targetTotal
|
|
1008
|
+
introducedDeprecated
|
|
1009
|
+
introducedDuplicates
|
|
1010
|
+
introducedConflicts
|
|
1011
|
+
introducedOutdated
|
|
1012
|
+
}
|
|
1013
|
+
unknowns
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
fragment PackageUpgradeAdvisoryFields on PackageUpgradeAdvisorySummary {
|
|
1019
|
+
id
|
|
1020
|
+
aliases
|
|
1021
|
+
summary
|
|
1022
|
+
severity
|
|
1023
|
+
severityLabel
|
|
1024
|
+
fixedIn
|
|
1025
|
+
isMalicious
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
fragment PackageUpgradeTransitivePackagePageFields on PackageUpgradeTransitivePackagePage {
|
|
1029
|
+
entries {
|
|
1030
|
+
id
|
|
1031
|
+
registry
|
|
1032
|
+
name
|
|
1033
|
+
versions
|
|
1034
|
+
affectedCount
|
|
1035
|
+
maxSeverityScore
|
|
1036
|
+
maxSeverityLabel
|
|
1037
|
+
advisoryIds
|
|
1038
|
+
}
|
|
1039
|
+
totalCount
|
|
1040
|
+
truncated
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
fragment PackageUpgradeChangelogEntryFields on PackageUpgradeChangelogEntry {
|
|
1044
|
+
version
|
|
1045
|
+
publishedAt
|
|
1046
|
+
htmlUrl
|
|
1047
|
+
body
|
|
1048
|
+
bodyPreview
|
|
1049
|
+
headline
|
|
1050
|
+
signals
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
fragment PackageUpgradeDependencyChangeGroupFields on PackageUpgradeDependencyChangeGroup {
|
|
1054
|
+
added {
|
|
1055
|
+
name
|
|
1056
|
+
registry
|
|
1057
|
+
version
|
|
1058
|
+
fromVersions
|
|
1059
|
+
toVersions
|
|
1060
|
+
constraint
|
|
1061
|
+
type
|
|
1062
|
+
}
|
|
1063
|
+
removed {
|
|
1064
|
+
name
|
|
1065
|
+
registry
|
|
1066
|
+
version
|
|
1067
|
+
fromVersions
|
|
1068
|
+
toVersions
|
|
1069
|
+
constraint
|
|
1070
|
+
type
|
|
1071
|
+
}
|
|
1072
|
+
changed {
|
|
1073
|
+
name
|
|
1074
|
+
registry
|
|
1075
|
+
version
|
|
1076
|
+
fromVersions
|
|
1077
|
+
toVersions
|
|
1078
|
+
constraint
|
|
1079
|
+
type
|
|
1080
|
+
}
|
|
1081
|
+
}`;var changelogPackageInfoSchema=z2.object({name:z2.string().nullable().optional(),registry:z2.string().nullable().optional(),repoUrl:z2.string().nullable().optional(),fromVersion:z2.string().nullable().optional(),toVersion:z2.string().nullable().optional(),limit:z2.number().int().nullable().optional()}).nullable().optional();var changelogEntryDetailSchema=z2.object({version:z2.string().nullable().optional(),normalizedVersion:z2.string().nullable().optional(),body:z2.string().nullable().optional(),htmlUrl:z2.string().nullable().optional(),publishedAt:z2.string().nullable().optional()});var changelogReportResponseSchema=z2.object({package:changelogPackageInfoSchema,source:z2.string().nullable().optional(),entries:z2.array(changelogEntryDetailSchema).nullable().optional()});var changelogGraphQLResponseSchema=z2.object({data:z2.object({packageChangelog:changelogReportResponseSchema.nullable().optional()}).nullable().optional(),errors:z2.array(graphQLErrorSchema2).optional()});var PACKAGE_CHANGELOG_QUERY=`
|
|
867
1082
|
query PackageChangelog(
|
|
868
1083
|
$registry: Registry
|
|
869
1084
|
$name: String
|
|
@@ -872,6 +1087,7 @@ query PackageChangelog(
|
|
|
872
1087
|
$fromVersion: String
|
|
873
1088
|
$toVersion: String
|
|
874
1089
|
$limit: Int
|
|
1090
|
+
$includeBodies: Boolean! = true
|
|
875
1091
|
) {
|
|
876
1092
|
packageChangelog(
|
|
877
1093
|
registry: $registry
|
|
@@ -894,10 +1110,9 @@ query PackageChangelog(
|
|
|
894
1110
|
entries {
|
|
895
1111
|
version
|
|
896
1112
|
normalizedVersion
|
|
897
|
-
body
|
|
1113
|
+
body @include(if: $includeBodies)
|
|
898
1114
|
htmlUrl
|
|
899
1115
|
publishedAt
|
|
900
|
-
metadata
|
|
901
1116
|
}
|
|
902
1117
|
}
|
|
903
1118
|
}`;var packageDocSourceKindSchema=z2.enum(["CRAWLED","REPOSITORY"]);var packageDocPageSummarySchema=z2.object({id:z2.string().nullable().optional(),title:z2.string().nullable().optional(),slug:z2.string().nullable().optional(),order:z2.number().int().nullable().optional(),linkName:z2.string().nullable().optional(),lastUpdatedAt:z2.string().nullable().optional(),sourceKind:packageDocSourceKindSchema.nullable().optional(),sourceUrl:z2.string().nullable().optional(),repoUrl:z2.string().nullable().optional(),gitRef:z2.string().nullable().optional(),requestedRef:z2.string().nullable().optional(),filePath:z2.string().nullable().optional()});var packageDocsPageInfoSchema=z2.object({hasNextPage:z2.boolean(),endCursor:z2.string().nullable().optional(),totalCount:z2.number().int().nullable().optional()}).nullable().optional();var packageDocsListResponseSchema=z2.object({registry:z2.string().nullable().optional(),packageName:z2.string().nullable().optional(),version:z2.string().nullable().optional(),stale:z2.boolean().nullable().optional(),pages:z2.array(packageDocPageSummarySchema).nullable().optional(),pageInfo:packageDocsPageInfoSchema});var packageDocSourceSchema=z2.object({url:z2.string().nullable().optional(),label:z2.string().nullable().optional()}).nullable().optional();var packageDocPageSchema=z2.object({id:z2.string().nullable().optional(),title:z2.string().nullable().optional(),content:z2.string().nullable().optional(),contentFormat:z2.string().nullable().optional(),breadcrumbs:z2.array(z2.string()).nullable().optional(),linkName:z2.string().nullable().optional(),lastUpdatedAt:z2.string().nullable().optional(),sourceKind:packageDocSourceKindSchema.nullable().optional(),source:packageDocSourceSchema,repoUrl:z2.string().nullable().optional(),gitRef:z2.string().nullable().optional(),requestedRef:z2.string().nullable().optional(),filePath:z2.string().nullable().optional(),baseUrl:z2.string().nullable().optional()}).nullable().optional();var packageDocResultResponseSchema=z2.object({registry:z2.string().nullable().optional(),packageName:z2.string().nullable().optional(),version:z2.string().nullable().optional(),sourceKind:packageDocSourceKindSchema.nullable().optional(),page:packageDocPageSchema});var packageDocsListGraphQLResponseSchema=z2.object({data:z2.object({listPackageDocs:packageDocsListResponseSchema.nullable().optional()}).nullable().optional(),errors:z2.array(graphQLErrorSchema2).optional()});var packageDocReadGraphQLResponseSchema=z2.object({data:z2.object({getDocPage:packageDocResultResponseSchema.nullable().optional()}).nullable().optional(),errors:z2.array(graphQLErrorSchema2).optional()});var LIST_PACKAGE_DOCS_QUERY=`
|
|
@@ -966,7 +1181,7 @@ query ReadPackageDoc($pageId: String!) {
|
|
|
966
1181
|
baseUrl
|
|
967
1182
|
}
|
|
968
1183
|
}
|
|
969
|
-
}`;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:(error)=>error instanceof AuthenticationError,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},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){const status=response.status;const detail=parseDetail3(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)}createTransportError(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})}createGraphQLError(errors){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,this.runtime.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:break}return new PackageIntelligenceBackendError(message,undefined,code,retryable)}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:(error)=>error instanceof AuthenticationError,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 version2=data.package?.version??undefined;if(!name||!version2){throw new MalformedPackageIntelligenceResponseError("Vulnerability report response missing required name/version.")}const identity={name,version:version2,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:(error)=>error instanceof AuthenticationError,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:(error)=>error instanceof AuthenticationError,executeWithToken:(token)=>this.executePackageUpgradeDependencyProbe(token,params)}))}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,maxDepth:params.maxDepth,lifecycle:params.lifecycle&¶ms.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 version2=data.package?.version??undefined;if(!name||!version2){throw new MalformedPackageIntelligenceResponseError("Package dependencies response missing required name/version.")}const identity={name,version:version2,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((version2)=>({version:version2.version,severity:version2.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:(error)=>error instanceof AuthenticationError,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},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&¶ms.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,metadata:entry.metadata??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:(error)=>error instanceof AuthenticationError,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:(error)=>error instanceof AuthenticationError,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 parseDetail3(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:(error)=>error instanceof AuthenticationError,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}}}var PKGSEER_REGISTRY_ARGS=["npm","pypi","hex","crates","nuget","maven","zig","vcpkg","packagist","rubygems","go","swift"];var registryMap={npm:"NPM",pypi:"PYPI",hex:"HEX",crates:"CRATES",nuget:"NUGET",maven:"MAVEN",zig:"ZIG",vcpkg:"VCPKG",packagist:"PACKAGIST",rubygems:"RUBYGEMS",go:"GO",swift:"SWIFT"};var PKGSEER_REGISTRY_LIST=PKGSEER_REGISTRY_ARGS.join(", ");function toPkgseerRegistry(registry){return registryMap[registry]}function toPkgseerRegistryLowercase(registry){for(const[lower,upper]of Object.entries(registryMap)){if(upper===registry)return lower}throw new Error(`Unknown registry value: ${String(registry)} (schema drift?)`)}function isKnownPkgseerRegistryArg(value){return value in registryMap}import{createHash as createHash2,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 createHash2("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{}}}var APP_DIR="githits";var USER_AUTH_STATE_DIR=".githits";function getAppConfigDir(fs){return getAppConfigDirForEnv(fs,process.env,process.platform,fs.getHomeDir())}function getAppConfigDirForEnv(fs,env,platform,home=getHomeDirForEnv(fs,env,platform)){if(platform==="win32"){return fs.joinPath(env.APPDATA??fs.joinPath(home,"AppData","Roaming"),APP_DIR)}return fs.joinPath(env.XDG_CONFIG_HOME??fs.joinPath(home,".config"),APP_DIR)}function getAuthConfigPath(fs){return fs.joinPath(getAppConfigDir(fs),"config.toml")}function getAuthConfigPathForEnv(fs,env,platform){return fs.joinPath(getAppConfigDirForEnv(fs,env,platform),"config.toml")}function getAuthFileStorageDir(fs){return fs.joinPath(getAppConfigDir(fs),"auth")}function getAuthFileStorageDirForEnv(fs,env,platform){return fs.joinPath(getAppConfigDirForEnv(fs,env,platform),"auth")}function getHomeDirForEnv(fs,env,platform){if(platform==="win32"&&env.USERPROFILE)return env.USERPROFILE;if(platform!=="win32"&&env.HOME)return env.HOME;return fs.getHomeDir()}function getLegacyAuthStorageDir(fs){return fs.joinPath(fs.getHomeDir(),USER_AUTH_STATE_DIR)}function getLegacyAuthStorageDirForEnv(fs,env,platform){return fs.joinPath(getHomeDirForEnv(fs,env,platform),USER_AUTH_STATE_DIR)}function getAuthLockDir(fs){return fs.joinPath(fs.getHomeDir(),USER_AUTH_STATE_DIR)}function getLegacyMacAppConfigDir(fs){return fs.joinPath(fs.getHomeDir(),"Library","Application Support",APP_DIR)}function getLegacyMacAppConfigDirForEnv(fs,env){return fs.joinPath(getHomeDirForEnv(fs,env,"darwin"),"Library","Application Support",APP_DIR)}function getLegacyMacAuthConfigPath(fs){return fs.joinPath(getLegacyMacAppConfigDir(fs),"config.toml")}function getLegacyMacAuthConfigPathForEnv(fs,env){return fs.joinPath(getLegacyMacAppConfigDirForEnv(fs,env),"config.toml")}function getLegacyMacAuthFileStorageDir(fs){return fs.joinPath(getLegacyMacAppConfigDir(fs),"auth")}function getLegacyMacAuthFileStorageDirForEnv(fs,env){return fs.joinPath(getLegacyMacAppConfigDirForEnv(fs,env),"auth")}import{parse as parseToml}from"smol-toml";import{z as z3}from"zod";var AUTH_STORAGE_MODES=["keychain","file"];var AUTH_STORAGE_MODE_VALUES=new Set(AUTH_STORAGE_MODES);var CONFIG_SCHEMA=z3.object({auth:z3.object({storage:z3.string().optional()}).optional()}).passthrough();class AuthConfigError extends Error{constructor(message){super(message);this.name="AuthConfigError"}}function parseAuthStorageMode(value){const normalized=value.trim().toLowerCase();if(AUTH_STORAGE_MODE_VALUES.has(normalized)){return normalized}throw new AuthConfigError(`Invalid auth storage mode "${value}". Use "keychain" or "file". File mode stores OAuth credentials unencrypted on disk.`)}async function loadAuthConfig(fs){let configPath=getAuthConfigPath(fs);const envMode=process.env.GITHITS_AUTH_STORAGE;if(envMode!==undefined&&envMode.trim()!==""){try{return{storage:parseAuthStorageMode(envMode),configPath}}catch(error){if(error instanceof AuthConfigError){throw new AuthConfigError(`Invalid GITHITS_AUTH_STORAGE: ${error.message}`)}throw error}}if(!await fs.exists(configPath)){const legacyMacConfigPath=getLegacyMacAuthConfigPath(fs);if(process.platform==="darwin"&&await fs.exists(legacyMacConfigPath)){configPath=legacyMacConfigPath}else{return{storage:"keychain",configPath}}}let rawConfig;try{rawConfig=parseToml(await fs.readFile(configPath))}catch(error){const message=error instanceof Error?error.message:String(error);throw new AuthConfigError(`Cannot parse GitHits config at ${configPath}: ${message}`)}const parsed=CONFIG_SCHEMA.safeParse(rawConfig);if(!parsed.success){throw new AuthConfigError(`Invalid GitHits config at ${configPath}: ${z3.prettifyError(parsed.error)}`)}const configuredMode=parsed.data.auth?.storage;if(configuredMode===undefined||configuredMode.trim()===""){return{storage:"keychain",configPath}}try{return{storage:parseAuthStorageMode(configuredMode),configPath}}catch(error){if(error instanceof AuthConfigError){throw new AuthConfigError(`Invalid GitHits config at ${configPath}: ${error.message}`)}throw error}}var AUTH_FILE="auth.json";var CLIENT_FILE="client.json";var DIR_MODE=448;class AuthStorageImpl{fs;configDir;authPath;clientPath;constructor(fs,configDir){this.fs=fs;this.configDir=configDir??getAuthFileStorageDir(fs);this.authPath=fs.joinPath(this.configDir,AUTH_FILE);this.clientPath=fs.joinPath(this.configDir,CLIENT_FILE)}getStorageLocation(){return this.configDir}async loadTokens(baseUrl2){const stored=await this.loadAuthFile();if(!stored)return null;return stored.tokens[normalizeBaseUrl(baseUrl2)]??null}async saveTokens(baseUrl2,data){const stored=await this.loadAuthFile()??{version:1,tokens:{}};stored.tokens[normalizeBaseUrl(baseUrl2)]=data;await this.fs.ensureDir(this.configDir,DIR_MODE);await this.fs.atomicWriteFile(this.authPath,JSON.stringify(stored,null,2))}async saveTokensIfUnchanged(baseUrl2,expected,data){const current=await this.loadTokens(baseUrl2);if(!sameTokenData(current,expected))return false;await this.saveTokens(baseUrl2,data);return true}async clearTokens(baseUrl2){const stored=await this.loadAuthFile();if(!stored)return;delete stored.tokens[normalizeBaseUrl(baseUrl2)];if(Object.keys(stored.tokens).length===0){await this.fs.deleteFile(this.authPath)}else{await this.fs.atomicWriteFile(this.authPath,JSON.stringify(stored,null,2))}}async clearTokensIfUnchanged(baseUrl2,expected){const current=await this.loadTokens(baseUrl2);if(!sameTokenData(current,expected))return false;await this.clearTokens(baseUrl2);return true}clearActiveTokensIfUnchanged(baseUrl2,expected){return this.clearTokensIfUnchanged(baseUrl2,expected)}async loadClient(baseUrl2){const stored=await this.loadClientFile();if(!stored)return null;return stored.clients[normalizeBaseUrl(baseUrl2)]??null}async clearClient(baseUrl2){const stored=await this.loadClientFile();if(!stored)return;delete stored.clients[normalizeBaseUrl(baseUrl2)];if(Object.keys(stored.clients).length===0){await this.fs.deleteFile(this.clientPath)}else{await this.fs.atomicWriteFile(this.clientPath,JSON.stringify(stored,null,2))}}async saveClient(baseUrl2,data){const stored=await this.loadClientFile()??{version:1,clients:{}};stored.clients[normalizeBaseUrl(baseUrl2)]=data;await this.fs.ensureDir(this.configDir,DIR_MODE);await this.fs.atomicWriteFile(this.clientPath,JSON.stringify(stored,null,2))}clearActiveClient(baseUrl2){return this.clearClient(baseUrl2)}async saveAuthSession(baseUrl2,client,tokens){await this.saveClient(baseUrl2,client);await this.saveTokens(baseUrl2,tokens)}async clearAuthSession(baseUrl2){await clearAuthSessionBestEffort(()=>this.clearTokens(baseUrl2),()=>this.clearClient(baseUrl2))}async loadAuthFile(){if(!await this.fs.exists(this.authPath))return null;try{const content=await this.fs.readFile(this.authPath);const data=JSON.parse(content);if(data.version!==1||!data.tokens)return null;return data}catch{return null}}async loadClientFile(){if(!await this.fs.exists(this.clientPath))return null;try{const content=await this.fs.readFile(this.clientPath);const data=JSON.parse(content);if(data.version!==1||!data.clients)return null;return data}catch{return null}}}function normalizeBaseUrl(url){return url.replace(/\/+$/,"")}function sameTokenData(a,b){if(a===null||b===null)return a===b;return a.accessToken===b.accessToken&&a.refreshToken===b.refreshToken&&a.expiresAt===b.expiresAt&&a.createdAt===b.createdAt}async function clearAuthSessionBestEffort(clearTokens,clearClient){let firstError;try{await clearTokens()}catch(error){firstError=error}try{await clearClient()}catch(error){firstError??=error}if(firstError)throw firstError}var DIAGNOSTICS_FILE="diagnostics.json";var DIR_MODE2=448;var CLEAR_REASONS=new Set(["logout","terminal_invalid_refresh_token","terminal_invalid_client"]);class AuthDiagnosticsStorage{fs;configDir;diagnosticsPath;constructor(fs,configDir){this.fs=fs;this.configDir=configDir??getAuthFileStorageDir(fs);this.diagnosticsPath=fs.joinPath(this.configDir,DIAGNOSTICS_FILE)}async recordClear(baseUrl2,reason){try{const stored=await this.loadFile()??{version:1,events:{}};stored.events[normalizeBaseUrl(baseUrl2)]={reason,at:new Date().toISOString()};await this.fs.ensureDir(this.configDir,DIR_MODE2);await this.fs.atomicWriteFile(this.diagnosticsPath,JSON.stringify(stored,null,2))}catch{}}async load(baseUrl2){const stored=await this.loadFile();if(!stored)return null;const event=stored.events[normalizeBaseUrl(baseUrl2)]??null;return isAuthClearEvent(event)?event:null}async loadFile(){if(!await this.fs.exists(this.diagnosticsPath))return null;try{const content=await this.fs.readFile(this.diagnosticsPath);const data=JSON.parse(content);if(!isRecord(data)||data.version!==1||!isRecord(data.events)){return null}return data}catch{return null}}}function isRecord(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function isAuthClearReason(value){return typeof value==="string"&&CLEAR_REASONS.has(value)}function isAuthClearEvent(value){if(value===null||typeof value!=="object")return false;return isAuthClearReason(value.reason)&&typeof value.at==="string"&&value.at.length>0}import{createServer}from"node:http";class TokenRefreshError extends Error{status;body;oauthError;oauthErrorDescription;constructor(status,body){const details=parseOAuthErrorBody(body);const description=details.oauthErrorDescription??details.oauthError??body.trim();super(description?`Token refresh failed: ${description}`:`Token refresh failed with HTTP ${status}`);this.name="TokenRefreshError";this.status=status;this.body=body;this.oauthError=details.oauthError;this.oauthErrorDescription=details.oauthErrorDescription}}class AuthServiceImpl{fetchFn;fetchTimeoutMs;constructor(fetchFn,fetchTimeoutMs=DEFAULT_FETCH_TIMEOUT_MS){this.fetchFn=fetchFn;this.fetchTimeoutMs=fetchTimeoutMs}async discoverEndpoints(mcpBaseUrl){const url=`${mcpBaseUrl}/.well-known/oauth-authorization-server`;const response=await fetchWithTimeout(url,{},this.fetchOptions());if(!response.ok){throw new Error(`Failed to discover OAuth endpoints: ${response.status} ${response.statusText}`)}const data=await response.json();const authorizationEndpoint=data.authorization_endpoint;const tokenEndpoint=data.token_endpoint;const registrationEndpoint=data.registration_endpoint;if(!authorizationEndpoint||!tokenEndpoint||!registrationEndpoint){throw new Error("OAuth metadata missing required endpoints")}return{authorizationEndpoint,tokenEndpoint,registrationEndpoint}}async registerClient(params){const response=await fetchWithTimeout(params.registrationEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:"GitHits CLI",redirect_uris:[params.redirectUri],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"client_secret_post"})},this.fetchOptions());if(!response.ok){const error=await response.text();throw new Error(`Client registration failed: ${error}`)}const data=await response.json();if(!data.client_id||!data.client_secret){throw new Error("Client registration response missing required fields")}return{clientId:data.client_id,clientSecret:data.client_secret}}generatePkceParams(){const verifier=generateCodeVerifier();return{verifier,challenge:generateCodeChallenge(verifier),state:generateState()}}buildAuthUrl(params){const url=new URL(params.authorizationEndpoint);url.searchParams.set("response_type","code");url.searchParams.set("client_id",params.clientId);url.searchParams.set("redirect_uri",params.redirectUri);url.searchParams.set("state",params.state);url.searchParams.set("code_challenge",params.codeChallenge);url.searchParams.set("code_challenge_method","S256");return url.toString()}startCallbackServer(port,expectedState){let closeTimer;const server=createServer();let callbackHandled=false;let resolved=false;const result=new Promise((resolve)=>{server.on("request",(req,res)=>{const address=server.address();const actualPort=typeof address==="object"&&address!==null?address.port:port;const url=new URL(req.url??"",`http://127.0.0.1:${actualPort}`);if(url.pathname==="/favicon.ico"){res.writeHead(204);res.end();return}if(url.pathname!=="/callback"){if(callbackHandled){sendHtmlResponse(res,200,successHtml("You're already signed in."));return}sendHtmlResponse(res,404,errorHtml("Invalid callback path.","Run `githits login` to start authentication."));return}const code=url.searchParams.get("code");const state=url.searchParams.get("state");const error=url.searchParams.get("error");const errorDescription=url.searchParams.get("error_description");const evaluation=evaluateCallback({code,state,error,errorDescription,expectedState});callbackHandled=true;sendHtmlResponse(res,evaluation.statusCode,evaluation.html);if(!resolved){resolved=true;resolve(evaluation.result)}if(closeTimer)clearTimeout(closeTimer);closeTimer=setTimeout(()=>closeServer(server),1500)})});return new Promise((resolve,reject)=>{const onError=(err)=>{reject(new Error(`Failed to start callback server: ${err.message}`))};server.once("error",onError);server.listen(port,"127.0.0.1",()=>{server.off("error",onError);server.on("error",()=>{});resolve({result,close:async()=>{if(closeTimer)clearTimeout(closeTimer);await closeServer(server)}})})})}async exchangeCodeForTokens(params){const body=new URLSearchParams({grant_type:"authorization_code",client_id:params.clientId,client_secret:params.clientSecret,code:params.code,code_verifier:params.codeVerifier,redirect_uri:params.redirectUri});const response=await fetchWithTimeout(params.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:body.toString()},this.fetchOptions());if(!response.ok){const error=await response.text();throw new Error(`Token exchange failed: ${error}`)}return parseTokenResponse(await response.json())}async refreshAccessToken(params){const body=new URLSearchParams({grant_type:"refresh_token",client_id:params.clientId,client_secret:params.clientSecret,refresh_token:params.refreshToken});const response=await fetchWithTimeout(params.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:body.toString()},this.fetchOptions());if(!response.ok){const error=await response.text();throw new TokenRefreshError(response.status,error)}return parseRefreshTokenResponse(await response.json())}fetchOptions(){return{fetchFn:this.fetchFn,timeoutMs:this.fetchTimeoutMs}}}function classifyTerminalRefreshError(error){if(!(error instanceof TokenRefreshError))return;const oauthError=error.oauthError?.toLowerCase();const text=[error.oauthError,error.oauthErrorDescription,error.body,error.message].filter((part)=>typeof part==="string").join(" ").toLowerCase();if(oauthError==="invalid_client"||text.includes("client not found")||text.includes("client id not found")||text.includes("client_id not found")||text.includes("oauth client not found")||text.includes("client does not match")||text.includes("client authentication required")||text.includes("invalid client credentials")){return"invalid_client"}if(oauthError==="invalid_grant"&&(text.includes("invalid refresh token")||text.includes("refresh token already used")||text.includes("already used")||text.includes("session expired")||text.includes("session not found"))){return"invalid_refresh_token"}return}function parseOAuthErrorBody(body){try{const parsed=JSON.parse(body);return{oauthError:stringField(parsed.error),oauthErrorDescription:stringField(parsed.error_description)??stringField(parsed.errorDescription)??stringField(parsed.message)??stringField(parsed.msg)}}catch{return{oauthError:undefined,oauthErrorDescription:undefined}}}function stringField(value){return typeof value==="string"&&value.trim()?value:undefined}function parseTokenResponse(data){const d=data;if(!d.access_token||!d.refresh_token){throw new Error("Token response missing required fields")}return{accessToken:d.access_token,refreshToken:d.refresh_token,expiresIn:d.expires_in||3600}}function parseRefreshTokenResponse(data){const d=data;if(!d.access_token){throw new Error("Token response missing required fields")}return{accessToken:d.access_token,refreshToken:typeof d.refresh_token==="string"?d.refresh_token:undefined,expiresIn:d.expires_in||3600}}function successHtml(title="You're signed in"){return`<!DOCTYPE html>
|
|
1184
|
+
}`;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:(error)=>error instanceof AuthenticationError,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){const status=response.status;const detail=parseDetail3(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)}createTransportError(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})}createGraphQLError(errors){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,this.runtime.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:break}return new PackageIntelligenceBackendError(message,undefined,code,retryable)}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:(error)=>error instanceof AuthenticationError,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 version2=data.package?.version??undefined;if(!name||!version2){throw new MalformedPackageIntelligenceResponseError("Vulnerability report response missing required name/version.")}const identity={name,version:version2,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:(error)=>error instanceof AuthenticationError,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:(error)=>error instanceof AuthenticationError,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:(error)=>error instanceof AuthenticationError,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&¶ms.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 version2=data.package?.version??undefined;if(!name||!version2){throw new MalformedPackageIntelligenceResponseError("Package dependencies response missing required name/version.")}const identity={name,version:version2,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((version2)=>({version:version2.version,severity:version2.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:(error)=>error instanceof AuthenticationError,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&¶ms.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:(error)=>error instanceof AuthenticationError,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:(error)=>error instanceof AuthenticationError,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 parseDetail3(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:(error)=>error instanceof AuthenticationError,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}}}var PKGSEER_REGISTRY_ARGS=["npm","pypi","hex","crates","nuget","maven","zig","vcpkg","packagist","rubygems","go","swift"];var registryMap={npm:"NPM",pypi:"PYPI",hex:"HEX",crates:"CRATES",nuget:"NUGET",maven:"MAVEN",zig:"ZIG",vcpkg:"VCPKG",packagist:"PACKAGIST",rubygems:"RUBYGEMS",go:"GO",swift:"SWIFT"};var PKGSEER_REGISTRY_LIST=PKGSEER_REGISTRY_ARGS.join(", ");function toPkgseerRegistry(registry){return registryMap[registry]}function toPkgseerRegistryLowercase(registry){for(const[lower,upper]of Object.entries(registryMap)){if(upper===registry)return lower}throw new Error(`Unknown registry value: ${String(registry)} (schema drift?)`)}function isKnownPkgseerRegistryArg(value){return value in registryMap}import{createHash as createHash2,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 createHash2("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{}}}var APP_DIR="githits";var USER_AUTH_STATE_DIR=".githits";function getAppConfigDir(fs){return getAppConfigDirForEnv(fs,process.env,process.platform,fs.getHomeDir())}function getAppConfigDirForEnv(fs,env,platform,home=getHomeDirForEnv(fs,env,platform)){if(platform==="win32"){return fs.joinPath(env.APPDATA??fs.joinPath(home,"AppData","Roaming"),APP_DIR)}return fs.joinPath(env.XDG_CONFIG_HOME??fs.joinPath(home,".config"),APP_DIR)}function getAuthConfigPath(fs){return fs.joinPath(getAppConfigDir(fs),"config.toml")}function getAuthConfigPathForEnv(fs,env,platform){return fs.joinPath(getAppConfigDirForEnv(fs,env,platform),"config.toml")}function getAuthFileStorageDir(fs){return fs.joinPath(getAppConfigDir(fs),"auth")}function getAuthFileStorageDirForEnv(fs,env,platform){return fs.joinPath(getAppConfigDirForEnv(fs,env,platform),"auth")}function getHomeDirForEnv(fs,env,platform){if(platform==="win32"&&env.USERPROFILE)return env.USERPROFILE;if(platform!=="win32"&&env.HOME)return env.HOME;return fs.getHomeDir()}function getLegacyAuthStorageDir(fs){return fs.joinPath(fs.getHomeDir(),USER_AUTH_STATE_DIR)}function getLegacyAuthStorageDirForEnv(fs,env,platform){return fs.joinPath(getHomeDirForEnv(fs,env,platform),USER_AUTH_STATE_DIR)}function getAuthLockDir(fs){return fs.joinPath(fs.getHomeDir(),USER_AUTH_STATE_DIR)}function getLegacyMacAppConfigDir(fs){return fs.joinPath(fs.getHomeDir(),"Library","Application Support",APP_DIR)}function getLegacyMacAppConfigDirForEnv(fs,env){return fs.joinPath(getHomeDirForEnv(fs,env,"darwin"),"Library","Application Support",APP_DIR)}function getLegacyMacAuthConfigPath(fs){return fs.joinPath(getLegacyMacAppConfigDir(fs),"config.toml")}function getLegacyMacAuthConfigPathForEnv(fs,env){return fs.joinPath(getLegacyMacAppConfigDirForEnv(fs,env),"config.toml")}function getLegacyMacAuthFileStorageDir(fs){return fs.joinPath(getLegacyMacAppConfigDir(fs),"auth")}function getLegacyMacAuthFileStorageDirForEnv(fs,env){return fs.joinPath(getLegacyMacAppConfigDirForEnv(fs,env),"auth")}import{parse as parseToml}from"smol-toml";import{z as z3}from"zod";var AUTH_STORAGE_MODES=["keychain","file"];var AUTH_STORAGE_MODE_VALUES=new Set(AUTH_STORAGE_MODES);var CONFIG_SCHEMA=z3.object({auth:z3.object({storage:z3.string().optional()}).optional()}).passthrough();class AuthConfigError extends Error{constructor(message){super(message);this.name="AuthConfigError"}}function parseAuthStorageMode(value){const normalized=value.trim().toLowerCase();if(AUTH_STORAGE_MODE_VALUES.has(normalized)){return normalized}throw new AuthConfigError(`Invalid auth storage mode "${value}". Use "keychain" or "file". File mode stores OAuth credentials unencrypted on disk.`)}async function loadAuthConfig(fs){let configPath=getAuthConfigPath(fs);const envMode=process.env.GITHITS_AUTH_STORAGE;if(envMode!==undefined&&envMode.trim()!==""){try{return{storage:parseAuthStorageMode(envMode),configPath}}catch(error){if(error instanceof AuthConfigError){throw new AuthConfigError(`Invalid GITHITS_AUTH_STORAGE: ${error.message}`)}throw error}}if(!await fs.exists(configPath)){const legacyMacConfigPath=getLegacyMacAuthConfigPath(fs);if(process.platform==="darwin"&&await fs.exists(legacyMacConfigPath)){configPath=legacyMacConfigPath}else{return{storage:"keychain",configPath}}}let rawConfig;try{rawConfig=parseToml(await fs.readFile(configPath))}catch(error){const message=error instanceof Error?error.message:String(error);throw new AuthConfigError(`Cannot parse GitHits config at ${configPath}: ${message}`)}const parsed=CONFIG_SCHEMA.safeParse(rawConfig);if(!parsed.success){throw new AuthConfigError(`Invalid GitHits config at ${configPath}: ${z3.prettifyError(parsed.error)}`)}const configuredMode=parsed.data.auth?.storage;if(configuredMode===undefined||configuredMode.trim()===""){return{storage:"keychain",configPath}}try{return{storage:parseAuthStorageMode(configuredMode),configPath}}catch(error){if(error instanceof AuthConfigError){throw new AuthConfigError(`Invalid GitHits config at ${configPath}: ${error.message}`)}throw error}}var AUTH_FILE="auth.json";var CLIENT_FILE="client.json";var DIR_MODE=448;class AuthStorageImpl{fs;configDir;authPath;clientPath;constructor(fs,configDir){this.fs=fs;this.configDir=configDir??getAuthFileStorageDir(fs);this.authPath=fs.joinPath(this.configDir,AUTH_FILE);this.clientPath=fs.joinPath(this.configDir,CLIENT_FILE)}getStorageLocation(){return this.configDir}async loadTokens(baseUrl2){const stored=await this.loadAuthFile();if(!stored)return null;return stored.tokens[normalizeBaseUrl(baseUrl2)]??null}async saveTokens(baseUrl2,data){const stored=await this.loadAuthFile()??{version:1,tokens:{}};stored.tokens[normalizeBaseUrl(baseUrl2)]=data;await this.fs.ensureDir(this.configDir,DIR_MODE);await this.fs.atomicWriteFile(this.authPath,JSON.stringify(stored,null,2))}async saveTokensIfUnchanged(baseUrl2,expected,data){const current=await this.loadTokens(baseUrl2);if(!sameTokenData(current,expected))return false;await this.saveTokens(baseUrl2,data);return true}async clearTokens(baseUrl2){const stored=await this.loadAuthFile();if(!stored)return;delete stored.tokens[normalizeBaseUrl(baseUrl2)];if(Object.keys(stored.tokens).length===0){await this.fs.deleteFile(this.authPath)}else{await this.fs.atomicWriteFile(this.authPath,JSON.stringify(stored,null,2))}}async clearTokensIfUnchanged(baseUrl2,expected){const current=await this.loadTokens(baseUrl2);if(!sameTokenData(current,expected))return false;await this.clearTokens(baseUrl2);return true}clearActiveTokensIfUnchanged(baseUrl2,expected){return this.clearTokensIfUnchanged(baseUrl2,expected)}async loadClient(baseUrl2){const stored=await this.loadClientFile();if(!stored)return null;return stored.clients[normalizeBaseUrl(baseUrl2)]??null}async clearClient(baseUrl2){const stored=await this.loadClientFile();if(!stored)return;delete stored.clients[normalizeBaseUrl(baseUrl2)];if(Object.keys(stored.clients).length===0){await this.fs.deleteFile(this.clientPath)}else{await this.fs.atomicWriteFile(this.clientPath,JSON.stringify(stored,null,2))}}async saveClient(baseUrl2,data){const stored=await this.loadClientFile()??{version:1,clients:{}};stored.clients[normalizeBaseUrl(baseUrl2)]=data;await this.fs.ensureDir(this.configDir,DIR_MODE);await this.fs.atomicWriteFile(this.clientPath,JSON.stringify(stored,null,2))}clearActiveClient(baseUrl2){return this.clearClient(baseUrl2)}async saveAuthSession(baseUrl2,client,tokens){await this.saveClient(baseUrl2,client);await this.saveTokens(baseUrl2,tokens)}async clearAuthSession(baseUrl2){await clearAuthSessionBestEffort(()=>this.clearTokens(baseUrl2),()=>this.clearClient(baseUrl2))}async loadAuthFile(){if(!await this.fs.exists(this.authPath))return null;try{const content=await this.fs.readFile(this.authPath);const data=JSON.parse(content);if(data.version!==1||!data.tokens)return null;return data}catch{return null}}async loadClientFile(){if(!await this.fs.exists(this.clientPath))return null;try{const content=await this.fs.readFile(this.clientPath);const data=JSON.parse(content);if(data.version!==1||!data.clients)return null;return data}catch{return null}}}function normalizeBaseUrl(url){return url.replace(/\/+$/,"")}function sameTokenData(a,b){if(a===null||b===null)return a===b;return a.accessToken===b.accessToken&&a.refreshToken===b.refreshToken&&a.expiresAt===b.expiresAt&&a.createdAt===b.createdAt}async function clearAuthSessionBestEffort(clearTokens,clearClient){let firstError;try{await clearTokens()}catch(error){firstError=error}try{await clearClient()}catch(error){firstError??=error}if(firstError)throw firstError}var DIAGNOSTICS_FILE="diagnostics.json";var DIR_MODE2=448;var CLEAR_REASONS=new Set(["logout","terminal_invalid_refresh_token","terminal_invalid_client"]);class AuthDiagnosticsStorage{fs;configDir;diagnosticsPath;constructor(fs,configDir){this.fs=fs;this.configDir=configDir??getAuthFileStorageDir(fs);this.diagnosticsPath=fs.joinPath(this.configDir,DIAGNOSTICS_FILE)}async recordClear(baseUrl2,reason){try{const stored=await this.loadFile()??{version:1,events:{}};stored.events[normalizeBaseUrl(baseUrl2)]={reason,at:new Date().toISOString()};await this.fs.ensureDir(this.configDir,DIR_MODE2);await this.fs.atomicWriteFile(this.diagnosticsPath,JSON.stringify(stored,null,2))}catch{}}async load(baseUrl2){const stored=await this.loadFile();if(!stored)return null;const event=stored.events[normalizeBaseUrl(baseUrl2)]??null;return isAuthClearEvent(event)?event:null}async loadFile(){if(!await this.fs.exists(this.diagnosticsPath))return null;try{const content=await this.fs.readFile(this.diagnosticsPath);const data=JSON.parse(content);if(!isRecord(data)||data.version!==1||!isRecord(data.events)){return null}return data}catch{return null}}}function isRecord(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function isAuthClearReason(value){return typeof value==="string"&&CLEAR_REASONS.has(value)}function isAuthClearEvent(value){if(value===null||typeof value!=="object")return false;return isAuthClearReason(value.reason)&&typeof value.at==="string"&&value.at.length>0}import{createServer}from"node:http";class TokenRefreshError extends Error{status;body;oauthError;oauthErrorDescription;constructor(status,body){const details=parseOAuthErrorBody(body);const description=details.oauthErrorDescription??details.oauthError??body.trim();super(description?`Token refresh failed: ${description}`:`Token refresh failed with HTTP ${status}`);this.name="TokenRefreshError";this.status=status;this.body=body;this.oauthError=details.oauthError;this.oauthErrorDescription=details.oauthErrorDescription}}class AuthServiceImpl{fetchFn;fetchTimeoutMs;constructor(fetchFn,fetchTimeoutMs=DEFAULT_FETCH_TIMEOUT_MS){this.fetchFn=fetchFn;this.fetchTimeoutMs=fetchTimeoutMs}async discoverEndpoints(mcpBaseUrl){const url=`${mcpBaseUrl}/.well-known/oauth-authorization-server`;const response=await fetchWithTimeout(url,{},this.fetchOptions());if(!response.ok){throw new Error(`Failed to discover OAuth endpoints: ${response.status} ${response.statusText}`)}const data=await response.json();const authorizationEndpoint=data.authorization_endpoint;const tokenEndpoint=data.token_endpoint;const registrationEndpoint=data.registration_endpoint;if(!authorizationEndpoint||!tokenEndpoint||!registrationEndpoint){throw new Error("OAuth metadata missing required endpoints")}return{authorizationEndpoint,tokenEndpoint,registrationEndpoint}}async registerClient(params){const response=await fetchWithTimeout(params.registrationEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:"GitHits CLI",redirect_uris:[params.redirectUri],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"client_secret_post"})},this.fetchOptions());if(!response.ok){const error=await response.text();throw new Error(`Client registration failed: ${error}`)}const data=await response.json();if(!data.client_id||!data.client_secret){throw new Error("Client registration response missing required fields")}return{clientId:data.client_id,clientSecret:data.client_secret}}generatePkceParams(){const verifier=generateCodeVerifier();return{verifier,challenge:generateCodeChallenge(verifier),state:generateState()}}buildAuthUrl(params){const url=new URL(params.authorizationEndpoint);url.searchParams.set("response_type","code");url.searchParams.set("client_id",params.clientId);url.searchParams.set("redirect_uri",params.redirectUri);url.searchParams.set("state",params.state);url.searchParams.set("code_challenge",params.codeChallenge);url.searchParams.set("code_challenge_method","S256");return url.toString()}startCallbackServer(port,expectedState){let closeTimer;const server=createServer();let callbackHandled=false;let resolved=false;const result=new Promise((resolve)=>{server.on("request",(req,res)=>{const address=server.address();const actualPort=typeof address==="object"&&address!==null?address.port:port;const url=new URL(req.url??"",`http://127.0.0.1:${actualPort}`);if(url.pathname==="/favicon.ico"){res.writeHead(204);res.end();return}if(url.pathname!=="/callback"){if(callbackHandled){sendHtmlResponse(res,200,successHtml("You're already signed in."));return}sendHtmlResponse(res,404,errorHtml("Invalid callback path.","Run `githits login` to start authentication."));return}const code=url.searchParams.get("code");const state=url.searchParams.get("state");const error=url.searchParams.get("error");const errorDescription=url.searchParams.get("error_description");const evaluation=evaluateCallback({code,state,error,errorDescription,expectedState});callbackHandled=true;sendHtmlResponse(res,evaluation.statusCode,evaluation.html);if(!resolved){resolved=true;resolve(evaluation.result)}if(closeTimer)clearTimeout(closeTimer);closeTimer=setTimeout(()=>closeServer(server),1500)})});return new Promise((resolve,reject)=>{const onError=(err)=>{reject(new Error(`Failed to start callback server: ${err.message}`))};server.once("error",onError);server.listen(port,"127.0.0.1",()=>{server.off("error",onError);server.on("error",()=>{});resolve({result,close:async()=>{if(closeTimer)clearTimeout(closeTimer);await closeServer(server)}})})})}async exchangeCodeForTokens(params){const body=new URLSearchParams({grant_type:"authorization_code",client_id:params.clientId,client_secret:params.clientSecret,code:params.code,code_verifier:params.codeVerifier,redirect_uri:params.redirectUri});const response=await fetchWithTimeout(params.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:body.toString()},this.fetchOptions());if(!response.ok){const error=await response.text();throw new Error(`Token exchange failed: ${error}`)}return parseTokenResponse(await response.json())}async refreshAccessToken(params){const body=new URLSearchParams({grant_type:"refresh_token",client_id:params.clientId,client_secret:params.clientSecret,refresh_token:params.refreshToken});const response=await fetchWithTimeout(params.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:body.toString()},this.fetchOptions());if(!response.ok){const error=await response.text();throw new TokenRefreshError(response.status,error)}return parseRefreshTokenResponse(await response.json())}fetchOptions(){return{fetchFn:this.fetchFn,timeoutMs:this.fetchTimeoutMs}}}function classifyTerminalRefreshError(error){if(!(error instanceof TokenRefreshError))return;const oauthError=error.oauthError?.toLowerCase();const text=[error.oauthError,error.oauthErrorDescription,error.body,error.message].filter((part)=>typeof part==="string").join(" ").toLowerCase();if(oauthError==="invalid_client"||text.includes("client not found")||text.includes("client id not found")||text.includes("client_id not found")||text.includes("oauth client not found")||text.includes("client does not match")||text.includes("client authentication required")||text.includes("invalid client credentials")){return"invalid_client"}if(oauthError==="invalid_grant"&&(text.includes("invalid refresh token")||text.includes("refresh token already used")||text.includes("already used")||text.includes("session expired")||text.includes("session not found"))){return"invalid_refresh_token"}return}function parseOAuthErrorBody(body){try{const parsed=JSON.parse(body);return{oauthError:stringField(parsed.error),oauthErrorDescription:stringField(parsed.error_description)??stringField(parsed.errorDescription)??stringField(parsed.message)??stringField(parsed.msg)}}catch{return{oauthError:undefined,oauthErrorDescription:undefined}}}function stringField(value){return typeof value==="string"&&value.trim()?value:undefined}function parseTokenResponse(data){const d=data;if(!d.access_token||!d.refresh_token){throw new Error("Token response missing required fields")}return{accessToken:d.access_token,refreshToken:d.refresh_token,expiresIn:d.expires_in||3600}}function parseRefreshTokenResponse(data){const d=data;if(!d.access_token){throw new Error("Token response missing required fields")}return{accessToken:d.access_token,refreshToken:typeof d.refresh_token==="string"?d.refresh_token:undefined,expiresIn:d.expires_in||3600}}function successHtml(title="You're signed in"){return`<!DOCTYPE html>
|
|
970
1185
|
<html><head>
|
|
971
1186
|
<title>GitHits CLI</title>
|
|
972
1187
|
<meta charset="utf-8">
|
|
@@ -1301,4 +1516,4 @@ Options:
|
|
|
1301
1516
|
in ${configPath}, or run with GITHITS_AUTH_STORAGE=file.
|
|
1302
1517
|
|
|
1303
1518
|
Warning: file storage is plaintext. Use it only on machines where local file access is trusted.`}class ModeAwareFileAuthStorage{storage;mode;configPath;constructor(storage,mode,configPath="your GitHits config.toml"){this.storage=storage;this.mode=mode;this.configPath=configPath}loadTokens(baseUrl2){return this.storage.loadTokens(baseUrl2)}async saveTokens(baseUrl2,data){this.assertFileMode();await this.storage.saveTokens(baseUrl2,data)}async saveTokensIfUnchanged(baseUrl2,expected,data){this.assertFileMode();return this.storage.saveTokensIfUnchanged(baseUrl2,expected,data)}clearTokens(baseUrl2){return this.storage.clearTokens(baseUrl2)}clearTokensIfUnchanged(baseUrl2,expected){return this.storage.clearTokensIfUnchanged(baseUrl2,expected)}clearActiveTokensIfUnchanged(baseUrl2,expected){return this.storage.clearActiveTokensIfUnchanged(baseUrl2,expected)}loadClient(baseUrl2){return this.storage.loadClient(baseUrl2)}async saveClient(baseUrl2,data){this.assertFileMode();await this.storage.saveClient(baseUrl2,data)}clearClient(baseUrl2){return this.storage.clearClient(baseUrl2)}clearActiveClient(baseUrl2){return this.storage.clearActiveClient(baseUrl2)}async saveAuthSession(baseUrl2,client,tokens){this.assertFileMode();await this.storage.saveAuthSession(baseUrl2,client,tokens)}clearAuthSession(baseUrl2){return this.storage.clearAuthSession(baseUrl2)}getStorageLocation(){return this.storage.getStorageLocation()}assertFileMode(){if(this.mode==="file")return;throw new AuthStoragePolicyError(createFileAuthStorageGuidance(this.configPath))}}class MigratingAuthStorage{primary;file;legacy;mode;configPath;onWarning;metadata;additionalLegacyStores;warnedAmbiguousPlaintext=false;constructor(primary,file,legacy,mode,configPath="your GitHits config.toml",onWarning=()=>{},metadata,additionalLegacyStores=[]){this.primary=primary;this.file=file;this.legacy=legacy;this.mode=mode;this.configPath=configPath;this.onWarning=onWarning;this.metadata=metadata;this.additionalLegacyStores=additionalLegacyStores}async loadTokens(baseUrl2){if(this.mode==="file"){return this.loadTokensFileMode(baseUrl2)}return this.loadTokensKeychainMode(baseUrl2)}async saveTokens(baseUrl2,data){if(this.mode==="file"){await this.file.saveTokens(baseUrl2,data);await this.saveMetadataBestEffort(baseUrl2,data);return}try{await this.primary.saveTokens(baseUrl2,data);await this.saveMetadataBestEffort(baseUrl2,data)}catch(error){throw this.toPolicyError(error)}}async saveTokensIfUnchanged(baseUrl2,expected,data){const current=await this.loadTokens(baseUrl2);if(!this.sameTokenData(current,expected))return false;await this.saveTokens(baseUrl2,data);return true}async clearTokens(baseUrl2){const primaryError=await this.clearBestEffort(()=>this.primary.clearTokens(baseUrl2));await this.clearBestEffort(()=>this.file.clearTokens(baseUrl2));await this.clearBestEffort(()=>this.legacy.clearTokens(baseUrl2));for(const legacy of this.additionalLegacyStores){await this.clearBestEffort(()=>legacy.clearTokens(baseUrl2))}await this.clearBestEffort(()=>this.metadata?.clear(baseUrl2)??Promise.resolve());if(primaryError&&!(primaryError instanceof KeychainUnavailableError)){throw primaryError}}async clearTokensIfUnchanged(baseUrl2,expected){const current=await this.loadTokens(baseUrl2);if(!this.sameTokenData(current,expected))return false;await this.clearTokens(baseUrl2);return true}async clearActiveTokensIfUnchanged(baseUrl2,expected){const current=await this.currentActiveTokens(baseUrl2);if(!this.sameTokenData(current,expected))return false;let firstError;for(const store of this.activeStores()){const error=await this.clearBestEffort(()=>store.clearTokens(baseUrl2));firstError??=error}const metadataError=await this.clearBestEffort(()=>this.metadata?.clear(baseUrl2)??Promise.resolve());firstError??=metadataError;if(firstError&&!(firstError instanceof KeychainUnavailableError)){throw firstError}return true}async loadClient(baseUrl2){if(this.mode==="file"){return this.loadClientFileMode(baseUrl2)}return this.loadClientKeychainMode(baseUrl2)}async saveClient(baseUrl2,data){if(this.mode==="file"){await this.file.saveClient(baseUrl2,data);return}try{await this.primary.saveClient(baseUrl2,data)}catch(error){throw this.toPolicyError(error)}}async clearClient(baseUrl2){const primaryError=await this.clearBestEffort(()=>this.primary.clearClient(baseUrl2));await this.clearBestEffort(()=>this.file.clearClient(baseUrl2));await this.clearBestEffort(()=>this.legacy.clearClient(baseUrl2));for(const legacy of this.additionalLegacyStores){await this.clearBestEffort(()=>legacy.clearClient(baseUrl2))}if(primaryError&&!(primaryError instanceof KeychainUnavailableError)){throw primaryError}}async clearActiveClient(baseUrl2){let firstError;for(const store of this.activeStores()){const error=await this.clearBestEffort(()=>store.clearClient(baseUrl2));firstError??=error}if(firstError&&!(firstError instanceof KeychainUnavailableError)){throw firstError}}async saveAuthSession(baseUrl2,client,tokens){if(this.mode==="file"){await this.file.saveAuthSession(baseUrl2,client,tokens);await this.saveMetadataBestEffort(baseUrl2,tokens);return}try{await this.primary.saveAuthSession(baseUrl2,client,tokens);await this.saveMetadataBestEffort(baseUrl2,tokens)}catch(error){throw this.toPolicyError(error)}}async clearAuthSession(baseUrl2){const primaryError=await this.clearBestEffort(()=>this.primary.clearAuthSession(baseUrl2));await this.clearBestEffort(()=>this.file.clearAuthSession(baseUrl2));await this.clearBestEffort(()=>this.legacy.clearAuthSession(baseUrl2));for(const legacy of this.additionalLegacyStores){await this.clearBestEffort(()=>legacy.clearAuthSession(baseUrl2))}await this.clearBestEffort(()=>this.metadata?.clear(baseUrl2)??Promise.resolve());if(primaryError&&!(primaryError instanceof KeychainUnavailableError)){throw primaryError}}getStorageLocation(){return this.mode==="file"?this.file.getStorageLocation():this.primary.getStorageLocation()}async loadTokensKeychainMode(baseUrl2){try{const primaryTokens=await this.primary.loadTokens(baseUrl2);if(primaryTokens){await this.saveMetadataBestEffort(baseUrl2,primaryTokens);return primaryTokens}}catch(error){if(!(error instanceof KeychainUnavailableError))throw error}return null}async loadTokensFileMode(baseUrl2){const candidate=await this.selectPlaintextTokenCandidate(baseUrl2);if(candidate){if(candidate.source==="legacy"){await this.file.saveTokens(baseUrl2,candidate.data);await this.clearBestEffort(()=>candidate.storage.clearTokens(baseUrl2))}await this.saveMetadataBestEffort(baseUrl2,candidate.data);return candidate.data}return null}async loadClientKeychainMode(baseUrl2){try{const primaryClient=await this.primary.loadClient(baseUrl2);if(primaryClient)return primaryClient}catch(error){if(!(error instanceof KeychainUnavailableError))throw error}return null}async loadClientFileMode(baseUrl2){const candidate=await this.selectPlaintextClientCandidate(baseUrl2);if(candidate){if(candidate.source==="legacy"){await this.file.saveClient(baseUrl2,candidate.data);await this.clearBestEffort(()=>candidate.storage.clearClient(baseUrl2))}return candidate.data}return null}async selectPlaintextTokenCandidate(baseUrl2){const candidates=[];const fileTokens=await this.file.loadTokens(baseUrl2);if(fileTokens){candidates.push({data:fileTokens,source:"file",storage:this.file,timestamp:fileTokens.createdAt,ambiguous:false})}for(const legacy of this.getLegacyStores()){const legacyTokens=await legacy.loadTokens(baseUrl2);if(legacyTokens){candidates.push({data:legacyTokens,source:"legacy",storage:legacy,timestamp:legacyTokens.createdAt,ambiguous:false})}}return this.selectNewestCandidate(candidates)}async selectPlaintextClientCandidate(baseUrl2){const candidates=[];const fileClient=await this.file.loadClient(baseUrl2);if(fileClient){candidates.push({data:fileClient,source:"file",storage:this.file,timestamp:fileClient.registeredAt,ambiguous:false})}for(const legacy of this.getLegacyStores()){const legacyClient=await legacy.loadClient(baseUrl2);if(legacyClient){candidates.push({data:legacyClient,source:"legacy",storage:legacy,timestamp:legacyClient.registeredAt,ambiguous:false})}}return this.selectNewestCandidate(candidates)}selectNewestCandidate(candidates){if(candidates.length===0)return null;if(candidates.length===1)return candidates[0]??null;const parsed=candidates.map((candidate)=>({candidate,timestampMs:Date.parse(candidate.timestamp)}));if(parsed.some((entry)=>Number.isNaN(entry.timestampMs))){this.warnAmbiguousPlaintext();const selected=candidates.find((candidate)=>candidate.source==="file")??null;if(selected)selected.ambiguous=true;return selected}const sorted=[...parsed].sort((a,b)=>b.timestampMs-a.timestampMs);const first=sorted[0];const second=sorted[1];if(!first)return candidates[0]??null;if(second&&first.timestampMs===second.timestampMs){this.warnAmbiguousPlaintext();const selected=candidates.find((candidate)=>candidate.source==="file")??null;if(!selected)return null;selected.ambiguous=true;return selected}return first.candidate}getLegacyStores(){return[...this.additionalLegacyStores,this.legacy]}activeStores(){return this.mode==="file"?[this.file,...this.getLegacyStores()]:[this.primary]}async currentActiveTokens(baseUrl2){if(this.mode==="file"){const candidate=await this.selectPlaintextTokenCandidate(baseUrl2);return candidate?.data??null}try{return await this.primary.loadTokens(baseUrl2)}catch(error){if(error instanceof KeychainUnavailableError)return null;throw error}}async clearBestEffort(fn){try{await fn();return}catch(error){return error}}async saveMetadataBestEffort(baseUrl2,tokens){await this.clearBestEffort(()=>this.metadata?.saveFromTokens(baseUrl2,tokens)??Promise.resolve())}toPolicyError(error){if(!(error instanceof KeychainUnavailableError))return error;return new AuthStoragePolicyError(`System keychain is unavailable. ${createFileAuthStorageGuidance(this.configPath)}`)}warnAmbiguousPlaintext(){if(this.warnedAmbiguousPlaintext)return;this.warnedAmbiguousPlaintext=true;this.onWarning("Warning: multiple plaintext auth entries exist with ambiguous timestamps; using the new config auth path and leaving the other entry intact.")}sameTokenData(a,b){if(a===null||b===null)return a===b;return a.accessToken===b.accessToken&&a.refreshToken===b.refreshToken&&a.expiresAt===b.expiresAt&&a.createdAt===b.createdAt}}var PROACTIVE_REFRESH_RATIO=0.9;function shouldRefreshToken(token,ratio,now){if(!token.expiresAt){return{expired:false,shouldRefresh:false}}const expiresAt=new Date(token.expiresAt).getTime();const nowMs=now.getTime();if(nowMs>=expiresAt){return{expired:true,shouldRefresh:true}}const createdAt=new Date(token.createdAt).getTime();const lifetime=expiresAt-createdAt;if(lifetime<=0){return{expired:false,shouldRefresh:false}}const threshold=createdAt+lifetime*ratio;return{expired:false,shouldRefresh:nowMs>=threshold}}async function refreshExpiredToken(authService,authStorage,mcpUrl){const manager=new TokenManager({authService,authStorage,mcpUrl});return manager.forceRefresh()}class TokenManager{authService;authStorage;mcpUrl;authDiagnostics;cachedToken=null;softRefreshPromise=null;forceRefreshPromise=null;constructor(deps){this.authService=deps.authService;this.authStorage=deps.authStorage;this.mcpUrl=deps.mcpUrl;this.authDiagnostics=deps.authDiagnostics}async getToken(){return withTelemetrySpan("token-manager.get-token",async()=>{const activeForceRefresh=this.forceRefreshPromise;if(activeForceRefresh){return(await activeForceRefresh).accessToken}if(!this.cachedToken){const storedToken=await withTelemetrySpan("token-manager.load-tokens",()=>this.authStorage.loadTokens(this.mcpUrl));const startedForceRefresh=this.forceRefreshPromise;if(startedForceRefresh){return(await startedForceRefresh).accessToken}if(!this.cachedToken){this.cachedToken=storedToken}if(!this.cachedToken)return}const currentToken=this.cachedToken.accessToken;const{expired,shouldRefresh}=shouldRefreshToken(this.cachedToken,PROACTIVE_REFRESH_RATIO,new Date);if(!shouldRefresh){return currentToken}const refresh=await this.refreshFromGetToken();if(refresh.accessToken){return refresh.accessToken}if(refresh.invalidatedCurrentToken){return}if(!expired){return currentToken}return})}async forceRefresh(){return withTelemetrySpan("token-manager.force-refresh",()=>this.refreshAfterAuthFailure())}refreshFromGetToken(){return this.softRefresh()}async softRefresh(){if(this.forceRefreshPromise)return this.forceRefreshPromise;if(this.softRefreshPromise)return this.softRefreshPromise;this.softRefreshPromise=this.executeRefresh();try{return await this.softRefreshPromise}finally{this.softRefreshPromise=null}}async refreshAfterAuthFailure(){const result=await this.forceEndpointRefresh();return result.accessToken}async forceEndpointRefresh(){if(this.forceRefreshPromise)return this.forceRefreshPromise;this.forceRefreshPromise=(async()=>{const softResult=await this.softRefreshPromise?.catch(()=>{return});if(softResult?.accessToken&&softResult.refreshedViaEndpoint){return softResult}return this.executeRefresh()})();try{return await this.forceRefreshPromise}finally{this.forceRefreshPromise=null}}async executeRefresh(){return withAuthStorageLock(this.authStorage,()=>withTelemetrySpan("token-manager.refresh",async()=>{const candidate=await this.loadRefreshCandidate();if(!candidate)return refreshResult(undefined,false);if(candidate.externallyUpdated){const{shouldRefresh}=shouldRefreshToken(candidate.tokens,PROACTIVE_REFRESH_RATIO,new Date);if(!shouldRefresh)return refreshResult(candidate.tokens.accessToken,false)}const tokens=candidate.tokens;const client=await withTelemetrySpan("token-manager.load-client",()=>this.authStorage.loadClient(this.mcpUrl));if(!client)return refreshResult(undefined,false);let response;try{const metadata=await withTelemetrySpan("token-manager.discover-endpoints",()=>this.authService.discoverEndpoints(this.mcpUrl));response=await withTelemetrySpan("token-manager.refresh-access-token",()=>this.authService.refreshAccessToken({tokenEndpoint:metadata.tokenEndpoint,clientId:client.clientId,clientSecret:client.clientSecret,refreshToken:tokens.refreshToken}))}catch(error){const terminalFailure=classifyTerminalRefreshError(error);const reloadedToken=await this.loadExternallyUpdatedToken(tokens);if(reloadedToken)return refreshResult(reloadedToken.accessToken,false);const isExpired=tokens.expiresAt?new Date>=new Date(tokens.expiresAt):false;if(terminalFailure){return this.clearTerminalRefreshFailure(tokens,terminalFailure)}if(candidate.externallyUpdated&&!isExpired){return refreshResult(tokens.accessToken,false)}if(isExpired){const currentStoredTokens=await this.loadExternallyUpdatedToken(tokens);if(currentStoredTokens){return refreshResult(currentStoredTokens.accessToken,false)}const cleared=await withTelemetrySpan("token-manager.clear-tokens-if-unchanged",()=>this.authStorage.clearActiveTokensIfUnchanged(this.mcpUrl,tokens));if(!cleared){const currentToken=await this.authStorage.loadTokens(this.mcpUrl);this.cachedToken=currentToken;return refreshResult(currentToken?.accessToken,false)}this.cachedToken=null}return refreshResult(undefined,false)}const newTokenData={accessToken:response.accessToken,refreshToken:response.refreshToken??tokens.refreshToken,expiresAt:new Date(Date.now()+response.expiresIn*1000).toISOString(),createdAt:new Date().toISOString()};const saved=await withTelemetrySpan("token-manager.save-tokens",()=>this.authStorage.saveTokensIfUnchanged(this.mcpUrl,tokens,newTokenData));if(!saved){return this.resolveSuccessfulRefreshConflict(tokens,response,newTokenData)}this.cachedToken=newTokenData;return refreshResult(response.accessToken,true)}))}async resolveSuccessfulRefreshConflict(refreshedFrom,response,newTokenData){const currentToken=await withTelemetrySpan("token-manager.reload-tokens",()=>this.authStorage.loadTokens(this.mcpUrl));if(!currentToken){this.cachedToken=null;return refreshResult(undefined,false)}if(!response.refreshToken||currentToken.refreshToken!==refreshedFrom.refreshToken){this.cachedToken=currentToken;return refreshResult(currentToken.accessToken,false)}const saved=await withTelemetrySpan("token-manager.save-rotated-tokens-after-conflict",()=>this.authStorage.saveTokensIfUnchanged(this.mcpUrl,currentToken,newTokenData));if(saved){this.cachedToken=newTokenData;return refreshResult(newTokenData.accessToken,true)}const latestToken=await withTelemetrySpan("token-manager.reload-tokens",()=>this.authStorage.loadTokens(this.mcpUrl));this.cachedToken=latestToken;return refreshResult(latestToken?.accessToken,false)}async clearTerminalRefreshFailure(failedTokens,reason){const cleared=await withTelemetrySpan("token-manager.clear-terminal-refresh-failure",()=>this.authStorage.clearActiveTokensIfUnchanged(this.mcpUrl,failedTokens),{reason:`terminal_${reason}`});if(!cleared){const latestToken=await withTelemetrySpan("token-manager.reload-tokens",()=>this.authStorage.loadTokens(this.mcpUrl));this.cachedToken=latestToken;return refreshResult(latestToken?.accessToken,false,!latestToken)}if(reason==="invalid_client"){await withTelemetrySpan("token-manager.clear-invalid-client",()=>this.authStorage.clearActiveClient(this.mcpUrl),{reason:"terminal_invalid_client"}).catch(()=>{return})}await this.authDiagnostics?.recordClear(this.mcpUrl,`terminal_${reason}`);this.cachedToken=null;return refreshResult(undefined,false,true)}async loadRefreshCandidate(){const storedTokens=await withTelemetrySpan("token-manager.load-tokens",()=>this.authStorage.loadTokens(this.mcpUrl));if(!this.cachedToken){this.cachedToken=storedTokens;return storedTokens?{tokens:storedTokens,externallyUpdated:false}:null}if(!storedTokens){this.cachedToken=null;return null}if(!areSameTokenData(storedTokens,this.cachedToken)){this.cachedToken=storedTokens;return{tokens:storedTokens,externallyUpdated:true}}return{tokens:this.cachedToken,externallyUpdated:false}}async loadExternallyUpdatedToken(failedTokens){const storedTokens=await withTelemetrySpan("token-manager.reload-tokens",()=>this.authStorage.loadTokens(this.mcpUrl));if(!storedTokens)return;if(areSameTokenData(storedTokens,failedTokens))return;this.cachedToken=storedTokens;return storedTokens}}function areSameTokenData(a,b){return a.accessToken===b.accessToken&&a.refreshToken===b.refreshToken&&a.expiresAt===b.expiresAt&&a.createdAt===b.createdAt}function refreshResult(accessToken,refreshedViaEndpoint,invalidatedCurrentToken=false){return{accessToken,refreshedViaEndpoint,invalidatedCurrentToken}}var BASE_CLIENT_NAME="githits-cli";var USER_AGENT=`${BASE_CLIENT_NAME}/${version}`;async function createAuthStorage(fileSystemService){return withTelemetrySpan("container.create-auth-storage",async()=>{const authConfig=await loadAuthConfig(fileSystemService);recordAuthFingerprint(authConfig.storage);return createAuthStorageForMode(fileSystemService,authConfig.storage,authConfig.configPath)})}function recordAuthFingerprint(mode,env=process.env){const handle=startTelemetrySpan("auth.fingerprint",{mode,platform:process.platform,homeSet:Boolean(env.HOME),xdgConfigHomeSet:Boolean(env.XDG_CONFIG_HOME),appDataSet:Boolean(env.APPDATA),userProfileSet:Boolean(env.USERPROFILE)});endTelemetrySpan(handle)}function createAuthStorageForMode(fileSystemService,mode,configPath="your GitHits config.toml"){const fileStorage=new ModeAwareFileAuthStorage(new AuthStorageImpl(fileSystemService,getAuthFileStorageDir(fileSystemService)),mode,configPath);const legacyStorage=new AuthStorageImpl(fileSystemService,getLegacyAuthStorageDir(fileSystemService));const additionalLegacyStores=process.platform==="darwin"?[new AuthStorageImpl(fileSystemService,getLegacyMacAuthFileStorageDir(fileSystemService))]:[];const rawKeyring=new KeyringServiceImpl;const keyring=process.platform==="win32"?new ChunkingKeyringService(rawKeyring,WINDOWS_MAX_ENTRY_SIZE):rawKeyring;const keychainStorage=new KeychainAuthStorage(keyring);const metadataStorage=new AuthSessionMetadataStorage(fileSystemService);return new LockedAuthStorage(new MigratingAuthStorage(keychainStorage,fileStorage,legacyStorage,mode,configPath,(message)=>console.error(message),metadataStorage,additionalLegacyStores),fileSystemService)}async function loadAutoLoginAuthSessionMetadata(){const envToken=getEnvApiToken();if(envToken){const now=new Date().toISOString();return{createdAt:now,expiresAt:null,updatedAt:now}}const fileSystemService=new FileSystemServiceImpl;const metadataStorage=new AuthSessionMetadataStorage(fileSystemService);return metadataStorage.load(getMcpUrl())}async function clearAutoLoginAuthSessionMetadata(){const fileSystemService=new FileSystemServiceImpl;const metadataStorage=new AuthSessionMetadataStorage(fileSystemService);await metadataStorage.clear(getMcpUrl())}async function createAuthCommandDependencies(){return withTelemetrySpan("container.create-auth-command",async()=>{const fileSystemService=new FileSystemServiceImpl;return{authStorage:await createAuthStorage(fileSystemService),authService:new AuthServiceImpl,browserService:new BrowserServiceImpl,fileSystemService,authDiagnostics:new AuthDiagnosticsStorage(fileSystemService),mcpUrl:getMcpUrl(),apiUrl:getApiUrl(),envApiToken:getEnvApiToken()}})}async function createAuthStatusDependencies(){return withTelemetrySpan("container.create-auth-status",async()=>{const fileSystemService=new FileSystemServiceImpl;const envApiToken=getEnvApiToken();return{authStorage:envApiToken?createAuthStorageForMode(fileSystemService,"keychain"):await createAuthStorage(fileSystemService),authService:new AuthServiceImpl,browserService:new BrowserServiceImpl,fileSystemService,authDiagnostics:new AuthDiagnosticsStorage(fileSystemService),mcpUrl:getMcpUrl(),apiUrl:getApiUrl(),envApiToken}})}async function createContainer(options={}){return withTelemetrySpan("container.create",async()=>{const resolveStoredToken=options.resolveStoredToken??true;const mcpUrl=getMcpUrl();const apiUrl=getApiUrl();const codeNavigationUrl=getCodeNavigationUrl();const fileSystemService=new FileSystemServiceImpl;const authService=new AuthServiceImpl;const browserService=new BrowserServiceImpl;const clientHeaders=createClientHeaderBuilder({clientName:options.clientName??BASE_CLIENT_NAME,clientVersion:version,agentProvider:options.agentProvider});const serviceRuntime={clientHeaders,userAgent:USER_AGENT,clientVersion:version};const envToken=getEnvApiToken();if(envToken){const authStorage2=createAuthStorageForMode(fileSystemService,"keychain");const tokenProvider=createStaticTokenProvider(envToken);const codeNavigationService2=new CodeNavigationServiceImpl(codeNavigationUrl,tokenProvider,globalThis.fetch,serviceRuntime);const packageIntelligenceService2=new PackageIntelligenceServiceImpl(codeNavigationUrl,tokenProvider,globalThis.fetch,serviceRuntime);return{authStorage:authStorage2,authService,browserService,fileSystemService,mcpUrl,apiUrl,apiToken:envToken,hasValidToken:true,envApiToken:envToken,codeNavigationUrl,codeNavigationService:codeNavigationService2,packageIntelligenceService:packageIntelligenceService2,githitsService:new GitHitsServiceImpl(apiUrl,envToken,undefined,undefined,serviceRuntime)}}const authStorage=await createAuthStorage(fileSystemService);const tokenManager=new TokenManager({authService,authStorage,mcpUrl,authDiagnostics:new AuthDiagnosticsStorage(fileSystemService)});const apiToken=resolveStoredToken?await withTelemetrySpan("container.token.get",()=>tokenManager.getToken()):undefined;if(resolveStoredToken&&apiToken===undefined){await new AuthSessionMetadataStorage(fileSystemService).clear(mcpUrl)}const codeNavigationService=new CodeNavigationServiceImpl(codeNavigationUrl,tokenManager,globalThis.fetch,serviceRuntime);const packageIntelligenceService=new PackageIntelligenceServiceImpl(codeNavigationUrl,tokenManager,globalThis.fetch,serviceRuntime);return{authStorage,authService,browserService,fileSystemService,mcpUrl,apiUrl,apiToken,hasValidToken:apiToken!==undefined,envApiToken:undefined,codeNavigationUrl,codeNavigationService,packageIntelligenceService,githitsService:new RefreshingGitHitsService(apiUrl,tokenManager,undefined,serviceRuntime)}})}
|
|
1304
|
-
export{CLIENT_UPDATE_REQUIRED_REASON,ClientUpdateRequiredError,debugLog,isTelemetryEnabled,withTelemetrySpan,startTelemetrySpan,endTelemetrySpan,flushTelemetry,LOCAL_AUTHENTICATION_MISSING_MESSAGE,AuthenticationError,CodeNavigationAccessError,CodeNavigationGraphQLError,CodeNavigationIndexingError,CodeNavigationUnresolvableError,MalformedCodeNavigationResponseError,CodeNavigationTargetNotFoundError,CodeNavigationFileNotFoundError,CodeNavigationVersionNotFoundError,CodeNavigationValidationError,CodeNavigationFeatureFlagRequiredError,CodeNavigationNetworkError,CodeNavigationBackendError,DEFAULT_MCP_URL,DEFAULT_API_URL,DEFAULT_CODE_NAV_URL,getCodeNavigationUrl,PackageIntelligenceAccessError,PackageIntelligenceFeatureFlagRequiredError,PackageIntelligenceNetworkError,PackageIntelligenceBackendError,PackageIntelligenceGraphQLError,PackageIntelligenceTargetNotFoundError,PackageIntelligenceValidationError,PackageIntelligenceVersionNotFoundError,MalformedPackageIntelligenceResponseError,PackageIntelligenceChangelogSourceNotFoundError,PKGSEER_REGISTRY_ARGS,PKGSEER_REGISTRY_LIST,toPkgseerRegistry,toPkgseerRegistryLowercase,isKnownPkgseerRegistryArg,getAppConfigDirForEnv,getAuthConfigPathForEnv,getAuthFileStorageDirForEnv,getLegacyAuthStorageDirForEnv,getLegacyMacAuthConfigPathForEnv,getLegacyMacAuthFileStorageDirForEnv,AuthConfigError,parseAuthStorageMode,AuthStorageLockTimeoutError,AuthStoragePolicyError,normalizeBaseUrl,isAuthClearReason,FileSystemServiceImpl,refreshExpiredToken,recordAuthFingerprint,loadAutoLoginAuthSessionMetadata,clearAutoLoginAuthSessionMetadata,createAuthCommandDependencies,createAuthStatusDependencies,createContainer};
|
|
1519
|
+
export{CLIENT_UPDATE_REQUIRED_REASON,ClientUpdateRequiredError,debugLog,isTelemetryEnabled,withTelemetrySpan,startTelemetrySpan,endTelemetrySpan,flushTelemetry,LOCAL_AUTHENTICATION_MISSING_MESSAGE,AuthenticationError,CodeNavigationAccessError,CodeNavigationGraphQLError,CodeNavigationIndexingError,CodeNavigationUnresolvableError,MalformedCodeNavigationResponseError,CodeNavigationTargetNotFoundError,CodeNavigationFileNotFoundError,CodeNavigationVersionNotFoundError,CodeNavigationRefNotFoundError,CodeNavigationValidationError,CodeNavigationFeatureFlagRequiredError,CodeNavigationNetworkError,CodeNavigationBackendError,DEFAULT_MCP_URL,DEFAULT_API_URL,DEFAULT_CODE_NAV_URL,getCodeNavigationUrl,PackageIntelligenceAccessError,PackageIntelligenceFeatureFlagRequiredError,PackageIntelligenceNetworkError,PackageIntelligenceBackendError,PackageIntelligenceGraphQLError,PackageIntelligenceTargetNotFoundError,PackageIntelligenceValidationError,PackageIntelligenceVersionNotFoundError,MalformedPackageIntelligenceResponseError,PackageIntelligenceChangelogSourceNotFoundError,PKGSEER_REGISTRY_ARGS,PKGSEER_REGISTRY_LIST,toPkgseerRegistry,toPkgseerRegistryLowercase,isKnownPkgseerRegistryArg,getAppConfigDirForEnv,getAuthConfigPathForEnv,getAuthFileStorageDirForEnv,getLegacyAuthStorageDirForEnv,getLegacyMacAuthConfigPathForEnv,getLegacyMacAuthFileStorageDirForEnv,AuthConfigError,parseAuthStorageMode,AuthStorageLockTimeoutError,AuthStoragePolicyError,normalizeBaseUrl,isAuthClearReason,FileSystemServiceImpl,refreshExpiredToken,recordAuthFingerprint,loadAutoLoginAuthSessionMetadata,clearAutoLoginAuthSessionMetadata,createAuthCommandDependencies,createAuthStatusDependencies,createContainer};
|