tdecollab 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +53 -217
- package/dist/{chunk-2IQ4QMK3.js → chunk-6AFNYE7N.js} +283 -288
- package/dist/chunk-6AFNYE7N.js.map +1 -0
- package/dist/{chunk-T73I3OT6.js → chunk-GMC75YB2.js} +181 -37
- package/dist/chunk-GMC75YB2.js.map +1 -0
- package/dist/{chunk-SJ7KPK6Q.js → chunk-IFYMZLQI.js} +21 -6
- package/dist/chunk-IFYMZLQI.js.map +1 -0
- package/dist/{image-downloader-D57KFAIQ.js → chunk-JBDK5WP3.js} +8 -6
- package/dist/chunk-JBDK5WP3.js.map +1 -0
- package/dist/chunk-JI2YUE7N.js +172 -0
- package/dist/chunk-JI2YUE7N.js.map +1 -0
- package/dist/cli.js +138 -18
- package/dist/cli.js.map +1 -1
- package/dist/image-downloader-VKPGS3TY.js +8 -0
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/server-M353VF2O.js +10 -0
- package/dist/server-M353VF2O.js.map +1 -0
- package/dist/tui/index.js +2754 -0
- package/dist/tui/index.js.map +1 -0
- package/package.json +33 -9
- package/dist/chunk-2IQ4QMK3.js.map +0 -1
- package/dist/chunk-SJ7KPK6Q.js.map +0 -1
- package/dist/chunk-T73I3OT6.js.map +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/image-downloader-D57KFAIQ.js.map +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/server-HS774DWY.js +0 -9
- /package/dist/{server-HS774DWY.js.map → image-downloader-VKPGS3TY.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../tools/confluence/api/content.ts","../tools/confluence/api/space.ts","../tools/confluence/api/search.ts","../tools/common/http-client.ts","../tools/common/errors.ts","../tools/confluence/api/client.ts","../tools/common/config.ts","../tools/confluence/converters/md-to-storage.ts","../tools/confluence/converters/storage-to-md.ts","../tools/jira/api/issue.ts","../tools/jira/api/search.ts","../tools/jira/api/client.ts","../tools/gitlab/api/merge-request.ts","../tools/gitlab/api/pipeline.ts","../tools/gitlab/api/client.ts"],"sourcesContent":["import { AxiosInstance } from 'axios';\nimport { ConfluencePageResponse, CreatePageParams, UpdatePageParams, ConfluenceLabel, ConfluenceAttachmentResponse } from '../types.js';\n\n\nexport class ConfluenceContentApi {\n constructor(private client: AxiosInstance) { }\n\n async getPage(id: string, expand?: string[]): Promise<ConfluencePageResponse> {\n const expandParam = expand ? expand.join(',') : 'body.storage,version,space,metadata.labels';\n const response = await this.client.get(`/rest/api/content/${id}`, {\n params: { expand: expandParam }\n });\n return response.data;\n }\n\n async getPageByTitle(spaceKey: string, title: string, expand?: string[]): Promise<ConfluencePageResponse | null> {\n const expandParam = expand ? expand.join(',') : 'body.storage,version,space';\n const response = await this.client.get('/rest/api/content', {\n params: {\n spaceKey,\n title,\n expand: expandParam,\n limit: 1\n }\n });\n\n if (response.data.results && response.data.results.length > 0) {\n return response.data.results[0];\n }\n return null;\n }\n\n async createPage(params: CreatePageParams): Promise<ConfluencePageResponse> {\n const data: any = {\n type: 'page',\n title: params.title,\n space: { key: params.spaceKey },\n body: {\n storage: {\n value: params.body,\n representation: 'storage'\n }\n }\n };\n\n if (params.parentId) {\n data.ancestors = [{ id: params.parentId }];\n }\n\n const response = await this.client.post('/rest/api/content', data);\n\n // add labels if provided\n if (params.labels && params.labels.length > 0) {\n await this.addLabels(response.data.id, params.labels);\n // refetch to include labels in response if needed, \n // but simpler to just return the create response.\n // Or we can construct the object.\n }\n\n return response.data;\n }\n\n async updatePage(params: UpdatePageParams): Promise<ConfluencePageResponse> {\n const data = {\n version: { number: params.version + 1 },\n title: params.title,\n type: 'page',\n body: {\n storage: {\n value: params.body,\n representation: 'storage'\n }\n }\n };\n\n const response = await this.client.put(`/rest/api/content/${params.id}`, data);\n return response.data;\n }\n\n async deletePage(id: string): Promise<void> {\n await this.client.delete(`/rest/api/content/${id}`);\n }\n\n async getChildPages(id: string, start = 0, limit = 25): Promise<ConfluencePageResponse[]> {\n const response = await this.client.get(`/rest/api/content/${id}/child/page`, {\n params: { start, limit }\n });\n return response.data.results;\n }\n\n // Label helper inside content api or separate? \n // Let's implement basic label addition here since it's used in create.\n // Actually, label logic is in label.ts, but due to circular dependency or convenience...\n // Let's implement it here privately or import it.\n // Better to keep it separate as per plan, but `this.client` is available here.\n // I'll implement a simple one here or use the separate class later. \n // For now, simple implementation to support createPage.\n private async addLabels(id: string, labels: string[]): Promise<void> {\n const data = labels.map(name => ({ prefix: 'global', name }));\n await this.client.post(`/rest/api/content/${id}/label`, data);\n }\n\n // Attachment 관련 메서드 (upsert: 기존 파일이 있으면 업데이트, 없으면 신규 업로드)\n async uploadAttachment(pageId: string, filename: string, fileContent: Buffer, contentType?: string): Promise<ConfluenceAttachmentResponse> {\n const FormData = (await import('form-data')).default;\n\n // 기존 첨부파일 존재 여부 확인\n const existingAttachments = await this.getAttachments(pageId, filename);\n const existing = existingAttachments.find(a => a.title === filename);\n\n const form = new FormData();\n form.append('file', fileContent, {\n filename: filename,\n contentType: contentType || 'application/octet-stream'\n });\n\n const headers = {\n ...form.getHeaders(),\n 'X-Atlassian-Token': 'nocheck',\n 'Accept': 'application/json',\n };\n\n let response;\n if (existing) {\n // 기존 파일 업데이트 (POST to /data endpoint)\n response = await this.client.post(\n `/rest/api/content/${pageId}/child/attachment/${existing.id}/data`,\n form,\n { headers }\n );\n } else {\n // 신규 업로드\n response = await this.client.post(\n `/rest/api/content/${pageId}/child/attachment`,\n form,\n { headers }\n );\n }\n\n // Confluence API returns { results: [Attachment] } \n if (response.data && response.data.results && response.data.results.length > 0) {\n return response.data.results[0];\n }\n return response.data;\n }\n\n async getAttachments(pageId: string, filename?: string): Promise<ConfluenceAttachmentResponse[]> {\n const response = await this.client.get(`/rest/api/content/${pageId}/child/attachment`, {\n params: {\n filename,\n expand: 'version'\n }\n });\n return response.data.results;\n }\n\n async downloadAttachment(downloadUrl: string): Promise<Buffer> {\n const response = await this.client.get(downloadUrl, {\n responseType: 'arraybuffer'\n });\n return Buffer.from(response.data);\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { ConfluenceSpaceResponse } from '../types.js';\n\nexport class ConfluenceSpaceApi {\n constructor(private client: AxiosInstance) { }\n\n async getSpaces(type: string = 'global', start = 0, limit = 25): Promise<ConfluenceSpaceResponse[]> {\n const response = await this.client.get('/rest/api/space', {\n params: { type, start, limit }\n });\n return response.data.results;\n }\n\n async getSpace(spaceKey: string): Promise<ConfluenceSpaceResponse> {\n const response = await this.client.get(`/rest/api/space/${spaceKey}`);\n return response.data;\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { ConfluenceSearchResponse } from '../types.js';\n\nexport class ConfluenceSearchApi {\n constructor(private client: AxiosInstance) { }\n\n async searchByCql(cql: string, start = 0, limit = 25, expand?: string[]): Promise<ConfluenceSearchResponse> {\n const expandParam = expand ? expand.join(',') : 'body.storage,version,space,metadata.labels';\n const response = await this.client.get('/rest/api/content/search', {\n params: {\n cql,\n start,\n limit,\n expand: expandParam\n }\n });\n\n return response.data;\n }\n}\n","import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';\nimport { ApiError, AuthError, NotFoundError, ConflictError } from './errors.js';\nimport { logger } from './logger.js';\nimport { ServiceConfig } from './types.js';\n\nexport function createHttpClient(config: ServiceConfig): AxiosInstance {\n const client = axios.create({\n baseURL: config.baseUrl,\n timeout: 30000, // 30초 타임아웃\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n // 요청 인터셉터: 인증 헤더 주입 및 로깅\n client.interceptors.request.use((reqConfig) => {\n // 1. 토큰 기반 Bearer 인증 (Confluence/JIRA PAT 권장 방식)\n if (config.auth.token && !reqConfig.headers.Authorization && !reqConfig.headers['PRIVATE-TOKEN']) {\n // GitLab은 PRIVATE-TOKEN 헤더를 선호하므로 제외\n reqConfig.headers.Authorization = `Bearer ${config.auth.token}`;\n }\n // 2. Basic 인증 (Username + Password/Token) - Bearer가 없을 때만 사용\n else if (config.auth.username && config.auth.token && !reqConfig.headers.Authorization) {\n const token = Buffer.from(`${config.auth.username}:${config.auth.token}`).toString('base64');\n reqConfig.headers.Authorization = `Basic ${token}`;\n }\n\n logger.debug(`[HTTP Request] ${reqConfig.method?.toUpperCase()} ${reqConfig.url}`, {\n headers: reqConfig.headers,\n params: reqConfig.params,\n data: reqConfig.data,\n });\n\n return reqConfig;\n });\n\n // 응답 인터셉터: 에러 핸들링 및 로깅\n client.interceptors.response.use(\n (response: AxiosResponse) => {\n logger.debug(`[HTTP Response] ${response.status} ${response.config.method?.toUpperCase()} ${response.config.url}`, {\n headers: response.headers,\n data: response.data,\n });\n return response;\n },\n (error: AxiosError) => {\n if (error.response) {\n const status = error.response.status;\n const method = error.config?.method?.toUpperCase();\n const url = error.config?.url;\n const message = (error.response.data as any)?.message || error.message;\n\n logger.error(`[HTTP Error] ${status} ${method} ${url}`, {\n message,\n responseData: error.response.data,\n requestHeaders: error.config?.headers,\n });\n\n // 상태 코드별 커스텀 에러 매핑\n if (status === 401 || status === 403) {\n throw new AuthError(`인증 실패: ${message}`);\n }\n if (status === 404) {\n throw new NotFoundError('리소스', url || 'unknown');\n }\n if (status === 409) {\n throw new ConflictError(`충돌 발생: ${message}`);\n }\n\n throw new ApiError(status, message, error.response.data);\n } else if (error.request) {\n logger.error(`[HTTP] No Response: ${error.message}`);\n throw new ApiError(0, `서버로부터 응답이 없습니다: ${error.message}`);\n } else {\n logger.error(`[HTTP] Request Error: ${error.message}`);\n throw new ApiError(0, `요청 설정 중 오류 발생: ${error.message}`);\n }\n }\n );\n\n return client;\n}\n","// TDE Collab 기본 에러 클래스\nexport class TdeCollabError extends Error {\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n// API 요청 실패 에러\nexport class ApiError extends TdeCollabError {\n constructor(\n public statusCode: number,\n message: string,\n public data?: any\n ) {\n super(`API 요청 실패 (${statusCode}): ${message}`);\n }\n}\n\n// 인증 실패 에러\nexport class AuthError extends TdeCollabError {\n constructor(message: string = '인증에 실패했습니다') {\n super(message);\n }\n}\n\n// 리소스 미발견 에러\nexport class NotFoundError extends TdeCollabError {\n constructor(resource: string, id: string) {\n super(`${resource} '${id}'를 찾을 수 없습니다`);\n }\n}\n\n// 리소스 충돌 에러\nexport class ConflictError extends TdeCollabError {\n constructor(message: string) {\n super(message);\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { ConfluenceConfig } from '../../common/types.js';\nimport { createHttpClient } from '../../common/http-client.js';\n\nexport function createConfluenceClient(config: ConfluenceConfig): AxiosInstance {\n // Confluence API base context path handling\n // If user provides 'https://example.atlassian.net/wiki', we should use that.\n // API path usually appends '/rest/api/content' etc.\n\n // Ensure config.baseUrl includes '/wiki' if it's a cloud instance, usually users put it in env.\n // But standard is commonly base domain.\n // We'll trust the config for now, but client consumers should append specific endpoints.\n // Typically, Confluence API is at /wiki/rest/api if cloud, or /rest/api if server.\n // Let's assume baseUrl in config points to the root of the instance, e.g. https://site.atlassian.net/wiki\n\n return createHttpClient(config);\n}\n","import dotenv from 'dotenv';\nimport { ConfluenceConfig, GitlabConfig, JiraConfig } from './types.js';\nimport { logger } from './logger.js';\n\ndotenv.config();\n\n// 환경변수 조회 및 미설정 시 에러 발생\nfunction getEnvOrThrow(key: string, description: string): string {\n const value = process.env[key];\n if (!value) {\n const errorMsg = `환경변수 '${key}'가 설정되지 않았습니다. (${description})`;\n logger.error(errorMsg);\n throw new Error(errorMsg);\n }\n return value;\n}\n\n// Confluence 설정 로드 (PAT 인증 권장)\nexport function loadConfluenceConfig(): ConfluenceConfig & { mermaidMacroName: string, inlineCodeStyle: string } {\n const baseUrl = getEnvOrThrow('CONFLUENCE_BASE_URL', 'Confluence 기본 URL');\n // PAT 사용 시 username은 불필요 (Basic Auth 사용 시에만 필요)\n const username = process.env.CONFLUENCE_USERNAME;\n const token = getEnvOrThrow('CONFLUENCE_API_TOKEN', 'Confluence PAT 토큰');\n \n // Mermaid 매크로 이름 (기본값: mermaiddiagram)\n const mermaidMacroName = process.env.CONFLUENCE_MERMAID_MACRO_NAME || 'mermaiddiagram';\n\n // 인라인 코드 강조 스타일 (기본값: 붉은색 굵게)\n const inlineCodeStyle = process.env.CONFLUENCE_INLINE_CODE_STYLE || 'color: #d04437; font-weight: bold;';\n\n return {\n baseUrl,\n auth: {\n username,\n token,\n },\n mermaidMacroName,\n inlineCodeStyle,\n };\n}\n\n// AI 서비스 설정 로드\nexport function loadAIConfig() {\n return {\n openaiApiKey: process.env.OPENAI_API_KEY,\n anthropicApiKey: process.env.ANTHROPIC_API_KEY,\n defaultProvider: process.env.AI_PROVIDER || 'openai',\n defaultModel: process.env.AI_MODEL || 'gpt-4o',\n };\n}\n\n// JIRA 설정 로드 (PAT 인증 권장)\nexport function loadJiraConfig(): JiraConfig {\n const baseUrl = getEnvOrThrow('JIRA_BASE_URL', 'JIRA 기본 URL');\n // PAT 사용 시 username은 불필요\n const username = process.env.JIRA_USERNAME;\n const token = getEnvOrThrow('JIRA_API_TOKEN', 'JIRA PAT 토큰');\n\n return {\n baseUrl,\n auth: {\n username,\n token,\n },\n };\n}\n\n// GitLab 설정 로드\nexport function loadGitlabConfig(): GitlabConfig {\n const baseUrl = process.env.GITLAB_BASE_URL || 'https://gitlab.com';\n const token = getEnvOrThrow('GITLAB_PRIVATE_TOKEN', 'GitLab Private Token');\n\n return {\n baseUrl,\n auth: {\n token,\n },\n };\n}\n","import MarkdownIt from 'markdown-it';\nimport { loadConfluenceConfig } from '../../common/config.js';\n\nexport class MarkdownToStorageConverter {\n private md: MarkdownIt;\n private mermaidMacroName: string;\n private inlineCodeStyle: string;\n\n constructor() {\n const config = loadConfluenceConfig();\n this.mermaidMacroName = config.mermaidMacroName;\n this.inlineCodeStyle = config.inlineCodeStyle;\n\n this.md = new MarkdownIt({\n html: true,\n linkify: true,\n breaks: true,\n xhtmlOut: true // Confluence XML 파서와의 호환성을 위해 XHTML 출력 활성화\n });\n\n // Custom renderer for code blocks\n this.md.renderer.rules.fence = (tokens, idx) => {\n const token = tokens[idx];\n const code = token.content.trim();\n const lang = token.info.trim().toLowerCase();\n\n // Mermaid 처리 (기존 로직 유지)\n if (lang === 'mermaid') {\n return `<ac:structured-macro ac:name=\"${this.mermaidMacroName}\" ac:schema-version=\"1\">\n <ac:plain-text-body><![CDATA[${code}]]></ac:plain-text-body>\n</ac:structured-macro>`;\n }\n\n // PlantUML 처리 → plantuml 매크로로 변환\n if (lang === 'plantuml') {\n return `<ac:structured-macro ac:name=\"plantuml\" ac:schema-version=\"1\">\n <ac:parameter ac:name=\"atlassian-macro-output-type\">INLINE</ac:parameter>\n <ac:plain-text-body><![CDATA[${code}]]></ac:plain-text-body>\n</ac:structured-macro>`;\n }\n\n // 일반 코드 블록\n return `<ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\">\n <ac:parameter ac:name=\"language\">${lang || 'text'}</ac:parameter>\n <ac:plain-text-body><![CDATA[${code}]]></ac:plain-text-body>\n</ac:structured-macro>`;\n };\n\n // Custom renderer for images\n this.md.renderer.rules.image = (tokens, idx, options, env, self) => {\n const token = tokens[idx];\n const src = token.attrGet('src') || '';\n const alt = token.content || '';\n\n // Handle URL vs Local file\n const isExternal = src.startsWith('http://') || src.startsWith('https://');\n\n // 외부 URL이면 URL 매크로, 아니면 첨부파일 매크로\n const altAttr = alt ? ` ac:alt=\"${this.md.utils.escapeHtml(alt)}\"` : '';\n if (isExternal) {\n return `<ac:image${altAttr}><ri:url ri:value=\"${src}\" /></ac:image>`;\n } else {\n // filename can just be the basename of the src path\n const filename = src.split('/').pop() || src;\n return `<ac:image${altAttr}><ri:attachment ri:filename=\"${filename}\" /></ac:image>`;\n }\n };\n\n // Custom renderer for inline code\n this.md.renderer.rules.code_inline = (tokens, idx) => {\n const token = tokens[idx];\n const content = this.md.utils.escapeHtml(token.content);\n return `<code style=\"${this.inlineCodeStyle}\">${content}</code>`;\n };\n\n // Task List 처리 (markdown-it 플러그인 없이 수동 처리 예시 - 실제로는 플러그인 도입 권장)\n }\n\n convert(markdown: string): string {\n return this.md.render(markdown);\n }\n\n extractLocalImages(markdown: string): string[] {\n const tokens = this.md.parse(markdown, {});\n const localImages = new Set<string>();\n\n const walk = (tokens: any[]) => {\n for (const token of tokens) {\n if (token.type === 'image') {\n const src = token.attrGet('src') || '';\n if (!src.startsWith('http://') && !src.startsWith('https://')) {\n localImages.add(src);\n }\n }\n if (token.children) {\n walk(token.children);\n }\n }\n };\n\n walk(tokens);\n return Array.from(localImages);\n }\n}\n","import TurndownService from 'turndown';\nimport { gfm } from 'turndown-plugin-gfm';\nimport { JSDOM } from 'jsdom';\n\nexport class StorageToMarkdownConverter {\n private turndown: TurndownService;\n\n constructor() {\n this.turndown = new TurndownService({\n headingStyle: 'atx',\n hr: '---',\n bulletListMarker: '-',\n codeBlockStyle: 'fenced'\n });\n\n this.turndown.use(gfm);\n this.setupRules();\n }\n\n private setupRules() {\n // Table 변환 규칙 강화 (정렬 정보 보존)\n this.turndown.addRule('tables', {\n filter: ['table'],\n replacement: (content, node) => {\n const element = node as HTMLTableElement;\n const rows = Array.from(element.rows);\n if (rows.length === 0) return '';\n\n let mdTable = '\\n\\n';\n\n rows.forEach((row, index) => {\n const cells = Array.from(row.cells);\n const cellContents = cells.map(cell => {\n // 셀 내부의 개행은 공백으로 치환하여 테이블 깨짐 방지\n return this.turndown.turndown(cell.innerHTML).replace(/\\n/g, ' ').trim();\n });\n\n mdTable += `| ${cellContents.join(' | ')} |\\n`;\n\n // 헤더 행 구분선 (정렬 정보 포함)\n if (index === 0) {\n const separators = cells.map(cell => {\n const style = (cell as HTMLElement).getAttribute('style') || '';\n const align = style.match(/text-align:\\s*(\\w+)/i)?.[1]?.toLowerCase();\n if (align === 'center') return ':---:';\n if (align === 'right') return '---:';\n if (align === 'left') return ':---';\n return '---';\n });\n mdTable += `| ${separators.join(' | ')} |\\n`;\n }\n });\n\n return mdTable + '\\n';\n }\n });\n\n // Confluence 매크로 (변환된 div 태그) 처리\n this.turndown.addRule('confluenceMacro', {\n filter: (node) => {\n return node.nodeName === 'DIV' && node.getAttribute('data-macro-name-tag') !== null;\n },\n replacement: (content, node) => {\n const element = node as HTMLElement;\n const macroName = element.getAttribute('data-macro-name');\n\n if (macroName === 'code') {\n const lang = element.querySelector('[data-macro-param-name=\"language\"]')?.textContent || 'text';\n let body = element.querySelector('[data-macro-body]')?.textContent || '';\n // 임시 CDATA 태그 제거\n body = body.replace(/__CDATA_START__/g, '').replace(/__CDATA_END__/g, '');\n return `\\n\\`\\`\\`${lang}\\n${body.trim()}\\n\\`\\`\\`\\n`;\n }\n\n if (macroName === 'mermaid' || macroName === 'mermaiddiagram' || macroName === 'capable-mermaid' || macroName === 'mermaid-macro') {\n let body = element.querySelector('[data-macro-body]')?.textContent || '';\n // 임시 CDATA 태그 제거\n body = body.replace(/__CDATA_START__/g, '').replace(/__CDATA_END__/g, '');\n return `\\n\\`\\`\\`mermaid\\n${body.trim()}\\n\\`\\`\\`\\n`;\n }\n\n if (macroName === 'plantuml') {\n let body = element.querySelector('[data-macro-body]')?.textContent || '';\n body = body.replace(/__CDATA_START__/g, '').replace(/__CDATA_END__/g, '');\n return `\\n\\`\\`\\`plantuml\\n${body.trim()}\\n\\`\\`\\`\\n`;\n }\n\n return `\\n<!-- Macro: ${macroName} -->\\n`;\n }\n });\n }\n\n convert(storageHtml: string, imageUrlMap?: Map<string, string>): string {\n if (!storageHtml) return '';\n\n // 1. Confluence 전용 태그를 표준 HTML 태그로 치환 (JSDOM 호환성)\n // CDATA 섹션을 텍스트로 보존하기 위해 임시 치환\n let processedHtml = storageHtml\n .replace(/<!\\[CDATA\\[([\\s\\S]*?)\\]\\]>/gi, (match, p1) => {\n return `__CDATA_START__${p1}__CDATA_END__`;\n })\n .replace(/<ac:structured-macro\\s+ac:name=\"([^\"]*)\"/gi, '<div data-macro-name-tag data-macro-name=\"$1\"')\n .replace(/<\\/ac:structured-macro>/gi, '</div>')\n .replace(/<ac:parameter\\s+ac:name=\"([^\"]*)\"/gi, '<div data-macro-param-tag data-macro-param-name=\"$1\"')\n .replace(/<\\/ac:parameter>/gi, '</div>')\n .replace(/<ac:plain-text-body>/gi, '<pre data-macro-body>')\n .replace(/<\\/ac:plain-text-body>/gi, '</pre>')\n .replace(/<ac:image([^>]*)>[\\s\\S]*?<ri:attachment\\s+ri:filename=\"([^\"]*)\"\\s*\\/?>[\\s\\S]*?<\\/ac:image>/gi, (match, attrs, filename) => {\n const altMatch = attrs.match(/ac:alt=\"([^\"]*)\"/i);\n const alt = altMatch ? altMatch[1] : filename;\n return `<img src=\"${filename}\" alt=\"${alt}\" />`;\n })\n .replace(/<ac:image([^>]*)>[\\s\\S]*?<ri:url\\s+ri:value=\"([^\"]*)\"\\s*\\/?>[\\s\\S]*?<\\/ac:image>/gi, (match, attrs, url) => {\n const altMatch = attrs.match(/ac:alt=\"([^\"]*)\"/i);\n const alt = altMatch ? altMatch[1] : '';\n return `<img src=\"${url}\" alt=\"${alt}\" />`;\n });\n\n // 2. JSDOM 파싱\n const dom = new JSDOM(processedHtml);\n const document = dom.window.document;\n\n // 이미지 처리\n if (imageUrlMap && imageUrlMap.size > 0) {\n const images = document.querySelectorAll('img');\n images.forEach(img => {\n const src = img.getAttribute('src');\n if (src && imageUrlMap.has(src)) {\n img.setAttribute('src', imageUrlMap.get(src)!);\n }\n });\n }\n\n // 3. Turndown 변환\n let markdown = this.turndown.turndown(document.body.innerHTML).trim();\n\n // 4. 헤딩 내 숫자 뒤 점 이스케이프 제거 (예: `## 1\\.` → `## 1.`)\n markdown = markdown.replace(/^(#{1,6}\\s.*?)\\\\\\./gm, '$1.');\n\n return markdown + '\\n';\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { JiraIssueResponse, CreateIssueParams, UpdateIssueParams } from '../types.js';\n\nexport class JiraIssueApi {\n constructor(private client: AxiosInstance) {}\n\n async getIssue(issueKey: string, fields?: string[], expand?: string[]): Promise<JiraIssueResponse> {\n const params: Record<string, string> = {};\n if (fields && fields.length > 0) {\n params.fields = fields.join(',');\n }\n if (expand && expand.length > 0) {\n params.expand = expand.join(',');\n }\n const response = await this.client.get(`/rest/api/2/issue/${issueKey}`, { params });\n return response.data;\n }\n\n async createIssue(params: CreateIssueParams): Promise<JiraIssueResponse> {\n const fields: Record<string, unknown> = {\n project: { key: params.projectKey },\n summary: params.summary,\n issuetype: { name: params.issueType },\n };\n\n if (params.description) fields.description = params.description;\n if (params.assignee) fields.assignee = { name: params.assignee };\n if (params.priority) fields.priority = { name: params.priority };\n if (params.labels) fields.labels = params.labels;\n if (params.components) {\n fields.components = params.components.map((name) => ({ name }));\n }\n if (params.parentKey) {\n fields.parent = { key: params.parentKey };\n }\n if (params.customFields) {\n Object.assign(fields, params.customFields);\n }\n\n const response = await this.client.post('/rest/api/2/issue', { fields });\n return response.data;\n }\n\n async updateIssue(issueKey: string, params: UpdateIssueParams): Promise<void> {\n const fields: Record<string, unknown> = {};\n\n if (params.summary) fields.summary = params.summary;\n if (params.description !== undefined) fields.description = params.description;\n if (params.assignee !== undefined) fields.assignee = params.assignee ? { name: params.assignee } : null;\n if (params.priority) fields.priority = { name: params.priority };\n if (params.labels) fields.labels = params.labels;\n if (params.components) {\n fields.components = params.components.map((name) => ({ name }));\n }\n if (params.customFields) {\n Object.assign(fields, params.customFields);\n }\n\n await this.client.put(`/rest/api/2/issue/${issueKey}`, { fields });\n }\n\n async deleteIssue(issueKey: string, deleteSubtasks = false): Promise<void> {\n await this.client.delete(`/rest/api/2/issue/${issueKey}`, {\n params: { deleteSubtasks },\n });\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { JiraSearchResponse } from '../types.js';\n\nexport class JiraSearchApi {\n constructor(private client: AxiosInstance) {}\n\n async searchByJql(\n jql: string,\n startAt = 0,\n maxResults = 50,\n fields?: string[],\n ): Promise<JiraSearchResponse> {\n const params: Record<string, unknown> = {\n jql,\n startAt,\n maxResults,\n };\n if (fields && fields.length > 0) {\n params.fields = fields.join(',');\n }\n const response = await this.client.get('/rest/api/2/search', { params });\n return response.data;\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { JiraConfig } from '../../common/types.js';\nimport { createHttpClient } from '../../common/http-client.js';\n\nexport function createJiraClient(config: JiraConfig): AxiosInstance {\n return createHttpClient(config);\n}\n","import { AxiosInstance } from 'axios';\nimport { GitlabMergeRequest, GitlabNote } from '../types.js';\n\nexport class GitlabMergeRequestApi {\n constructor(private client: AxiosInstance) {}\n\n async getMergeRequests(\n projectId: number,\n params?: { state?: string; scope?: string; labels?: string; perPage?: number },\n ): Promise<GitlabMergeRequest[]> {\n const response = await this.client.get(`/projects/${projectId}/merge_requests`, {\n params: {\n state: params?.state || 'opened',\n scope: params?.scope,\n labels: params?.labels,\n per_page: params?.perPage || 20,\n },\n });\n return response.data;\n }\n\n async getMergeRequest(projectId: number, mrIid: number): Promise<GitlabMergeRequest> {\n const response = await this.client.get(\n `/projects/${projectId}/merge_requests/${mrIid}`,\n );\n return response.data;\n }\n\n async getMergeRequestChanges(projectId: number, mrIid: number): Promise<GitlabMergeRequest> {\n const response = await this.client.get(\n `/projects/${projectId}/merge_requests/${mrIid}/changes`,\n );\n return response.data;\n }\n\n async createMergeRequest(\n projectId: number,\n data: {\n source_branch: string;\n target_branch: string;\n title: string;\n description?: string;\n assignee_id?: number;\n reviewer_ids?: number[];\n labels?: string;\n },\n ): Promise<GitlabMergeRequest> {\n const response = await this.client.post(`/projects/${projectId}/merge_requests`, data);\n return response.data;\n }\n\n async updateMergeRequest(\n projectId: number,\n mrIid: number,\n data: {\n title?: string;\n description?: string;\n assignee_id?: number;\n reviewer_ids?: number[];\n labels?: string;\n state_event?: 'close' | 'reopen';\n },\n ): Promise<GitlabMergeRequest> {\n const response = await this.client.put(\n `/projects/${projectId}/merge_requests/${mrIid}`,\n data,\n );\n return response.data;\n }\n\n async mergeMergeRequest(\n projectId: number,\n mrIid: number,\n params?: {\n merge_commit_message?: string;\n squash?: boolean;\n should_remove_source_branch?: boolean;\n },\n ): Promise<GitlabMergeRequest> {\n const response = await this.client.put(\n `/projects/${projectId}/merge_requests/${mrIid}/merge`,\n params,\n );\n return response.data;\n }\n\n async getMergeRequestNotes(projectId: number, mrIid: number): Promise<GitlabNote[]> {\n const response = await this.client.get(\n `/projects/${projectId}/merge_requests/${mrIid}/notes`,\n );\n return response.data;\n }\n\n async addMergeRequestNote(\n projectId: number,\n mrIid: number,\n body: string,\n ): Promise<GitlabNote> {\n const response = await this.client.post(\n `/projects/${projectId}/merge_requests/${mrIid}/notes`,\n { body },\n );\n return response.data;\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { GitlabPipeline, GitlabJob } from '../types.js';\n\nexport class GitlabPipelineApi {\n constructor(private client: AxiosInstance) {}\n\n async getPipelines(\n projectId: number,\n params?: { status?: string; ref?: string; perPage?: number },\n ): Promise<GitlabPipeline[]> {\n const response = await this.client.get(`/projects/${projectId}/pipelines`, {\n params: {\n status: params?.status,\n ref: params?.ref,\n per_page: params?.perPage || 20,\n },\n });\n return response.data;\n }\n\n async getPipeline(projectId: number, pipelineId: number): Promise<GitlabPipeline> {\n const response = await this.client.get(\n `/projects/${projectId}/pipelines/${pipelineId}`,\n );\n return response.data;\n }\n\n async getPipelineJobs(projectId: number, pipelineId: number): Promise<GitlabJob[]> {\n const response = await this.client.get(\n `/projects/${projectId}/pipelines/${pipelineId}/jobs`,\n );\n return response.data;\n }\n\n async getMergeRequestPipelines(\n projectId: number,\n mrIid: number,\n ): Promise<GitlabPipeline[]> {\n const response = await this.client.get(\n `/projects/${projectId}/merge_requests/${mrIid}/pipelines`,\n );\n return response.data;\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { GitlabConfig } from '../../common/types.js';\nimport { createHttpClient } from '../../common/http-client.js';\n\nexport function createGitlabClient(config: GitlabConfig): AxiosInstance {\n const client = createHttpClient({\n ...config,\n baseUrl: `${config.baseUrl}/api/v4`,\n });\n\n // GitLab Self-hosted는 PRIVATE-TOKEN 헤더 사용\n client.defaults.headers.common['PRIVATE-TOKEN'] = config.auth.token!;\n\n return client;\n}\n"],"mappings":";;;;;AAIO,IAAM,uBAAN,MAA2B;AAAA,EAC9B,YAAoB,QAAuB;AAAvB;AAAA,EAAyB;AAAA,EAE7C,MAAM,QAAQ,IAAY,QAAoD;AAC1E,UAAM,cAAc,SAAS,OAAO,KAAK,GAAG,IAAI;AAChD,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,qBAAqB,EAAE,IAAI;AAAA,MAC9D,QAAQ,EAAE,QAAQ,YAAY;AAAA,IAClC,CAAC;AACD,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,eAAe,UAAkB,OAAe,QAA2D;AAC7G,UAAM,cAAc,SAAS,OAAO,KAAK,GAAG,IAAI;AAChD,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,qBAAqB;AAAA,MACxD,QAAQ;AAAA,QACJ;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,OAAO;AAAA,MACX;AAAA,IACJ,CAAC;AAED,QAAI,SAAS,KAAK,WAAW,SAAS,KAAK,QAAQ,SAAS,GAAG;AAC3D,aAAO,SAAS,KAAK,QAAQ,CAAC;AAAA,IAClC;AACA,WAAO;AAAA,EACX;AAAA,EAEA,MAAM,WAAW,QAA2D;AACxE,UAAM,OAAY;AAAA,MACd,MAAM;AAAA,MACN,OAAO,OAAO;AAAA,MACd,OAAO,EAAE,KAAK,OAAO,SAAS;AAAA,MAC9B,MAAM;AAAA,QACF,SAAS;AAAA,UACL,OAAO,OAAO;AAAA,UACd,gBAAgB;AAAA,QACpB;AAAA,MACJ;AAAA,IACJ;AAEA,QAAI,OAAO,UAAU;AACjB,WAAK,YAAY,CAAC,EAAE,IAAI,OAAO,SAAS,CAAC;AAAA,IAC7C;AAEA,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,qBAAqB,IAAI;AAGjE,QAAI,OAAO,UAAU,OAAO,OAAO,SAAS,GAAG;AAC3C,YAAM,KAAK,UAAU,SAAS,KAAK,IAAI,OAAO,MAAM;AAAA,IAIxD;AAEA,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,WAAW,QAA2D;AACxE,UAAM,OAAO;AAAA,MACT,SAAS,EAAE,QAAQ,OAAO,UAAU,EAAE;AAAA,MACtC,OAAO,OAAO;AAAA,MACd,MAAM;AAAA,MACN,MAAM;AAAA,QACF,SAAS;AAAA,UACL,OAAO,OAAO;AAAA,UACd,gBAAgB;AAAA,QACpB;AAAA,MACJ;AAAA,IACJ;AAEA,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,qBAAqB,OAAO,EAAE,IAAI,IAAI;AAC7E,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,WAAW,IAA2B;AACxC,UAAM,KAAK,OAAO,OAAO,qBAAqB,EAAE,EAAE;AAAA,EACtD;AAAA,EAEA,MAAM,cAAc,IAAY,QAAQ,GAAG,QAAQ,IAAuC;AACtF,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,qBAAqB,EAAE,eAAe;AAAA,MACzE,QAAQ,EAAE,OAAO,MAAM;AAAA,IAC3B,CAAC;AACD,WAAO,SAAS,KAAK;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,UAAU,IAAY,QAAiC;AACjE,UAAM,OAAO,OAAO,IAAI,WAAS,EAAE,QAAQ,UAAU,KAAK,EAAE;AAC5D,UAAM,KAAK,OAAO,KAAK,qBAAqB,EAAE,UAAU,IAAI;AAAA,EAChE;AAAA;AAAA,EAGA,MAAM,iBAAiB,QAAgB,UAAkB,aAAqB,aAA6D;AACvI,UAAM,YAAY,MAAM,OAAO,WAAW,GAAG;AAG7C,UAAM,sBAAsB,MAAM,KAAK,eAAe,QAAQ,QAAQ;AACtE,UAAM,WAAW,oBAAoB,KAAK,OAAK,EAAE,UAAU,QAAQ;AAEnE,UAAM,OAAO,IAAI,SAAS;AAC1B,SAAK,OAAO,QAAQ,aAAa;AAAA,MAC7B;AAAA,MACA,aAAa,eAAe;AAAA,IAChC,CAAC;AAED,UAAM,UAAU;AAAA,MACZ,GAAG,KAAK,WAAW;AAAA,MACnB,qBAAqB;AAAA,MACrB,UAAU;AAAA,IACd;AAEA,QAAI;AACJ,QAAI,UAAU;AAEV,iBAAW,MAAM,KAAK,OAAO;AAAA,QACzB,qBAAqB,MAAM,qBAAqB,SAAS,EAAE;AAAA,QAC3D;AAAA,QACA,EAAE,QAAQ;AAAA,MACd;AAAA,IACJ,OAAO;AAEH,iBAAW,MAAM,KAAK,OAAO;AAAA,QACzB,qBAAqB,MAAM;AAAA,QAC3B;AAAA,QACA,EAAE,QAAQ;AAAA,MACd;AAAA,IACJ;AAGA,QAAI,SAAS,QAAQ,SAAS,KAAK,WAAW,SAAS,KAAK,QAAQ,SAAS,GAAG;AAC5E,aAAO,SAAS,KAAK,QAAQ,CAAC;AAAA,IAClC;AACA,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,eAAe,QAAgB,UAA4D;AAC7F,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,qBAAqB,MAAM,qBAAqB;AAAA,MACnF,QAAQ;AAAA,QACJ;AAAA,QACA,QAAQ;AAAA,MACZ;AAAA,IACJ,CAAC;AACD,WAAO,SAAS,KAAK;AAAA,EACzB;AAAA,EAEA,MAAM,mBAAmB,aAAsC;AAC3D,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,aAAa;AAAA,MAChD,cAAc;AAAA,IAClB,CAAC;AACD,WAAO,OAAO,KAAK,SAAS,IAAI;AAAA,EACpC;AACJ;;;AC/JO,IAAM,qBAAN,MAAyB;AAAA,EAC5B,YAAoB,QAAuB;AAAvB;AAAA,EAAyB;AAAA,EAE7C,MAAM,UAAU,OAAe,UAAU,QAAQ,GAAG,QAAQ,IAAwC;AAChG,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,mBAAmB;AAAA,MACtD,QAAQ,EAAE,MAAM,OAAO,MAAM;AAAA,IACjC,CAAC;AACD,WAAO,SAAS,KAAK;AAAA,EACzB;AAAA,EAEA,MAAM,SAAS,UAAoD;AAC/D,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,mBAAmB,QAAQ,EAAE;AACpE,WAAO,SAAS;AAAA,EACpB;AACJ;;;ACdO,IAAM,sBAAN,MAA0B;AAAA,EAC7B,YAAoB,QAAuB;AAAvB;AAAA,EAAyB;AAAA,EAE7C,MAAM,YAAY,KAAa,QAAQ,GAAG,QAAQ,IAAI,QAAsD;AACxG,UAAM,cAAc,SAAS,OAAO,KAAK,GAAG,IAAI;AAChD,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,4BAA4B;AAAA,MAC/D,QAAQ;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MACZ;AAAA,IACJ,CAAC;AAED,WAAO,SAAS;AAAA,EACpB;AACJ;;;ACnBA,OAAO,WAA6E;;;ACC7E,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACtC,YAAY,SAAiB;AACzB,UAAM,OAAO;AACb,SAAK,OAAO,KAAK,YAAY;AAC7B,UAAM,kBAAkB,MAAM,KAAK,WAAW;AAAA,EAClD;AACJ;AAGO,IAAM,WAAN,cAAuB,eAAe;AAAA,EACzC,YACW,YACP,SACO,MACT;AACE,UAAM,kCAAc,UAAU,MAAM,OAAO,EAAE;AAJtC;AAEA;AAAA,EAGX;AACJ;AAGO,IAAM,YAAN,cAAwB,eAAe;AAAA,EAC1C,YAAY,UAAkB,2DAAc;AACxC,UAAM,OAAO;AAAA,EACjB;AACJ;AAGO,IAAM,gBAAN,cAA4B,eAAe;AAAA,EAC9C,YAAY,UAAkB,IAAY;AACtC,UAAM,GAAG,QAAQ,KAAK,EAAE,sDAAc;AAAA,EAC1C;AACJ;AAGO,IAAM,gBAAN,cAA4B,eAAe;AAAA,EAC9C,YAAY,SAAiB;AACzB,UAAM,OAAO;AAAA,EACjB;AACJ;;;ADlCO,SAAS,iBAAiB,QAAsC;AACnE,QAAM,SAAS,MAAM,OAAO;AAAA,IACxB,SAAS,OAAO;AAAA,IAChB,SAAS;AAAA;AAAA,IACT,SAAS;AAAA,MACL,gBAAgB;AAAA,IACpB;AAAA,EACJ,CAAC;AAGD,SAAO,aAAa,QAAQ,IAAI,CAAC,cAAc;AAE3C,QAAI,OAAO,KAAK,SAAS,CAAC,UAAU,QAAQ,iBAAiB,CAAC,UAAU,QAAQ,eAAe,GAAG;AAE9F,gBAAU,QAAQ,gBAAgB,UAAU,OAAO,KAAK,KAAK;AAAA,IACjE,WAES,OAAO,KAAK,YAAY,OAAO,KAAK,SAAS,CAAC,UAAU,QAAQ,eAAe;AACpF,YAAM,QAAQ,OAAO,KAAK,GAAG,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,EAAE,EAAE,SAAS,QAAQ;AAC3F,gBAAU,QAAQ,gBAAgB,SAAS,KAAK;AAAA,IACpD;AAEA,WAAO,MAAM,kBAAkB,UAAU,QAAQ,YAAY,CAAC,IAAI,UAAU,GAAG,IAAI;AAAA,MAC/E,SAAS,UAAU;AAAA,MACnB,QAAQ,UAAU;AAAA,MAClB,MAAM,UAAU;AAAA,IACpB,CAAC;AAED,WAAO;AAAA,EACX,CAAC;AAGD,SAAO,aAAa,SAAS;AAAA,IACzB,CAAC,aAA4B;AACzB,aAAO,MAAM,mBAAmB,SAAS,MAAM,IAAI,SAAS,OAAO,QAAQ,YAAY,CAAC,IAAI,SAAS,OAAO,GAAG,IAAI;AAAA,QAC/G,SAAS,SAAS;AAAA,QAClB,MAAM,SAAS;AAAA,MACnB,CAAC;AACD,aAAO;AAAA,IACX;AAAA,IACA,CAAC,UAAsB;AACnB,UAAI,MAAM,UAAU;AAChB,cAAM,SAAS,MAAM,SAAS;AAC9B,cAAM,SAAS,MAAM,QAAQ,QAAQ,YAAY;AACjD,cAAM,MAAM,MAAM,QAAQ;AAC1B,cAAM,UAAW,MAAM,SAAS,MAAc,WAAW,MAAM;AAE/D,eAAO,MAAM,gBAAgB,MAAM,IAAI,MAAM,IAAI,GAAG,IAAI;AAAA,UACpD;AAAA,UACA,cAAc,MAAM,SAAS;AAAA,UAC7B,gBAAgB,MAAM,QAAQ;AAAA,QAClC,CAAC;AAGD,YAAI,WAAW,OAAO,WAAW,KAAK;AAClC,gBAAM,IAAI,UAAU,8BAAU,OAAO,EAAE;AAAA,QAC3C;AACA,YAAI,WAAW,KAAK;AAChB,gBAAM,IAAI,cAAc,sBAAO,OAAO,SAAS;AAAA,QACnD;AACA,YAAI,WAAW,KAAK;AAChB,gBAAM,IAAI,cAAc,8BAAU,OAAO,EAAE;AAAA,QAC/C;AAEA,cAAM,IAAI,SAAS,QAAQ,SAAS,MAAM,SAAS,IAAI;AAAA,MAC3D,WAAW,MAAM,SAAS;AACtB,eAAO,MAAM,uBAAuB,MAAM,OAAO,EAAE;AACnD,cAAM,IAAI,SAAS,GAAG,+EAAmB,MAAM,OAAO,EAAE;AAAA,MAC5D,OAAO;AACH,eAAO,MAAM,yBAAyB,MAAM,OAAO,EAAE;AACrD,cAAM,IAAI,SAAS,GAAG,+DAAkB,MAAM,OAAO,EAAE;AAAA,MAC3D;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO;AACX;;;AE7EO,SAAS,uBAAuB,QAAyC;AAW5E,SAAO,iBAAiB,MAAM;AAClC;;;AChBA,OAAO,YAAY;AAInB,OAAO,OAAO;AAGd,SAAS,cAAc,KAAa,aAA6B;AAC7D,QAAM,QAAQ,QAAQ,IAAI,GAAG;AAC7B,MAAI,CAAC,OAAO;AACR,UAAM,WAAW,6BAAS,GAAG,qEAAmB,WAAW;AAC3D,WAAO,MAAM,QAAQ;AACrB,UAAM,IAAI,MAAM,QAAQ;AAAA,EAC5B;AACA,SAAO;AACX;AAGO,SAAS,uBAAiG;AAC7G,QAAM,UAAU,cAAc,uBAAuB,6BAAmB;AAExE,QAAM,WAAW,QAAQ,IAAI;AAC7B,QAAM,QAAQ,cAAc,wBAAwB,6BAAmB;AAGvE,QAAM,mBAAmB,QAAQ,IAAI,iCAAiC;AAGtE,QAAM,kBAAkB,QAAQ,IAAI,gCAAgC;AAEpE,SAAO;AAAA,IACH;AAAA,IACA,MAAM;AAAA,MACF;AAAA,MACA;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AACJ;AAGO,SAAS,eAAe;AAC3B,SAAO;AAAA,IACH,cAAc,QAAQ,IAAI;AAAA,IAC1B,iBAAiB,QAAQ,IAAI;AAAA,IAC7B,iBAAiB,QAAQ,IAAI,eAAe;AAAA,IAC5C,cAAc,QAAQ,IAAI,YAAY;AAAA,EAC1C;AACJ;AAGO,SAAS,iBAA6B;AACzC,QAAM,UAAU,cAAc,iBAAiB,uBAAa;AAE5D,QAAM,WAAW,QAAQ,IAAI;AAC7B,QAAM,QAAQ,cAAc,kBAAkB,uBAAa;AAE3D,SAAO;AAAA,IACH;AAAA,IACA,MAAM;AAAA,MACF;AAAA,MACA;AAAA,IACJ;AAAA,EACJ;AACJ;AAGO,SAAS,mBAAiC;AAC7C,QAAM,UAAU,QAAQ,IAAI,mBAAmB;AAC/C,QAAM,QAAQ,cAAc,wBAAwB,sBAAsB;AAE1E,SAAO;AAAA,IACH;AAAA,IACA,MAAM;AAAA,MACF;AAAA,IACJ;AAAA,EACJ;AACJ;;;AC9EA,OAAO,gBAAgB;AAGhB,IAAM,6BAAN,MAAiC;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EAER,cAAc;AACV,UAAM,SAAS,qBAAqB;AACpC,SAAK,mBAAmB,OAAO;AAC/B,SAAK,kBAAkB,OAAO;AAE9B,SAAK,KAAK,IAAI,WAAW;AAAA,MACrB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,UAAU;AAAA;AAAA,IACd,CAAC;AAGD,SAAK,GAAG,SAAS,MAAM,QAAQ,CAAC,QAAQ,QAAQ;AAC5C,YAAM,QAAQ,OAAO,GAAG;AACxB,YAAM,OAAO,MAAM,QAAQ,KAAK;AAChC,YAAM,OAAO,MAAM,KAAK,KAAK,EAAE,YAAY;AAG3C,UAAI,SAAS,WAAW;AACpB,eAAO,iCAAiC,KAAK,gBAAgB;AAAA,iCAC5C,IAAI;AAAA;AAAA,MAEzB;AAGA,UAAI,SAAS,YAAY;AACrB,eAAO;AAAA;AAAA,iCAEU,IAAI;AAAA;AAAA,MAEzB;AAGA,aAAO;AAAA,qCACkB,QAAQ,MAAM;AAAA,iCAClB,IAAI;AAAA;AAAA,IAE7B;AAGA,SAAK,GAAG,SAAS,MAAM,QAAQ,CAAC,QAAQ,KAAK,SAAS,KAAK,SAAS;AAChE,YAAM,QAAQ,OAAO,GAAG;AACxB,YAAM,MAAM,MAAM,QAAQ,KAAK,KAAK;AACpC,YAAM,MAAM,MAAM,WAAW;AAG7B,YAAM,aAAa,IAAI,WAAW,SAAS,KAAK,IAAI,WAAW,UAAU;AAGzE,YAAM,UAAU,MAAM,YAAY,KAAK,GAAG,MAAM,WAAW,GAAG,CAAC,MAAM;AACrE,UAAI,YAAY;AACZ,eAAO,YAAY,OAAO,sBAAsB,GAAG;AAAA,MACvD,OAAO;AAEH,cAAM,WAAW,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK;AACzC,eAAO,YAAY,OAAO,gCAAgC,QAAQ;AAAA,MACtE;AAAA,IACJ;AAGA,SAAK,GAAG,SAAS,MAAM,cAAc,CAAC,QAAQ,QAAQ;AAClD,YAAM,QAAQ,OAAO,GAAG;AACxB,YAAM,UAAU,KAAK,GAAG,MAAM,WAAW,MAAM,OAAO;AACtD,aAAO,gBAAgB,KAAK,eAAe,KAAK,OAAO;AAAA,IAC3D;AAAA,EAGJ;AAAA,EAEA,QAAQ,UAA0B;AAC9B,WAAO,KAAK,GAAG,OAAO,QAAQ;AAAA,EAClC;AAAA,EAEA,mBAAmB,UAA4B;AAC3C,UAAM,SAAS,KAAK,GAAG,MAAM,UAAU,CAAC,CAAC;AACzC,UAAM,cAAc,oBAAI,IAAY;AAEpC,UAAM,OAAO,CAACA,YAAkB;AAC5B,iBAAW,SAASA,SAAQ;AACxB,YAAI,MAAM,SAAS,SAAS;AACxB,gBAAM,MAAM,MAAM,QAAQ,KAAK,KAAK;AACpC,cAAI,CAAC,IAAI,WAAW,SAAS,KAAK,CAAC,IAAI,WAAW,UAAU,GAAG;AAC3D,wBAAY,IAAI,GAAG;AAAA,UACvB;AAAA,QACJ;AACA,YAAI,MAAM,UAAU;AAChB,eAAK,MAAM,QAAQ;AAAA,QACvB;AAAA,MACJ;AAAA,IACJ;AAEA,SAAK,MAAM;AACX,WAAO,MAAM,KAAK,WAAW;AAAA,EACjC;AACJ;;;ACvGA,OAAO,qBAAqB;AAC5B,SAAS,WAAW;AACpB,SAAS,aAAa;AAEf,IAAM,6BAAN,MAAiC;AAAA,EAC5B;AAAA,EAER,cAAc;AACV,SAAK,WAAW,IAAI,gBAAgB;AAAA,MAChC,cAAc;AAAA,MACd,IAAI;AAAA,MACJ,kBAAkB;AAAA,MAClB,gBAAgB;AAAA,IACpB,CAAC;AAED,SAAK,SAAS,IAAI,GAAG;AACrB,SAAK,WAAW;AAAA,EACpB;AAAA,EAEQ,aAAa;AAEjB,SAAK,SAAS,QAAQ,UAAU;AAAA,MAC5B,QAAQ,CAAC,OAAO;AAAA,MAChB,aAAa,CAAC,SAAS,SAAS;AAC5B,cAAM,UAAU;AAChB,cAAM,OAAO,MAAM,KAAK,QAAQ,IAAI;AACpC,YAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,YAAI,UAAU;AAEd,aAAK,QAAQ,CAAC,KAAK,UAAU;AACzB,gBAAM,QAAQ,MAAM,KAAK,IAAI,KAAK;AAClC,gBAAM,eAAe,MAAM,IAAI,UAAQ;AAEnC,mBAAO,KAAK,SAAS,SAAS,KAAK,SAAS,EAAE,QAAQ,OAAO,GAAG,EAAE,KAAK;AAAA,UAC3E,CAAC;AAED,qBAAW,KAAK,aAAa,KAAK,KAAK,CAAC;AAAA;AAGxC,cAAI,UAAU,GAAG;AACb,kBAAM,aAAa,MAAM,IAAI,UAAQ;AACjC,oBAAM,QAAS,KAAqB,aAAa,OAAO,KAAK;AAC7D,oBAAM,QAAQ,MAAM,MAAM,sBAAsB,IAAI,CAAC,GAAG,YAAY;AACpE,kBAAI,UAAU,SAAU,QAAO;AAC/B,kBAAI,UAAU,QAAS,QAAO;AAC9B,kBAAI,UAAU,OAAQ,QAAO;AAC7B,qBAAO;AAAA,YACX,CAAC;AACD,uBAAW,KAAK,WAAW,KAAK,KAAK,CAAC;AAAA;AAAA,UAC1C;AAAA,QACJ,CAAC;AAED,eAAO,UAAU;AAAA,MACrB;AAAA,IACJ,CAAC;AAGD,SAAK,SAAS,QAAQ,mBAAmB;AAAA,MACrC,QAAQ,CAAC,SAAS;AACd,eAAO,KAAK,aAAa,SAAS,KAAK,aAAa,qBAAqB,MAAM;AAAA,MACnF;AAAA,MACA,aAAa,CAAC,SAAS,SAAS;AAC5B,cAAM,UAAU;AAChB,cAAM,YAAY,QAAQ,aAAa,iBAAiB;AAExD,YAAI,cAAc,QAAQ;AACtB,gBAAM,OAAO,QAAQ,cAAc,oCAAoC,GAAG,eAAe;AACzF,cAAI,OAAO,QAAQ,cAAc,mBAAmB,GAAG,eAAe;AAEtE,iBAAO,KAAK,QAAQ,oBAAoB,EAAE,EAAE,QAAQ,kBAAkB,EAAE;AACxE,iBAAO;AAAA,QAAW,IAAI;AAAA,EAAK,KAAK,KAAK,CAAC;AAAA;AAAA;AAAA,QAC1C;AAEA,YAAI,cAAc,aAAa,cAAc,oBAAoB,cAAc,qBAAqB,cAAc,iBAAiB;AAC/H,cAAI,OAAO,QAAQ,cAAc,mBAAmB,GAAG,eAAe;AAEtE,iBAAO,KAAK,QAAQ,oBAAoB,EAAE,EAAE,QAAQ,kBAAkB,EAAE;AACxE,iBAAO;AAAA;AAAA,EAAoB,KAAK,KAAK,CAAC;AAAA;AAAA;AAAA,QAC1C;AAEA,YAAI,cAAc,YAAY;AAC1B,cAAI,OAAO,QAAQ,cAAc,mBAAmB,GAAG,eAAe;AACtE,iBAAO,KAAK,QAAQ,oBAAoB,EAAE,EAAE,QAAQ,kBAAkB,EAAE;AACxE,iBAAO;AAAA;AAAA,EAAqB,KAAK,KAAK,CAAC;AAAA;AAAA;AAAA,QAC3C;AAEA,eAAO;AAAA,cAAiB,SAAS;AAAA;AAAA,MACrC;AAAA,IACJ,CAAC;AAAA,EACL;AAAA,EAEA,QAAQ,aAAqB,aAA2C;AACpE,QAAI,CAAC,YAAa,QAAO;AAIzB,QAAI,gBAAgB,YACf,QAAQ,gCAAgC,CAAC,OAAO,OAAO;AACpD,aAAO,kBAAkB,EAAE;AAAA,IAC/B,CAAC,EACA,QAAQ,8CAA8C,+CAA+C,EACrG,QAAQ,6BAA6B,QAAQ,EAC7C,QAAQ,uCAAuC,sDAAsD,EACrG,QAAQ,sBAAsB,QAAQ,EACtC,QAAQ,0BAA0B,uBAAuB,EACzD,QAAQ,4BAA4B,QAAQ,EAC5C,QAAQ,gGAAgG,CAAC,OAAO,OAAO,aAAa;AACjI,YAAM,WAAW,MAAM,MAAM,mBAAmB;AAChD,YAAM,MAAM,WAAW,SAAS,CAAC,IAAI;AACrC,aAAO,aAAa,QAAQ,UAAU,GAAG;AAAA,IAC7C,CAAC,EACA,QAAQ,sFAAsF,CAAC,OAAO,OAAO,QAAQ;AAClH,YAAM,WAAW,MAAM,MAAM,mBAAmB;AAChD,YAAM,MAAM,WAAW,SAAS,CAAC,IAAI;AACrC,aAAO,aAAa,GAAG,UAAU,GAAG;AAAA,IACxC,CAAC;AAGL,UAAM,MAAM,IAAI,MAAM,aAAa;AACnC,UAAM,WAAW,IAAI,OAAO;AAG5B,QAAI,eAAe,YAAY,OAAO,GAAG;AACrC,YAAM,SAAS,SAAS,iBAAiB,KAAK;AAC9C,aAAO,QAAQ,SAAO;AAClB,cAAM,MAAM,IAAI,aAAa,KAAK;AAClC,YAAI,OAAO,YAAY,IAAI,GAAG,GAAG;AAC7B,cAAI,aAAa,OAAO,YAAY,IAAI,GAAG,CAAE;AAAA,QACjD;AAAA,MACJ,CAAC;AAAA,IACL;AAGA,QAAI,WAAW,KAAK,SAAS,SAAS,SAAS,KAAK,SAAS,EAAE,KAAK;AAGpE,eAAW,SAAS,QAAQ,wBAAwB,KAAK;AAEzD,WAAO,WAAW;AAAA,EACtB;AACJ;;;AC1IO,IAAM,eAAN,MAAmB;AAAA,EACtB,YAAoB,QAAuB;AAAvB;AAAA,EAAwB;AAAA,EAE5C,MAAM,SAAS,UAAkB,QAAmB,QAA+C;AAC/F,UAAM,SAAiC,CAAC;AACxC,QAAI,UAAU,OAAO,SAAS,GAAG;AAC7B,aAAO,SAAS,OAAO,KAAK,GAAG;AAAA,IACnC;AACA,QAAI,UAAU,OAAO,SAAS,GAAG;AAC7B,aAAO,SAAS,OAAO,KAAK,GAAG;AAAA,IACnC;AACA,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,qBAAqB,QAAQ,IAAI,EAAE,OAAO,CAAC;AAClF,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,YAAY,QAAuD;AACrE,UAAM,SAAkC;AAAA,MACpC,SAAS,EAAE,KAAK,OAAO,WAAW;AAAA,MAClC,SAAS,OAAO;AAAA,MAChB,WAAW,EAAE,MAAM,OAAO,UAAU;AAAA,IACxC;AAEA,QAAI,OAAO,YAAa,QAAO,cAAc,OAAO;AACpD,QAAI,OAAO,SAAU,QAAO,WAAW,EAAE,MAAM,OAAO,SAAS;AAC/D,QAAI,OAAO,SAAU,QAAO,WAAW,EAAE,MAAM,OAAO,SAAS;AAC/D,QAAI,OAAO,OAAQ,QAAO,SAAS,OAAO;AAC1C,QAAI,OAAO,YAAY;AACnB,aAAO,aAAa,OAAO,WAAW,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE;AAAA,IAClE;AACA,QAAI,OAAO,WAAW;AAClB,aAAO,SAAS,EAAE,KAAK,OAAO,UAAU;AAAA,IAC5C;AACA,QAAI,OAAO,cAAc;AACrB,aAAO,OAAO,QAAQ,OAAO,YAAY;AAAA,IAC7C;AAEA,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,qBAAqB,EAAE,OAAO,CAAC;AACvE,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,YAAY,UAAkB,QAA0C;AAC1E,UAAM,SAAkC,CAAC;AAEzC,QAAI,OAAO,QAAS,QAAO,UAAU,OAAO;AAC5C,QAAI,OAAO,gBAAgB,OAAW,QAAO,cAAc,OAAO;AAClE,QAAI,OAAO,aAAa,OAAW,QAAO,WAAW,OAAO,WAAW,EAAE,MAAM,OAAO,SAAS,IAAI;AACnG,QAAI,OAAO,SAAU,QAAO,WAAW,EAAE,MAAM,OAAO,SAAS;AAC/D,QAAI,OAAO,OAAQ,QAAO,SAAS,OAAO;AAC1C,QAAI,OAAO,YAAY;AACnB,aAAO,aAAa,OAAO,WAAW,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE;AAAA,IAClE;AACA,QAAI,OAAO,cAAc;AACrB,aAAO,OAAO,QAAQ,OAAO,YAAY;AAAA,IAC7C;AAEA,UAAM,KAAK,OAAO,IAAI,qBAAqB,QAAQ,IAAI,EAAE,OAAO,CAAC;AAAA,EACrE;AAAA,EAEA,MAAM,YAAY,UAAkB,iBAAiB,OAAsB;AACvE,UAAM,KAAK,OAAO,OAAO,qBAAqB,QAAQ,IAAI;AAAA,MACtD,QAAQ,EAAE,eAAe;AAAA,IAC7B,CAAC;AAAA,EACL;AACJ;;;AC/DO,IAAM,gBAAN,MAAoB;AAAA,EACvB,YAAoB,QAAuB;AAAvB;AAAA,EAAwB;AAAA,EAE5C,MAAM,YACF,KACA,UAAU,GACV,aAAa,IACb,QAC2B;AAC3B,UAAM,SAAkC;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,QAAI,UAAU,OAAO,SAAS,GAAG;AAC7B,aAAO,SAAS,OAAO,KAAK,GAAG;AAAA,IACnC;AACA,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,sBAAsB,EAAE,OAAO,CAAC;AACvE,WAAO,SAAS;AAAA,EACpB;AACJ;;;ACnBO,SAAS,iBAAiB,QAAmC;AAChE,SAAO,iBAAiB,MAAM;AAClC;;;ACHO,IAAM,wBAAN,MAA4B;AAAA,EAC/B,YAAoB,QAAuB;AAAvB;AAAA,EAAwB;AAAA,EAE5C,MAAM,iBACF,WACA,QAC6B;AAC7B,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,aAAa,SAAS,mBAAmB;AAAA,MAC5E,QAAQ;AAAA,QACJ,OAAO,QAAQ,SAAS;AAAA,QACxB,OAAO,QAAQ;AAAA,QACf,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ,WAAW;AAAA,MACjC;AAAA,IACJ,CAAC;AACD,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,gBAAgB,WAAmB,OAA4C;AACjF,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MAC/B,aAAa,SAAS,mBAAmB,KAAK;AAAA,IAClD;AACA,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,uBAAuB,WAAmB,OAA4C;AACxF,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MAC/B,aAAa,SAAS,mBAAmB,KAAK;AAAA,IAClD;AACA,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,mBACF,WACA,MAS2B;AAC3B,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,aAAa,SAAS,mBAAmB,IAAI;AACrF,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,mBACF,WACA,OACA,MAQ2B;AAC3B,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MAC/B,aAAa,SAAS,mBAAmB,KAAK;AAAA,MAC9C;AAAA,IACJ;AACA,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,kBACF,WACA,OACA,QAK2B;AAC3B,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MAC/B,aAAa,SAAS,mBAAmB,KAAK;AAAA,MAC9C;AAAA,IACJ;AACA,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,qBAAqB,WAAmB,OAAsC;AAChF,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MAC/B,aAAa,SAAS,mBAAmB,KAAK;AAAA,IAClD;AACA,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,oBACF,WACA,OACA,MACmB;AACnB,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MAC/B,aAAa,SAAS,mBAAmB,KAAK;AAAA,MAC9C,EAAE,KAAK;AAAA,IACX;AACA,WAAO,SAAS;AAAA,EACpB;AACJ;;;ACrGO,IAAM,oBAAN,MAAwB;AAAA,EAC3B,YAAoB,QAAuB;AAAvB;AAAA,EAAwB;AAAA,EAE5C,MAAM,aACF,WACA,QACyB;AACzB,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,aAAa,SAAS,cAAc;AAAA,MACvE,QAAQ;AAAA,QACJ,QAAQ,QAAQ;AAAA,QAChB,KAAK,QAAQ;AAAA,QACb,UAAU,QAAQ,WAAW;AAAA,MACjC;AAAA,IACJ,CAAC;AACD,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,YAAY,WAAmB,YAA6C;AAC9E,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MAC/B,aAAa,SAAS,cAAc,UAAU;AAAA,IAClD;AACA,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,gBAAgB,WAAmB,YAA0C;AAC/E,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MAC/B,aAAa,SAAS,cAAc,UAAU;AAAA,IAClD;AACA,WAAO,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,yBACF,WACA,OACyB;AACzB,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MAC/B,aAAa,SAAS,mBAAmB,KAAK;AAAA,IAClD;AACA,WAAO,SAAS;AAAA,EACpB;AACJ;;;ACvCO,SAAS,mBAAmB,QAAqC;AACpE,QAAM,SAAS,iBAAiB;AAAA,IAC5B,GAAG;AAAA,IACH,SAAS,GAAG,OAAO,OAAO;AAAA,EAC9B,CAAC;AAGD,SAAO,SAAS,QAAQ,OAAO,eAAe,IAAI,OAAO,KAAK;AAE9D,SAAO;AACX;","names":["tokens"]}
|
|
@@ -1,38 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GitlabBranchApi,
|
|
3
|
+
GitlabProjectApi,
|
|
4
|
+
GitlabRepositoryApi,
|
|
5
|
+
JiraCommentApi,
|
|
6
|
+
JiraProjectApi,
|
|
7
|
+
JiraTransitionApi
|
|
8
|
+
} from "./chunk-JI2YUE7N.js";
|
|
1
9
|
import {
|
|
2
10
|
ConfluenceContentApi,
|
|
3
11
|
ConfluenceSearchApi,
|
|
4
12
|
ConfluenceSpaceApi,
|
|
5
|
-
GitlabBranchApi,
|
|
6
13
|
GitlabMergeRequestApi,
|
|
7
14
|
GitlabPipelineApi,
|
|
8
|
-
GitlabProjectApi,
|
|
9
|
-
GitlabRepositoryApi,
|
|
10
|
-
JiraCommentApi,
|
|
11
15
|
JiraIssueApi,
|
|
12
|
-
JiraProjectApi,
|
|
13
16
|
JiraSearchApi,
|
|
14
|
-
JiraTransitionApi,
|
|
15
17
|
MarkdownToStorageConverter,
|
|
16
18
|
StorageToMarkdownConverter,
|
|
17
19
|
createConfluenceClient,
|
|
18
20
|
createGitlabClient,
|
|
19
21
|
createJiraClient,
|
|
22
|
+
loadAIConfig,
|
|
20
23
|
loadConfluenceConfig,
|
|
21
24
|
loadGitlabConfig,
|
|
22
25
|
loadJiraConfig
|
|
23
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-6AFNYE7N.js";
|
|
24
27
|
import {
|
|
25
28
|
logger
|
|
26
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-IFYMZLQI.js";
|
|
27
30
|
|
|
28
|
-
//
|
|
31
|
+
// tools/mcp/server.ts
|
|
29
32
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
30
33
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
31
34
|
|
|
32
|
-
//
|
|
35
|
+
// tools/confluence/tools/index.ts
|
|
33
36
|
import { z } from "zod";
|
|
37
|
+
import fs from "fs";
|
|
38
|
+
import path from "path";
|
|
34
39
|
|
|
35
|
-
//
|
|
40
|
+
// tools/confluence/api/label.ts
|
|
36
41
|
var ConfluenceLabelApi = class {
|
|
37
42
|
constructor(client) {
|
|
38
43
|
this.client = client;
|
|
@@ -52,7 +57,59 @@ var ConfluenceLabelApi = class {
|
|
|
52
57
|
}
|
|
53
58
|
};
|
|
54
59
|
|
|
55
|
-
//
|
|
60
|
+
// tools/confluence/converters/ai-refiner.ts
|
|
61
|
+
import axios from "axios";
|
|
62
|
+
var AIConversionService = class {
|
|
63
|
+
config = loadAIConfig();
|
|
64
|
+
async refine(request) {
|
|
65
|
+
if (!this.config.openaiApiKey && !this.config.anthropicApiKey) {
|
|
66
|
+
throw new Error("AI \uBCC0\uD658\uC744 \uC704\uD55C API \uD0A4\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
|
|
67
|
+
}
|
|
68
|
+
logger.info(`AI\uB97C \uC774\uC6A9\uD55C \uC9C0\uB2A5\uD615 \uBCC0\uD658 \uC2DC\uC791: ${request.sourceType} -> ${request.targetType}`);
|
|
69
|
+
try {
|
|
70
|
+
const prompt = this.buildPrompt(request);
|
|
71
|
+
const response = await axios.post(
|
|
72
|
+
"https://api.openai.com/v1/chat/completions",
|
|
73
|
+
{
|
|
74
|
+
model: this.config.defaultModel,
|
|
75
|
+
messages: [
|
|
76
|
+
{ role: "system", content: "\uB2F9\uC2E0\uC740 \uC804\uBB38 \uAE30\uC220 \uBB38\uC11C \uBCC0\uD658 \uC5D0\uC774\uC804\uD2B8\uC785\uB2C8\uB2E4. \uC8FC\uC5B4\uC9C4 \uD14D\uC2A4\uD2B8\uB97C \uB300\uC0C1 \uD615\uC2DD\uC73C\uB85C \uC644\uBCBD\uD558\uAC8C \uBCC0\uD658\uD558\uC2ED\uC2DC\uC624. \uCD94\uAC00 \uC124\uBA85 \uC5C6\uC774 \uACB0\uACFC \uB370\uC774\uD130\uB9CC \uBC18\uD658\uD558\uC2ED\uC2DC\uC624." },
|
|
77
|
+
{ role: "user", content: prompt }
|
|
78
|
+
],
|
|
79
|
+
temperature: 0
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
headers: {
|
|
83
|
+
"Authorization": `Bearer ${this.config.openaiApiKey}`,
|
|
84
|
+
"Content-Type": "application/json"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
const result = response.data.choices[0].message.content.trim();
|
|
89
|
+
const cleanResult = result.replace(/^```[a-z]*\n([\s\S]*)\n```$/i, "$1");
|
|
90
|
+
return {
|
|
91
|
+
convertedContent: cleanResult,
|
|
92
|
+
confidence: 0.95
|
|
93
|
+
};
|
|
94
|
+
} catch (error) {
|
|
95
|
+
logger.error("AI \uBCC0\uD658 \uC911 \uC624\uB958 \uBC1C\uC0DD:", error);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
buildPrompt(request) {
|
|
100
|
+
return `
|
|
101
|
+
\uC6D0\uBCF8 \uD615\uC2DD: ${request.sourceType}
|
|
102
|
+
\uB300\uC0C1 \uD615\uC2DD: ${request.targetType}
|
|
103
|
+
\uCD94\uAC00 \uCEE8\uD14D\uC2A4\uD2B8: ${request.context || "\uC5C6\uC74C"}
|
|
104
|
+
|
|
105
|
+
\uB2E4\uC74C \uD14D\uC2A4\uD2B8\uB97C \uBCC0\uD658\uD558\uC2ED\uC2DC\uC624:
|
|
106
|
+
|
|
107
|
+
${request.sourceContent}
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// tools/confluence/tools/index.ts
|
|
56
113
|
function registerConfluenceTools(server) {
|
|
57
114
|
try {
|
|
58
115
|
const config = loadConfluenceConfig();
|
|
@@ -63,22 +120,24 @@ function registerConfluenceTools(server) {
|
|
|
63
120
|
const labelApi = new ConfluenceLabelApi(client);
|
|
64
121
|
const mdToStorage = new MarkdownToStorageConverter();
|
|
65
122
|
const storageToMd = new StorageToMarkdownConverter();
|
|
123
|
+
const aiService = new AIConversionService();
|
|
66
124
|
server.tool(
|
|
67
125
|
"confluence_get_page",
|
|
68
126
|
"TDE Confluence \uD398\uC774\uC9C0 \uC0C1\uC138 \uC870\uD68C. \uD398\uC774\uC9C0 \uB0B4\uC6A9\uC744 Markdown\uC73C\uB85C \uBCC0\uD658\uD558\uC5EC \uBC18\uD658\uD569\uB2C8\uB2E4.",
|
|
69
127
|
{
|
|
70
128
|
pageId: z.string().describe("\uD398\uC774\uC9C0 ID"),
|
|
71
129
|
downloadImages: z.boolean().optional().describe("\uC774\uBBF8\uC9C0 \uB2E4\uC6B4\uB85C\uB4DC \uC5EC\uBD80"),
|
|
72
|
-
imageDir: z.string().optional().describe("\uC774\uBBF8\uC9C0 \uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC (\uAE30\uBCF8\uAC12: ./images)")
|
|
130
|
+
imageDir: z.string().optional().describe("\uC774\uBBF8\uC9C0 \uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC (\uAE30\uBCF8\uAC12: ./images)"),
|
|
131
|
+
useAiFallback: z.boolean().optional().describe("\uBCC0\uD658 \uACB0\uACFC \uBCF4\uC815\uC744 \uC704\uD574 AI\uB97C \uC0AC\uC6A9\uD560\uC9C0 \uC5EC\uBD80")
|
|
73
132
|
},
|
|
74
|
-
async ({ pageId, downloadImages, imageDir }) => {
|
|
133
|
+
async ({ pageId, downloadImages, imageDir, useAiFallback }) => {
|
|
75
134
|
const page = await contentApi.getPage(pageId);
|
|
76
135
|
let md = "";
|
|
77
136
|
let imageInfo = "";
|
|
78
137
|
if (page.body?.storage?.value) {
|
|
79
138
|
let imageUrlMap;
|
|
80
139
|
if (downloadImages) {
|
|
81
|
-
const { ImageDownloader } = await import("./image-downloader-
|
|
140
|
+
const { ImageDownloader } = await import("./image-downloader-VKPGS3TY.js");
|
|
82
141
|
const downloader = new ImageDownloader(contentApi, {
|
|
83
142
|
outputDir: imageDir || "./images",
|
|
84
143
|
pageId: page.id,
|
|
@@ -90,6 +149,15 @@ function registerConfluenceTools(server) {
|
|
|
90
149
|
\uB2E4\uC6B4\uB85C\uB4DC\uB41C \uC774\uBBF8\uC9C0: ${imageUrlMap.size}\uAC1C`;
|
|
91
150
|
}
|
|
92
151
|
md = storageToMd.convert(page.body.storage.value, imageUrlMap);
|
|
152
|
+
if (useAiFallback) {
|
|
153
|
+
const aiResult = await aiService.refine({
|
|
154
|
+
sourceContent: md,
|
|
155
|
+
sourceType: "markdown",
|
|
156
|
+
targetType: "markdown",
|
|
157
|
+
context: "\uC774\uC804 \uBCC0\uD658 \uACB0\uACFC\uAC00 \uAE68\uC84C\uAC70\uB098 \uD45C \uD615\uC2DD\uC774 \uBD80\uC801\uC808\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uAE68\uB057\uD55C GFM \uD615\uC2DD\uC73C\uB85C \uBCF4\uC815\uD574\uC8FC\uC138\uC694."
|
|
158
|
+
});
|
|
159
|
+
md = aiResult.convertedContent;
|
|
160
|
+
}
|
|
93
161
|
}
|
|
94
162
|
return {
|
|
95
163
|
content: [
|
|
@@ -114,10 +182,20 @@ ${md}`
|
|
|
114
182
|
title: z.string().describe("\uD398\uC774\uC9C0 \uC81C\uBAA9"),
|
|
115
183
|
content: z.string().describe("\uD398\uC774\uC9C0 \uB0B4\uC6A9 (Markdown)"),
|
|
116
184
|
parentId: z.string().optional().describe("\uBD80\uBAA8 \uD398\uC774\uC9C0 ID"),
|
|
117
|
-
labels: z.array(z.string()).optional().describe("\uB77C\uBCA8 \uBAA9\uB85D")
|
|
185
|
+
labels: z.array(z.string()).optional().describe("\uB77C\uBCA8 \uBAA9\uB85D"),
|
|
186
|
+
useAiFallback: z.boolean().optional().describe("\uBCF5\uC7A1\uD55C \uBCC0\uD658\uC744 \uC704\uD574 AI\uB97C \uC0AC\uC6A9\uD560\uC9C0 \uC5EC\uBD80")
|
|
118
187
|
},
|
|
119
|
-
async ({ spaceKey, title, content, parentId, labels }) => {
|
|
120
|
-
|
|
188
|
+
async ({ spaceKey, title, content, parentId, labels, useAiFallback }) => {
|
|
189
|
+
let storageBody = mdToStorage.convert(content);
|
|
190
|
+
if (useAiFallback) {
|
|
191
|
+
const aiResult = await aiService.refine({
|
|
192
|
+
sourceContent: content,
|
|
193
|
+
sourceType: "markdown",
|
|
194
|
+
targetType: "storage-xml",
|
|
195
|
+
context: "Confluence Storage XML \uD615\uC2DD\uC73C\uB85C \uBCC0\uD658\uD574\uC8FC\uC138\uC694. Mermaid\uB294 mermaiddiagram \uB9E4\uD06C\uB85C\uB97C \uC0AC\uC6A9\uD558\uC138\uC694."
|
|
196
|
+
});
|
|
197
|
+
storageBody = aiResult.convertedContent;
|
|
198
|
+
}
|
|
121
199
|
const page = await contentApi.createPage({
|
|
122
200
|
spaceKey,
|
|
123
201
|
title,
|
|
@@ -141,23 +219,77 @@ URL: ${page._links?.base}${page._links?.webui}`
|
|
|
141
219
|
"TDE Confluence \uD398\uC774\uC9C0\uB97C \uC218\uC815\uD569\uB2C8\uB2E4. Markdown \uD615\uC2DD\uC758 \uB0B4\uC6A9\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
142
220
|
{
|
|
143
221
|
pageId: z.string().describe("\uD398\uC774\uC9C0 ID"),
|
|
144
|
-
title: z.string().describe("\uD398\uC774\uC9C0 \uC81C\uBAA9"),
|
|
222
|
+
title: z.string().optional().describe("\uD398\uC774\uC9C0 \uC81C\uBAA9 (\uC0DD\uB7B5 \uC2DC \uAE30\uC874 \uC81C\uBAA9 \uC720\uC9C0)"),
|
|
145
223
|
content: z.string().describe("\uD398\uC774\uC9C0 \uB0B4\uC6A9 (Markdown)"),
|
|
146
|
-
version: z.number().describe("\uD604\uC7AC \uD398\uC774\uC9C0 \uBC84\uC804 (\
|
|
224
|
+
version: z.number().optional().describe("\uD604\uC7AC \uD398\uC774\uC9C0 \uBC84\uC804 (\uC0DD\uB7B5 \uC2DC \uC790\uB3D9 \uC870\uD68C)"),
|
|
225
|
+
useAiFallback: z.boolean().optional().describe("\uBCF5\uC7A1\uD55C \uBCC0\uD658\uC744 \uC704\uD574 AI\uB97C \uC0AC\uC6A9\uD560\uC9C0 \uC5EC\uBD80"),
|
|
226
|
+
baseDir: z.string().optional().describe("\uB85C\uCEEC \uC774\uBBF8\uC9C0\uB97C \uCC3E\uC744 \uAE30\uC900 \uB514\uB809\uD1A0\uB9AC \uC808\uB300 \uACBD\uB85C")
|
|
147
227
|
},
|
|
148
|
-
async ({ pageId, title, content, version }) => {
|
|
149
|
-
|
|
228
|
+
async ({ pageId, title, content, version, useAiFallback, baseDir }) => {
|
|
229
|
+
let currentVersion = version;
|
|
230
|
+
let currentTitle = title;
|
|
231
|
+
if (currentVersion === void 0 || !currentTitle) {
|
|
232
|
+
const currentPage = await contentApi.getPage(pageId, ["version", "title"]);
|
|
233
|
+
if (currentVersion === void 0) {
|
|
234
|
+
currentVersion = currentPage.version?.number ?? 1;
|
|
235
|
+
}
|
|
236
|
+
if (!currentTitle) {
|
|
237
|
+
currentTitle = currentPage.title;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
let storageBody = mdToStorage.convert(content);
|
|
241
|
+
if (useAiFallback) {
|
|
242
|
+
const aiResult = await aiService.refine({
|
|
243
|
+
sourceContent: content,
|
|
244
|
+
sourceType: "markdown",
|
|
245
|
+
targetType: "storage-xml",
|
|
246
|
+
context: "Confluence Storage XML \uD615\uC2DD\uC73C\uB85C \uBCC0\uD658\uD574\uC8FC\uC138\uC694. Mermaid\uB294 mermaiddiagram \uB9E4\uD06C\uB85C\uB97C \uC0AC\uC6A9\uD558\uC138\uC694."
|
|
247
|
+
});
|
|
248
|
+
storageBody = aiResult.convertedContent;
|
|
249
|
+
}
|
|
150
250
|
const page = await contentApi.updatePage({
|
|
151
251
|
id: pageId,
|
|
152
|
-
title,
|
|
252
|
+
title: currentTitle,
|
|
153
253
|
body: storageBody,
|
|
154
|
-
version
|
|
254
|
+
version: currentVersion
|
|
155
255
|
});
|
|
256
|
+
let imageUploadLog = "";
|
|
257
|
+
if (baseDir) {
|
|
258
|
+
const localImages = mdToStorage.extractLocalImages(content);
|
|
259
|
+
if (localImages.length > 0) {
|
|
260
|
+
imageUploadLog += `
|
|
261
|
+
|
|
262
|
+
\uB85C\uCEEC \uC774\uBBF8\uC9C0 \uC5C5\uB85C\uB4DC (${localImages.length}\uAC1C):`;
|
|
263
|
+
for (const imgSrc of localImages) {
|
|
264
|
+
try {
|
|
265
|
+
const imagePath = path.resolve(baseDir, imgSrc);
|
|
266
|
+
if (fs.existsSync(imagePath)) {
|
|
267
|
+
const fileBuffer = fs.readFileSync(imagePath);
|
|
268
|
+
const filename = path.basename(imgSrc);
|
|
269
|
+
let contentType = "application/octet-stream";
|
|
270
|
+
if (filename.endsWith(".png")) contentType = "image/png";
|
|
271
|
+
else if (filename.endsWith(".jpg") || filename.endsWith(".jpeg")) contentType = "image/jpeg";
|
|
272
|
+
else if (filename.endsWith(".svg")) contentType = "image/svg+xml";
|
|
273
|
+
else if (filename.endsWith(".gif")) contentType = "image/gif";
|
|
274
|
+
await contentApi.uploadAttachment(page.id, filename, fileBuffer, contentType);
|
|
275
|
+
imageUploadLog += `
|
|
276
|
+
- \uC131\uACF5: ${filename}`;
|
|
277
|
+
} else {
|
|
278
|
+
imageUploadLog += `
|
|
279
|
+
- \uC2E4\uD328 (\uD30C\uC77C \uC5C6\uC74C): ${imagePath}`;
|
|
280
|
+
}
|
|
281
|
+
} catch (uploadErr) {
|
|
282
|
+
imageUploadLog += `
|
|
283
|
+
- \uC5C5\uB85C\uB4DC \uC2E4\uD328 (${imgSrc}): ${uploadErr.message}`;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
156
288
|
return {
|
|
157
289
|
content: [
|
|
158
290
|
{
|
|
159
291
|
type: "text",
|
|
160
|
-
text: `\uD398\uC774\uC9C0 \uC218\uC815 \uC131\uACF5: ${page.title} (Version: ${page.version?.number})`
|
|
292
|
+
text: `\uD398\uC774\uC9C0 \uC218\uC815 \uC131\uACF5: ${page.title} (Version: ${page.version?.number})${imageUploadLog}`
|
|
161
293
|
}
|
|
162
294
|
]
|
|
163
295
|
};
|
|
@@ -279,14 +411,26 @@ ${summary}`
|
|
|
279
411
|
"TDE Confluence \uCEE8\uD150\uCE20 \uD3EC\uB9F7\uC744 \uBCC0\uD658\uD569\uB2C8\uB2E4. Markdown\uACFC Confluence Storage Format \uAC04 \uC591\uBC29\uD5A5 \uBCC0\uD658\uC744 \uC9C0\uC6D0\uD569\uB2C8\uB2E4.",
|
|
280
412
|
{
|
|
281
413
|
content: z.string().describe("\uBCC0\uD658\uD560 \uCEE8\uD150\uCE20"),
|
|
282
|
-
format: z.enum(["storage_to_markdown", "markdown_to_storage"]).describe("\uBCC0\uD658 \uBC29\uD5A5")
|
|
414
|
+
format: z.enum(["storage_to_markdown", "markdown_to_storage"]).describe("\uBCC0\uD658 \uBC29\uD5A5"),
|
|
415
|
+
useAi: z.boolean().optional().describe("\uC9C0\uB2A5\uD615 \uBCC0\uD658\uC744 \uC704\uD574 AI\uB97C \uC0AC\uC6A9\uD560\uC9C0 \uC5EC\uBD80")
|
|
283
416
|
},
|
|
284
|
-
async ({ content, format }) => {
|
|
417
|
+
async ({ content, format, useAi }) => {
|
|
285
418
|
let result = "";
|
|
286
|
-
if (
|
|
287
|
-
|
|
419
|
+
if (useAi) {
|
|
420
|
+
const sourceType = format === "storage_to_markdown" ? "storage-xml" : "markdown";
|
|
421
|
+
const targetType = format === "storage_to_markdown" ? "markdown" : "storage-xml";
|
|
422
|
+
const aiResult = await aiService.refine({
|
|
423
|
+
sourceContent: content,
|
|
424
|
+
sourceType,
|
|
425
|
+
targetType
|
|
426
|
+
});
|
|
427
|
+
result = aiResult.convertedContent;
|
|
288
428
|
} else {
|
|
289
|
-
|
|
429
|
+
if (format === "storage_to_markdown") {
|
|
430
|
+
result = storageToMd.convert(content);
|
|
431
|
+
} else {
|
|
432
|
+
result = mdToStorage.convert(content);
|
|
433
|
+
}
|
|
290
434
|
}
|
|
291
435
|
return {
|
|
292
436
|
content: [{ type: "text", text: result }]
|
|
@@ -298,7 +442,7 @@ ${summary}`
|
|
|
298
442
|
}
|
|
299
443
|
}
|
|
300
444
|
|
|
301
|
-
//
|
|
445
|
+
// tools/jira/tools/index.ts
|
|
302
446
|
import { z as z2 } from "zod";
|
|
303
447
|
function registerJiraTools(server) {
|
|
304
448
|
try {
|
|
@@ -576,7 +720,7 @@ ${summary}` }]
|
|
|
576
720
|
}
|
|
577
721
|
}
|
|
578
722
|
|
|
579
|
-
//
|
|
723
|
+
// tools/gitlab/tools/index.ts
|
|
580
724
|
import { z as z3 } from "zod";
|
|
581
725
|
function registerGitlabTools(server) {
|
|
582
726
|
try {
|
|
@@ -899,10 +1043,10 @@ ${summary}`
|
|
|
899
1043
|
type: z3.enum(["file", "tree"]).optional().describe('"file" (\uAE30\uBCF8) \uB610\uB294 "tree"'),
|
|
900
1044
|
recursive: z3.boolean().optional().describe("\uC7AC\uADC0 \uC870\uD68C (type=tree \uC2DC)")
|
|
901
1045
|
},
|
|
902
|
-
async ({ projectId, path, ref, type, recursive }) => {
|
|
1046
|
+
async ({ projectId, path: path2, ref, type, recursive }) => {
|
|
903
1047
|
if (type === "tree") {
|
|
904
1048
|
const entries = await repoApi.getTree(projectId, {
|
|
905
|
-
path,
|
|
1049
|
+
path: path2,
|
|
906
1050
|
ref,
|
|
907
1051
|
recursive
|
|
908
1052
|
});
|
|
@@ -917,7 +1061,7 @@ ${summary}`
|
|
|
917
1061
|
]
|
|
918
1062
|
};
|
|
919
1063
|
} else {
|
|
920
|
-
const file = await repoApi.getFile(projectId,
|
|
1064
|
+
const file = await repoApi.getFile(projectId, path2, ref);
|
|
921
1065
|
const lines = [
|
|
922
1066
|
`File: ${file.file_path}`,
|
|
923
1067
|
`Size: ${file.size} bytes`,
|
|
@@ -938,7 +1082,7 @@ ${summary}`
|
|
|
938
1082
|
}
|
|
939
1083
|
}
|
|
940
1084
|
|
|
941
|
-
//
|
|
1085
|
+
// tools/mcp/server.ts
|
|
942
1086
|
async function runServer() {
|
|
943
1087
|
try {
|
|
944
1088
|
const server = new McpServer({
|
|
@@ -961,4 +1105,4 @@ async function runServer() {
|
|
|
961
1105
|
export {
|
|
962
1106
|
runServer
|
|
963
1107
|
};
|
|
964
|
-
//# sourceMappingURL=chunk-
|
|
1108
|
+
//# sourceMappingURL=chunk-GMC75YB2.js.map
|