@gitlab/gitlab-ai-provider 3.1.1 → 3.1.3

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/gitlab-agentic-language-model.ts","../src/gitlab-direct-access.ts","../src/gitlab-error.ts","../src/gitlab-oauth-types.ts","../src/gitlab-oauth-manager.ts","../src/model-mappings.ts","../src/gitlab-provider.ts","../src/gitlab-api-tools.ts","../src/gitlab-anthropic-tools.ts","../src/gitlab-project-detector.ts","../src/gitlab-project-cache.ts"],"sourcesContent":["import Anthropic from '@anthropic-ai/sdk';\nimport type { Tool } from '@anthropic-ai/sdk/resources/messages';\nimport { GitLabDirectAccessClient } from './gitlab-direct-access';\nimport { GitLabError } from './gitlab-error';\nimport type {\n LanguageModelV2,\n LanguageModelV2CallOptions,\n LanguageModelV2StreamPart,\n LanguageModelV2FinishReason,\n LanguageModelV2CallWarning,\n LanguageModelV2Content,\n LanguageModelV2Usage,\n LanguageModelV2FunctionTool,\n LanguageModelV2Message,\n LanguageModelV2ToolChoice,\n} from '@ai-sdk/provider';\n\nexport interface GitLabAgenticConfig {\n provider: string;\n instanceUrl: string;\n getHeaders: () => Record<string, string>;\n fetch?: typeof fetch;\n\n /**\n * Optional callback to refresh the API key when a 401 error occurs.\n * Should clear cached credentials and re-fetch from auth provider.\n */\n refreshApiKey?: () => Promise<void>;\n\n /**\n * The Anthropic model to use (e.g., 'claude-sonnet-4-5-20250929')\n * @default 'claude-sonnet-4-5-20250929'\n */\n anthropicModel?: string;\n\n /**\n * Maximum tokens to generate\n * @default 8192\n */\n maxTokens?: number;\n\n /**\n * Feature flags to pass to the GitLab API\n * @default { DuoAgentPlatformNext: true }\n */\n featureFlags?: {\n DuoAgentPlatformNext: true;\n } & Record<string, boolean>;\n}\n\n/**\n * GitLab Agentic Language Model\n *\n * This model uses GitLab's Anthropic proxy to provide native tool calling support\n * for the duo-chat model. It connects to Claude through GitLab's cloud proxy\n * at https://cloud.gitlab.com/ai/v1/proxy/anthropic/\n */\nexport class GitLabAgenticLanguageModel implements LanguageModelV2 {\n readonly specificationVersion = 'v2' as const;\n readonly modelId: string;\n readonly supportedUrls: Record<string, RegExp[]> = {};\n\n private readonly config: GitLabAgenticConfig;\n private readonly directAccessClient: GitLabDirectAccessClient;\n private anthropicClient: Anthropic | null = null;\n\n constructor(modelId: string, config: GitLabAgenticConfig) {\n this.modelId = modelId;\n this.config = config;\n\n this.directAccessClient = new GitLabDirectAccessClient({\n instanceUrl: config.instanceUrl,\n getHeaders: config.getHeaders,\n refreshApiKey: config.refreshApiKey,\n fetch: config.fetch,\n featureFlags: config.featureFlags,\n });\n }\n\n get provider(): string {\n return this.config.provider;\n }\n\n /**\n * Get or create an Anthropic client with valid credentials\n * @param forceRefresh - If true, forces a token refresh before creating the client\n */\n private async getAnthropicClient(forceRefresh: boolean = false): Promise<Anthropic> {\n // Get token from GitLab (will use cache unless forceRefresh is true)\n const tokenData = await this.directAccessClient.getDirectAccessToken(forceRefresh);\n\n // Create new client with the token\n // GitLab's proxy expects:\n // - authToken: sets Authorization: Bearer header (NOT apiKey which sets x-api-key)\n // - defaultHeaders: additional headers from the direct access response\n this.anthropicClient = new Anthropic({\n authToken: tokenData.token,\n baseURL: this.directAccessClient.getAnthropicProxyUrl(),\n defaultHeaders: tokenData.headers,\n });\n\n return this.anthropicClient;\n }\n\n /**\n * Check if an error is a token-related authentication error that can be retried\n */\n private isTokenError(error: unknown): boolean {\n if (error instanceof Anthropic.APIError) {\n // 401 Unauthorized - token expired or revoked\n if (error.status === 401) {\n return true;\n }\n // Check for token-related error messages\n const message = error.message?.toLowerCase() || '';\n if (\n message.includes('token') &&\n (message.includes('expired') || message.includes('revoked') || message.includes('invalid'))\n ) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Convert AI SDK tools to Anthropic tool format\n */\n private convertTools(tools?: LanguageModelV2CallOptions['tools']): Tool[] | undefined {\n if (!tools || tools.length === 0) {\n return undefined;\n }\n\n return tools\n .filter((tool): tool is LanguageModelV2FunctionTool => tool.type === 'function')\n .map((tool) => {\n const schema = tool.inputSchema as { properties?: object; required?: string[] } | undefined;\n return {\n name: tool.name,\n description: tool.description || '',\n input_schema: {\n type: 'object' as const,\n properties: schema?.properties || {},\n required: schema?.required || [],\n },\n };\n });\n }\n\n /**\n * Convert AI SDK tool choice to Anthropic format\n */\n private convertToolChoice(\n toolChoice?: LanguageModelV2ToolChoice\n ): Anthropic.MessageCreateParams['tool_choice'] {\n if (!toolChoice) {\n return undefined;\n }\n\n switch (toolChoice.type) {\n case 'auto':\n return { type: 'auto' };\n case 'none':\n // Anthropic doesn't have a direct 'none' - we handle this by not sending tools\n return undefined;\n case 'required':\n return { type: 'any' };\n case 'tool':\n return { type: 'tool', name: toolChoice.toolName };\n default:\n return undefined;\n }\n }\n\n /**\n * Convert AI SDK prompt to Anthropic messages format\n */\n private convertPrompt(prompt: LanguageModelV2Message[]): {\n system?: string;\n messages: Anthropic.MessageParam[];\n } {\n let systemMessage: string | undefined;\n const messages: Anthropic.MessageParam[] = [];\n\n for (const message of prompt) {\n if (message.role === 'system') {\n systemMessage = message.content;\n continue;\n }\n\n if (message.role === 'user') {\n const content: Anthropic.ContentBlockParam[] = [];\n\n for (const part of message.content) {\n if (part.type === 'text') {\n content.push({ type: 'text', text: part.text });\n } else if (part.type === 'file') {\n // Handle file/image content if needed\n // For now, skip non-text content\n }\n }\n\n if (content.length > 0) {\n messages.push({ role: 'user', content });\n }\n } else if (message.role === 'assistant') {\n const content: Anthropic.ContentBlockParam[] = [];\n\n for (const part of message.content) {\n if (part.type === 'text') {\n content.push({ type: 'text', text: part.text });\n } else if (part.type === 'tool-call') {\n content.push({\n type: 'tool_use',\n id: part.toolCallId,\n name: part.toolName,\n input: typeof part.input === 'string' ? JSON.parse(part.input) : part.input,\n });\n }\n }\n\n if (content.length > 0) {\n messages.push({ role: 'assistant', content });\n }\n } else if (message.role === 'tool') {\n // Tool results need to be sent as user messages with tool_result content\n const content: Anthropic.ToolResultBlockParam[] = [];\n\n for (const part of message.content) {\n if (part.type === 'tool-result') {\n let resultContent: string;\n\n // Convert tool result output to string\n if (part.output.type === 'text') {\n resultContent = part.output.value;\n } else if (part.output.type === 'json') {\n resultContent = JSON.stringify(part.output.value);\n } else if (part.output.type === 'error-text') {\n resultContent = part.output.value;\n } else if (part.output.type === 'error-json') {\n resultContent = JSON.stringify(part.output.value);\n } else {\n resultContent = JSON.stringify(part.output);\n }\n\n content.push({\n type: 'tool_result',\n tool_use_id: part.toolCallId,\n content: resultContent,\n is_error: part.output.type.startsWith('error'),\n });\n }\n }\n\n if (content.length > 0) {\n messages.push({ role: 'user', content });\n }\n }\n }\n\n return { system: systemMessage, messages };\n }\n\n /**\n * Convert Anthropic finish reason to AI SDK format\n */\n private convertFinishReason(stopReason: string | null): LanguageModelV2FinishReason {\n switch (stopReason) {\n case 'end_turn':\n return 'stop';\n case 'stop_sequence':\n return 'stop';\n case 'max_tokens':\n return 'length';\n case 'tool_use':\n return 'tool-calls';\n default:\n return 'unknown';\n }\n }\n\n async doGenerate(options: LanguageModelV2CallOptions): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n warnings: LanguageModelV2CallWarning[];\n }> {\n return this.doGenerateWithRetry(options, false);\n }\n\n private async doGenerateWithRetry(\n options: LanguageModelV2CallOptions,\n isRetry: boolean\n ): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n warnings: LanguageModelV2CallWarning[];\n }> {\n const client = await this.getAnthropicClient(isRetry);\n const { system, messages } = this.convertPrompt(options.prompt);\n const tools = this.convertTools(options.tools);\n const toolChoice =\n options.toolChoice?.type !== 'none' ? this.convertToolChoice(options.toolChoice) : undefined;\n\n const anthropicModel = this.config.anthropicModel || 'claude-sonnet-4-5-20250929';\n const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n\n try {\n const response = await client.messages.create({\n model: anthropicModel,\n max_tokens: maxTokens,\n system: system,\n messages: messages,\n tools: tools,\n tool_choice: tools ? toolChoice : undefined,\n temperature: options.temperature,\n top_p: options.topP,\n stop_sequences: options.stopSequences,\n });\n\n const content: LanguageModelV2Content[] = [];\n\n for (const block of response.content) {\n if (block.type === 'text') {\n content.push({\n type: 'text',\n text: block.text,\n });\n } else if (block.type === 'tool_use') {\n content.push({\n type: 'tool-call',\n toolCallId: block.id,\n toolName: block.name,\n input: JSON.stringify(block.input),\n });\n }\n }\n\n const usage: LanguageModelV2Usage = {\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n totalTokens: response.usage.input_tokens + response.usage.output_tokens,\n };\n\n return {\n content,\n finishReason: this.convertFinishReason(response.stop_reason),\n usage,\n warnings: [],\n };\n } catch (error) {\n // If this is a token error and we haven't retried yet, refresh token and retry\n if (!isRetry && this.isTokenError(error)) {\n this.directAccessClient.invalidateToken();\n return this.doGenerateWithRetry(options, true);\n }\n\n if (error instanceof Anthropic.APIError) {\n throw new GitLabError({\n message: `Anthropic API error: ${error.message}`,\n cause: error,\n });\n }\n throw error;\n }\n }\n\n async doStream(options: LanguageModelV2CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n request?: { body?: unknown };\n response?: { headers?: Record<string, string> };\n }> {\n return this.doStreamWithRetry(options, false);\n }\n\n private async doStreamWithRetry(\n options: LanguageModelV2CallOptions,\n isRetry: boolean\n ): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n request?: { body?: unknown };\n response?: { headers?: Record<string, string> };\n }> {\n const client = await this.getAnthropicClient(isRetry);\n const { system, messages } = this.convertPrompt(options.prompt);\n const tools = this.convertTools(options.tools);\n const toolChoice =\n options.toolChoice?.type !== 'none' ? this.convertToolChoice(options.toolChoice) : undefined;\n\n const anthropicModel = this.config.anthropicModel || 'claude-sonnet-4-5-20250929';\n const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n\n const requestBody = {\n model: anthropicModel,\n max_tokens: maxTokens,\n system: system,\n messages: messages,\n tools: tools,\n tool_choice: tools ? toolChoice : undefined,\n temperature: options.temperature,\n top_p: options.topP,\n stop_sequences: options.stopSequences,\n stream: true as const,\n };\n\n // Reference to this for use in the stream callback\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n\n const stream = new ReadableStream<LanguageModelV2StreamPart>({\n start: async (controller) => {\n try {\n const anthropicStream = client.messages.stream(requestBody);\n\n // Track current state\n let currentTextBlockId: string | null = null;\n let currentToolBlockId: string | null = null;\n let currentToolName: string | null = null;\n const usage: LanguageModelV2Usage = {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n };\n let finishReason: LanguageModelV2FinishReason = 'unknown';\n\n // Stream start\n controller.enqueue({\n type: 'stream-start',\n warnings: [],\n });\n\n for await (const event of anthropicStream) {\n switch (event.type) {\n case 'message_start':\n if (event.message.usage) {\n usage.inputTokens = event.message.usage.input_tokens;\n }\n controller.enqueue({\n type: 'response-metadata',\n id: event.message.id,\n modelId: event.message.model,\n });\n break;\n\n case 'content_block_start':\n if (event.content_block.type === 'text') {\n currentTextBlockId = `text-${event.index}`;\n controller.enqueue({\n type: 'text-start',\n id: currentTextBlockId,\n });\n } else if (event.content_block.type === 'tool_use') {\n currentToolBlockId = event.content_block.id;\n currentToolName = event.content_block.name;\n controller.enqueue({\n type: 'tool-input-start',\n id: currentToolBlockId,\n toolName: currentToolName,\n });\n }\n break;\n\n case 'content_block_delta':\n if (event.delta.type === 'text_delta' && currentTextBlockId) {\n controller.enqueue({\n type: 'text-delta',\n id: currentTextBlockId,\n delta: event.delta.text,\n });\n } else if (event.delta.type === 'input_json_delta' && currentToolBlockId) {\n controller.enqueue({\n type: 'tool-input-delta',\n id: currentToolBlockId,\n delta: event.delta.partial_json,\n });\n }\n break;\n\n case 'content_block_stop':\n if (currentTextBlockId) {\n controller.enqueue({\n type: 'text-end',\n id: currentTextBlockId,\n });\n currentTextBlockId = null;\n }\n if (currentToolBlockId) {\n controller.enqueue({\n type: 'tool-input-end',\n id: currentToolBlockId,\n });\n currentToolBlockId = null;\n currentToolName = null;\n }\n break;\n\n case 'message_delta':\n if (event.usage) {\n usage.outputTokens = event.usage.output_tokens;\n usage.totalTokens = (usage.inputTokens || 0) + event.usage.output_tokens;\n }\n if (event.delta.stop_reason) {\n finishReason = self.convertFinishReason(event.delta.stop_reason);\n }\n break;\n\n case 'message_stop': {\n // Final message - get tool calls from accumulated content\n const finalMessage = await anthropicStream.finalMessage();\n\n // Emit tool-call events for any tool uses\n for (const block of finalMessage.content) {\n if (block.type === 'tool_use') {\n controller.enqueue({\n type: 'tool-call',\n toolCallId: block.id,\n toolName: block.name,\n input: JSON.stringify(block.input),\n });\n }\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage,\n });\n break;\n }\n }\n }\n\n controller.close();\n } catch (error) {\n // If this is a token error and we haven't retried yet, we need to signal retry\n // For streaming, we close this stream with an error and the caller should retry\n if (!isRetry && self.isTokenError(error)) {\n self.directAccessClient.invalidateToken();\n // Signal that a retry is needed with a special error\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: 'TOKEN_REFRESH_NEEDED',\n cause: error,\n }),\n });\n controller.close();\n return;\n }\n\n if (error instanceof Anthropic.APIError) {\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: `Anthropic API error: ${error.message}`,\n cause: error,\n }),\n });\n } else {\n controller.enqueue({\n type: 'error',\n error,\n });\n }\n controller.close();\n }\n },\n });\n\n return {\n stream,\n request: { body: requestBody },\n };\n }\n}\n","import { z } from 'zod';\nimport { GitLabError } from './gitlab-error';\n\n/**\n * Response from /api/v4/ai/third_party_agents/direct_access\n */\nexport const directAccessTokenSchema = z.object({\n headers: z.record(z.string()),\n token: z.string(),\n});\n\nexport type DirectAccessToken = z.infer<typeof directAccessTokenSchema>;\n\nexport interface GitLabDirectAccessConfig {\n instanceUrl: string;\n getHeaders: () => Record<string, string>;\n fetch?: typeof fetch;\n /**\n * Optional callback to refresh the API key when a 401 error occurs.\n * Should clear cached credentials and re-fetch from auth provider.\n */\n refreshApiKey?: () => Promise<void>;\n /**\n * Feature flags to pass to the GitLab API\n */\n featureFlags?: Record<string, boolean>;\n}\n\n/**\n * Client for GitLab's third-party agents direct access API.\n * This allows routing requests through GitLab's proxy to Anthropic.\n */\nexport class GitLabDirectAccessClient {\n private readonly config: GitLabDirectAccessConfig;\n private readonly fetchFn: typeof fetch;\n private cachedToken: DirectAccessToken | null = null;\n private tokenExpiresAt: number = 0;\n\n constructor(config: GitLabDirectAccessConfig) {\n this.config = config;\n this.fetchFn = config.fetch ?? fetch;\n }\n\n /**\n * Get a direct access token for the Anthropic proxy.\n * Tokens are cached for 25 minutes (they expire after 30 minutes).\n * @param forceRefresh - If true, ignores the cache and fetches a new token\n */\n async getDirectAccessToken(forceRefresh: boolean = false): Promise<DirectAccessToken> {\n // Check if we have a valid cached token (unless force refresh is requested)\n const now = Date.now();\n if (!forceRefresh && this.cachedToken && this.tokenExpiresAt > now) {\n return this.cachedToken;\n }\n\n // Clear cache if forcing refresh\n if (forceRefresh) {\n this.invalidateToken();\n }\n\n const url = `${this.config.instanceUrl}/api/v4/ai/third_party_agents/direct_access`;\n\n // Prepare request body with feature flags if provided\n const requestBody: Record<string, unknown> = {};\n if (this.config.featureFlags && Object.keys(this.config.featureFlags).length > 0) {\n requestBody.feature_flags = this.config.featureFlags;\n }\n\n try {\n const response = await this.fetchFn(url, {\n method: 'POST',\n headers: {\n ...this.config.getHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n\n // If we get a 401 and have a refresh callback, try refreshing the API key once\n if (response.status === 401 && this.config.refreshApiKey && !forceRefresh) {\n try {\n // Refresh the API key (this should clear cached credentials and re-fetch from auth)\n await this.config.refreshApiKey();\n\n // Retry the request with the refreshed credentials\n return await this.getDirectAccessToken(true);\n } catch (refreshError) {\n // If refresh fails, throw the original 401 error\n throw new GitLabError({\n message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${errorText}`,\n });\n }\n }\n\n throw new GitLabError({\n message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${errorText}`,\n });\n }\n\n const data = await response.json();\n const token = directAccessTokenSchema.parse(data);\n\n // Cache the token for 25 minutes (tokens expire after 30 minutes)\n this.cachedToken = token;\n this.tokenExpiresAt = now + 25 * 60 * 1000;\n\n return token;\n } catch (error) {\n if (error instanceof GitLabError) {\n throw error;\n }\n throw new GitLabError({\n message: `Failed to get direct access token: ${error}`,\n cause: error,\n });\n }\n }\n\n /**\n * Get the Anthropic proxy base URL\n */\n getAnthropicProxyUrl(): string {\n return 'https://cloud.gitlab.com/ai/v1/proxy/anthropic/';\n }\n\n /**\n * Invalidate the cached token\n */\n invalidateToken(): void {\n this.cachedToken = null;\n this.tokenExpiresAt = 0;\n }\n}\n","export interface GitLabErrorOptions {\n message: string;\n statusCode?: number;\n responseBody?: string;\n cause?: unknown;\n}\n\nexport class GitLabError extends Error {\n readonly statusCode?: number;\n readonly responseBody?: string;\n readonly cause?: unknown;\n\n constructor(options: GitLabErrorOptions) {\n super(options.message);\n this.name = 'GitLabError';\n this.statusCode = options.statusCode;\n this.responseBody = options.responseBody;\n this.cause = options.cause;\n\n // Maintain proper stack trace for where error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, GitLabError);\n }\n }\n\n static fromResponse(response: Response, body: string): GitLabError {\n return new GitLabError({\n message: `GitLab API error: ${response.status} ${response.statusText}`,\n statusCode: response.status,\n responseBody: body,\n });\n }\n\n isAuthError(): boolean {\n return this.statusCode === 401;\n }\n\n isRateLimitError(): boolean {\n return this.statusCode === 429;\n }\n\n isForbiddenError(): boolean {\n return this.statusCode === 403;\n }\n\n isServerError(): boolean {\n return this.statusCode !== undefined && this.statusCode >= 500;\n }\n}\n","/**\n * OAuth types and constants for GitLab authentication\n * Based on gitlab-vscode-extension and gitlab-lsp patterns\n */\n\nexport interface GitLabOAuthTokens {\n accessToken: string;\n refreshToken: string;\n expiresAt: number; // Unix timestamp in milliseconds\n instanceUrl: string;\n}\n\nexport interface OpenCodeAuthOAuth {\n type: 'oauth';\n refresh: string;\n access: string;\n expires: number; // Unix timestamp in milliseconds\n instanceUrl?: string;\n}\n\nexport interface OpenCodeAuthApi {\n type: 'api';\n key: string;\n}\n\nexport type OpenCodeAuth = OpenCodeAuthOAuth | OpenCodeAuthApi;\n\n/**\n * Bundled OAuth client ID for GitLab.com\n * Same as used in gitlab-vscode-extension\n */\nexport const BUNDLED_CLIENT_ID = '36f2a70cddeb5a0889d4fd8295c241b7e9848e89cf9e599d0eed2d8e5350fbf5';\n\n/**\n * GitLab.com URL constant\n */\nexport const GITLAB_COM_URL = 'https://gitlab.com';\n\n/**\n * Token expiry skew in milliseconds (5 minutes)\n * Refresh tokens this many milliseconds before they expire\n */\nexport const TOKEN_EXPIRY_SKEW_MS = 5 * 60 * 1000;\n\n/**\n * OAuth scopes to request\n */\nexport const OAUTH_SCOPES = ['api'];\n","/**\n * GitLab OAuth Manager\n * Handles OAuth token management, refresh, and exchange\n * Based on gitlab-vscode-extension TokenExchangeService and gitlab-lsp OAuthClientProvider\n */\n\nimport { GitLabError } from './gitlab-error';\nimport type { GitLabOAuthTokenResponse } from './gitlab-api-types';\nimport {\n type GitLabOAuthTokens,\n TOKEN_EXPIRY_SKEW_MS,\n BUNDLED_CLIENT_ID,\n GITLAB_COM_URL,\n} from './gitlab-oauth-types';\n\nexport interface TokenExchangeParams {\n instanceUrl: string;\n clientId?: string;\n redirectUri?: string;\n}\n\nexport interface AuthorizationCodeParams extends TokenExchangeParams {\n code: string;\n codeVerifier: string;\n}\n\nexport interface RefreshTokenParams extends TokenExchangeParams {\n refreshToken: string;\n}\n\nexport class GitLabOAuthManager {\n private fetch: typeof fetch;\n\n constructor(fetchImpl: typeof fetch = fetch) {\n this.fetch = fetchImpl;\n }\n\n /**\n * Check if a token is expired\n */\n isTokenExpired(expiresAt: number): boolean {\n return Date.now() >= expiresAt;\n }\n\n /**\n * Check if a token needs refresh (within skew window)\n */\n needsRefresh(expiresAt: number): boolean {\n return Date.now() >= expiresAt - TOKEN_EXPIRY_SKEW_MS;\n }\n\n /**\n * Refresh tokens if needed\n * Returns the same tokens if refresh is not needed, or new tokens if refreshed\n */\n async refreshIfNeeded(tokens: GitLabOAuthTokens, clientId?: string): Promise<GitLabOAuthTokens> {\n if (!this.needsRefresh(tokens.expiresAt)) {\n return tokens;\n }\n\n if (this.isTokenExpired(tokens.expiresAt)) {\n throw new GitLabError({\n message: 'OAuth token has expired and cannot be used',\n });\n }\n\n return this.exchangeRefreshToken({\n instanceUrl: tokens.instanceUrl,\n refreshToken: tokens.refreshToken,\n clientId,\n });\n }\n\n /**\n * Exchange authorization code for tokens\n * Based on gitlab-vscode-extension createOAuthAccountFromCode\n */\n async exchangeAuthorizationCode(params: AuthorizationCodeParams): Promise<GitLabOAuthTokens> {\n const { instanceUrl, code, codeVerifier, clientId, redirectUri } = params;\n\n const tokenResponse = await this.exchangeToken({\n instanceUrl,\n grantType: 'authorization_code',\n code,\n codeVerifier,\n clientId: clientId || this.getClientId(instanceUrl),\n redirectUri,\n });\n\n return this.createTokensFromResponse(tokenResponse, instanceUrl);\n }\n\n /**\n * Exchange refresh token for new tokens\n * Based on gitlab-vscode-extension TokenExchangeService\n */\n async exchangeRefreshToken(params: RefreshTokenParams): Promise<GitLabOAuthTokens> {\n const { instanceUrl, refreshToken, clientId } = params;\n\n const tokenResponse = await this.exchangeToken({\n instanceUrl,\n grantType: 'refresh_token',\n refreshToken,\n clientId: clientId || this.getClientId(instanceUrl),\n });\n\n return this.createTokensFromResponse(tokenResponse, instanceUrl);\n }\n\n /**\n * Get the OAuth client ID for an instance\n */\n private getClientId(instanceUrl: string): string {\n // Use bundled client ID for GitLab.com\n if (instanceUrl === GITLAB_COM_URL) {\n return BUNDLED_CLIENT_ID;\n }\n\n throw new GitLabError({\n message: `No OAuth client ID configured for instance ${instanceUrl}. Please provide a clientId parameter.`,\n });\n }\n\n /**\n * Exchange token with GitLab OAuth endpoint\n * Based on gitlab-vscode-extension GitLabService.exchangeToken\n */\n private async exchangeToken(params: {\n instanceUrl: string;\n grantType: 'authorization_code' | 'refresh_token';\n code?: string;\n codeVerifier?: string;\n refreshToken?: string;\n clientId: string;\n redirectUri?: string;\n }): Promise<GitLabOAuthTokenResponse> {\n const { instanceUrl, grantType, code, codeVerifier, refreshToken, clientId, redirectUri } =\n params;\n\n const body: Record<string, string> = {\n client_id: clientId,\n grant_type: grantType,\n };\n\n if (grantType === 'authorization_code') {\n if (!code || !codeVerifier || !redirectUri) {\n throw new GitLabError({\n message:\n 'Authorization code, code verifier, and redirect URI are required for authorization_code grant',\n });\n }\n body.code = code;\n body.code_verifier = codeVerifier;\n body.redirect_uri = redirectUri;\n } else if (grantType === 'refresh_token') {\n if (!refreshToken) {\n throw new GitLabError({\n message: 'Refresh token is required for refresh_token grant',\n });\n }\n body.refresh_token = refreshToken;\n }\n\n const url = `${instanceUrl}/oauth/token`;\n\n try {\n const response = await this.fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams(body).toString(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new GitLabError({\n message: `OAuth token exchange failed: ${response.status} ${response.statusText}`,\n cause: new Error(errorText),\n });\n }\n\n const data = await response.json();\n return data as GitLabOAuthTokenResponse;\n } catch (error) {\n if (error instanceof GitLabError) {\n throw error;\n }\n throw new GitLabError({\n message: `Failed to exchange OAuth token: ${error instanceof Error ? error.message : String(error)}`,\n cause: error instanceof Error ? error : undefined,\n });\n }\n }\n\n /**\n * Create GitLabOAuthTokens from token response\n */\n private createTokensFromResponse(\n response: GitLabOAuthTokenResponse,\n instanceUrl: string\n ): GitLabOAuthTokens {\n const expiresAt = this.createExpiresTimestamp(response);\n\n return {\n accessToken: response.access_token,\n refreshToken: response.refresh_token || '',\n expiresAt,\n instanceUrl,\n };\n }\n\n /**\n * Create expiry timestamp from token response\n * Based on gitlab-vscode-extension createExpiresTimestamp\n */\n private createExpiresTimestamp(response: GitLabOAuthTokenResponse): number {\n // GitLab returns created_at (Unix timestamp in seconds) and expires_in (seconds)\n const createdAt = response.created_at * 1000; // Convert to milliseconds\n const expiresIn = response.expires_in * 1000; // Convert to milliseconds\n return createdAt + expiresIn;\n }\n}\n","/**\n * Maps GitLab model IDs to their corresponding Anthropic model identifiers.\n *\n * This mapping allows users to specify model variants by model ID without\n * needing to manually configure the anthropicModel option.\n *\n * @example\n * const model = gitlab.agenticChat('duo-chat-opus-4-5');\n * // Automatically uses 'claude-opus-4-5-20251101'\n */\nexport const MODEL_ID_TO_ANTHROPIC_MODEL: Record<string, string> = {\n 'duo-chat-opus-4-5': 'claude-opus-4-5-20251101',\n 'duo-chat-sonnet-4-5': 'claude-sonnet-4-5-20250929',\n 'duo-chat-haiku-4-5': 'claude-haiku-4-5-20251001',\n};\n\n/**\n * Gets the Anthropic model identifier for a given GitLab model ID.\n *\n * @param modelId - The GitLab model ID (e.g., 'duo-chat-opus-4-5')\n * @returns The Anthropic model identifier, or undefined if no mapping exists\n *\n * @example\n * getAnthropicModelForModelId('duo-chat-opus-4-5')\n * // Returns: 'claude-opus-4-5-20251101'\n *\n * @example\n * getAnthropicModelForModelId('duo-chat')\n * // Returns: undefined (uses default)\n */\nexport function getAnthropicModelForModelId(modelId: string): string | undefined {\n return MODEL_ID_TO_ANTHROPIC_MODEL[modelId];\n}\n","import { GitLabAgenticLanguageModel } from './gitlab-agentic-language-model';\nimport { GitLabError } from './gitlab-error';\nimport type { LanguageModelV2 } from '@ai-sdk/provider';\nimport { GitLabOAuthManager } from './gitlab-oauth-manager';\nimport type { OpenCodeAuth } from './gitlab-oauth-types';\nimport { getAnthropicModelForModelId } from './model-mappings';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport interface GitLabProvider {\n (modelId: string): LanguageModelV2;\n readonly specificationVersion: 'v2';\n languageModel(modelId: string): LanguageModelV2;\n chat(modelId: string): LanguageModelV2;\n /**\n * Create an agentic chat model with tool calling support\n *\n * @param modelId - GitLab model identifier. Some IDs automatically map to specific Anthropic models.\n * @param options - Configuration options for the agentic model\n * @returns A language model with native tool calling support via Anthropic\n *\n * @example\n * // Automatic model mapping\n * const model = gitlab.agenticChat('duo-chat-opus-4-5');\n * // Uses claude-opus-4-5-20251101\n *\n * @example\n * // Explicit model override\n * const model = gitlab.agenticChat('duo-chat', {\n * anthropicModel: 'claude-sonnet-4-5-20250929'\n * });\n */\n agenticChat(modelId: string, options?: GitLabAgenticOptions): GitLabAgenticLanguageModel;\n textEmbeddingModel(modelId: string): never;\n imageModel(modelId: string): never;\n}\n\nexport interface GitLabAgenticOptions {\n /**\n * The Anthropic model to use\n *\n * If not specified, automatically maps from the model ID:\n * - 'duo-chat-opus-4-5' → 'claude-opus-4-5-20251101'\n * - 'duo-chat-sonnet-4-5' → 'claude-sonnet-4-5-20250929'\n * - 'duo-chat-haiku-4-5' → 'claude-haiku-4-5-20251001'\n *\n * For unmapped model IDs, defaults to 'claude-sonnet-4-5-20250929'\n *\n * @default Automatically mapped from model ID, or 'claude-sonnet-4-5-20250929'\n * @example\n * // Use automatic mapping\n * const model = gitlab.agenticChat('duo-chat-opus-4-5');\n *\n * @example\n * // Override with explicit model\n * const model = gitlab.agenticChat('duo-chat-opus-4-5', {\n * anthropicModel: 'claude-sonnet-4-5-20250929'\n * });\n */\n anthropicModel?: string;\n\n /**\n * Maximum tokens to generate\n * @default 8192\n */\n maxTokens?: number;\n\n /**\n * Feature flags to pass to the GitLab API\n */\n featureFlags?: Record<string, boolean>;\n}\n\nexport interface GitLabProviderSettings {\n /**\n * GitLab instance URL (e.g., 'https://gitlab.com')\n * @default 'https://gitlab.com'\n */\n instanceUrl?: string;\n\n /**\n * API token (Personal Access Token or OAuth access token)\n * Can also be set via GITLAB_TOKEN environment variable\n */\n apiKey?: string;\n\n /**\n * OAuth refresh token (optional, for OAuth flow)\n */\n refreshToken?: string;\n\n /**\n * OAuth client ID (required for OAuth flow)\n */\n clientId?: string;\n\n /**\n * OAuth redirect URI (required for OAuth flow)\n */\n redirectUri?: string;\n\n /**\n * Custom headers to include in requests\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation\n */\n fetch?: typeof fetch;\n\n /**\n * Provider name override\n */\n name?: string;\n\n /**\n * Default feature flags to pass to the GitLab API for all agentic chat models\n */\n featureFlags?: Record<string, boolean>;\n}\n\nconst VERSION = '0.0.1';\n\n/**\n * Get OpenCode auth file path\n * Uses XDG Base Directory specification\n */\nfunction getOpenCodeAuthPath(): string {\n const homeDir = os.homedir();\n\n // Check XDG_DATA_HOME first (Linux/Mac standard)\n const xdgDataHome = process.env.XDG_DATA_HOME;\n if (xdgDataHome) {\n return path.join(xdgDataHome, 'opencode', 'auth.json');\n }\n\n // Fallback to ~/.local/share/opencode/auth.json (XDG default)\n if (process.platform !== 'win32') {\n return path.join(homeDir, '.local', 'share', 'opencode', 'auth.json');\n }\n\n // Windows fallback\n return path.join(homeDir, '.opencode', 'auth.json');\n}\n\n/**\n * Load OpenCode auth.json file\n */\nasync function loadOpenCodeAuth(instanceUrl: string): Promise<OpenCodeAuth | undefined> {\n try {\n const authPath = getOpenCodeAuthPath();\n\n if (!fs.existsSync(authPath)) {\n return undefined;\n }\n\n const authData = JSON.parse(fs.readFileSync(authPath, 'utf-8'));\n\n // Priority 1: Check 'gitlab' key (used by opencode-gitlab-auth plugin)\n if (authData.gitlab?.type === 'oauth') {\n const gitlabAuth = authData.gitlab;\n // Verify it matches the requested instance URL\n if (\n gitlabAuth.enterpriseUrl === instanceUrl ||\n gitlabAuth.enterpriseUrl === instanceUrl.replace(/\\/$/, '')\n ) {\n return gitlabAuth as OpenCodeAuth;\n }\n }\n\n // Priority 2: Try to find auth for this instance by URL\n // Check both with and without trailing slash\n const normalizedUrl = instanceUrl.replace(/\\/$/, '');\n const auth = authData[normalizedUrl] || authData[`${normalizedUrl}/`];\n\n return auth as OpenCodeAuth | undefined;\n } catch (error) {\n // Silently fail if we can't read auth.json\n return undefined;\n }\n}\n\n/**\n * Load GitLab API key with OAuth support\n * Priority: explicit apiKey > OAuth token > env var\n */\nasync function loadApiKey(\n options: {\n apiKey?: string;\n environmentVariableName: string;\n description: string;\n },\n instanceUrl: string,\n clientId?: string\n): Promise<string> {\n // Priority 1: Explicit apiKey\n if (options.apiKey) {\n return options.apiKey;\n }\n\n // Priority 2: OAuth token from OpenCode auth.json\n const auth = await loadOpenCodeAuth(instanceUrl);\n if (auth?.type === 'oauth') {\n const oauthManager = new GitLabOAuthManager();\n\n // Check if token needs refresh\n if (oauthManager.needsRefresh(auth.expires)) {\n try {\n const refreshed = await oauthManager.exchangeRefreshToken({\n instanceUrl,\n refreshToken: auth.refresh,\n clientId,\n });\n\n // Update stored token\n const authPath = getOpenCodeAuthPath();\n const authData = JSON.parse(fs.readFileSync(authPath, 'utf-8'));\n const normalizedUrl = instanceUrl.replace(/\\/$/, '');\n\n authData[normalizedUrl] = {\n type: 'oauth',\n refresh: refreshed.refreshToken,\n access: refreshed.accessToken,\n expires: refreshed.expiresAt,\n instanceUrl,\n };\n\n fs.writeFileSync(authPath, JSON.stringify(authData, null, 2));\n\n return refreshed.accessToken;\n } catch (error) {\n // If refresh fails, fall through to env var\n console.warn(\n `Failed to refresh OAuth token: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n } else {\n return auth.access;\n }\n }\n\n // Priority 3: Environment variable\n const apiKey = process.env[options.environmentVariableName];\n\n if (!apiKey) {\n throw new GitLabError({\n message: `${options.description} API key is missing. Pass it as the 'apiKey' parameter, set the ${options.environmentVariableName} environment variable, or authenticate with 'opencode auth login gitlab'.`,\n });\n }\n\n return apiKey;\n}\n\nfunction withUserAgentSuffix(\n headers: Record<string, string>,\n suffix: string\n): Record<string, string> {\n const userAgent = headers['User-Agent'];\n return {\n ...headers,\n 'User-Agent': userAgent ? `${userAgent} ${suffix}` : suffix,\n };\n}\n\nexport function createGitLab(options: GitLabProviderSettings = {}): GitLabProvider {\n const instanceUrl = options.instanceUrl ?? 'https://gitlab.com';\n const providerName = options.name ?? 'gitlab';\n\n // Cache for the API key - loaded lazily on first use\n let cachedApiKey: string | undefined;\n let apiKeyPromise: Promise<string> | undefined;\n\n const getApiKey = async (): Promise<string> => {\n if (cachedApiKey) {\n return cachedApiKey;\n }\n\n if (apiKeyPromise) {\n return apiKeyPromise;\n }\n\n apiKeyPromise = loadApiKey(\n {\n apiKey: options.apiKey,\n environmentVariableName: 'GITLAB_TOKEN',\n description: 'GitLab',\n },\n instanceUrl,\n options.clientId\n );\n\n cachedApiKey = await apiKeyPromise;\n apiKeyPromise = undefined;\n return cachedApiKey;\n };\n\n /**\n * Refresh the API key by clearing the cache and re-fetching from auth provider.\n * This is called when a 401 error occurs to trigger OAuth token refresh.\n */\n const refreshApiKey = async (): Promise<void> => {\n // Clear the cached API key to force a refresh\n cachedApiKey = undefined;\n apiKeyPromise = undefined;\n\n // Re-fetch the API key (this will trigger the auth plugin's loader() which handles token refresh)\n cachedApiKey = await getApiKey();\n };\n\n const getHeaders = () => {\n // For synchronous access, we need to have the key already loaded\n // or fall back to env var/explicit key\n const apiKey = cachedApiKey || options.apiKey || process.env['GITLAB_TOKEN'] || '';\n\n if (!apiKey) {\n throw new GitLabError({\n message:\n \"GitLab API key is missing. Pass it as the 'apiKey' parameter, set the GITLAB_TOKEN environment variable, or authenticate with 'opencode auth login gitlab'.\",\n });\n }\n\n return withUserAgentSuffix(\n {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n `ai-sdk-gitlab/${VERSION}`\n );\n };\n\n // Pre-load the API key asynchronously\n getApiKey().catch(() => {\n // Silently fail - will be caught when getHeaders is called\n });\n\n // Anthropic-based chat model using GitLab's Anthropic proxy (with tool support)\n const createAgenticChatModel = (modelId: string, agenticOptions?: GitLabAgenticOptions) => {\n // Merge provider-level and model-level feature flags (model-level takes precedence)\n // Always include DuoAgentPlatformNext: true as required by the API\n const featureFlags = {\n DuoAgentPlatformNext: true as const,\n ...options.featureFlags,\n ...agenticOptions?.featureFlags,\n };\n\n return new GitLabAgenticLanguageModel(modelId, {\n provider: `${providerName}.agentic`,\n instanceUrl,\n getHeaders,\n refreshApiKey,\n fetch: options.fetch,\n anthropicModel: agenticOptions?.anthropicModel ?? getAnthropicModelForModelId(modelId),\n maxTokens: agenticOptions?.maxTokens,\n featureFlags,\n });\n };\n\n // Default model factory - uses Anthropic backend for tool support\n const createDefaultModel = (modelId: string): LanguageModelV2 => {\n // Use Anthropic-based model by default for all models to get tool support\n return createAgenticChatModel(modelId);\n };\n\n const provider = Object.assign((modelId: string) => createDefaultModel(modelId), {\n specificationVersion: 'v2' as const,\n languageModel: createDefaultModel,\n chat: createDefaultModel,\n agenticChat: createAgenticChatModel,\n }) as GitLabProvider;\n\n // Unsupported model types\n provider.textEmbeddingModel = (modelId: string) => {\n throw new GitLabError({\n message: `GitLab provider does not support text embedding models. Model ID: ${modelId}`,\n });\n };\n\n provider.imageModel = (modelId: string) => {\n throw new GitLabError({\n message: `GitLab provider does not support image models. Model ID: ${modelId}`,\n });\n };\n\n return provider;\n}\n\n/**\n * Default GitLab Duo provider instance\n *\n * @example\n * ```typescript\n * import { gitlab } from '@ai-sdk/gitlab';\n *\n * const model = gitlab('duo-chat');\n * ```\n */\nexport const gitlab = createGitLab();\n","import type { Tool } from '@anthropic-ai/sdk/resources/messages';\nimport type { ToolResult, ToolInput } from './gitlab-anthropic-tools';\n\n/**\n * GitLab API tools for interacting with GitLab resources\n * These tools allow the AI to access merge requests, issues, pipelines, etc.\n */\nexport const GITLAB_API_TOOLS: Tool[] = [\n // Merge Request Tools\n {\n name: 'gitlab_get_merge_request',\n description: `Get details of a specific merge request by project and MR IID.\nReturns: title, description, state, author, assignees, reviewers, labels, diff stats, and discussion notes.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path (e.g., \"gitlab-org/gitlab\" or \"123\")',\n },\n mr_iid: {\n type: 'number',\n description: 'The internal ID of the merge request within the project',\n },\n include_changes: {\n type: 'boolean',\n description: 'Whether to include the list of changed files (default: false)',\n },\n },\n required: ['project_id', 'mr_iid'],\n },\n },\n {\n name: 'gitlab_list_merge_requests',\n description: `List merge requests for a project or search globally.\nCan filter by state (opened, closed, merged, all), scope (assigned_to_me, created_by_me), and labels.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or path. If not provided, searches globally.',\n },\n state: {\n type: 'string',\n enum: ['opened', 'closed', 'merged', 'all'],\n description: 'Filter by MR state (default: opened)',\n },\n scope: {\n type: 'string',\n enum: ['assigned_to_me', 'created_by_me', 'all'],\n description: 'Filter by scope',\n },\n search: {\n type: 'string',\n description: 'Search MRs by title or description',\n },\n labels: {\n type: 'string',\n description: 'Comma-separated list of labels to filter by',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results (default: 20)',\n },\n },\n required: [],\n },\n },\n {\n name: 'gitlab_get_mr_changes',\n description: `Get the file changes (diff) for a merge request.\nReturns the list of files changed with their diffs.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n mr_iid: {\n type: 'number',\n description: 'The internal ID of the merge request',\n },\n },\n required: ['project_id', 'mr_iid'],\n },\n },\n {\n name: 'gitlab_list_mr_discussions',\n description: `List discussions (comments/threads) on a merge request.\nReturns all discussion threads including resolved status.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n mr_iid: {\n type: 'number',\n description: 'The internal ID of the merge request',\n },\n },\n required: ['project_id', 'mr_iid'],\n },\n },\n {\n name: 'gitlab_create_mr_note',\n description: `Add a comment/note to a merge request.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n mr_iid: {\n type: 'number',\n description: 'The internal ID of the merge request',\n },\n body: {\n type: 'string',\n description: 'The content of the note/comment (supports Markdown)',\n },\n },\n required: ['project_id', 'mr_iid', 'body'],\n },\n },\n\n // Issue Tools\n {\n name: 'gitlab_get_issue',\n description: `Get details of a specific issue by project and issue IID.\nReturns: title, description, state, author, assignees, labels, milestone, weight, and comments.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n issue_iid: {\n type: 'number',\n description: 'The internal ID of the issue within the project',\n },\n },\n required: ['project_id', 'issue_iid'],\n },\n },\n {\n name: 'gitlab_list_issues',\n description: `List issues for a project or search globally.\nCan filter by state, labels, assignee, milestone.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or path. If not provided, searches globally.',\n },\n state: {\n type: 'string',\n enum: ['opened', 'closed', 'all'],\n description: 'Filter by issue state (default: opened)',\n },\n scope: {\n type: 'string',\n enum: ['assigned_to_me', 'created_by_me', 'all'],\n description: 'Filter by scope',\n },\n search: {\n type: 'string',\n description: 'Search issues by title or description',\n },\n labels: {\n type: 'string',\n description: 'Comma-separated list of labels to filter by',\n },\n milestone: {\n type: 'string',\n description: 'Filter by milestone title',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results (default: 20)',\n },\n },\n required: [],\n },\n },\n {\n name: 'gitlab_create_issue_note',\n description: `Add a comment/note to an issue.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n issue_iid: {\n type: 'number',\n description: 'The internal ID of the issue',\n },\n body: {\n type: 'string',\n description: 'The content of the note/comment (supports Markdown)',\n },\n },\n required: ['project_id', 'issue_iid', 'body'],\n },\n },\n\n // Pipeline/CI Tools\n {\n name: 'gitlab_list_pipelines',\n description: `List pipelines for a project.\nCan filter by status, ref (branch/tag), username.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n status: {\n type: 'string',\n enum: ['running', 'pending', 'success', 'failed', 'canceled', 'skipped', 'manual'],\n description: 'Filter by pipeline status',\n },\n ref: {\n type: 'string',\n description: 'Filter by branch or tag name',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results (default: 20)',\n },\n },\n required: ['project_id'],\n },\n },\n {\n name: 'gitlab_get_pipeline',\n description: `Get details of a specific pipeline including its jobs.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n pipeline_id: {\n type: 'number',\n description: 'The ID of the pipeline',\n },\n },\n required: ['project_id', 'pipeline_id'],\n },\n },\n {\n name: 'gitlab_list_pipeline_jobs',\n description: `List jobs for a pipeline, optionally filter by scope (failed, success, etc).`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n pipeline_id: {\n type: 'number',\n description: 'The ID of the pipeline',\n },\n scope: {\n type: 'string',\n enum: [\n 'created',\n 'pending',\n 'running',\n 'failed',\n 'success',\n 'canceled',\n 'skipped',\n 'manual',\n ],\n description: 'Filter jobs by scope/status',\n },\n },\n required: ['project_id', 'pipeline_id'],\n },\n },\n {\n name: 'gitlab_get_job_log',\n description: `Get the log/trace output of a specific CI job.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n job_id: {\n type: 'number',\n description: 'The ID of the job',\n },\n },\n required: ['project_id', 'job_id'],\n },\n },\n {\n name: 'gitlab_retry_job',\n description: `Retry a failed or canceled CI job.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n job_id: {\n type: 'number',\n description: 'The ID of the job to retry',\n },\n },\n required: ['project_id', 'job_id'],\n },\n },\n\n // Repository Tools\n {\n name: 'gitlab_get_file',\n description: `Get the contents of a file from a repository.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n file_path: {\n type: 'string',\n description: 'Path to the file in the repository',\n },\n ref: {\n type: 'string',\n description: 'Branch, tag, or commit SHA (default: default branch)',\n },\n },\n required: ['project_id', 'file_path'],\n },\n },\n {\n name: 'gitlab_list_commits',\n description: `List commits in a repository. Can filter by branch/ref and path.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n ref: {\n type: 'string',\n description: 'Branch or tag name',\n },\n path: {\n type: 'string',\n description: 'File or directory path to filter commits',\n },\n since: {\n type: 'string',\n description: 'Only commits after this date (ISO 8601 format)',\n },\n until: {\n type: 'string',\n description: 'Only commits before this date (ISO 8601 format)',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results (default: 20)',\n },\n },\n required: ['project_id'],\n },\n },\n {\n name: 'gitlab_get_commit_diff',\n description: `Get the diff for a specific commit.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n sha: {\n type: 'string',\n description: 'The commit SHA',\n },\n },\n required: ['project_id', 'sha'],\n },\n },\n {\n name: 'gitlab_list_branches',\n description: `List branches in a repository.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n search: {\n type: 'string',\n description: 'Search branches by name',\n },\n },\n required: ['project_id'],\n },\n },\n\n // Search Tools\n {\n name: 'gitlab_search',\n description: `Search across GitLab for various resources.\nScopes: projects, issues, merge_requests, milestones, users, blobs (code), commits, notes, wiki_blobs`,\n input_schema: {\n type: 'object' as const,\n properties: {\n scope: {\n type: 'string',\n enum: [\n 'projects',\n 'issues',\n 'merge_requests',\n 'milestones',\n 'users',\n 'blobs',\n 'commits',\n 'notes',\n 'wiki_blobs',\n ],\n description: 'The scope of the search',\n },\n search: {\n type: 'string',\n description: 'The search query',\n },\n project_id: {\n type: 'string',\n description: 'Limit search to a specific project (optional)',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results (default: 20)',\n },\n },\n required: ['scope', 'search'],\n },\n },\n\n // Project Tools\n {\n name: 'gitlab_get_project',\n description: `Get details of a specific project.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path (e.g., \"gitlab-org/gitlab\")',\n },\n },\n required: ['project_id'],\n },\n },\n {\n name: 'gitlab_list_project_members',\n description: `List members of a project.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n project_id: {\n type: 'string',\n description: 'The project ID or URL-encoded path',\n },\n },\n required: ['project_id'],\n },\n },\n];\n\nexport interface GitLabApiToolsConfig {\n instanceUrl: string;\n token: string;\n fetch?: typeof fetch;\n}\n\n/**\n * Executor for GitLab API tools\n */\nexport class GitLabApiToolExecutor {\n private readonly config: GitLabApiToolsConfig;\n\n constructor(config: GitLabApiToolsConfig) {\n this.config = config;\n }\n\n private get headers(): Record<string, string> {\n return {\n Authorization: `Bearer ${this.config.token}`,\n 'Content-Type': 'application/json',\n };\n }\n\n private async fetchApi<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.config.instanceUrl}/api/v4${path}`;\n const fetchFn = this.config.fetch || fetch;\n\n const response = await fetchFn(url, {\n method,\n headers: this.headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`GitLab API error ${response.status}: ${errorText}`);\n }\n\n // Handle empty responses (204 No Content, etc.)\n const text = await response.text();\n if (!text) {\n return {} as T;\n }\n\n return JSON.parse(text) as T;\n }\n\n private encodeProjectId(projectId: string): string {\n // If it contains a slash, URL-encode the entire path\n if (projectId.includes('/')) {\n return encodeURIComponent(projectId);\n }\n return projectId;\n }\n\n /**\n * Execute a GitLab API tool by name\n */\n async execute(toolName: string, input: ToolInput): Promise<ToolResult> {\n try {\n switch (toolName) {\n // Merge Request tools\n case 'gitlab_get_merge_request':\n return this.getMergeRequest(input);\n case 'gitlab_list_merge_requests':\n return this.listMergeRequests(input);\n case 'gitlab_get_mr_changes':\n return this.getMrChanges(input);\n case 'gitlab_list_mr_discussions':\n return this.listMrDiscussions(input);\n case 'gitlab_create_mr_note':\n return this.createMrNote(input);\n\n // Issue tools\n case 'gitlab_get_issue':\n return this.getIssue(input);\n case 'gitlab_list_issues':\n return this.listIssues(input);\n case 'gitlab_create_issue_note':\n return this.createIssueNote(input);\n\n // Pipeline tools\n case 'gitlab_list_pipelines':\n return this.listPipelines(input);\n case 'gitlab_get_pipeline':\n return this.getPipeline(input);\n case 'gitlab_list_pipeline_jobs':\n return this.listPipelineJobs(input);\n case 'gitlab_get_job_log':\n return this.getJobLog(input);\n case 'gitlab_retry_job':\n return this.retryJob(input);\n\n // Repository tools\n case 'gitlab_get_file':\n return this.getFile(input);\n case 'gitlab_list_commits':\n return this.listCommits(input);\n case 'gitlab_get_commit_diff':\n return this.getCommitDiff(input);\n case 'gitlab_list_branches':\n return this.listBranches(input);\n\n // Search tools\n case 'gitlab_search':\n return this.search(input);\n\n // Project tools\n case 'gitlab_get_project':\n return this.getProject(input);\n case 'gitlab_list_project_members':\n return this.listProjectMembers(input);\n\n default:\n return { result: '', error: `Unknown GitLab tool: ${toolName}` };\n }\n } catch (error) {\n return {\n result: '',\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n // ========== Merge Request Tools ==========\n\n private async getMergeRequest(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const mrIid = input.mr_iid as number;\n const includeChanges = input.include_changes as boolean;\n\n let path = `/projects/${projectId}/merge_requests/${mrIid}`;\n if (includeChanges) {\n path += '?include_diverged_commits_count=true';\n }\n\n const mr = await this.fetchApi<Record<string, unknown>>('GET', path);\n return { result: JSON.stringify(mr, null, 2) };\n }\n\n private async listMergeRequests(input: ToolInput): Promise<ToolResult> {\n const params = new URLSearchParams();\n params.set('per_page', String(input.limit || 20));\n\n if (input.state) params.set('state', input.state as string);\n if (input.scope) params.set('scope', input.scope as string);\n if (input.search) params.set('search', input.search as string);\n if (input.labels) params.set('labels', input.labels as string);\n\n let path: string;\n if (input.project_id) {\n const projectId = this.encodeProjectId(input.project_id as string);\n path = `/projects/${projectId}/merge_requests?${params}`;\n } else {\n path = `/merge_requests?${params}`;\n }\n\n const mrs = await this.fetchApi<Record<string, unknown>[]>('GET', path);\n return { result: JSON.stringify(mrs, null, 2) };\n }\n\n private async getMrChanges(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const mrIid = input.mr_iid as number;\n\n const changes = await this.fetchApi<Record<string, unknown>>(\n 'GET',\n `/projects/${projectId}/merge_requests/${mrIid}/changes`\n );\n return { result: JSON.stringify(changes, null, 2) };\n }\n\n private async listMrDiscussions(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const mrIid = input.mr_iid as number;\n\n const discussions = await this.fetchApi<Record<string, unknown>[]>(\n 'GET',\n `/projects/${projectId}/merge_requests/${mrIid}/discussions`\n );\n return { result: JSON.stringify(discussions, null, 2) };\n }\n\n private async createMrNote(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const mrIid = input.mr_iid as number;\n const body = input.body as string;\n\n const note = await this.fetchApi<Record<string, unknown>>(\n 'POST',\n `/projects/${projectId}/merge_requests/${mrIid}/notes`,\n { body }\n );\n return { result: JSON.stringify(note, null, 2) };\n }\n\n // ========== Issue Tools ==========\n\n private async getIssue(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const issueIid = input.issue_iid as number;\n\n const issue = await this.fetchApi<Record<string, unknown>>(\n 'GET',\n `/projects/${projectId}/issues/${issueIid}`\n );\n return { result: JSON.stringify(issue, null, 2) };\n }\n\n private async listIssues(input: ToolInput): Promise<ToolResult> {\n const params = new URLSearchParams();\n params.set('per_page', String(input.limit || 20));\n\n if (input.state) params.set('state', input.state as string);\n if (input.scope) params.set('scope', input.scope as string);\n if (input.search) params.set('search', input.search as string);\n if (input.labels) params.set('labels', input.labels as string);\n if (input.milestone) params.set('milestone', input.milestone as string);\n\n let path: string;\n if (input.project_id) {\n const projectId = this.encodeProjectId(input.project_id as string);\n path = `/projects/${projectId}/issues?${params}`;\n } else {\n path = `/issues?${params}`;\n }\n\n const issues = await this.fetchApi<Record<string, unknown>[]>('GET', path);\n return { result: JSON.stringify(issues, null, 2) };\n }\n\n private async createIssueNote(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const issueIid = input.issue_iid as number;\n const body = input.body as string;\n\n const note = await this.fetchApi<Record<string, unknown>>(\n 'POST',\n `/projects/${projectId}/issues/${issueIid}/notes`,\n { body }\n );\n return { result: JSON.stringify(note, null, 2) };\n }\n\n // ========== Pipeline Tools ==========\n\n private async listPipelines(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const params = new URLSearchParams();\n params.set('per_page', String(input.limit || 20));\n\n if (input.status) params.set('status', input.status as string);\n if (input.ref) params.set('ref', input.ref as string);\n\n const pipelines = await this.fetchApi<Record<string, unknown>[]>(\n 'GET',\n `/projects/${projectId}/pipelines?${params}`\n );\n return { result: JSON.stringify(pipelines, null, 2) };\n }\n\n private async getPipeline(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const pipelineId = input.pipeline_id as number;\n\n const pipeline = await this.fetchApi<Record<string, unknown>>(\n 'GET',\n `/projects/${projectId}/pipelines/${pipelineId}`\n );\n return { result: JSON.stringify(pipeline, null, 2) };\n }\n\n private async listPipelineJobs(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const pipelineId = input.pipeline_id as number;\n const params = new URLSearchParams();\n\n if (input.scope) params.set('scope[]', input.scope as string);\n\n const jobs = await this.fetchApi<Record<string, unknown>[]>(\n 'GET',\n `/projects/${projectId}/pipelines/${pipelineId}/jobs?${params}`\n );\n return { result: JSON.stringify(jobs, null, 2) };\n }\n\n private async getJobLog(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const jobId = input.job_id as number;\n\n const url = `${this.config.instanceUrl}/api/v4/projects/${projectId}/jobs/${jobId}/trace`;\n const fetchFn = this.config.fetch || fetch;\n\n const response = await fetchFn(url, {\n method: 'GET',\n headers: this.headers,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`GitLab API error ${response.status}: ${errorText}`);\n }\n\n const log = await response.text();\n // Truncate very long logs\n const maxLength = 50000;\n if (log.length > maxLength) {\n return {\n result: `[Log truncated, showing last ${maxLength} characters]\\n\\n${log.slice(-maxLength)}`,\n };\n }\n return { result: log };\n }\n\n private async retryJob(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const jobId = input.job_id as number;\n\n const job = await this.fetchApi<Record<string, unknown>>(\n 'POST',\n `/projects/${projectId}/jobs/${jobId}/retry`\n );\n return { result: JSON.stringify(job, null, 2) };\n }\n\n // ========== Repository Tools ==========\n\n private async getFile(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const filePath = encodeURIComponent(input.file_path as string);\n const ref = (input.ref as string) || 'HEAD';\n\n const file = await this.fetchApi<{ content: string; encoding: string }>(\n 'GET',\n `/projects/${projectId}/repository/files/${filePath}?ref=${encodeURIComponent(ref)}`\n );\n\n // Decode base64 content\n if (file.encoding === 'base64') {\n const decoded = Buffer.from(file.content, 'base64').toString('utf-8');\n return { result: decoded };\n }\n\n return { result: file.content };\n }\n\n private async listCommits(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const params = new URLSearchParams();\n params.set('per_page', String(input.limit || 20));\n\n if (input.ref) params.set('ref_name', input.ref as string);\n if (input.path) params.set('path', input.path as string);\n if (input.since) params.set('since', input.since as string);\n if (input.until) params.set('until', input.until as string);\n\n const commits = await this.fetchApi<Record<string, unknown>[]>(\n 'GET',\n `/projects/${projectId}/repository/commits?${params}`\n );\n return { result: JSON.stringify(commits, null, 2) };\n }\n\n private async getCommitDiff(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const sha = input.sha as string;\n\n const diff = await this.fetchApi<Record<string, unknown>[]>(\n 'GET',\n `/projects/${projectId}/repository/commits/${sha}/diff`\n );\n return { result: JSON.stringify(diff, null, 2) };\n }\n\n private async listBranches(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n const params = new URLSearchParams();\n\n if (input.search) params.set('search', input.search as string);\n\n const branches = await this.fetchApi<Record<string, unknown>[]>(\n 'GET',\n `/projects/${projectId}/repository/branches?${params}`\n );\n return { result: JSON.stringify(branches, null, 2) };\n }\n\n // ========== Search Tools ==========\n\n private async search(input: ToolInput): Promise<ToolResult> {\n const scope = input.scope as string;\n const searchQuery = input.search as string;\n const params = new URLSearchParams();\n params.set('scope', scope);\n params.set('search', searchQuery);\n params.set('per_page', String(input.limit || 20));\n\n let path: string;\n if (input.project_id) {\n const projectId = this.encodeProjectId(input.project_id as string);\n path = `/projects/${projectId}/search?${params}`;\n } else {\n path = `/search?${params}`;\n }\n\n const results = await this.fetchApi<Record<string, unknown>[]>('GET', path);\n return { result: JSON.stringify(results, null, 2) };\n }\n\n // ========== Project Tools ==========\n\n private async getProject(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n\n const project = await this.fetchApi<Record<string, unknown>>('GET', `/projects/${projectId}`);\n return { result: JSON.stringify(project, null, 2) };\n }\n\n private async listProjectMembers(input: ToolInput): Promise<ToolResult> {\n const projectId = this.encodeProjectId(input.project_id as string);\n\n const members = await this.fetchApi<Record<string, unknown>[]>(\n 'GET',\n `/projects/${projectId}/members`\n );\n return { result: JSON.stringify(members, null, 2) };\n }\n}\n\n/**\n * Check if a tool name is a GitLab API tool\n */\nexport function isGitLabApiTool(toolName: string): boolean {\n return toolName.startsWith('gitlab_');\n}\n","import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { spawn } from 'child_process';\nimport type { Tool } from '@anthropic-ai/sdk/resources/messages';\n\n/**\n * Tool definitions for Anthropic Claude\n */\nexport const ANTHROPIC_TOOLS: Tool[] = [\n {\n name: 'list_dir',\n description: `List directory contents. Shows files and subdirectories relative to the working directory.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n directory: {\n type: 'string',\n description: 'Directory path relative to the working directory',\n },\n },\n required: ['directory'],\n },\n },\n {\n name: 'read_file',\n description: `Read the contents of a file.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n file_path: {\n type: 'string',\n description: 'The file path to read',\n },\n },\n required: ['file_path'],\n },\n },\n {\n name: 'create_file_with_contents',\n description: `Create and write contents to a file.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n file_path: {\n type: 'string',\n description: 'The file path to write to',\n },\n contents: {\n type: 'string',\n description: 'The contents to write',\n },\n },\n required: ['file_path', 'contents'],\n },\n },\n {\n name: 'edit_file',\n description: `Edit an existing file by replacing a string with a new string.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n file_path: {\n type: 'string',\n description: 'The path of the file to edit',\n },\n old_str: {\n type: 'string',\n description: 'The string to replace (include context for uniqueness)',\n },\n new_str: {\n type: 'string',\n description: 'The new string value',\n },\n },\n required: ['file_path', 'old_str', 'new_str'],\n },\n },\n {\n name: 'find_files',\n description: `Find files by name pattern. Uses glob-like matching.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n name_pattern: {\n type: 'string',\n description: 'The pattern to search for (e.g., \"*.py\", \"test_*.js\")',\n },\n },\n required: ['name_pattern'],\n },\n },\n {\n name: 'mkdir',\n description: `Create a new directory.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n directory_path: {\n type: 'string',\n description: 'The directory path to create',\n },\n },\n required: ['directory_path'],\n },\n },\n {\n name: 'grep',\n description: `Search for text patterns within files.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n pattern: {\n type: 'string',\n description: 'The text pattern to search for',\n },\n search_directory: {\n type: 'string',\n description: 'The directory to search in (default: \".\")',\n },\n case_insensitive: {\n type: 'boolean',\n description: 'Whether to ignore case (default: false)',\n },\n },\n required: ['pattern'],\n },\n },\n {\n name: 'run_command',\n description: `Run a shell command. Note: git commands should use run_git_command instead.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n program: {\n type: 'string',\n description: 'The program to execute (e.g., \"npm\", \"python\")',\n },\n args: {\n type: 'string',\n description: 'Arguments as a single string',\n },\n },\n required: ['program'],\n },\n },\n {\n name: 'run_git_command',\n description: `Run a git command in the repository.`,\n input_schema: {\n type: 'object' as const,\n properties: {\n command: {\n type: 'string',\n description: 'Git command (e.g., \"status\", \"log\", \"diff\")',\n },\n args: {\n type: 'string',\n description: 'Git command arguments',\n },\n },\n required: ['command'],\n },\n },\n];\n\nexport interface ToolResult {\n result: string;\n error?: string;\n}\n\nexport interface ToolInput {\n [key: string]: unknown;\n}\n\n/**\n * Tool executor for local file and command operations\n */\nexport class AnthropicToolExecutor {\n private readonly workingDirectory: string;\n\n constructor(workingDirectory: string) {\n this.workingDirectory = workingDirectory;\n }\n\n /**\n * Execute a tool by name with given input\n */\n async execute(toolName: string, input: ToolInput): Promise<ToolResult> {\n try {\n switch (toolName) {\n case 'list_dir':\n return this.listDir(input.directory as string);\n case 'read_file':\n return this.readFile(input.file_path as string);\n case 'create_file_with_contents':\n return this.writeFile(input.file_path as string, input.contents as string);\n case 'edit_file':\n return this.editFile(\n input.file_path as string,\n input.old_str as string,\n input.new_str as string\n );\n case 'find_files':\n return this.findFiles(input.name_pattern as string);\n case 'mkdir':\n return this.mkdir(input.directory_path as string);\n case 'grep':\n return this.grep(\n input.pattern as string,\n input.search_directory as string | undefined,\n input.case_insensitive as boolean | undefined\n );\n case 'run_command':\n return this.runCommand(input.program as string, input.args as string | undefined);\n case 'run_git_command':\n return this.runGitCommand(input.command as string, input.args as string | undefined);\n default:\n return { result: '', error: `Unknown tool: ${toolName}` };\n }\n } catch (error) {\n return {\n result: '',\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n private resolvePath(filePath: string): string {\n if (path.isAbsolute(filePath)) {\n return filePath;\n }\n return path.resolve(this.workingDirectory, filePath);\n }\n\n private async listDir(directory: string): Promise<ToolResult> {\n const dirPath = this.resolvePath(directory || '.');\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n\n const result = entries\n .map((entry) => {\n const type = entry.isDirectory() ? 'd' : '-';\n return `${type} ${entry.name}`;\n })\n .join('\\n');\n\n return { result };\n }\n\n private async readFile(filePath: string): Promise<ToolResult> {\n const fullPath = this.resolvePath(filePath);\n const content = await fs.readFile(fullPath, 'utf-8');\n return { result: content };\n }\n\n private async writeFile(filePath: string, contents: string): Promise<ToolResult> {\n const fullPath = this.resolvePath(filePath);\n await fs.mkdir(path.dirname(fullPath), { recursive: true });\n await fs.writeFile(fullPath, contents, 'utf-8');\n return { result: `File written successfully: ${filePath}` };\n }\n\n private async editFile(filePath: string, oldStr: string, newStr: string): Promise<ToolResult> {\n const fullPath = this.resolvePath(filePath);\n const content = await fs.readFile(fullPath, 'utf-8');\n\n if (!content.includes(oldStr)) {\n return { result: '', error: `String not found in file: \"${oldStr.substring(0, 50)}...\"` };\n }\n\n const newContent = content.replace(oldStr, newStr);\n await fs.writeFile(fullPath, newContent, 'utf-8');\n return { result: `File edited successfully: ${filePath}` };\n }\n\n private async findFiles(namePattern: string): Promise<ToolResult> {\n const results: string[] = [];\n const regex = new RegExp('^' + namePattern.replace(/\\*/g, '.*').replace(/\\?/g, '.') + '$');\n\n const search = async (dir: string, relativePath: string = '') => {\n try {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const entryRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;\n\n if (entry.isDirectory()) {\n // Skip common ignored directories\n if (!['node_modules', '.git', 'dist', 'build', '__pycache__'].includes(entry.name)) {\n await search(path.join(dir, entry.name), entryRelativePath);\n }\n } else if (regex.test(entry.name)) {\n results.push(entryRelativePath);\n }\n }\n } catch {\n // Ignore permission errors\n }\n };\n\n await search(this.workingDirectory);\n return { result: results.join('\\n') || 'No files found' };\n }\n\n private async mkdir(directoryPath: string): Promise<ToolResult> {\n const fullPath = this.resolvePath(directoryPath);\n await fs.mkdir(fullPath, { recursive: true });\n return { result: `Directory created: ${directoryPath}` };\n }\n\n private async grep(\n pattern: string,\n searchDirectory?: string,\n caseInsensitive?: boolean\n ): Promise<ToolResult> {\n const results: string[] = [];\n const flags = caseInsensitive ? 'gi' : 'g';\n const regex = new RegExp(pattern, flags);\n const searchDir = this.resolvePath(searchDirectory || '.');\n\n const search = async (dir: string, relativePath: string = '') => {\n try {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const entryRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if (!['node_modules', '.git', 'dist', 'build', '__pycache__'].includes(entry.name)) {\n await search(fullPath, entryRelativePath);\n }\n } else {\n try {\n const content = await fs.readFile(fullPath, 'utf-8');\n const lines = content.split('\\n');\n for (let i = 0; i < lines.length; i++) {\n if (regex.test(lines[i])) {\n results.push(`${entryRelativePath}:${i + 1}: ${lines[i].trim()}`);\n }\n }\n } catch {\n // Skip binary files\n }\n }\n }\n } catch {\n // Ignore permission errors\n }\n };\n\n await search(searchDir);\n return { result: results.slice(0, 100).join('\\n') || 'No matches found' };\n }\n\n private runCommand(program: string, args?: string): Promise<ToolResult> {\n // Block git commands - should use run_git_command\n if (program === 'git') {\n return Promise.resolve({\n result: '',\n error: 'Use run_git_command for git operations',\n });\n }\n\n const parsedArgs = args ? args.match(/(?:[^\\s\"]+|\"[^\"]*\")+/g) || [] : [];\n const cleanedArgs = parsedArgs.map((arg: string) => arg.replace(/^\"(.*)\"$/, '$1'));\n\n return this.executeCommand(program, cleanedArgs);\n }\n\n private runGitCommand(command: string, args?: string): Promise<ToolResult> {\n const gitArgs = [command];\n if (args) {\n const parsedArgs = args.match(/(?:[^\\s\"]+|\"[^\"]*\")+/g) || [];\n gitArgs.push(...parsedArgs.map((arg) => arg.replace(/^\"(.*)\"$/, '$1')));\n }\n\n return this.executeCommand('git', gitArgs);\n }\n\n private executeCommand(program: string, args: string[]): Promise<ToolResult> {\n return new Promise((resolve) => {\n const child = spawn(program, args, {\n cwd: this.workingDirectory,\n timeout: 30000,\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data) => {\n stderr += data.toString();\n });\n\n child.on('error', (error) => {\n resolve({\n result: '',\n error: `Command failed: ${error.message}`,\n });\n });\n\n child.on('close', (exitCode) => {\n if (exitCode !== 0 && stderr) {\n resolve({\n result: stdout,\n error: stderr,\n });\n } else {\n resolve({\n result: stdout || stderr || `Command completed with exit code ${exitCode}`,\n });\n }\n });\n });\n }\n}\n","import { spawn } from 'child_process';\nimport * as path from 'path';\nimport { GitLabProjectCache, type GitLabProject } from './gitlab-project-cache';\nimport { GitLabError } from './gitlab-error';\n\n// Noop debug function (workflow debug removed)\nconst debugLog = (..._args: unknown[]) => {};\n\nexport interface GitLabProjectDetectorConfig {\n instanceUrl: string;\n getHeaders: () => Record<string, string>;\n fetch?: typeof fetch;\n cache?: GitLabProjectCache;\n gitTimeout?: number;\n}\n\n/**\n * Detects GitLab project information from git remote URLs\n *\n * This class provides functionality to:\n * - Parse git remote URLs (SSH, HTTPS, custom domains)\n * - Execute git commands to get remote URLs\n * - Fetch project details from GitLab API\n * - Cache project information to avoid repeated API calls\n */\nexport class GitLabProjectDetector {\n private readonly config: GitLabProjectDetectorConfig;\n private readonly fetchFn: typeof fetch;\n private readonly cache: GitLabProjectCache;\n\n constructor(config: GitLabProjectDetectorConfig) {\n this.config = {\n gitTimeout: 5000, // 5 seconds default\n ...config,\n };\n this.fetchFn = config.fetch ?? fetch;\n this.cache = config.cache ?? new GitLabProjectCache();\n }\n\n /**\n * Auto-detect GitLab project from git remote in the working directory\n *\n * @param workingDirectory - The directory to check for git remote\n * @param remoteName - The git remote name to use (default: 'origin')\n * @returns The detected project or null if detection fails\n */\n async detectProject(\n workingDirectory: string,\n remoteName: string = 'origin'\n ): Promise<GitLabProject | null> {\n // 1. Check cache first\n const cacheKey = path.resolve(workingDirectory);\n const cached = this.cache.get(cacheKey);\n if (cached) {\n return cached;\n }\n\n try {\n // 2. Get git remote URL\n debugLog(`[GitLabProjectDetector] Getting git remote URL from: ${workingDirectory}`);\n const remoteUrl = await this.getGitRemoteUrl(workingDirectory, remoteName);\n if (!remoteUrl) {\n debugLog(`[GitLabProjectDetector] No git remote URL found`);\n return null; // Not a git repo or no remote\n }\n debugLog(`[GitLabProjectDetector] Git remote URL: ${remoteUrl}`);\n\n // 3. Parse project path from URL\n debugLog(\n `[GitLabProjectDetector] Parsing project path from URL (instance: ${this.config.instanceUrl})`\n );\n const projectPath = this.parseGitRemoteUrl(remoteUrl, this.config.instanceUrl);\n if (!projectPath) {\n debugLog(\n `[GitLabProjectDetector] Could not parse project path from URL (remote doesn't match instance)`\n );\n return null; // Remote doesn't match instance\n }\n debugLog(`[GitLabProjectDetector] Parsed project path: ${projectPath}`);\n\n // 4. Fetch project from GitLab API\n debugLog(`[GitLabProjectDetector] Fetching project from GitLab API: ${projectPath}`);\n const project = await this.getProjectByPath(projectPath);\n debugLog(`[GitLabProjectDetector] ✓ Project fetched successfully:`, project);\n\n // 5. Cache the result\n this.cache.set(cacheKey, project);\n\n return project;\n } catch (error) {\n // Log error but don't throw - graceful degradation\n if (error instanceof GitLabError) {\n // GitLab API errors are expected (e.g., project not found)\n debugLog(`[GitLabProjectDetector] GitLab API error:`, error.message || error);\n return null;\n }\n // Log unexpected errors for debugging\n debugLog(`[GitLabProjectDetector] Unexpected error:`, error);\n console.warn(`Failed to auto-detect GitLab project: ${error}`);\n return null;\n }\n }\n\n /**\n * Parse a git remote URL to extract the project path\n *\n * Supports:\n * - SSH: git@gitlab.com:namespace/project.git\n * - HTTPS: https://gitlab.com/namespace/project.git\n * - HTTP: http://gitlab.local/namespace/project.git\n * - Custom domains and ports\n *\n * @param remoteUrl - The git remote URL\n * @param instanceUrl - The GitLab instance URL to match against\n * @returns The project path (e.g., \"namespace/project\") or null if parsing fails\n */\n parseGitRemoteUrl(remoteUrl: string, instanceUrl: string): string | null {\n try {\n // Extract hostname from instanceUrl\n const instanceHost = new URL(instanceUrl).hostname;\n\n // SSH format: git@host:path.git or git@host:port/path.git\n const sshMatch = remoteUrl.match(/^git@([^:]+):(.+?)(?:\\.git)?$/);\n if (sshMatch) {\n const [, host, pathPart] = sshMatch;\n // Handle port in SSH URLs (git@host:port/path)\n const hostWithoutPort = host.split(':')[0];\n if (hostWithoutPort === instanceHost) {\n // Remove port from path if present\n const cleanPath = pathPart.replace(/^\\d+\\//, '');\n return cleanPath.endsWith('.git') ? cleanPath.slice(0, -4) : cleanPath;\n }\n }\n\n // HTTPS/HTTP format: https://host/path.git or https://host:port/path.git\n const httpsMatch = remoteUrl.match(/^(https?):\\/\\/([^/]+)\\/(.+?)(?:\\.git)?$/);\n if (httpsMatch) {\n const [, , hostWithPort, pathPart] = httpsMatch;\n const host = hostWithPort.split(':')[0];\n if (host === instanceHost) {\n return pathPart.endsWith('.git') ? pathPart.slice(0, -4) : pathPart;\n }\n }\n\n return null;\n } catch (error) {\n // URL parsing failed\n return null;\n }\n }\n\n /**\n * Get the git remote URL from a working directory\n *\n * @param workingDirectory - The directory to check\n * @param remoteName - The git remote name (default: 'origin')\n * @returns The remote URL or null if not found\n */\n async getGitRemoteUrl(\n workingDirectory: string,\n remoteName: string = 'origin'\n ): Promise<string | null> {\n return new Promise((resolve) => {\n const child = spawn('git', ['config', '--get', `remote.${remoteName}.url`], {\n cwd: workingDirectory,\n timeout: this.config.gitTimeout,\n });\n\n let stdout = '';\n let _stderr = '';\n\n child.stdout?.on('data', (data) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data) => {\n _stderr += data.toString();\n });\n\n child.on('close', (exitCode) => {\n if (exitCode === 0 && stdout.trim()) {\n resolve(stdout.trim());\n } else {\n resolve(null);\n }\n });\n\n child.on('error', () => {\n // Git not available or command failed\n resolve(null);\n });\n });\n }\n\n /**\n * Fetch project details from GitLab API by project path\n *\n * @param projectPath - The project path (e.g., \"namespace/project\")\n * @returns The project details\n * @throws GitLabError if the API call fails\n */\n async getProjectByPath(projectPath: string): Promise<GitLabProject> {\n // URL-encode the project path\n const encodedPath = encodeURIComponent(projectPath);\n const url = `${this.config.instanceUrl}/api/v4/projects/${encodedPath}`;\n\n try {\n const response = await this.fetchFn(url, {\n method: 'GET',\n headers: this.config.getHeaders(),\n });\n\n if (!response.ok) {\n throw new GitLabError({\n message: `Failed to fetch project '${projectPath}': ${response.status} ${response.statusText}`,\n });\n }\n\n const data = (await response.json()) as {\n id: number;\n path: string;\n path_with_namespace: string;\n name: string;\n namespace?: { id: number };\n };\n\n return {\n id: data.id,\n path: data.path,\n pathWithNamespace: data.path_with_namespace,\n name: data.name,\n namespaceId: data.namespace?.id,\n };\n } catch (error) {\n if (error instanceof GitLabError) {\n throw error;\n }\n throw new GitLabError({\n message: `Failed to fetch project '${projectPath}': ${error}`,\n cause: error,\n });\n }\n }\n\n /**\n * Clear the project cache\n */\n clearCache(): void {\n this.cache.clear();\n }\n\n /**\n * Get the cache instance (useful for testing)\n */\n getCache(): GitLabProjectCache {\n return this.cache;\n }\n}\n","/**\n * Simple in-memory cache for GitLab project information\n * Used to avoid repeated API calls when detecting projects from git remotes\n */\n\nexport interface GitLabProject {\n id: number;\n path: string;\n pathWithNamespace: string;\n name: string;\n namespaceId?: number;\n}\n\ninterface CacheEntry {\n project: GitLabProject;\n expiresAt: number;\n}\n\n/**\n * In-memory cache for GitLab project information with TTL support\n */\nexport class GitLabProjectCache {\n private cache = new Map<string, CacheEntry>();\n private defaultTTL: number;\n\n /**\n * Create a new project cache\n * @param defaultTTL - Default time-to-live in milliseconds (default: 5 minutes)\n */\n constructor(defaultTTL: number = 5 * 60 * 1000) {\n this.defaultTTL = defaultTTL;\n }\n\n /**\n * Get a cached project by key\n * @param key - Cache key (typically the working directory path)\n * @returns The cached project or null if not found or expired\n */\n get(key: string): GitLabProject | null {\n const entry = this.cache.get(key);\n if (!entry) {\n return null;\n }\n\n // Check if entry has expired\n if (Date.now() > entry.expiresAt) {\n this.cache.delete(key);\n return null;\n }\n\n return entry.project;\n }\n\n /**\n * Store a project in the cache\n * @param key - Cache key (typically the working directory path)\n * @param project - The project to cache\n * @param ttl - Optional custom TTL in milliseconds\n */\n set(key: string, project: GitLabProject, ttl?: number): void {\n this.cache.set(key, {\n project,\n expiresAt: Date.now() + (ttl ?? this.defaultTTL),\n });\n }\n\n /**\n * Check if a key exists in the cache (and is not expired)\n * @param key - Cache key to check\n * @returns true if the key exists and is not expired\n */\n has(key: string): boolean {\n return this.get(key) !== null;\n }\n\n /**\n * Remove a specific entry from the cache\n * @param key - Cache key to remove\n */\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n /**\n * Clear all entries from the cache\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Get the number of entries in the cache (including expired ones)\n */\n get size(): number {\n return this.cache.size;\n }\n\n /**\n * Clean up expired entries from the cache\n * This is useful for long-running processes to prevent memory leaks\n */\n cleanup(): void {\n const now = Date.now();\n for (const [key, entry] of this.cache.entries()) {\n if (now > entry.expiresAt) {\n this.cache.delete(key);\n }\n }\n }\n}\n"],"mappings":"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","names":["path","fs","path","resolve","spawn","path","resolve","spawn"]}
1
+ {"version":3,"sources":["../src/gitlab-agentic-language-model.ts","../src/gitlab-direct-access.ts","../src/gitlab-error.ts","../src/gitlab-oauth-types.ts","../src/gitlab-oauth-manager.ts","../src/model-mappings.ts","../src/gitlab-provider.ts","../src/gitlab-project-detector.ts","../src/gitlab-project-cache.ts"],"sourcesContent":["import Anthropic from '@anthropic-ai/sdk';\nimport type { Tool } from '@anthropic-ai/sdk/resources/messages';\nimport { GitLabDirectAccessClient } from './gitlab-direct-access';\nimport { GitLabError } from './gitlab-error';\n\nimport type {\n LanguageModelV2,\n LanguageModelV2CallOptions,\n LanguageModelV2StreamPart,\n LanguageModelV2FinishReason,\n LanguageModelV2CallWarning,\n LanguageModelV2Content,\n LanguageModelV2Usage,\n LanguageModelV2FunctionTool,\n LanguageModelV2Message,\n LanguageModelV2ToolChoice,\n} from '@ai-sdk/provider';\n\nexport interface GitLabAgenticConfig {\n provider: string;\n instanceUrl: string;\n getHeaders: () => Record<string, string>;\n fetch?: typeof fetch;\n\n /**\n * Optional callback to refresh the API key when a 401 error occurs.\n * Should clear cached credentials and re-fetch from auth provider.\n */\n refreshApiKey?: () => Promise<void>;\n\n /**\n * The Anthropic model to use (e.g., 'claude-sonnet-4-5-20250929')\n * @default 'claude-sonnet-4-5-20250929'\n */\n anthropicModel?: string;\n\n /**\n * Maximum tokens to generate\n * @default 8192\n */\n maxTokens?: number;\n\n /**\n * Feature flags to pass to the GitLab API\n * @default { DuoAgentPlatformNext: true }\n */\n featureFlags?: {\n DuoAgentPlatformNext: true;\n } & Record<string, boolean>;\n\n /**\n * AI Gateway URL for the Anthropic proxy.\n * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.\n * @default 'https://cloud.gitlab.com'\n */\n aiGatewayUrl?: string;\n}\n\n/**\n * GitLab Agentic Language Model\n *\n * This model uses GitLab's Anthropic proxy to provide native tool calling support\n * for the duo-chat model. It connects to Claude through GitLab's cloud proxy\n * at https://cloud.gitlab.com/ai/v1/proxy/anthropic/\n */\nexport class GitLabAgenticLanguageModel implements LanguageModelV2 {\n readonly specificationVersion = 'v2' as const;\n readonly modelId: string;\n readonly supportedUrls: Record<string, RegExp[]> = {};\n\n private readonly config: GitLabAgenticConfig;\n private readonly directAccessClient: GitLabDirectAccessClient;\n private anthropicClient: Anthropic | null = null;\n\n constructor(modelId: string, config: GitLabAgenticConfig) {\n this.modelId = modelId;\n this.config = config;\n\n this.directAccessClient = new GitLabDirectAccessClient({\n instanceUrl: config.instanceUrl,\n getHeaders: config.getHeaders,\n refreshApiKey: config.refreshApiKey,\n fetch: config.fetch,\n featureFlags: config.featureFlags,\n aiGatewayUrl: config.aiGatewayUrl,\n });\n }\n\n get provider(): string {\n return this.config.provider;\n }\n\n /**\n * Get or create an Anthropic client with valid credentials\n * @param forceRefresh - If true, forces a token refresh before creating the client\n */\n private async getAnthropicClient(forceRefresh: boolean = false): Promise<Anthropic> {\n // Get token from GitLab (will use cache unless forceRefresh is true)\n const tokenData = await this.directAccessClient.getDirectAccessToken(forceRefresh);\n\n // Create new client with the token\n // GitLab's proxy expects:\n // - authToken: sets Authorization: Bearer header (NOT apiKey which sets x-api-key)\n // - defaultHeaders: additional headers from the direct access response\n // Filter out x-api-key from headers if present - we use authToken for Bearer auth\n const { 'x-api-key': _removed, ...filteredHeaders } = tokenData.headers;\n\n this.anthropicClient = new Anthropic({\n apiKey: null,\n authToken: tokenData.token,\n baseURL: this.directAccessClient.getAnthropicProxyUrl(),\n defaultHeaders: filteredHeaders,\n });\n\n return this.anthropicClient;\n }\n\n /**\n * Check if an error is a token-related authentication error that can be retried\n */\n private isTokenError(error: unknown): boolean {\n if (error instanceof Anthropic.APIError) {\n // 401 Unauthorized - token expired or revoked\n if (error.status === 401) {\n return true;\n }\n // Check for token-related error messages\n const message = error.message?.toLowerCase() || '';\n if (\n message.includes('token') &&\n (message.includes('expired') || message.includes('revoked') || message.includes('invalid'))\n ) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Convert AI SDK tools to Anthropic tool format\n */\n private convertTools(tools?: LanguageModelV2CallOptions['tools']): Tool[] | undefined {\n if (!tools || tools.length === 0) {\n return undefined;\n }\n\n return tools\n .filter((tool): tool is LanguageModelV2FunctionTool => tool.type === 'function')\n .map((tool) => {\n const schema = tool.inputSchema as { properties?: object; required?: string[] } | undefined;\n return {\n name: tool.name,\n description: tool.description || '',\n input_schema: {\n type: 'object' as const,\n properties: schema?.properties || {},\n required: schema?.required || [],\n },\n };\n });\n }\n\n /**\n * Convert AI SDK tool choice to Anthropic format\n */\n private convertToolChoice(\n toolChoice?: LanguageModelV2ToolChoice\n ): Anthropic.MessageCreateParams['tool_choice'] {\n if (!toolChoice) {\n return undefined;\n }\n\n switch (toolChoice.type) {\n case 'auto':\n return { type: 'auto' };\n case 'none':\n // Anthropic doesn't have a direct 'none' - we handle this by not sending tools\n return undefined;\n case 'required':\n return { type: 'any' };\n case 'tool':\n return { type: 'tool', name: toolChoice.toolName };\n default:\n return undefined;\n }\n }\n\n /**\n * Convert AI SDK prompt to Anthropic messages format\n */\n private convertPrompt(prompt: LanguageModelV2Message[]): {\n system?: string;\n messages: Anthropic.MessageParam[];\n } {\n let systemMessage: string | undefined;\n const messages: Anthropic.MessageParam[] = [];\n\n for (const message of prompt) {\n if (message.role === 'system') {\n systemMessage = message.content;\n continue;\n }\n\n if (message.role === 'user') {\n const content: Anthropic.ContentBlockParam[] = [];\n\n for (const part of message.content) {\n if (part.type === 'text') {\n content.push({ type: 'text', text: part.text });\n } else if (part.type === 'file') {\n // Handle file/image content if needed\n // For now, skip non-text content\n }\n }\n\n if (content.length > 0) {\n messages.push({ role: 'user', content });\n }\n } else if (message.role === 'assistant') {\n const content: Anthropic.ContentBlockParam[] = [];\n\n for (const part of message.content) {\n if (part.type === 'text') {\n content.push({ type: 'text', text: part.text });\n } else if (part.type === 'tool-call') {\n content.push({\n type: 'tool_use',\n id: part.toolCallId,\n name: part.toolName,\n input: typeof part.input === 'string' ? JSON.parse(part.input) : part.input,\n });\n }\n }\n\n if (content.length > 0) {\n messages.push({ role: 'assistant', content });\n }\n } else if (message.role === 'tool') {\n // Tool results need to be sent as user messages with tool_result content\n const content: Anthropic.ToolResultBlockParam[] = [];\n\n for (const part of message.content) {\n if (part.type === 'tool-result') {\n let resultContent: string;\n\n // Convert tool result output to string\n if (part.output.type === 'text') {\n resultContent = part.output.value;\n } else if (part.output.type === 'json') {\n resultContent = JSON.stringify(part.output.value);\n } else if (part.output.type === 'error-text') {\n resultContent = part.output.value;\n } else if (part.output.type === 'error-json') {\n resultContent = JSON.stringify(part.output.value);\n } else {\n resultContent = JSON.stringify(part.output);\n }\n\n content.push({\n type: 'tool_result',\n tool_use_id: part.toolCallId,\n content: resultContent,\n is_error: part.output.type.startsWith('error'),\n });\n }\n }\n\n if (content.length > 0) {\n messages.push({ role: 'user', content });\n }\n }\n }\n\n return { system: systemMessage, messages };\n }\n\n /**\n * Convert Anthropic finish reason to AI SDK format\n */\n private convertFinishReason(stopReason: string | null): LanguageModelV2FinishReason {\n switch (stopReason) {\n case 'end_turn':\n return 'stop';\n case 'stop_sequence':\n return 'stop';\n case 'max_tokens':\n return 'length';\n case 'tool_use':\n return 'tool-calls';\n default:\n return 'unknown';\n }\n }\n\n async doGenerate(options: LanguageModelV2CallOptions): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n warnings: LanguageModelV2CallWarning[];\n }> {\n return this.doGenerateWithRetry(options, false);\n }\n\n private async doGenerateWithRetry(\n options: LanguageModelV2CallOptions,\n isRetry: boolean\n ): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n warnings: LanguageModelV2CallWarning[];\n }> {\n const client = await this.getAnthropicClient(isRetry);\n const { system, messages } = this.convertPrompt(options.prompt);\n const tools = this.convertTools(options.tools);\n const toolChoice =\n options.toolChoice?.type !== 'none' ? this.convertToolChoice(options.toolChoice) : undefined;\n\n const anthropicModel = this.config.anthropicModel || 'claude-sonnet-4-5-20250929';\n const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n\n try {\n const response = await client.messages.create({\n model: anthropicModel,\n max_tokens: maxTokens,\n system: system,\n messages: messages,\n tools: tools,\n tool_choice: tools ? toolChoice : undefined,\n temperature: options.temperature,\n top_p: options.topP,\n stop_sequences: options.stopSequences,\n });\n\n const content: LanguageModelV2Content[] = [];\n\n for (const block of response.content) {\n if (block.type === 'text') {\n content.push({\n type: 'text',\n text: block.text,\n });\n } else if (block.type === 'tool_use') {\n content.push({\n type: 'tool-call',\n toolCallId: block.id,\n toolName: block.name,\n input: JSON.stringify(block.input),\n });\n }\n }\n\n const usage: LanguageModelV2Usage = {\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n totalTokens: response.usage.input_tokens + response.usage.output_tokens,\n };\n\n return {\n content,\n finishReason: this.convertFinishReason(response.stop_reason),\n usage,\n warnings: [],\n };\n } catch (error) {\n // If this is a token error and we haven't retried yet, refresh token and retry\n if (!isRetry && this.isTokenError(error)) {\n this.directAccessClient.invalidateToken();\n return this.doGenerateWithRetry(options, true);\n }\n\n if (error instanceof Anthropic.APIError) {\n throw new GitLabError({\n message: `Anthropic API error: ${error.message}`,\n cause: error,\n });\n }\n throw error;\n }\n }\n\n async doStream(options: LanguageModelV2CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n request?: { body?: unknown };\n response?: { headers?: Record<string, string> };\n }> {\n return this.doStreamWithRetry(options, false);\n }\n\n private async doStreamWithRetry(\n options: LanguageModelV2CallOptions,\n isRetry: boolean\n ): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n request?: { body?: unknown };\n response?: { headers?: Record<string, string> };\n }> {\n const client = await this.getAnthropicClient(isRetry);\n const { system, messages } = this.convertPrompt(options.prompt);\n const tools = this.convertTools(options.tools);\n const toolChoice =\n options.toolChoice?.type !== 'none' ? this.convertToolChoice(options.toolChoice) : undefined;\n\n const anthropicModel = this.config.anthropicModel || 'claude-sonnet-4-5-20250929';\n const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n\n const requestBody = {\n model: anthropicModel,\n max_tokens: maxTokens,\n system: system,\n messages: messages,\n tools: tools,\n tool_choice: tools ? toolChoice : undefined,\n temperature: options.temperature,\n top_p: options.topP,\n stop_sequences: options.stopSequences,\n stream: true as const,\n };\n\n // Reference to this for use in the stream callback\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n\n const stream = new ReadableStream<LanguageModelV2StreamPart>({\n start: async (controller) => {\n const contentBlocks: Record<\n number,\n | { type: 'text'; id: string }\n | { type: 'tool-call'; toolCallId: string; toolName: string; input: string }\n > = {};\n\n const usage: LanguageModelV2Usage = {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n };\n let finishReason: LanguageModelV2FinishReason = 'unknown';\n\n try {\n const anthropicStream = client.messages.stream(requestBody, {\n signal: options.abortSignal,\n });\n\n // Stream start\n controller.enqueue({\n type: 'stream-start',\n warnings: [],\n });\n\n // Use event-based approach instead of for-await to ensure all events are received\n await new Promise<void>((resolve, reject) => {\n anthropicStream.on('streamEvent', (event) => {\n try {\n switch (event.type) {\n case 'message_start':\n if (event.message.usage) {\n usage.inputTokens = event.message.usage.input_tokens;\n }\n controller.enqueue({\n type: 'response-metadata',\n id: event.message.id,\n modelId: event.message.model,\n });\n break;\n\n case 'content_block_start':\n if (event.content_block.type === 'text') {\n const textId = `text-${event.index}`;\n contentBlocks[event.index] = { type: 'text', id: textId };\n controller.enqueue({\n type: 'text-start',\n id: textId,\n });\n } else if (event.content_block.type === 'tool_use') {\n contentBlocks[event.index] = {\n type: 'tool-call',\n toolCallId: event.content_block.id,\n toolName: event.content_block.name,\n input: '',\n };\n controller.enqueue({\n type: 'tool-input-start',\n id: event.content_block.id,\n toolName: event.content_block.name,\n });\n }\n break;\n\n case 'content_block_delta': {\n const block = contentBlocks[event.index];\n if (event.delta.type === 'text_delta' && block?.type === 'text') {\n controller.enqueue({\n type: 'text-delta',\n id: block.id,\n delta: event.delta.text,\n });\n } else if (\n event.delta.type === 'input_json_delta' &&\n block?.type === 'tool-call'\n ) {\n block.input += event.delta.partial_json;\n controller.enqueue({\n type: 'tool-input-delta',\n id: block.toolCallId,\n delta: event.delta.partial_json,\n });\n }\n break;\n }\n\n case 'content_block_stop': {\n const block = contentBlocks[event.index];\n if (block?.type === 'text') {\n controller.enqueue({\n type: 'text-end',\n id: block.id,\n });\n } else if (block?.type === 'tool-call') {\n controller.enqueue({\n type: 'tool-input-end',\n id: block.toolCallId,\n });\n\n controller.enqueue({\n type: 'tool-call',\n toolCallId: block.toolCallId,\n toolName: block.toolName,\n input: block.input === '' ? '{}' : block.input,\n });\n }\n delete contentBlocks[event.index];\n break;\n }\n\n case 'message_delta':\n if (event.usage) {\n usage.outputTokens = event.usage.output_tokens;\n usage.totalTokens = (usage.inputTokens || 0) + event.usage.output_tokens;\n }\n if (event.delta.stop_reason) {\n finishReason = self.convertFinishReason(event.delta.stop_reason);\n }\n break;\n\n case 'message_stop': {\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage,\n });\n break;\n }\n }\n } catch {\n // Ignore errors processing individual events\n }\n });\n\n anthropicStream.on('end', () => {\n resolve();\n });\n\n anthropicStream.on('error', (error) => {\n reject(error);\n });\n });\n\n // Emit any pending tool calls if stream ended without content_block_stop\n for (const [, block] of Object.entries(contentBlocks)) {\n if (block.type === 'tool-call') {\n controller.enqueue({\n type: 'tool-input-end',\n id: block.toolCallId,\n });\n controller.enqueue({\n type: 'tool-call',\n toolCallId: block.toolCallId,\n toolName: block.toolName,\n input: block.input === '' ? '{}' : block.input,\n });\n }\n }\n\n controller.close();\n } catch (error) {\n // Emit any pending tool calls before handling the error\n for (const [, block] of Object.entries(contentBlocks)) {\n if (block.type === 'tool-call') {\n controller.enqueue({\n type: 'tool-input-end',\n id: block.toolCallId,\n });\n controller.enqueue({\n type: 'tool-call',\n toolCallId: block.toolCallId,\n toolName: block.toolName,\n input: block.input === '' ? '{}' : block.input,\n });\n }\n }\n\n // If this is a token error and we haven't retried yet, we need to signal retry\n // For streaming, we close this stream with an error and the caller should retry\n if (!isRetry && self.isTokenError(error)) {\n self.directAccessClient.invalidateToken();\n // Signal that a retry is needed with a special error\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: 'TOKEN_REFRESH_NEEDED',\n cause: error,\n }),\n });\n controller.close();\n return;\n }\n\n if (error instanceof Anthropic.APIError) {\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: `Anthropic API error: ${error.message}`,\n cause: error,\n }),\n });\n } else {\n controller.enqueue({\n type: 'error',\n error,\n });\n }\n controller.close();\n }\n },\n });\n\n return {\n stream,\n request: { body: requestBody },\n };\n }\n}\n","import { z } from 'zod';\nimport { GitLabError } from './gitlab-error';\n\n/**\n * Response from /api/v4/ai/third_party_agents/direct_access\n */\nexport const directAccessTokenSchema = z.object({\n headers: z.record(z.string()),\n token: z.string(),\n});\n\nexport type DirectAccessToken = z.infer<typeof directAccessTokenSchema>;\n\nexport const DEFAULT_AI_GATEWAY_URL = 'https://cloud.gitlab.com';\n\nexport interface GitLabDirectAccessConfig {\n instanceUrl: string;\n getHeaders: () => Record<string, string>;\n fetch?: typeof fetch;\n /**\n * Optional callback to refresh the API key when a 401 error occurs.\n * Should clear cached credentials and re-fetch from auth provider.\n */\n refreshApiKey?: () => Promise<void>;\n /**\n * Feature flags to pass to the GitLab API\n */\n featureFlags?: Record<string, boolean>;\n /**\n * AI Gateway URL for the Anthropic proxy.\n * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.\n * @default 'https://cloud.gitlab.com'\n */\n aiGatewayUrl?: string;\n}\n\n/**\n * Client for GitLab's third-party agents direct access API.\n * This allows routing requests through GitLab's proxy to Anthropic.\n */\nexport class GitLabDirectAccessClient {\n private readonly config: GitLabDirectAccessConfig;\n private readonly fetchFn: typeof fetch;\n private readonly aiGatewayUrl: string;\n private cachedToken: DirectAccessToken | null = null;\n private tokenExpiresAt: number = 0;\n\n constructor(config: GitLabDirectAccessConfig) {\n this.config = config;\n this.fetchFn = config.fetch ?? fetch;\n this.aiGatewayUrl =\n config.aiGatewayUrl || process.env['GITLAB_AI_GATEWAY_URL'] || DEFAULT_AI_GATEWAY_URL;\n }\n\n /**\n * Get a direct access token for the Anthropic proxy.\n * Tokens are cached for 25 minutes (they expire after 30 minutes).\n * @param forceRefresh - If true, ignores the cache and fetches a new token\n */\n async getDirectAccessToken(forceRefresh: boolean = false): Promise<DirectAccessToken> {\n // Check if we have a valid cached token (unless force refresh is requested)\n const now = Date.now();\n if (!forceRefresh && this.cachedToken && this.tokenExpiresAt > now) {\n return this.cachedToken;\n }\n\n // Clear cache if forcing refresh\n if (forceRefresh) {\n this.invalidateToken();\n }\n\n const url = `${this.config.instanceUrl}/api/v4/ai/third_party_agents/direct_access`;\n\n // Prepare request body with feature flags if provided\n const requestBody: Record<string, unknown> = {};\n if (this.config.featureFlags && Object.keys(this.config.featureFlags).length > 0) {\n requestBody.feature_flags = this.config.featureFlags;\n }\n\n try {\n const response = await this.fetchFn(url, {\n method: 'POST',\n headers: {\n ...this.config.getHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n\n // If we get a 401 and have a refresh callback, try refreshing the API key once\n if (response.status === 401 && this.config.refreshApiKey && !forceRefresh) {\n try {\n // Refresh the API key (this should clear cached credentials and re-fetch from auth)\n await this.config.refreshApiKey();\n\n // Retry the request with the refreshed credentials\n return await this.getDirectAccessToken(true);\n } catch (refreshError) {\n // If refresh fails, throw the original 401 error\n throw new GitLabError({\n message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${errorText}`,\n statusCode: response.status,\n responseBody: errorText,\n });\n }\n }\n\n // Provide helpful error message for 403 errors (common with self-hosted instances)\n if (response.status === 403) {\n throw new GitLabError({\n message:\n `Access denied to GitLab AI features (${this.config.instanceUrl}). ` +\n `This may indicate that: (1) GitLab Duo is not enabled on this instance, ` +\n `(2) Your account does not have access to AI features, or ` +\n `(3) The third-party agents feature is not available. ` +\n `Original error: ${response.status} ${response.statusText} - ${errorText}`,\n statusCode: response.status,\n responseBody: errorText,\n });\n }\n\n throw new GitLabError({\n message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${errorText}`,\n statusCode: response.status,\n responseBody: errorText,\n });\n }\n\n const data = await response.json();\n const token = directAccessTokenSchema.parse(data);\n\n // Cache the token for 25 minutes (tokens expire after 30 minutes)\n this.cachedToken = token;\n this.tokenExpiresAt = now + 25 * 60 * 1000;\n\n return token;\n } catch (error) {\n if (error instanceof GitLabError) {\n throw error;\n }\n throw new GitLabError({\n message: `Failed to get direct access token: ${error}`,\n cause: error,\n });\n }\n }\n\n /**\n * Get the Anthropic proxy base URL\n */\n getAnthropicProxyUrl(): string {\n const baseUrl = this.aiGatewayUrl.replace(/\\/$/, '');\n return `${baseUrl}/ai/v1/proxy/anthropic/`;\n }\n\n /**\n * Invalidate the cached token\n */\n invalidateToken(): void {\n this.cachedToken = null;\n this.tokenExpiresAt = 0;\n }\n}\n","export interface GitLabErrorOptions {\n message: string;\n statusCode?: number;\n responseBody?: string;\n cause?: unknown;\n}\n\nexport class GitLabError extends Error {\n readonly statusCode?: number;\n readonly responseBody?: string;\n readonly cause?: unknown;\n\n constructor(options: GitLabErrorOptions) {\n super(options.message);\n this.name = 'GitLabError';\n this.statusCode = options.statusCode;\n this.responseBody = options.responseBody;\n this.cause = options.cause;\n\n // Maintain proper stack trace for where error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, GitLabError);\n }\n }\n\n static fromResponse(response: Response, body: string): GitLabError {\n return new GitLabError({\n message: `GitLab API error: ${response.status} ${response.statusText}`,\n statusCode: response.status,\n responseBody: body,\n });\n }\n\n isAuthError(): boolean {\n return this.statusCode === 401;\n }\n\n isRateLimitError(): boolean {\n return this.statusCode === 429;\n }\n\n isForbiddenError(): boolean {\n return this.statusCode === 403;\n }\n\n isServerError(): boolean {\n return this.statusCode !== undefined && this.statusCode >= 500;\n }\n}\n","/**\n * OAuth types and constants for GitLab authentication\n * Based on gitlab-vscode-extension and gitlab-lsp patterns\n */\n\nexport interface GitLabOAuthTokens {\n accessToken: string;\n refreshToken: string;\n expiresAt: number; // Unix timestamp in milliseconds\n instanceUrl: string;\n}\n\nexport interface OpenCodeAuthOAuth {\n type: 'oauth';\n refresh: string;\n access: string;\n expires: number; // Unix timestamp in milliseconds\n instanceUrl?: string;\n}\n\nexport interface OpenCodeAuthApi {\n type: 'api';\n key: string;\n}\n\nexport type OpenCodeAuth = OpenCodeAuthOAuth | OpenCodeAuthApi;\n\n/**\n * Bundled OAuth client ID for GitLab.com\n * Same as used in gitlab-vscode-extension\n */\nexport const BUNDLED_CLIENT_ID = '36f2a70cddeb5a0889d4fd8295c241b7e9848e89cf9e599d0eed2d8e5350fbf5';\n\n/**\n * GitLab.com URL constant\n */\nexport const GITLAB_COM_URL = 'https://gitlab.com';\n\n/**\n * Token expiry skew in milliseconds (5 minutes)\n * Refresh tokens this many milliseconds before they expire\n */\nexport const TOKEN_EXPIRY_SKEW_MS = 5 * 60 * 1000;\n\n/**\n * OAuth scopes to request\n */\nexport const OAUTH_SCOPES = ['api'];\n","/**\n * GitLab OAuth Manager\n * Handles OAuth token management, refresh, and exchange\n * Based on gitlab-vscode-extension TokenExchangeService and gitlab-lsp OAuthClientProvider\n */\n\nimport { GitLabError } from './gitlab-error';\nimport type { GitLabOAuthTokenResponse } from './gitlab-api-types';\nimport {\n type GitLabOAuthTokens,\n TOKEN_EXPIRY_SKEW_MS,\n BUNDLED_CLIENT_ID,\n GITLAB_COM_URL,\n} from './gitlab-oauth-types';\n\nexport interface TokenExchangeParams {\n instanceUrl: string;\n clientId?: string;\n redirectUri?: string;\n}\n\nexport interface AuthorizationCodeParams extends TokenExchangeParams {\n code: string;\n codeVerifier: string;\n}\n\nexport interface RefreshTokenParams extends TokenExchangeParams {\n refreshToken: string;\n}\n\nexport class GitLabOAuthManager {\n private fetch: typeof fetch;\n\n constructor(fetchImpl: typeof fetch = fetch) {\n this.fetch = fetchImpl;\n }\n\n /**\n * Check if a token is expired\n */\n isTokenExpired(expiresAt: number): boolean {\n return Date.now() >= expiresAt;\n }\n\n /**\n * Check if a token needs refresh (within skew window)\n */\n needsRefresh(expiresAt: number): boolean {\n return Date.now() >= expiresAt - TOKEN_EXPIRY_SKEW_MS;\n }\n\n /**\n * Refresh tokens if needed\n * Returns the same tokens if refresh is not needed, or new tokens if refreshed\n */\n async refreshIfNeeded(tokens: GitLabOAuthTokens, clientId?: string): Promise<GitLabOAuthTokens> {\n if (!this.needsRefresh(tokens.expiresAt)) {\n return tokens;\n }\n\n if (this.isTokenExpired(tokens.expiresAt)) {\n throw new GitLabError({\n message: 'OAuth token has expired and cannot be used',\n });\n }\n\n return this.exchangeRefreshToken({\n instanceUrl: tokens.instanceUrl,\n refreshToken: tokens.refreshToken,\n clientId,\n });\n }\n\n /**\n * Exchange authorization code for tokens\n * Based on gitlab-vscode-extension createOAuthAccountFromCode\n */\n async exchangeAuthorizationCode(params: AuthorizationCodeParams): Promise<GitLabOAuthTokens> {\n const { instanceUrl, code, codeVerifier, clientId, redirectUri } = params;\n\n const tokenResponse = await this.exchangeToken({\n instanceUrl,\n grantType: 'authorization_code',\n code,\n codeVerifier,\n clientId: clientId || this.getClientId(instanceUrl),\n redirectUri,\n });\n\n return this.createTokensFromResponse(tokenResponse, instanceUrl);\n }\n\n /**\n * Exchange refresh token for new tokens\n * Based on gitlab-vscode-extension TokenExchangeService\n */\n async exchangeRefreshToken(params: RefreshTokenParams): Promise<GitLabOAuthTokens> {\n const { instanceUrl, refreshToken, clientId } = params;\n\n const tokenResponse = await this.exchangeToken({\n instanceUrl,\n grantType: 'refresh_token',\n refreshToken,\n clientId: clientId || this.getClientId(instanceUrl),\n });\n\n return this.createTokensFromResponse(tokenResponse, instanceUrl);\n }\n\n /**\n * Get the OAuth client ID for an instance\n */\n private getClientId(instanceUrl: string): string {\n // Use bundled client ID for GitLab.com\n if (instanceUrl === GITLAB_COM_URL) {\n return BUNDLED_CLIENT_ID;\n }\n\n throw new GitLabError({\n message: `No OAuth client ID configured for instance ${instanceUrl}. Please provide a clientId parameter.`,\n });\n }\n\n /**\n * Exchange token with GitLab OAuth endpoint\n * Based on gitlab-vscode-extension GitLabService.exchangeToken\n */\n private async exchangeToken(params: {\n instanceUrl: string;\n grantType: 'authorization_code' | 'refresh_token';\n code?: string;\n codeVerifier?: string;\n refreshToken?: string;\n clientId: string;\n redirectUri?: string;\n }): Promise<GitLabOAuthTokenResponse> {\n const { instanceUrl, grantType, code, codeVerifier, refreshToken, clientId, redirectUri } =\n params;\n\n const body: Record<string, string> = {\n client_id: clientId,\n grant_type: grantType,\n };\n\n if (grantType === 'authorization_code') {\n if (!code || !codeVerifier || !redirectUri) {\n throw new GitLabError({\n message:\n 'Authorization code, code verifier, and redirect URI are required for authorization_code grant',\n });\n }\n body.code = code;\n body.code_verifier = codeVerifier;\n body.redirect_uri = redirectUri;\n } else if (grantType === 'refresh_token') {\n if (!refreshToken) {\n throw new GitLabError({\n message: 'Refresh token is required for refresh_token grant',\n });\n }\n body.refresh_token = refreshToken;\n }\n\n const url = `${instanceUrl}/oauth/token`;\n\n try {\n const response = await this.fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams(body).toString(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new GitLabError({\n message: `OAuth token exchange failed: ${response.status} ${response.statusText}`,\n cause: new Error(errorText),\n });\n }\n\n const data = await response.json();\n return data as GitLabOAuthTokenResponse;\n } catch (error) {\n if (error instanceof GitLabError) {\n throw error;\n }\n throw new GitLabError({\n message: `Failed to exchange OAuth token: ${error instanceof Error ? error.message : String(error)}`,\n cause: error instanceof Error ? error : undefined,\n });\n }\n }\n\n /**\n * Create GitLabOAuthTokens from token response\n */\n private createTokensFromResponse(\n response: GitLabOAuthTokenResponse,\n instanceUrl: string\n ): GitLabOAuthTokens {\n const expiresAt = this.createExpiresTimestamp(response);\n\n return {\n accessToken: response.access_token,\n refreshToken: response.refresh_token || '',\n expiresAt,\n instanceUrl,\n };\n }\n\n /**\n * Create expiry timestamp from token response\n * Based on gitlab-vscode-extension createExpiresTimestamp\n */\n private createExpiresTimestamp(response: GitLabOAuthTokenResponse): number {\n // GitLab returns created_at (Unix timestamp in seconds) and expires_in (seconds)\n const createdAt = response.created_at * 1000; // Convert to milliseconds\n const expiresIn = response.expires_in * 1000; // Convert to milliseconds\n return createdAt + expiresIn;\n }\n}\n","/**\n * Maps GitLab model IDs to their corresponding Anthropic model identifiers.\n *\n * This mapping allows users to specify model variants by model ID without\n * needing to manually configure the anthropicModel option.\n *\n * @example\n * const model = gitlab.agenticChat('duo-chat-opus-4-5');\n * // Automatically uses 'claude-opus-4-5-20251101'\n */\nexport const MODEL_ID_TO_ANTHROPIC_MODEL: Record<string, string> = {\n 'duo-chat-opus-4-5': 'claude-opus-4-5-20251101',\n 'duo-chat-sonnet-4-5': 'claude-sonnet-4-5-20250929',\n 'duo-chat-haiku-4-5': 'claude-haiku-4-5-20251001',\n};\n\n/**\n * Gets the Anthropic model identifier for a given GitLab model ID.\n *\n * @param modelId - The GitLab model ID (e.g., 'duo-chat-opus-4-5')\n * @returns The Anthropic model identifier, or undefined if no mapping exists\n *\n * @example\n * getAnthropicModelForModelId('duo-chat-opus-4-5')\n * // Returns: 'claude-opus-4-5-20251101'\n *\n * @example\n * getAnthropicModelForModelId('duo-chat')\n * // Returns: undefined (uses default)\n */\nexport function getAnthropicModelForModelId(modelId: string): string | undefined {\n return MODEL_ID_TO_ANTHROPIC_MODEL[modelId];\n}\n","import { GitLabAgenticLanguageModel } from './gitlab-agentic-language-model';\nimport { GitLabError } from './gitlab-error';\nimport type { LanguageModelV2 } from '@ai-sdk/provider';\nimport { GitLabOAuthManager } from './gitlab-oauth-manager';\nimport type { OpenCodeAuth } from './gitlab-oauth-types';\nimport { getAnthropicModelForModelId } from './model-mappings';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport interface GitLabProvider {\n (modelId: string): LanguageModelV2;\n readonly specificationVersion: 'v2';\n languageModel(modelId: string): LanguageModelV2;\n chat(modelId: string): LanguageModelV2;\n /**\n * Create an agentic chat model with tool calling support\n *\n * @param modelId - GitLab model identifier. Some IDs automatically map to specific Anthropic models.\n * @param options - Configuration options for the agentic model\n * @returns A language model with native tool calling support via Anthropic\n *\n * @example\n * // Automatic model mapping\n * const model = gitlab.agenticChat('duo-chat-opus-4-5');\n * // Uses claude-opus-4-5-20251101\n *\n * @example\n * // Explicit model override\n * const model = gitlab.agenticChat('duo-chat', {\n * anthropicModel: 'claude-sonnet-4-5-20250929'\n * });\n */\n agenticChat(modelId: string, options?: GitLabAgenticOptions): GitLabAgenticLanguageModel;\n textEmbeddingModel(modelId: string): never;\n imageModel(modelId: string): never;\n}\n\nexport interface GitLabAgenticOptions {\n /**\n * The Anthropic model to use\n *\n * If not specified, automatically maps from the model ID:\n * - 'duo-chat-opus-4-5' → 'claude-opus-4-5-20251101'\n * - 'duo-chat-sonnet-4-5' → 'claude-sonnet-4-5-20250929'\n * - 'duo-chat-haiku-4-5' → 'claude-haiku-4-5-20251001'\n *\n * For unmapped model IDs, defaults to 'claude-sonnet-4-5-20250929'\n *\n * @default Automatically mapped from model ID, or 'claude-sonnet-4-5-20250929'\n * @example\n * // Use automatic mapping\n * const model = gitlab.agenticChat('duo-chat-opus-4-5');\n *\n * @example\n * // Override with explicit model\n * const model = gitlab.agenticChat('duo-chat-opus-4-5', {\n * anthropicModel: 'claude-sonnet-4-5-20250929'\n * });\n */\n anthropicModel?: string;\n\n /**\n * Maximum tokens to generate\n * @default 8192\n */\n maxTokens?: number;\n\n /**\n * Feature flags to pass to the GitLab API\n */\n featureFlags?: Record<string, boolean>;\n}\n\nexport interface GitLabProviderSettings {\n /**\n * GitLab instance URL (e.g., 'https://gitlab.com')\n * @default 'https://gitlab.com'\n */\n instanceUrl?: string;\n\n /**\n * API token (Personal Access Token or OAuth access token)\n * Can also be set via GITLAB_TOKEN environment variable\n */\n apiKey?: string;\n\n /**\n * OAuth refresh token (optional, for OAuth flow)\n */\n refreshToken?: string;\n\n /**\n * OAuth client ID (required for OAuth flow)\n */\n clientId?: string;\n\n /**\n * OAuth redirect URI (required for OAuth flow)\n */\n redirectUri?: string;\n\n /**\n * Custom headers to include in requests\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation\n */\n fetch?: typeof fetch;\n\n /**\n * Provider name override\n */\n name?: string;\n\n /**\n * Default feature flags to pass to the GitLab API for all agentic chat models\n */\n featureFlags?: Record<string, boolean>;\n\n /**\n * AI Gateway URL for the Anthropic proxy.\n * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.\n * @default 'https://cloud.gitlab.com'\n */\n aiGatewayUrl?: string;\n}\n\nconst VERSION = '0.0.1';\n\n/**\n * Get OpenCode auth file path\n * Uses XDG Base Directory specification\n */\nfunction getOpenCodeAuthPath(): string {\n const homeDir = os.homedir();\n\n // Check XDG_DATA_HOME first (Linux/Mac standard)\n const xdgDataHome = process.env.XDG_DATA_HOME;\n if (xdgDataHome) {\n return path.join(xdgDataHome, 'opencode', 'auth.json');\n }\n\n // Fallback to ~/.local/share/opencode/auth.json (XDG default)\n if (process.platform !== 'win32') {\n return path.join(homeDir, '.local', 'share', 'opencode', 'auth.json');\n }\n\n // Windows fallback\n return path.join(homeDir, '.opencode', 'auth.json');\n}\n\n/**\n * Load OpenCode auth.json file\n */\nasync function loadOpenCodeAuth(instanceUrl: string): Promise<OpenCodeAuth | undefined> {\n try {\n const authPath = getOpenCodeAuthPath();\n\n if (!fs.existsSync(authPath)) {\n return undefined;\n }\n\n const authData = JSON.parse(fs.readFileSync(authPath, 'utf-8'));\n\n // Priority 1: Check 'gitlab' key (used by opencode-gitlab-auth plugin)\n if (authData.gitlab?.type === 'oauth') {\n const gitlabAuth = authData.gitlab;\n // Verify it matches the requested instance URL\n if (\n gitlabAuth.enterpriseUrl === instanceUrl ||\n gitlabAuth.enterpriseUrl === instanceUrl.replace(/\\/$/, '')\n ) {\n return gitlabAuth as OpenCodeAuth;\n }\n }\n\n // Priority 2: Try to find auth for this instance by URL\n // Check both with and without trailing slash\n const normalizedUrl = instanceUrl.replace(/\\/$/, '');\n const auth = authData[normalizedUrl] || authData[`${normalizedUrl}/`];\n\n return auth as OpenCodeAuth | undefined;\n } catch (error) {\n // Silently fail if we can't read auth.json\n return undefined;\n }\n}\n\n/**\n * Load GitLab API key with OAuth support\n * Priority: explicit apiKey > OAuth token > env var\n */\nasync function loadApiKey(\n options: {\n apiKey?: string;\n environmentVariableName: string;\n description: string;\n },\n instanceUrl: string,\n clientId?: string\n): Promise<string> {\n // Priority 1: Explicit apiKey\n if (options.apiKey) {\n return options.apiKey;\n }\n\n // Priority 2: OAuth token from OpenCode auth.json\n const auth = await loadOpenCodeAuth(instanceUrl);\n if (auth?.type === 'oauth') {\n const oauthManager = new GitLabOAuthManager();\n\n // Check if token needs refresh\n if (oauthManager.needsRefresh(auth.expires)) {\n try {\n const refreshed = await oauthManager.exchangeRefreshToken({\n instanceUrl,\n refreshToken: auth.refresh,\n clientId,\n });\n\n // Update stored token\n const authPath = getOpenCodeAuthPath();\n const authData = JSON.parse(fs.readFileSync(authPath, 'utf-8'));\n const normalizedUrl = instanceUrl.replace(/\\/$/, '');\n\n authData[normalizedUrl] = {\n type: 'oauth',\n refresh: refreshed.refreshToken,\n access: refreshed.accessToken,\n expires: refreshed.expiresAt,\n instanceUrl,\n };\n\n fs.writeFileSync(authPath, JSON.stringify(authData, null, 2));\n\n return refreshed.accessToken;\n } catch (error) {\n // If refresh fails, fall through to env var\n console.warn(\n `Failed to refresh OAuth token: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n } else {\n return auth.access;\n }\n }\n\n // Priority 3: Environment variable\n const apiKey = process.env[options.environmentVariableName];\n\n if (!apiKey) {\n throw new GitLabError({\n message: `${options.description} API key is missing. Pass it as the 'apiKey' parameter, set the ${options.environmentVariableName} environment variable, or authenticate with 'opencode auth login gitlab'.`,\n });\n }\n\n return apiKey;\n}\n\nfunction withUserAgentSuffix(\n headers: Record<string, string>,\n suffix: string\n): Record<string, string> {\n const userAgent = headers['User-Agent'];\n return {\n ...headers,\n 'User-Agent': userAgent ? `${userAgent} ${suffix}` : suffix,\n };\n}\n\nexport function createGitLab(options: GitLabProviderSettings = {}): GitLabProvider {\n const instanceUrl = options.instanceUrl ?? 'https://gitlab.com';\n const providerName = options.name ?? 'gitlab';\n\n // Cache for the API key - loaded lazily on first use\n let cachedApiKey: string | undefined;\n let apiKeyPromise: Promise<string> | undefined;\n\n const getApiKey = async (): Promise<string> => {\n if (cachedApiKey) {\n return cachedApiKey;\n }\n\n if (apiKeyPromise) {\n return apiKeyPromise;\n }\n\n apiKeyPromise = loadApiKey(\n {\n apiKey: options.apiKey,\n environmentVariableName: 'GITLAB_TOKEN',\n description: 'GitLab',\n },\n instanceUrl,\n options.clientId\n );\n\n cachedApiKey = await apiKeyPromise;\n apiKeyPromise = undefined;\n return cachedApiKey;\n };\n\n /**\n * Refresh the API key by clearing the cache and re-fetching from auth provider.\n * This is called when a 401 error occurs to trigger OAuth token refresh.\n */\n const refreshApiKey = async (): Promise<void> => {\n // Clear the cached API key to force a refresh\n cachedApiKey = undefined;\n apiKeyPromise = undefined;\n\n // Re-fetch the API key (this will trigger the auth plugin's loader() which handles token refresh)\n cachedApiKey = await getApiKey();\n };\n\n const getHeaders = () => {\n // For synchronous access, we need to have the key already loaded\n // or fall back to env var/explicit key\n const apiKey = cachedApiKey || options.apiKey || process.env['GITLAB_TOKEN'] || '';\n\n if (!apiKey) {\n throw new GitLabError({\n message:\n \"GitLab API key is missing. Pass it as the 'apiKey' parameter, set the GITLAB_TOKEN environment variable, or authenticate with 'opencode auth login gitlab'.\",\n });\n }\n\n return withUserAgentSuffix(\n {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n `ai-sdk-gitlab/${VERSION}`\n );\n };\n\n // Pre-load the API key asynchronously\n getApiKey().catch(() => {\n // Silently fail - will be caught when getHeaders is called\n });\n\n // Anthropic-based chat model using GitLab's Anthropic proxy (with tool support)\n const createAgenticChatModel = (modelId: string, agenticOptions?: GitLabAgenticOptions) => {\n // Merge provider-level and model-level feature flags (model-level takes precedence)\n // Always include DuoAgentPlatformNext: true as required by the API\n const featureFlags = {\n DuoAgentPlatformNext: true as const,\n ...options.featureFlags,\n ...agenticOptions?.featureFlags,\n };\n\n return new GitLabAgenticLanguageModel(modelId, {\n provider: `${providerName}.agentic`,\n instanceUrl,\n getHeaders,\n refreshApiKey,\n fetch: options.fetch,\n anthropicModel: agenticOptions?.anthropicModel ?? getAnthropicModelForModelId(modelId),\n maxTokens: agenticOptions?.maxTokens,\n featureFlags,\n aiGatewayUrl: options.aiGatewayUrl,\n });\n };\n\n // Default model factory - uses Anthropic backend for tool support\n const createDefaultModel = (modelId: string): LanguageModelV2 => {\n // Use Anthropic-based model by default for all models to get tool support\n return createAgenticChatModel(modelId);\n };\n\n const provider = Object.assign((modelId: string) => createDefaultModel(modelId), {\n specificationVersion: 'v2' as const,\n languageModel: createDefaultModel,\n chat: createDefaultModel,\n agenticChat: createAgenticChatModel,\n }) as GitLabProvider;\n\n // Unsupported model types\n provider.textEmbeddingModel = (modelId: string) => {\n throw new GitLabError({\n message: `GitLab provider does not support text embedding models. Model ID: ${modelId}`,\n });\n };\n\n provider.imageModel = (modelId: string) => {\n throw new GitLabError({\n message: `GitLab provider does not support image models. Model ID: ${modelId}`,\n });\n };\n\n return provider;\n}\n\n/**\n * Default GitLab Duo provider instance\n *\n * @example\n * ```typescript\n * import { gitlab } from '@ai-sdk/gitlab';\n *\n * const model = gitlab('duo-chat');\n * ```\n */\nexport const gitlab = createGitLab();\n","import { spawn } from 'child_process';\nimport * as path from 'path';\nimport { GitLabProjectCache, type GitLabProject } from './gitlab-project-cache';\nimport { GitLabError } from './gitlab-error';\n\n// Noop debug function (workflow debug removed)\nconst debugLog = (..._args: unknown[]) => {};\n\nexport interface GitLabProjectDetectorConfig {\n instanceUrl: string;\n getHeaders: () => Record<string, string>;\n fetch?: typeof fetch;\n cache?: GitLabProjectCache;\n gitTimeout?: number;\n}\n\n/**\n * Detects GitLab project information from git remote URLs\n *\n * This class provides functionality to:\n * - Parse git remote URLs (SSH, HTTPS, custom domains)\n * - Execute git commands to get remote URLs\n * - Fetch project details from GitLab API\n * - Cache project information to avoid repeated API calls\n */\nexport class GitLabProjectDetector {\n private readonly config: GitLabProjectDetectorConfig;\n private readonly fetchFn: typeof fetch;\n private readonly cache: GitLabProjectCache;\n\n constructor(config: GitLabProjectDetectorConfig) {\n this.config = {\n gitTimeout: 5000, // 5 seconds default\n ...config,\n };\n this.fetchFn = config.fetch ?? fetch;\n this.cache = config.cache ?? new GitLabProjectCache();\n }\n\n /**\n * Auto-detect GitLab project from git remote in the working directory\n *\n * @param workingDirectory - The directory to check for git remote\n * @param remoteName - The git remote name to use (default: 'origin')\n * @returns The detected project or null if detection fails\n */\n async detectProject(\n workingDirectory: string,\n remoteName: string = 'origin'\n ): Promise<GitLabProject | null> {\n // 1. Check cache first\n const cacheKey = path.resolve(workingDirectory);\n const cached = this.cache.get(cacheKey);\n if (cached) {\n return cached;\n }\n\n try {\n // 2. Get git remote URL\n debugLog(`[GitLabProjectDetector] Getting git remote URL from: ${workingDirectory}`);\n const remoteUrl = await this.getGitRemoteUrl(workingDirectory, remoteName);\n if (!remoteUrl) {\n debugLog(`[GitLabProjectDetector] No git remote URL found`);\n return null; // Not a git repo or no remote\n }\n debugLog(`[GitLabProjectDetector] Git remote URL: ${remoteUrl}`);\n\n // 3. Parse project path from URL\n debugLog(\n `[GitLabProjectDetector] Parsing project path from URL (instance: ${this.config.instanceUrl})`\n );\n const projectPath = this.parseGitRemoteUrl(remoteUrl, this.config.instanceUrl);\n if (!projectPath) {\n debugLog(\n `[GitLabProjectDetector] Could not parse project path from URL (remote doesn't match instance)`\n );\n return null; // Remote doesn't match instance\n }\n debugLog(`[GitLabProjectDetector] Parsed project path: ${projectPath}`);\n\n // 4. Fetch project from GitLab API\n debugLog(`[GitLabProjectDetector] Fetching project from GitLab API: ${projectPath}`);\n const project = await this.getProjectByPath(projectPath);\n debugLog(`[GitLabProjectDetector] ✓ Project fetched successfully:`, project);\n\n // 5. Cache the result\n this.cache.set(cacheKey, project);\n\n return project;\n } catch (error) {\n // Log error but don't throw - graceful degradation\n if (error instanceof GitLabError) {\n // GitLab API errors are expected (e.g., project not found)\n debugLog(`[GitLabProjectDetector] GitLab API error:`, error.message || error);\n return null;\n }\n // Log unexpected errors for debugging\n debugLog(`[GitLabProjectDetector] Unexpected error:`, error);\n console.warn(`Failed to auto-detect GitLab project: ${error}`);\n return null;\n }\n }\n\n /**\n * Parse a git remote URL to extract the project path\n *\n * Supports:\n * - SSH: git@gitlab.com:namespace/project.git\n * - HTTPS: https://gitlab.com/namespace/project.git\n * - HTTP: http://gitlab.local/namespace/project.git\n * - Custom domains and ports\n *\n * @param remoteUrl - The git remote URL\n * @param instanceUrl - The GitLab instance URL to match against\n * @returns The project path (e.g., \"namespace/project\") or null if parsing fails\n */\n parseGitRemoteUrl(remoteUrl: string, instanceUrl: string): string | null {\n try {\n // Extract hostname from instanceUrl\n const instanceHost = new URL(instanceUrl).hostname;\n\n // SSH format: git@host:path.git or git@host:port/path.git\n const sshMatch = remoteUrl.match(/^git@([^:]+):(.+?)(?:\\.git)?$/);\n if (sshMatch) {\n const [, host, pathPart] = sshMatch;\n // Handle port in SSH URLs (git@host:port/path)\n const hostWithoutPort = host.split(':')[0];\n if (hostWithoutPort === instanceHost) {\n // Remove port from path if present\n const cleanPath = pathPart.replace(/^\\d+\\//, '');\n return cleanPath.endsWith('.git') ? cleanPath.slice(0, -4) : cleanPath;\n }\n }\n\n // HTTPS/HTTP format: https://host/path.git or https://host:port/path.git\n const httpsMatch = remoteUrl.match(/^(https?):\\/\\/([^/]+)\\/(.+?)(?:\\.git)?$/);\n if (httpsMatch) {\n const [, , hostWithPort, pathPart] = httpsMatch;\n const host = hostWithPort.split(':')[0];\n if (host === instanceHost) {\n return pathPart.endsWith('.git') ? pathPart.slice(0, -4) : pathPart;\n }\n }\n\n return null;\n } catch (error) {\n // URL parsing failed\n return null;\n }\n }\n\n /**\n * Get the git remote URL from a working directory\n *\n * @param workingDirectory - The directory to check\n * @param remoteName - The git remote name (default: 'origin')\n * @returns The remote URL or null if not found\n */\n async getGitRemoteUrl(\n workingDirectory: string,\n remoteName: string = 'origin'\n ): Promise<string | null> {\n return new Promise((resolve) => {\n const child = spawn('git', ['config', '--get', `remote.${remoteName}.url`], {\n cwd: workingDirectory,\n timeout: this.config.gitTimeout,\n });\n\n let stdout = '';\n let _stderr = '';\n\n child.stdout?.on('data', (data) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data) => {\n _stderr += data.toString();\n });\n\n child.on('close', (exitCode) => {\n if (exitCode === 0 && stdout.trim()) {\n resolve(stdout.trim());\n } else {\n resolve(null);\n }\n });\n\n child.on('error', () => {\n // Git not available or command failed\n resolve(null);\n });\n });\n }\n\n /**\n * Fetch project details from GitLab API by project path\n *\n * @param projectPath - The project path (e.g., \"namespace/project\")\n * @returns The project details\n * @throws GitLabError if the API call fails\n */\n async getProjectByPath(projectPath: string): Promise<GitLabProject> {\n // URL-encode the project path\n const encodedPath = encodeURIComponent(projectPath);\n const url = `${this.config.instanceUrl}/api/v4/projects/${encodedPath}`;\n\n try {\n const response = await this.fetchFn(url, {\n method: 'GET',\n headers: this.config.getHeaders(),\n });\n\n if (!response.ok) {\n throw new GitLabError({\n message: `Failed to fetch project '${projectPath}': ${response.status} ${response.statusText}`,\n });\n }\n\n const data = (await response.json()) as {\n id: number;\n path: string;\n path_with_namespace: string;\n name: string;\n namespace?: { id: number };\n };\n\n return {\n id: data.id,\n path: data.path,\n pathWithNamespace: data.path_with_namespace,\n name: data.name,\n namespaceId: data.namespace?.id,\n };\n } catch (error) {\n if (error instanceof GitLabError) {\n throw error;\n }\n throw new GitLabError({\n message: `Failed to fetch project '${projectPath}': ${error}`,\n cause: error,\n });\n }\n }\n\n /**\n * Clear the project cache\n */\n clearCache(): void {\n this.cache.clear();\n }\n\n /**\n * Get the cache instance (useful for testing)\n */\n getCache(): GitLabProjectCache {\n return this.cache;\n }\n}\n","/**\n * Simple in-memory cache for GitLab project information\n * Used to avoid repeated API calls when detecting projects from git remotes\n */\n\nexport interface GitLabProject {\n id: number;\n path: string;\n pathWithNamespace: string;\n name: string;\n namespaceId?: number;\n}\n\ninterface CacheEntry {\n project: GitLabProject;\n expiresAt: number;\n}\n\n/**\n * In-memory cache for GitLab project information with TTL support\n */\nexport class GitLabProjectCache {\n private cache = new Map<string, CacheEntry>();\n private defaultTTL: number;\n\n /**\n * Create a new project cache\n * @param defaultTTL - Default time-to-live in milliseconds (default: 5 minutes)\n */\n constructor(defaultTTL: number = 5 * 60 * 1000) {\n this.defaultTTL = defaultTTL;\n }\n\n /**\n * Get a cached project by key\n * @param key - Cache key (typically the working directory path)\n * @returns The cached project or null if not found or expired\n */\n get(key: string): GitLabProject | null {\n const entry = this.cache.get(key);\n if (!entry) {\n return null;\n }\n\n // Check if entry has expired\n if (Date.now() > entry.expiresAt) {\n this.cache.delete(key);\n return null;\n }\n\n return entry.project;\n }\n\n /**\n * Store a project in the cache\n * @param key - Cache key (typically the working directory path)\n * @param project - The project to cache\n * @param ttl - Optional custom TTL in milliseconds\n */\n set(key: string, project: GitLabProject, ttl?: number): void {\n this.cache.set(key, {\n project,\n expiresAt: Date.now() + (ttl ?? this.defaultTTL),\n });\n }\n\n /**\n * Check if a key exists in the cache (and is not expired)\n * @param key - Cache key to check\n * @returns true if the key exists and is not expired\n */\n has(key: string): boolean {\n return this.get(key) !== null;\n }\n\n /**\n * Remove a specific entry from the cache\n * @param key - Cache key to remove\n */\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n /**\n * Clear all entries from the cache\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Get the number of entries in the cache (including expired ones)\n */\n get size(): number {\n return this.cache.size;\n }\n\n /**\n * Clean up expired entries from the cache\n * This is useful for long-running processes to prevent memory leaks\n */\n cleanup(): void {\n const now = Date.now();\n for (const [key, entry] of this.cache.entries()) {\n if (now > entry.expiresAt) {\n this.cache.delete(key);\n }\n }\n }\n}\n"],"mappings":";AAAA,OAAO,eAAe;;;ACAtB,SAAS,SAAS;;;ACOX,IAAM,cAAN,MAAM,qBAAoB,MAAM;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,SAA6B;AACvC,UAAM,QAAQ,OAAO;AACrB,SAAK,OAAO;AACZ,SAAK,aAAa,QAAQ;AAC1B,SAAK,eAAe,QAAQ;AAC5B,SAAK,QAAQ,QAAQ;AAGrB,QAAI,MAAM,mBAAmB;AAC3B,YAAM,kBAAkB,MAAM,YAAW;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,OAAO,aAAa,UAAoB,MAA2B;AACjE,WAAO,IAAI,aAAY;AAAA,MACrB,SAAS,qBAAqB,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,MACpE,YAAY,SAAS;AAAA,MACrB,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEA,cAAuB;AACrB,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEA,mBAA4B;AAC1B,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEA,mBAA4B;AAC1B,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEA,gBAAyB;AACvB,WAAO,KAAK,eAAe,UAAa,KAAK,cAAc;AAAA,EAC7D;AACF;;;AD1CO,IAAM,0BAA0B,EAAE,OAAO;AAAA,EAC9C,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC;AAAA,EAC5B,OAAO,EAAE,OAAO;AAClB,CAAC;AAIM,IAAM,yBAAyB;AA2B/B,IAAM,2BAAN,MAA+B;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACT,cAAwC;AAAA,EACxC,iBAAyB;AAAA,EAEjC,YAAY,QAAkC;AAC5C,SAAK,SAAS;AACd,SAAK,UAAU,OAAO,SAAS;AAC/B,SAAK,eACH,OAAO,gBAAgB,QAAQ,IAAI,uBAAuB,KAAK;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,qBAAqB,eAAwB,OAAmC;AAEpF,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,CAAC,gBAAgB,KAAK,eAAe,KAAK,iBAAiB,KAAK;AAClE,aAAO,KAAK;AAAA,IACd;AAGA,QAAI,cAAc;AAChB,WAAK,gBAAgB;AAAA,IACvB;AAEA,UAAM,MAAM,GAAG,KAAK,OAAO,WAAW;AAGtC,UAAM,cAAuC,CAAC;AAC9C,QAAI,KAAK,OAAO,gBAAgB,OAAO,KAAK,KAAK,OAAO,YAAY,EAAE,SAAS,GAAG;AAChF,kBAAY,gBAAgB,KAAK,OAAO;AAAA,IAC1C;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,KAAK;AAAA,QACvC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,GAAG,KAAK,OAAO,WAAW;AAAA,UAC1B,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU,WAAW;AAAA,MAClC,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,YAAY,MAAM,SAAS,KAAK;AAGtC,YAAI,SAAS,WAAW,OAAO,KAAK,OAAO,iBAAiB,CAAC,cAAc;AACzE,cAAI;AAEF,kBAAM,KAAK,OAAO,cAAc;AAGhC,mBAAO,MAAM,KAAK,qBAAqB,IAAI;AAAA,UAC7C,SAAS,cAAc;AAErB,kBAAM,IAAI,YAAY;AAAA,cACpB,SAAS,sCAAsC,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,SAAS;AAAA,cACpG,YAAY,SAAS;AAAA,cACrB,cAAc;AAAA,YAChB,CAAC;AAAA,UACH;AAAA,QACF;AAGA,YAAI,SAAS,WAAW,KAAK;AAC3B,gBAAM,IAAI,YAAY;AAAA,YACpB,SACE,wCAAwC,KAAK,OAAO,WAAW,4MAI5C,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,SAAS;AAAA,YAC1E,YAAY,SAAS;AAAA,YACrB,cAAc;AAAA,UAChB,CAAC;AAAA,QACH;AAEA,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,sCAAsC,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,SAAS;AAAA,UACpG,YAAY,SAAS;AAAA,UACrB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAM,QAAQ,wBAAwB,MAAM,IAAI;AAGhD,WAAK,cAAc;AACnB,WAAK,iBAAiB,MAAM,KAAK,KAAK;AAEtC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,iBAAiB,aAAa;AAChC,cAAM;AAAA,MACR;AACA,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,sCAAsC,KAAK;AAAA,QACpD,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,uBAA+B;AAC7B,UAAM,UAAU,KAAK,aAAa,QAAQ,OAAO,EAAE;AACnD,WAAO,GAAG,OAAO;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAwB;AACtB,SAAK,cAAc;AACnB,SAAK,iBAAiB;AAAA,EACxB;AACF;;;ADpGO,IAAM,6BAAN,MAA4D;AAAA,EACxD,uBAAuB;AAAA,EACvB;AAAA,EACA,gBAA0C,CAAC;AAAA,EAEnC;AAAA,EACA;AAAA,EACT,kBAAoC;AAAA,EAE5C,YAAY,SAAiB,QAA6B;AACxD,SAAK,UAAU;AACf,SAAK,SAAS;AAEd,SAAK,qBAAqB,IAAI,yBAAyB;AAAA,MACrD,aAAa,OAAO;AAAA,MACpB,YAAY,OAAO;AAAA,MACnB,eAAe,OAAO;AAAA,MACtB,OAAO,OAAO;AAAA,MACd,cAAc,OAAO;AAAA,MACrB,cAAc,OAAO;AAAA,IACvB,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,WAAmB;AACrB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,mBAAmB,eAAwB,OAA2B;AAElF,UAAM,YAAY,MAAM,KAAK,mBAAmB,qBAAqB,YAAY;AAOjF,UAAM,EAAE,aAAa,UAAU,GAAG,gBAAgB,IAAI,UAAU;AAEhE,SAAK,kBAAkB,IAAI,UAAU;AAAA,MACnC,QAAQ;AAAA,MACR,WAAW,UAAU;AAAA,MACrB,SAAS,KAAK,mBAAmB,qBAAqB;AAAA,MACtD,gBAAgB;AAAA,IAClB,CAAC;AAED,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,OAAyB;AAC5C,QAAI,iBAAiB,UAAU,UAAU;AAEvC,UAAI,MAAM,WAAW,KAAK;AACxB,eAAO;AAAA,MACT;AAEA,YAAM,UAAU,MAAM,SAAS,YAAY,KAAK;AAChD,UACE,QAAQ,SAAS,OAAO,MACvB,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,SAAS,IACzF;AACA,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,OAAiE;AACpF,QAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,aAAO;AAAA,IACT;AAEA,WAAO,MACJ,OAAO,CAAC,SAA8C,KAAK,SAAS,UAAU,EAC9E,IAAI,CAAC,SAAS;AACb,YAAM,SAAS,KAAK;AACpB,aAAO;AAAA,QACL,MAAM,KAAK;AAAA,QACX,aAAa,KAAK,eAAe;AAAA,QACjC,cAAc;AAAA,UACZ,MAAM;AAAA,UACN,YAAY,QAAQ,cAAc,CAAC;AAAA,UACnC,UAAU,QAAQ,YAAY,CAAC;AAAA,QACjC;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKQ,kBACN,YAC8C;AAC9C,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,IACT;AAEA,YAAQ,WAAW,MAAM;AAAA,MACvB,KAAK;AACH,eAAO,EAAE,MAAM,OAAO;AAAA,MACxB,KAAK;AAEH,eAAO;AAAA,MACT,KAAK;AACH,eAAO,EAAE,MAAM,MAAM;AAAA,MACvB,KAAK;AACH,eAAO,EAAE,MAAM,QAAQ,MAAM,WAAW,SAAS;AAAA,MACnD;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,QAGpB;AACA,QAAI;AACJ,UAAM,WAAqC,CAAC;AAE5C,eAAW,WAAW,QAAQ;AAC5B,UAAI,QAAQ,SAAS,UAAU;AAC7B,wBAAgB,QAAQ;AACxB;AAAA,MACF;AAEA,UAAI,QAAQ,SAAS,QAAQ;AAC3B,cAAM,UAAyC,CAAC;AAEhD,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,QAAQ;AACxB,oBAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,KAAK,KAAK,CAAC;AAAA,UAChD,WAAW,KAAK,SAAS,QAAQ;AAAA,UAGjC;AAAA,QACF;AAEA,YAAI,QAAQ,SAAS,GAAG;AACtB,mBAAS,KAAK,EAAE,MAAM,QAAQ,QAAQ,CAAC;AAAA,QACzC;AAAA,MACF,WAAW,QAAQ,SAAS,aAAa;AACvC,cAAM,UAAyC,CAAC;AAEhD,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,QAAQ;AACxB,oBAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,KAAK,KAAK,CAAC;AAAA,UAChD,WAAW,KAAK,SAAS,aAAa;AACpC,oBAAQ,KAAK;AAAA,cACX,MAAM;AAAA,cACN,IAAI,KAAK;AAAA,cACT,MAAM,KAAK;AAAA,cACX,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,MAAM,KAAK,KAAK,IAAI,KAAK;AAAA,YACxE,CAAC;AAAA,UACH;AAAA,QACF;AAEA,YAAI,QAAQ,SAAS,GAAG;AACtB,mBAAS,KAAK,EAAE,MAAM,aAAa,QAAQ,CAAC;AAAA,QAC9C;AAAA,MACF,WAAW,QAAQ,SAAS,QAAQ;AAElC,cAAM,UAA4C,CAAC;AAEnD,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,eAAe;AAC/B,gBAAI;AAGJ,gBAAI,KAAK,OAAO,SAAS,QAAQ;AAC/B,8BAAgB,KAAK,OAAO;AAAA,YAC9B,WAAW,KAAK,OAAO,SAAS,QAAQ;AACtC,8BAAgB,KAAK,UAAU,KAAK,OAAO,KAAK;AAAA,YAClD,WAAW,KAAK,OAAO,SAAS,cAAc;AAC5C,8BAAgB,KAAK,OAAO;AAAA,YAC9B,WAAW,KAAK,OAAO,SAAS,cAAc;AAC5C,8BAAgB,KAAK,UAAU,KAAK,OAAO,KAAK;AAAA,YAClD,OAAO;AACL,8BAAgB,KAAK,UAAU,KAAK,MAAM;AAAA,YAC5C;AAEA,oBAAQ,KAAK;AAAA,cACX,MAAM;AAAA,cACN,aAAa,KAAK;AAAA,cAClB,SAAS;AAAA,cACT,UAAU,KAAK,OAAO,KAAK,WAAW,OAAO;AAAA,YAC/C,CAAC;AAAA,UACH;AAAA,QACF;AAEA,YAAI,QAAQ,SAAS,GAAG;AACtB,mBAAS,KAAK,EAAE,MAAM,QAAQ,QAAQ,CAAC;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAEA,WAAO,EAAE,QAAQ,eAAe,SAAS;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,YAAwD;AAClF,YAAQ,YAAY;AAAA,MAClB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,SAKd;AACD,WAAO,KAAK,oBAAoB,SAAS,KAAK;AAAA,EAChD;AAAA,EAEA,MAAc,oBACZ,SACA,SAMC;AACD,UAAM,SAAS,MAAM,KAAK,mBAAmB,OAAO;AACpD,UAAM,EAAE,QAAQ,SAAS,IAAI,KAAK,cAAc,QAAQ,MAAM;AAC9D,UAAM,QAAQ,KAAK,aAAa,QAAQ,KAAK;AAC7C,UAAM,aACJ,QAAQ,YAAY,SAAS,SAAS,KAAK,kBAAkB,QAAQ,UAAU,IAAI;AAErF,UAAM,iBAAiB,KAAK,OAAO,kBAAkB;AACrD,UAAM,YAAY,QAAQ,mBAAmB,KAAK,OAAO,aAAa;AAEtE,QAAI;AACF,YAAM,WAAW,MAAM,OAAO,SAAS,OAAO;AAAA,QAC5C,OAAO;AAAA,QACP,YAAY;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,QAAQ,aAAa;AAAA,QAClC,aAAa,QAAQ;AAAA,QACrB,OAAO,QAAQ;AAAA,QACf,gBAAgB,QAAQ;AAAA,MAC1B,CAAC;AAED,YAAM,UAAoC,CAAC;AAE3C,iBAAW,SAAS,SAAS,SAAS;AACpC,YAAI,MAAM,SAAS,QAAQ;AACzB,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,MAAM,MAAM;AAAA,UACd,CAAC;AAAA,QACH,WAAW,MAAM,SAAS,YAAY;AACpC,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,YAAY,MAAM;AAAA,YAClB,UAAU,MAAM;AAAA,YAChB,OAAO,KAAK,UAAU,MAAM,KAAK;AAAA,UACnC,CAAC;AAAA,QACH;AAAA,MACF;AAEA,YAAM,QAA8B;AAAA,QAClC,aAAa,SAAS,MAAM;AAAA,QAC5B,cAAc,SAAS,MAAM;AAAA,QAC7B,aAAa,SAAS,MAAM,eAAe,SAAS,MAAM;AAAA,MAC5D;AAEA,aAAO;AAAA,QACL;AAAA,QACA,cAAc,KAAK,oBAAoB,SAAS,WAAW;AAAA,QAC3D;AAAA,QACA,UAAU,CAAC;AAAA,MACb;AAAA,IACF,SAAS,OAAO;AAEd,UAAI,CAAC,WAAW,KAAK,aAAa,KAAK,GAAG;AACxC,aAAK,mBAAmB,gBAAgB;AACxC,eAAO,KAAK,oBAAoB,SAAS,IAAI;AAAA,MAC/C;AAEA,UAAI,iBAAiB,UAAU,UAAU;AACvC,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,wBAAwB,MAAM,OAAO;AAAA,UAC9C,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,SAIZ;AACD,WAAO,KAAK,kBAAkB,SAAS,KAAK;AAAA,EAC9C;AAAA,EAEA,MAAc,kBACZ,SACA,SAKC;AACD,UAAM,SAAS,MAAM,KAAK,mBAAmB,OAAO;AACpD,UAAM,EAAE,QAAQ,SAAS,IAAI,KAAK,cAAc,QAAQ,MAAM;AAC9D,UAAM,QAAQ,KAAK,aAAa,QAAQ,KAAK;AAC7C,UAAM,aACJ,QAAQ,YAAY,SAAS,SAAS,KAAK,kBAAkB,QAAQ,UAAU,IAAI;AAErF,UAAM,iBAAiB,KAAK,OAAO,kBAAkB;AACrD,UAAM,YAAY,QAAQ,mBAAmB,KAAK,OAAO,aAAa;AAEtE,UAAM,cAAc;AAAA,MAClB,OAAO;AAAA,MACP,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,QAAQ,aAAa;AAAA,MAClC,aAAa,QAAQ;AAAA,MACrB,OAAO,QAAQ;AAAA,MACf,gBAAgB,QAAQ;AAAA,MACxB,QAAQ;AAAA,IACV;AAIA,UAAM,OAAO;AAEb,UAAM,SAAS,IAAI,eAA0C;AAAA,MAC3D,OAAO,OAAO,eAAe;AAC3B,cAAM,gBAIF,CAAC;AAEL,cAAM,QAA8B;AAAA,UAClC,aAAa;AAAA,UACb,cAAc;AAAA,UACd,aAAa;AAAA,QACf;AACA,YAAI,eAA4C;AAEhD,YAAI;AACF,gBAAM,kBAAkB,OAAO,SAAS,OAAO,aAAa;AAAA,YAC1D,QAAQ,QAAQ;AAAA,UAClB,CAAC;AAGD,qBAAW,QAAQ;AAAA,YACjB,MAAM;AAAA,YACN,UAAU,CAAC;AAAA,UACb,CAAC;AAGD,gBAAM,IAAI,QAAc,CAACA,UAAS,WAAW;AAC3C,4BAAgB,GAAG,eAAe,CAAC,UAAU;AAC3C,kBAAI;AACF,wBAAQ,MAAM,MAAM;AAAA,kBAClB,KAAK;AACH,wBAAI,MAAM,QAAQ,OAAO;AACvB,4BAAM,cAAc,MAAM,QAAQ,MAAM;AAAA,oBAC1C;AACA,+BAAW,QAAQ;AAAA,sBACjB,MAAM;AAAA,sBACN,IAAI,MAAM,QAAQ;AAAA,sBAClB,SAAS,MAAM,QAAQ;AAAA,oBACzB,CAAC;AACD;AAAA,kBAEF,KAAK;AACH,wBAAI,MAAM,cAAc,SAAS,QAAQ;AACvC,4BAAM,SAAS,QAAQ,MAAM,KAAK;AAClC,oCAAc,MAAM,KAAK,IAAI,EAAE,MAAM,QAAQ,IAAI,OAAO;AACxD,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI;AAAA,sBACN,CAAC;AAAA,oBACH,WAAW,MAAM,cAAc,SAAS,YAAY;AAClD,oCAAc,MAAM,KAAK,IAAI;AAAA,wBAC3B,MAAM;AAAA,wBACN,YAAY,MAAM,cAAc;AAAA,wBAChC,UAAU,MAAM,cAAc;AAAA,wBAC9B,OAAO;AAAA,sBACT;AACA,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI,MAAM,cAAc;AAAA,wBACxB,UAAU,MAAM,cAAc;AAAA,sBAChC,CAAC;AAAA,oBACH;AACA;AAAA,kBAEF,KAAK,uBAAuB;AAC1B,0BAAM,QAAQ,cAAc,MAAM,KAAK;AACvC,wBAAI,MAAM,MAAM,SAAS,gBAAgB,OAAO,SAAS,QAAQ;AAC/D,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI,MAAM;AAAA,wBACV,OAAO,MAAM,MAAM;AAAA,sBACrB,CAAC;AAAA,oBACH,WACE,MAAM,MAAM,SAAS,sBACrB,OAAO,SAAS,aAChB;AACA,4BAAM,SAAS,MAAM,MAAM;AAC3B,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI,MAAM;AAAA,wBACV,OAAO,MAAM,MAAM;AAAA,sBACrB,CAAC;AAAA,oBACH;AACA;AAAA,kBACF;AAAA,kBAEA,KAAK,sBAAsB;AACzB,0BAAM,QAAQ,cAAc,MAAM,KAAK;AACvC,wBAAI,OAAO,SAAS,QAAQ;AAC1B,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI,MAAM;AAAA,sBACZ,CAAC;AAAA,oBACH,WAAW,OAAO,SAAS,aAAa;AACtC,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI,MAAM;AAAA,sBACZ,CAAC;AAED,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,YAAY,MAAM;AAAA,wBAClB,UAAU,MAAM;AAAA,wBAChB,OAAO,MAAM,UAAU,KAAK,OAAO,MAAM;AAAA,sBAC3C,CAAC;AAAA,oBACH;AACA,2BAAO,cAAc,MAAM,KAAK;AAChC;AAAA,kBACF;AAAA,kBAEA,KAAK;AACH,wBAAI,MAAM,OAAO;AACf,4BAAM,eAAe,MAAM,MAAM;AACjC,4BAAM,eAAe,MAAM,eAAe,KAAK,MAAM,MAAM;AAAA,oBAC7D;AACA,wBAAI,MAAM,MAAM,aAAa;AAC3B,qCAAe,KAAK,oBAAoB,MAAM,MAAM,WAAW;AAAA,oBACjE;AACA;AAAA,kBAEF,KAAK,gBAAgB;AACnB,+BAAW,QAAQ;AAAA,sBACjB,MAAM;AAAA,sBACN;AAAA,sBACA;AAAA,oBACF,CAAC;AACD;AAAA,kBACF;AAAA,gBACF;AAAA,cACF,QAAQ;AAAA,cAER;AAAA,YACF,CAAC;AAED,4BAAgB,GAAG,OAAO,MAAM;AAC9B,cAAAA,SAAQ;AAAA,YACV,CAAC;AAED,4BAAgB,GAAG,SAAS,CAAC,UAAU;AACrC,qBAAO,KAAK;AAAA,YACd,CAAC;AAAA,UACH,CAAC;AAGD,qBAAW,CAAC,EAAE,KAAK,KAAK,OAAO,QAAQ,aAAa,GAAG;AACrD,gBAAI,MAAM,SAAS,aAAa;AAC9B,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,IAAI,MAAM;AAAA,cACZ,CAAC;AACD,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,YAAY,MAAM;AAAA,gBAClB,UAAU,MAAM;AAAA,gBAChB,OAAO,MAAM,UAAU,KAAK,OAAO,MAAM;AAAA,cAC3C,CAAC;AAAA,YACH;AAAA,UACF;AAEA,qBAAW,MAAM;AAAA,QACnB,SAAS,OAAO;AAEd,qBAAW,CAAC,EAAE,KAAK,KAAK,OAAO,QAAQ,aAAa,GAAG;AACrD,gBAAI,MAAM,SAAS,aAAa;AAC9B,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,IAAI,MAAM;AAAA,cACZ,CAAC;AACD,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,YAAY,MAAM;AAAA,gBAClB,UAAU,MAAM;AAAA,gBAChB,OAAO,MAAM,UAAU,KAAK,OAAO,MAAM;AAAA,cAC3C,CAAC;AAAA,YACH;AAAA,UACF;AAIA,cAAI,CAAC,WAAW,KAAK,aAAa,KAAK,GAAG;AACxC,iBAAK,mBAAmB,gBAAgB;AAExC,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY;AAAA,gBACrB,SAAS;AAAA,gBACT,OAAO;AAAA,cACT,CAAC;AAAA,YACH,CAAC;AACD,uBAAW,MAAM;AACjB;AAAA,UACF;AAEA,cAAI,iBAAiB,UAAU,UAAU;AACvC,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY;AAAA,gBACrB,SAAS,wBAAwB,MAAM,OAAO;AAAA,gBAC9C,OAAO;AAAA,cACT,CAAC;AAAA,YACH,CAAC;AAAA,UACH,OAAO;AACL,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN;AAAA,YACF,CAAC;AAAA,UACH;AACA,qBAAW,MAAM;AAAA,QACnB;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA,SAAS,EAAE,MAAM,YAAY;AAAA,IAC/B;AAAA,EACF;AACF;;;AGlmBO,IAAM,oBAAoB;AAK1B,IAAM,iBAAiB;AAMvB,IAAM,uBAAuB,IAAI,KAAK;AAKtC,IAAM,eAAe,CAAC,KAAK;;;ACjB3B,IAAM,qBAAN,MAAyB;AAAA,EACtB;AAAA,EAER,YAAY,YAA0B,OAAO;AAC3C,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,WAA4B;AACzC,WAAO,KAAK,IAAI,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,WAA4B;AACvC,WAAO,KAAK,IAAI,KAAK,YAAY;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,QAA2B,UAA+C;AAC9F,QAAI,CAAC,KAAK,aAAa,OAAO,SAAS,GAAG;AACxC,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,eAAe,OAAO,SAAS,GAAG;AACzC,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAEA,WAAO,KAAK,qBAAqB;AAAA,MAC/B,aAAa,OAAO;AAAA,MACpB,cAAc,OAAO;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,0BAA0B,QAA6D;AAC3F,UAAM,EAAE,aAAa,MAAM,cAAc,UAAU,YAAY,IAAI;AAEnE,UAAM,gBAAgB,MAAM,KAAK,cAAc;AAAA,MAC7C;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA,UAAU,YAAY,KAAK,YAAY,WAAW;AAAA,MAClD;AAAA,IACF,CAAC;AAED,WAAO,KAAK,yBAAyB,eAAe,WAAW;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,qBAAqB,QAAwD;AACjF,UAAM,EAAE,aAAa,cAAc,SAAS,IAAI;AAEhD,UAAM,gBAAgB,MAAM,KAAK,cAAc;AAAA,MAC7C;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA,UAAU,YAAY,KAAK,YAAY,WAAW;AAAA,IACpD,CAAC;AAED,WAAO,KAAK,yBAAyB,eAAe,WAAW;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,aAA6B;AAE/C,QAAI,gBAAgB,gBAAgB;AAClC,aAAO;AAAA,IACT;AAEA,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS,8CAA8C,WAAW;AAAA,IACpE,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,cAAc,QAQU;AACpC,UAAM,EAAE,aAAa,WAAW,MAAM,cAAc,cAAc,UAAU,YAAY,IACtF;AAEF,UAAM,OAA+B;AAAA,MACnC,WAAW;AAAA,MACX,YAAY;AAAA,IACd;AAEA,QAAI,cAAc,sBAAsB;AACtC,UAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,aAAa;AAC1C,cAAM,IAAI,YAAY;AAAA,UACpB,SACE;AAAA,QACJ,CAAC;AAAA,MACH;AACA,WAAK,OAAO;AACZ,WAAK,gBAAgB;AACrB,WAAK,eAAe;AAAA,IACtB,WAAW,cAAc,iBAAiB;AACxC,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AACA,WAAK,gBAAgB;AAAA,IACvB;AAEA,UAAM,MAAM,GAAG,WAAW;AAE1B,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,MAAM,KAAK;AAAA,QACrC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,IAAI,gBAAgB,IAAI,EAAE,SAAS;AAAA,MAC3C,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,YAAY,MAAM,SAAS,KAAK;AACtC,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,gCAAgC,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,UAC/E,OAAO,IAAI,MAAM,SAAS;AAAA,QAC5B,CAAC;AAAA,MACH;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,iBAAiB,aAAa;AAChC,cAAM;AAAA,MACR;AACA,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,mCAAmC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAClG,OAAO,iBAAiB,QAAQ,QAAQ;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,yBACN,UACA,aACmB;AACnB,UAAM,YAAY,KAAK,uBAAuB,QAAQ;AAEtD,WAAO;AAAA,MACL,aAAa,SAAS;AAAA,MACtB,cAAc,SAAS,iBAAiB;AAAA,MACxC;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAAuB,UAA4C;AAEzE,UAAM,YAAY,SAAS,aAAa;AACxC,UAAM,YAAY,SAAS,aAAa;AACxC,WAAO,YAAY;AAAA,EACrB;AACF;;;ACpNO,IAAM,8BAAsD;AAAA,EACjE,qBAAqB;AAAA,EACrB,uBAAuB;AAAA,EACvB,sBAAsB;AACxB;AAgBO,SAAS,4BAA4B,SAAqC;AAC/E,SAAO,4BAA4B,OAAO;AAC5C;;;AC1BA,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,YAAY,QAAQ;AA0HpB,IAAM,UAAU;AAMhB,SAAS,sBAA8B;AACrC,QAAM,UAAa,WAAQ;AAG3B,QAAM,cAAc,QAAQ,IAAI;AAChC,MAAI,aAAa;AACf,WAAY,UAAK,aAAa,YAAY,WAAW;AAAA,EACvD;AAGA,MAAI,QAAQ,aAAa,SAAS;AAChC,WAAY,UAAK,SAAS,UAAU,SAAS,YAAY,WAAW;AAAA,EACtE;AAGA,SAAY,UAAK,SAAS,aAAa,WAAW;AACpD;AAKA,eAAe,iBAAiB,aAAwD;AACtF,MAAI;AACF,UAAM,WAAW,oBAAoB;AAErC,QAAI,CAAI,cAAW,QAAQ,GAAG;AAC5B,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,KAAK,MAAS,gBAAa,UAAU,OAAO,CAAC;AAG9D,QAAI,SAAS,QAAQ,SAAS,SAAS;AACrC,YAAM,aAAa,SAAS;AAE5B,UACE,WAAW,kBAAkB,eAC7B,WAAW,kBAAkB,YAAY,QAAQ,OAAO,EAAE,GAC1D;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAIA,UAAM,gBAAgB,YAAY,QAAQ,OAAO,EAAE;AACnD,UAAM,OAAO,SAAS,aAAa,KAAK,SAAS,GAAG,aAAa,GAAG;AAEpE,WAAO;AAAA,EACT,SAAS,OAAO;AAEd,WAAO;AAAA,EACT;AACF;AAMA,eAAe,WACb,SAKA,aACA,UACiB;AAEjB,MAAI,QAAQ,QAAQ;AAClB,WAAO,QAAQ;AAAA,EACjB;AAGA,QAAM,OAAO,MAAM,iBAAiB,WAAW;AAC/C,MAAI,MAAM,SAAS,SAAS;AAC1B,UAAM,eAAe,IAAI,mBAAmB;AAG5C,QAAI,aAAa,aAAa,KAAK,OAAO,GAAG;AAC3C,UAAI;AACF,cAAM,YAAY,MAAM,aAAa,qBAAqB;AAAA,UACxD;AAAA,UACA,cAAc,KAAK;AAAA,UACnB;AAAA,QACF,CAAC;AAGD,cAAM,WAAW,oBAAoB;AACrC,cAAM,WAAW,KAAK,MAAS,gBAAa,UAAU,OAAO,CAAC;AAC9D,cAAM,gBAAgB,YAAY,QAAQ,OAAO,EAAE;AAEnD,iBAAS,aAAa,IAAI;AAAA,UACxB,MAAM;AAAA,UACN,SAAS,UAAU;AAAA,UACnB,QAAQ,UAAU;AAAA,UAClB,SAAS,UAAU;AAAA,UACnB;AAAA,QACF;AAEA,QAAG,iBAAc,UAAU,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAE5D,eAAO,UAAU;AAAA,MACnB,SAAS,OAAO;AAEd,gBAAQ;AAAA,UACN,kCAAkC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAC1F;AAAA,MACF;AAAA,IACF,OAAO;AACL,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAGA,QAAM,SAAS,QAAQ,IAAI,QAAQ,uBAAuB;AAE1D,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS,GAAG,QAAQ,WAAW,mEAAmE,QAAQ,uBAAuB;AAAA,IACnI,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,SAAS,oBACP,SACA,QACwB;AACxB,QAAM,YAAY,QAAQ,YAAY;AACtC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,cAAc,YAAY,GAAG,SAAS,IAAI,MAAM,KAAK;AAAA,EACvD;AACF;AAEO,SAAS,aAAa,UAAkC,CAAC,GAAmB;AACjF,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,eAAe,QAAQ,QAAQ;AAGrC,MAAI;AACJ,MAAI;AAEJ,QAAM,YAAY,YAA6B;AAC7C,QAAI,cAAc;AAChB,aAAO;AAAA,IACT;AAEA,QAAI,eAAe;AACjB,aAAO;AAAA,IACT;AAEA,oBAAgB;AAAA,MACd;AAAA,QACE,QAAQ,QAAQ;AAAA,QAChB,yBAAyB;AAAA,QACzB,aAAa;AAAA,MACf;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IACV;AAEA,mBAAe,MAAM;AACrB,oBAAgB;AAChB,WAAO;AAAA,EACT;AAMA,QAAM,gBAAgB,YAA2B;AAE/C,mBAAe;AACf,oBAAgB;AAGhB,mBAAe,MAAM,UAAU;AAAA,EACjC;AAEA,QAAM,aAAa,MAAM;AAGvB,UAAM,SAAS,gBAAgB,QAAQ,UAAU,QAAQ,IAAI,cAAc,KAAK;AAEhF,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,YAAY;AAAA,QACpB,SACE;AAAA,MACJ,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL;AAAA,QACE,eAAe,UAAU,MAAM;AAAA,QAC/B,gBAAgB;AAAA,QAChB,GAAG,QAAQ;AAAA,MACb;AAAA,MACA,iBAAiB,OAAO;AAAA,IAC1B;AAAA,EACF;AAGA,YAAU,EAAE,MAAM,MAAM;AAAA,EAExB,CAAC;AAGD,QAAM,yBAAyB,CAAC,SAAiB,mBAA0C;AAGzF,UAAM,eAAe;AAAA,MACnB,sBAAsB;AAAA,MACtB,GAAG,QAAQ;AAAA,MACX,GAAG,gBAAgB;AAAA,IACrB;AAEA,WAAO,IAAI,2BAA2B,SAAS;AAAA,MAC7C,UAAU,GAAG,YAAY;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,gBAAgB,gBAAgB,kBAAkB,4BAA4B,OAAO;AAAA,MACrF,WAAW,gBAAgB;AAAA,MAC3B;AAAA,MACA,cAAc,QAAQ;AAAA,IACxB,CAAC;AAAA,EACH;AAGA,QAAM,qBAAqB,CAAC,YAAqC;AAE/D,WAAO,uBAAuB,OAAO;AAAA,EACvC;AAEA,QAAM,WAAW,OAAO,OAAO,CAAC,YAAoB,mBAAmB,OAAO,GAAG;AAAA,IAC/E,sBAAsB;AAAA,IACtB,eAAe;AAAA,IACf,MAAM;AAAA,IACN,aAAa;AAAA,EACf,CAAC;AAGD,WAAS,qBAAqB,CAAC,YAAoB;AACjD,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS,qEAAqE,OAAO;AAAA,IACvF,CAAC;AAAA,EACH;AAEA,WAAS,aAAa,CAAC,YAAoB;AACzC,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS,4DAA4D,OAAO;AAAA,IAC9E,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAYO,IAAM,SAAS,aAAa;;;ACvZnC,SAAS,aAAa;AACtB,YAAYC,WAAU;;;ACoBf,IAAM,qBAAN,MAAyB;AAAA,EACtB,QAAQ,oBAAI,IAAwB;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMR,YAAY,aAAqB,IAAI,KAAK,KAAM;AAC9C,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,KAAmC;AACrC,UAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAChC,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,IAAI,IAAI,MAAM,WAAW;AAChC,WAAK,MAAM,OAAO,GAAG;AACrB,aAAO;AAAA,IACT;AAEA,WAAO,MAAM;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,KAAa,SAAwB,KAAoB;AAC3D,SAAK,MAAM,IAAI,KAAK;AAAA,MAClB;AAAA,MACA,WAAW,KAAK,IAAI,KAAK,OAAO,KAAK;AAAA,IACvC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,KAAsB;AACxB,WAAO,KAAK,IAAI,GAAG,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAmB;AACxB,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAgB;AACd,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,MAAM,QAAQ,GAAG;AAC/C,UAAI,MAAM,MAAM,WAAW;AACzB,aAAK,MAAM,OAAO,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AACF;;;ADvGA,IAAM,WAAW,IAAI,UAAqB;AAAC;AAmBpC,IAAM,wBAAN,MAA4B;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,QAAqC;AAC/C,SAAK,SAAS;AAAA,MACZ,YAAY;AAAA;AAAA,MACZ,GAAG;AAAA,IACL;AACA,SAAK,UAAU,OAAO,SAAS;AAC/B,SAAK,QAAQ,OAAO,SAAS,IAAI,mBAAmB;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,cACJ,kBACA,aAAqB,UACU;AAE/B,UAAM,WAAgB,cAAQ,gBAAgB;AAC9C,UAAM,SAAS,KAAK,MAAM,IAAI,QAAQ;AACtC,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,QAAI;AAEF,eAAS,wDAAwD,gBAAgB,EAAE;AACnF,YAAM,YAAY,MAAM,KAAK,gBAAgB,kBAAkB,UAAU;AACzE,UAAI,CAAC,WAAW;AACd,iBAAS,iDAAiD;AAC1D,eAAO;AAAA,MACT;AACA,eAAS,2CAA2C,SAAS,EAAE;AAG/D;AAAA,QACE,oEAAoE,KAAK,OAAO,WAAW;AAAA,MAC7F;AACA,YAAM,cAAc,KAAK,kBAAkB,WAAW,KAAK,OAAO,WAAW;AAC7E,UAAI,CAAC,aAAa;AAChB;AAAA,UACE;AAAA,QACF;AACA,eAAO;AAAA,MACT;AACA,eAAS,gDAAgD,WAAW,EAAE;AAGtE,eAAS,6DAA6D,WAAW,EAAE;AACnF,YAAM,UAAU,MAAM,KAAK,iBAAiB,WAAW;AACvD,eAAS,gEAA2D,OAAO;AAG3E,WAAK,MAAM,IAAI,UAAU,OAAO;AAEhC,aAAO;AAAA,IACT,SAAS,OAAO;AAEd,UAAI,iBAAiB,aAAa;AAEhC,iBAAS,6CAA6C,MAAM,WAAW,KAAK;AAC5E,eAAO;AAAA,MACT;AAEA,eAAS,6CAA6C,KAAK;AAC3D,cAAQ,KAAK,yCAAyC,KAAK,EAAE;AAC7D,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,kBAAkB,WAAmB,aAAoC;AACvE,QAAI;AAEF,YAAM,eAAe,IAAI,IAAI,WAAW,EAAE;AAG1C,YAAM,WAAW,UAAU,MAAM,+BAA+B;AAChE,UAAI,UAAU;AACZ,cAAM,CAAC,EAAE,MAAM,QAAQ,IAAI;AAE3B,cAAM,kBAAkB,KAAK,MAAM,GAAG,EAAE,CAAC;AACzC,YAAI,oBAAoB,cAAc;AAEpC,gBAAM,YAAY,SAAS,QAAQ,UAAU,EAAE;AAC/C,iBAAO,UAAU,SAAS,MAAM,IAAI,UAAU,MAAM,GAAG,EAAE,IAAI;AAAA,QAC/D;AAAA,MACF;AAGA,YAAM,aAAa,UAAU,MAAM,yCAAyC;AAC5E,UAAI,YAAY;AACd,cAAM,CAAC,EAAE,EAAE,cAAc,QAAQ,IAAI;AACrC,cAAM,OAAO,aAAa,MAAM,GAAG,EAAE,CAAC;AACtC,YAAI,SAAS,cAAc;AACzB,iBAAO,SAAS,SAAS,MAAM,IAAI,SAAS,MAAM,GAAG,EAAE,IAAI;AAAA,QAC7D;AAAA,MACF;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AAEd,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,gBACJ,kBACA,aAAqB,UACG;AACxB,WAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,YAAM,QAAQ,MAAM,OAAO,CAAC,UAAU,SAAS,UAAU,UAAU,MAAM,GAAG;AAAA,QAC1E,KAAK;AAAA,QACL,SAAS,KAAK,OAAO;AAAA,MACvB,CAAC;AAED,UAAI,SAAS;AACb,UAAI,UAAU;AAEd,YAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS;AACjC,kBAAU,KAAK,SAAS;AAAA,MAC1B,CAAC;AAED,YAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS;AACjC,mBAAW,KAAK,SAAS;AAAA,MAC3B,CAAC;AAED,YAAM,GAAG,SAAS,CAAC,aAAa;AAC9B,YAAI,aAAa,KAAK,OAAO,KAAK,GAAG;AACnC,UAAAA,SAAQ,OAAO,KAAK,CAAC;AAAA,QACvB,OAAO;AACL,UAAAA,SAAQ,IAAI;AAAA,QACd;AAAA,MACF,CAAC;AAED,YAAM,GAAG,SAAS,MAAM;AAEtB,QAAAA,SAAQ,IAAI;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,iBAAiB,aAA6C;AAElE,UAAM,cAAc,mBAAmB,WAAW;AAClD,UAAM,MAAM,GAAG,KAAK,OAAO,WAAW,oBAAoB,WAAW;AAErE,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,KAAK;AAAA,QACvC,QAAQ;AAAA,QACR,SAAS,KAAK,OAAO,WAAW;AAAA,MAClC,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,4BAA4B,WAAW,MAAM,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,QAC9F,CAAC;AAAA,MACH;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAQlC,aAAO;AAAA,QACL,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,mBAAmB,KAAK;AAAA,QACxB,MAAM,KAAK;AAAA,QACX,aAAa,KAAK,WAAW;AAAA,MAC/B;AAAA,IACF,SAAS,OAAO;AACd,UAAI,iBAAiB,aAAa;AAChC,cAAM;AAAA,MACR;AACA,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,4BAA4B,WAAW,MAAM,KAAK;AAAA,QAC3D,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,WAA+B;AAC7B,WAAO,KAAK;AAAA,EACd;AACF;","names":["resolve","path","resolve"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/gitlab-ai-provider",
3
- "version": "3.1.1",
3
+ "version": "3.1.3",
4
4
  "description": "GitLab Duo provider for Vercel AI SDK",
5
5
  "license": "MIT",
6
6
  "author": {