tdecollab 0.2.3 → 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 -257
- package/dist/{chunk-UH2YGKTB.js → chunk-6AFNYE7N.js} +10 -170
- package/dist/chunk-6AFNYE7N.js.map +1 -0
- package/dist/{chunk-2HLUO2TQ.js → chunk-GMC75YB2.js} +130 -19
- package/dist/chunk-GMC75YB2.js.map +1 -0
- package/dist/{image-downloader-IY2A3R5N.js → chunk-JBDK5WP3.js} +2 -1
- package/dist/chunk-JI2YUE7N.js +172 -0
- package/dist/chunk-JI2YUE7N.js.map +1 -0
- package/dist/cli.js +19 -13
- package/dist/cli.js.map +1 -1
- package/dist/image-downloader-VKPGS3TY.js +8 -0
- package/dist/index.js +3 -2
- 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 +21 -3
- package/dist/chunk-2HLUO2TQ.js.map +0 -1
- package/dist/chunk-UH2YGKTB.js.map +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/server-GLKCDDKS.js +0 -9
- /package/dist/{image-downloader-IY2A3R5N.js.map → chunk-JBDK5WP3.js.map} +0 -0
- /package/dist/{server-GLKCDDKS.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":"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","names":["tokens"]}
|
|
@@ -1,26 +1,29 @@
|
|
|
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
29
|
} from "./chunk-IFYMZLQI.js";
|
|
@@ -31,6 +34,8 @@ 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 {
|
|
@@ -52,6 +57,58 @@ var ConfluenceLabelApi = class {
|
|
|
52
57
|
}
|
|
53
58
|
};
|
|
54
59
|
|
|
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
|
+
|
|
55
112
|
// tools/confluence/tools/index.ts
|
|
56
113
|
function registerConfluenceTools(server) {
|
|
57
114
|
try {
|
|
@@ -80,7 +137,7 @@ function registerConfluenceTools(server) {
|
|
|
80
137
|
if (page.body?.storage?.value) {
|
|
81
138
|
let imageUrlMap;
|
|
82
139
|
if (downloadImages) {
|
|
83
|
-
const { ImageDownloader } = await import("./image-downloader-
|
|
140
|
+
const { ImageDownloader } = await import("./image-downloader-VKPGS3TY.js");
|
|
84
141
|
const downloader = new ImageDownloader(contentApi, {
|
|
85
142
|
outputDir: imageDir || "./images",
|
|
86
143
|
pageId: page.id,
|
|
@@ -162,23 +219,77 @@ URL: ${page._links?.base}${page._links?.webui}`
|
|
|
162
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.",
|
|
163
220
|
{
|
|
164
221
|
pageId: z.string().describe("\uD398\uC774\uC9C0 ID"),
|
|
165
|
-
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)"),
|
|
166
223
|
content: z.string().describe("\uD398\uC774\uC9C0 \uB0B4\uC6A9 (Markdown)"),
|
|
167
|
-
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")
|
|
168
227
|
},
|
|
169
|
-
async ({ pageId, title, content, version }) => {
|
|
170
|
-
|
|
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
|
+
}
|
|
171
250
|
const page = await contentApi.updatePage({
|
|
172
251
|
id: pageId,
|
|
173
|
-
title,
|
|
252
|
+
title: currentTitle,
|
|
174
253
|
body: storageBody,
|
|
175
|
-
version
|
|
254
|
+
version: currentVersion
|
|
176
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
|
+
}
|
|
177
288
|
return {
|
|
178
289
|
content: [
|
|
179
290
|
{
|
|
180
291
|
type: "text",
|
|
181
|
-
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}`
|
|
182
293
|
}
|
|
183
294
|
]
|
|
184
295
|
};
|
|
@@ -932,10 +1043,10 @@ ${summary}`
|
|
|
932
1043
|
type: z3.enum(["file", "tree"]).optional().describe('"file" (\uAE30\uBCF8) \uB610\uB294 "tree"'),
|
|
933
1044
|
recursive: z3.boolean().optional().describe("\uC7AC\uADC0 \uC870\uD68C (type=tree \uC2DC)")
|
|
934
1045
|
},
|
|
935
|
-
async ({ projectId, path, ref, type, recursive }) => {
|
|
1046
|
+
async ({ projectId, path: path2, ref, type, recursive }) => {
|
|
936
1047
|
if (type === "tree") {
|
|
937
1048
|
const entries = await repoApi.getTree(projectId, {
|
|
938
|
-
path,
|
|
1049
|
+
path: path2,
|
|
939
1050
|
ref,
|
|
940
1051
|
recursive
|
|
941
1052
|
});
|
|
@@ -950,7 +1061,7 @@ ${summary}`
|
|
|
950
1061
|
]
|
|
951
1062
|
};
|
|
952
1063
|
} else {
|
|
953
|
-
const file = await repoApi.getFile(projectId,
|
|
1064
|
+
const file = await repoApi.getFile(projectId, path2, ref);
|
|
954
1065
|
const lines = [
|
|
955
1066
|
`File: ${file.file_path}`,
|
|
956
1067
|
`Size: ${file.size} bytes`,
|
|
@@ -994,4 +1105,4 @@ async function runServer() {
|
|
|
994
1105
|
export {
|
|
995
1106
|
runServer
|
|
996
1107
|
};
|
|
997
|
-
//# sourceMappingURL=chunk-
|
|
1108
|
+
//# sourceMappingURL=chunk-GMC75YB2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../tools/mcp/server.ts","../tools/confluence/tools/index.ts","../tools/confluence/api/label.ts","../tools/confluence/converters/ai-refiner.ts","../tools/jira/tools/index.ts","../tools/gitlab/tools/index.ts"],"sourcesContent":["\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { registerConfluenceTools } from '../confluence/tools/index.js';\nimport { registerJiraTools } from '../jira/tools/index.js';\nimport { registerGitlabTools } from '../gitlab/tools/index.js';\nimport { logger } from '../common/logger.js';\n\nexport async function runServer() {\n try {\n const server = new McpServer({\n name: 'TDE Collab',\n version: '1.0.0',\n description: 'TDE 포털(Confluence, JIRA, GitLab) 통합 도구. Confluence 페이지 관리, JIRA 이슈 관리, 검색 기능을 제공합니다.',\n });\n\n // Confluence 도구 등록\n registerConfluenceTools(server);\n\n // JIRA 도구 등록\n registerJiraTools(server);\n\n // GitLab 도구 등록\n registerGitlabTools(server);\n\n // Stdio 전송 계층 연결\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n logger.info('TDE Collab MCP Server running on stdio');\n } catch (error) {\n logger.error(`Fatal error in MCP Server: ${error}`);\n process.exit(1);\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport fs from 'fs';\nimport path from 'path';\nimport { ConfluenceContentApi } from '../api/content.js';\nimport { ConfluenceSpaceApi } from '../api/space.js';\nimport { ConfluenceSearchApi } from '../api/search.js';\nimport { ConfluenceLabelApi } from '../api/label.js';\nimport { createConfluenceClient } from '../api/client.js';\nimport { MarkdownToStorageConverter } from '../converters/md-to-storage.js';\nimport { StorageToMarkdownConverter } from '../converters/storage-to-md.js';\nimport { AIConversionService } from '../converters/ai-refiner.js';\nimport { loadConfluenceConfig } from '../../common/config.js';\nimport { logger } from '../../common/logger.js';\n\nexport function registerConfluenceTools(server: McpServer) {\n try {\n const config = loadConfluenceConfig();\n const client = createConfluenceClient(config);\n\n const contentApi = new ConfluenceContentApi(client);\n const spaceApi = new ConfluenceSpaceApi(client);\n const searchApi = new ConfluenceSearchApi(client);\n const labelApi = new ConfluenceLabelApi(client);\n\n const mdToStorage = new MarkdownToStorageConverter();\n const storageToMd = new StorageToMarkdownConverter();\n const aiService = new AIConversionService();\n\n // Tools\n\n server.tool(\n 'confluence_get_page',\n 'TDE Confluence 페이지 상세 조회. 페이지 내용을 Markdown으로 변환하여 반환합니다.',\n {\n pageId: z.string().describe('페이지 ID'),\n downloadImages: z.boolean().optional().describe('이미지 다운로드 여부'),\n imageDir: z.string().optional().describe('이미지 저장 디렉토리 (기본값: ./images)'),\n useAiFallback: z.boolean().optional().describe('변환 결과 보정을 위해 AI를 사용할지 여부'),\n },\n async ({ pageId, downloadImages, imageDir, useAiFallback }) => {\n const page = await contentApi.getPage(pageId);\n\n let md = '';\n let imageInfo = '';\n\n if (page.body?.storage?.value) {\n let imageUrlMap: Map<string, string> | undefined;\n\n // 이미지 다운로드 옵션이 활성화된 경우\n if (downloadImages) {\n const { ImageDownloader } = await import('../utils/image-downloader.js');\n const downloader = new ImageDownloader(contentApi, {\n outputDir: imageDir || './images',\n pageId: page.id,\n baseUrl: config.baseUrl\n });\n\n imageUrlMap = await downloader.downloadAllImages(page.body.storage.value);\n imageInfo = `\\n\\n다운로드된 이미지: ${imageUrlMap.size}개`;\n }\n\n md = storageToMd.convert(page.body.storage.value, imageUrlMap);\n \n if (useAiFallback) {\n const aiResult = await aiService.refine({\n sourceContent: md,\n sourceType: 'markdown',\n targetType: 'markdown',\n context: '이전 변환 결과가 깨졌거나 표 형식이 부적절할 수 있습니다. 깨끗한 GFM 형식으로 보정해주세요.'\n });\n md = aiResult.convertedContent;\n }\n }\n\n return {\n content: [\n {\n type: 'text',\n text: `Title: ${page.title}\\nID: ${page.id}\\nSpace: ${page.space?.name} (${page.space?.key})\\nURL: ${page._links?.base}${page._links?.webui}${imageInfo}\\n\\n${md}`,\n },\n ],\n };\n }\n );\n\n server.tool(\n 'confluence_create_page',\n 'TDE Confluence에 새 페이지를 생성합니다. Markdown 형식의 내용을 Confluence Storage Format으로 자동 변환합니다.',\n {\n spaceKey: z.string().describe('스페이스 키'),\n title: z.string().describe('페이지 제목'),\n content: z.string().describe('페이지 내용 (Markdown)'),\n parentId: z.string().optional().describe('부모 페이지 ID'),\n labels: z.array(z.string()).optional().describe('라벨 목록'),\n useAiFallback: z.boolean().optional().describe('복잡한 변환을 위해 AI를 사용할지 여부'),\n },\n async ({ spaceKey, title, content, parentId, labels, useAiFallback }) => {\n let storageBody = mdToStorage.convert(content);\n \n if (useAiFallback) {\n const aiResult = await aiService.refine({\n sourceContent: content,\n sourceType: 'markdown',\n targetType: 'storage-xml',\n context: 'Confluence Storage XML 형식으로 변환해주세요. Mermaid는 mermaiddiagram 매크로를 사용하세요.'\n });\n storageBody = aiResult.convertedContent;\n }\n\n const page = await contentApi.createPage({\n spaceKey,\n title,\n body: storageBody,\n parentId,\n labels\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `페이지 생성 성공: ${page.title} (ID: ${page.id})\\nURL: ${page._links?.base}${page._links?.webui}`,\n },\n ],\n };\n }\n );\n\n server.tool(\n 'confluence_update_page',\n 'TDE Confluence 페이지를 수정합니다. Markdown 형식의 내용으로 업데이트할 수 있습니다.',\n {\n pageId: z.string().describe('페이지 ID'),\n title: z.string().optional().describe('페이지 제목 (생략 시 기존 제목 유지)'),\n content: z.string().describe('페이지 내용 (Markdown)'),\n version: z.number().optional().describe('현재 페이지 버전 (생략 시 자동 조회)'),\n useAiFallback: z.boolean().optional().describe('복잡한 변환을 위해 AI를 사용할지 여부'),\n baseDir: z.string().optional().describe('로컬 이미지를 찾을 기준 디렉토리 절대 경로'),\n },\n async ({ pageId, title, content, version, useAiFallback, baseDir }) => {\n let currentVersion = version;\n let currentTitle = title;\n \n if (currentVersion === undefined || !currentTitle) {\n const currentPage = await contentApi.getPage(pageId, ['version', 'title']);\n if (currentVersion === undefined) {\n currentVersion = currentPage.version?.number ?? 1;\n }\n if (!currentTitle) {\n currentTitle = currentPage.title;\n }\n }\n\n let storageBody = mdToStorage.convert(content);\n \n if (useAiFallback) {\n const aiResult = await aiService.refine({\n sourceContent: content,\n sourceType: 'markdown',\n targetType: 'storage-xml',\n context: 'Confluence Storage XML 형식으로 변환해주세요. Mermaid는 mermaiddiagram 매크로를 사용하세요.'\n });\n storageBody = aiResult.convertedContent;\n }\n\n const page = await contentApi.updatePage({\n id: pageId,\n title: currentTitle,\n body: storageBody,\n version: currentVersion\n });\n\n let imageUploadLog = '';\n if (baseDir) {\n const localImages = mdToStorage.extractLocalImages(content);\n if (localImages.length > 0) {\n imageUploadLog += `\\n\\n로컬 이미지 업로드 (${localImages.length}개):`;\n for (const imgSrc of localImages) {\n try {\n const imagePath = path.resolve(baseDir, imgSrc);\n if (fs.existsSync(imagePath)) {\n const fileBuffer = fs.readFileSync(imagePath);\n const filename = path.basename(imgSrc);\n let contentType = 'application/octet-stream';\n if (filename.endsWith('.png')) contentType = 'image/png';\n else if (filename.endsWith('.jpg') || filename.endsWith('.jpeg')) contentType = 'image/jpeg';\n else if (filename.endsWith('.svg')) contentType = 'image/svg+xml';\n else if (filename.endsWith('.gif')) contentType = 'image/gif';\n\n await contentApi.uploadAttachment(page.id, filename, fileBuffer, contentType);\n imageUploadLog += `\\n - 성공: ${filename}`;\n } else {\n imageUploadLog += `\\n - 실패 (파일 없음): ${imagePath}`;\n }\n } catch (uploadErr: any) {\n imageUploadLog += `\\n - 업로드 실패 (${imgSrc}): ${(uploadErr as Error).message}`;\n }\n }\n }\n }\n\n return {\n content: [\n {\n type: 'text',\n text: `페이지 수정 성공: ${page.title} (Version: ${page.version?.number})${imageUploadLog}`,\n },\n ],\n };\n }\n );\n\n server.tool(\n 'confluence_search_pages',\n 'TDE Confluence에서 페이지를 검색합니다. CQL(Confluence Query Language)을 사용하여 고급 검색이 가능합니다.',\n {\n cql: z.string().describe('Confluence Query Language (예: title ~ \"guide\")'),\n limit: z.number().default(10).describe('결과 개수 제한'),\n },\n async ({ cql, limit }) => {\n const result = await searchApi.searchByCql(cql, 0, limit);\n const summary = result.results.map(p => `- [${p.id}] ${p.title} (Space: ${p.space?.key})`).join('\\n');\n\n return {\n content: [\n {\n type: 'text',\n text: `검색 결과 (${result.size}/${result.totalSize}):\\n${summary}`,\n },\n ],\n };\n }\n );\n\n server.tool(\n 'confluence_get_spaces',\n 'TDE Confluence의 스페이스 목록을 조회합니다.',\n {\n limit: z.number().default(20).describe('결과 개수 제한')\n },\n async ({ limit }) => {\n const spaces = await spaceApi.getSpaces('global', 0, limit);\n const summary = spaces.map(s => `- [${s.key}] ${s.name}`).join('\\n');\n return {\n content: [{ type: 'text', text: `스페이스 목록:\\n${summary}` }]\n };\n }\n );\n\n server.tool(\n 'confluence_delete_page',\n 'TDE Confluence 페이지를 삭제합니다.',\n {\n pageId: z.string().describe('페이지 ID'),\n },\n async ({ pageId }) => {\n await contentApi.deletePage(pageId);\n return {\n content: [\n {\n type: 'text',\n text: `페이지 삭제 성공 (ID: ${pageId})`,\n },\n ],\n };\n }\n );\n\n server.tool(\n 'confluence_get_page_tree',\n 'TDE Confluence 페이지의 하위 페이지(자식 페이지) 목록을 조회합니다.',\n {\n pageId: z.string().describe('페이지 ID'),\n limit: z.number().default(20).describe('결과 개수 제한'),\n },\n async ({ pageId, limit }) => {\n const children = await contentApi.getChildPages(pageId, 0, limit);\n const summary = children.map(p => `- [${p.id}] ${p.title}`).join('\\n');\n return {\n content: [\n {\n type: 'text',\n text: `자식 페이지 목록 (${children.length}):\\n${summary}`,\n },\n ],\n };\n }\n );\n\n server.tool(\n 'confluence_manage_labels',\n 'TDE Confluence 페이지의 라벨을 관리합니다. 라벨 조회, 추가, 삭제 기능을 제공합니다.',\n {\n pageId: z.string().describe('페이지 ID'),\n action: z.enum(['list', 'add', 'remove']).describe('작업 유형'),\n labels: z.array(z.string()).optional().describe('추가할 라벨 목록 (add 작업 시 필수)'),\n label: z.string().optional().describe('삭제할 라벨 (remove 작업 시 필수)'),\n },\n async ({ pageId, action, labels, label }) => {\n if (action === 'list') {\n const result = await labelApi.getLabels(pageId);\n const summary = result.map(l => l.name).join(', ');\n return {\n content: [{ type: 'text', text: `라벨 목록: ${summary}` }],\n };\n } else if (action === 'add') {\n if (!labels || labels.length === 0) {\n throw new Error('라벨 목록을 입력해주세요.');\n }\n await labelApi.addLabels(pageId, labels);\n return {\n content: [{ type: 'text', text: `라벨 추가 성공: ${labels.join(', ')}` }],\n };\n } else if (action === 'remove') {\n if (!label) {\n throw new Error('삭제할 라벨을 입력해주세요.');\n }\n await labelApi.removeLabel(pageId, label);\n return {\n content: [{ type: 'text', text: `라벨 삭제 성공: ${label}` }],\n };\n }\n return { content: [] };\n }\n );\n\n server.tool(\n 'confluence_convert_content',\n 'TDE Confluence 컨텐츠 포맷을 변환합니다. Markdown과 Confluence Storage Format 간 양방향 변환을 지원합니다.',\n {\n content: z.string().describe('변환할 컨텐츠'),\n format: z.enum(['storage_to_markdown', 'markdown_to_storage']).describe('변환 방향'),\n useAi: z.boolean().optional().describe('지능형 변환을 위해 AI를 사용할지 여부'),\n },\n async ({ content, format, useAi }) => {\n let result = '';\n if (useAi) {\n const sourceType = format === 'storage_to_markdown' ? 'storage-xml' : 'markdown';\n const targetType = format === 'storage_to_markdown' ? 'markdown' : 'storage-xml';\n const aiResult = await aiService.refine({\n sourceContent: content,\n sourceType,\n targetType\n });\n result = aiResult.convertedContent;\n } else {\n if (format === 'storage_to_markdown') {\n result = storageToMd.convert(content);\n } else {\n result = mdToStorage.convert(content);\n }\n }\n return {\n content: [{ type: 'text', text: result }],\n };\n }\n );\n\n } catch (error) {\n logger.warn(`Confluence 설정 로드 실패 또는 도구 등록 중 오류 발생: ${(error as Error).message}`);\n // Do not throw, just skip registration if config is missing (optional module pattern)\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { ConfluenceLabel } from '../types.js';\n\nexport class ConfluenceLabelApi {\n constructor(private client: AxiosInstance) { }\n\n async getLabels(pageId: string): Promise<ConfluenceLabel[]> {\n const response = await this.client.get(`/rest/api/content/${pageId}/label`);\n return response.data.results;\n }\n\n async addLabels(pageId: string, labels: string[]): Promise<void> {\n const data = labels.map(name => ({ prefix: 'global', name }));\n await this.client.post(`/rest/api/content/${pageId}/label`, data);\n }\n\n async removeLabel(pageId: string, labelName: string): Promise<void> {\n // Label deletion usually requires query param for name\n // /rest/api/content/{id}/label?name={name}\n await this.client.delete(`/rest/api/content/${pageId}/label`, {\n params: { name: labelName }\n });\n }\n}\n","import axios from 'axios';\nimport { loadAIConfig } from '../../common/config.js';\nimport { logger } from '../../common/logger.js';\n\nexport interface AIConversionRequest {\n sourceContent: string;\n sourceType: 'markdown' | 'storage-xml';\n targetType: 'markdown' | 'storage-xml';\n context?: string;\n}\n\nexport interface AIConversionResponse {\n convertedContent: string;\n confidence: number;\n warnings?: string[];\n}\n\nexport class AIConversionService {\n private config = loadAIConfig();\n\n async refine(request: AIConversionRequest): Promise<AIConversionResponse> {\n if (!this.config.openaiApiKey && !this.config.anthropicApiKey) {\n throw new Error('AI 변환을 위한 API 키가 설정되지 않았습니다.');\n }\n\n logger.info(`AI를 이용한 지능형 변환 시작: ${request.sourceType} -> ${request.targetType}`);\n\n try {\n // 실제 구현 시 제공자(OpenAI/Anthropic)에 따라 분기 처리\n // 현재는 OpenAI GPT-4o를 기본 예시로 함\n const prompt = this.buildPrompt(request);\n \n const response = await axios.post(\n 'https://api.openai.com/v1/chat/completions',\n {\n model: this.config.defaultModel,\n messages: [\n { role: 'system', content: '당신은 전문 기술 문서 변환 에이전트입니다. 주어진 텍스트를 대상 형식으로 완벽하게 변환하십시오. 추가 설명 없이 결과 데이터만 반환하십시오.' },\n { role: 'user', content: prompt }\n ],\n temperature: 0\n },\n {\n headers: {\n 'Authorization': `Bearer ${this.config.openaiApiKey}`,\n 'Content-Type': 'application/json'\n }\n }\n );\n\n const result = response.data.choices[0].message.content.trim();\n \n // Markdown 코드 블록이 포함되어 돌아온 경우 스트립 처리\n const cleanResult = result.replace(/^```[a-z]*\\n([\\s\\S]*)\\n```$/i, '$1');\n\n return {\n convertedContent: cleanResult,\n confidence: 0.95\n };\n } catch (error) {\n logger.error('AI 변환 중 오류 발생:', error);\n throw error;\n }\n }\n\n private buildPrompt(request: AIConversionRequest): string {\n return `\n원본 형식: ${request.sourceType}\n대상 형식: ${request.targetType}\n추가 컨텍스트: ${request.context || '없음'}\n\n다음 텍스트를 변환하십시오:\n\n${request.sourceContent}\n`;\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { JiraIssueApi } from '../api/issue.js';\nimport { JiraSearchApi } from '../api/search.js';\nimport { JiraTransitionApi } from '../api/transition.js';\nimport { JiraCommentApi } from '../api/comment.js';\nimport { JiraProjectApi } from '../api/project.js';\nimport { createJiraClient } from '../api/client.js';\nimport { loadJiraConfig } from '../../common/config.js';\nimport { logger } from '../../common/logger.js';\n\nexport function registerJiraTools(server: McpServer) {\n try {\n const config = loadJiraConfig();\n const client = createJiraClient(config);\n\n const issueApi = new JiraIssueApi(client);\n const searchApi = new JiraSearchApi(client);\n const transitionApi = new JiraTransitionApi(client);\n const commentApi = new JiraCommentApi(client);\n const projectApi = new JiraProjectApi(client);\n\n // 이슈 상세 조회\n server.tool(\n 'jira_get_issue',\n 'TDE JIRA 이슈를 상세 조회합니다. 이슈 키(예: PROJ-123)로 조회하며, 필드 목록을 지정할 수 있습니다.',\n {\n issueKey: z.string().describe('이슈 키 (예: PROJ-123)'),\n fields: z\n .array(z.string())\n .optional()\n .describe('조회할 필드 목록 (미지정 시 전체)'),\n },\n async ({ issueKey, fields }) => {\n const issue = await issueApi.getIssue(issueKey, fields);\n const f = issue.fields;\n\n const lines = [\n `Key: ${issue.key}`,\n `Summary: ${f.summary}`,\n `Status: ${f.status?.name || 'N/A'}`,\n `Type: ${f.issuetype?.name || 'N/A'}`,\n `Priority: ${f.priority?.name || 'N/A'}`,\n `Assignee: ${f.assignee?.displayName || '미배정'}`,\n `Reporter: ${f.reporter?.displayName || 'N/A'}`,\n `Labels: ${f.labels?.join(', ') || '없음'}`,\n `Created: ${f.created || 'N/A'}`,\n `Updated: ${f.updated || 'N/A'}`,\n ];\n\n if (f.parent) {\n lines.push(`Parent: ${f.parent.key} - ${f.parent.fields?.summary || ''}`);\n }\n\n if (f.description) {\n lines.push('', '--- Description ---', f.description);\n }\n\n if (f.subtasks && f.subtasks.length > 0) {\n lines.push(\n '',\n '--- Subtasks ---',\n ...f.subtasks.map(\n (st) => `- [${st.key}] ${st.fields.summary} (${st.fields.status.name})`,\n ),\n );\n }\n\n return {\n content: [{ type: 'text', text: lines.join('\\n') }],\n };\n },\n );\n\n // 이슈 생성\n server.tool(\n 'jira_create_issue',\n 'TDE JIRA에 새 이슈를 생성합니다.',\n {\n projectKey: z.string().describe('프로젝트 키 (예: PROJ)'),\n summary: z.string().describe('이슈 제목'),\n issueType: z.string().describe('이슈 유형 (예: Task, Bug, Story, Sub-task)'),\n description: z.string().optional().describe('이슈 설명'),\n assignee: z.string().optional().describe('담당자 사용자 이름'),\n priority: z.string().optional().describe('우선순위 (예: High, Medium, Low)'),\n labels: z.array(z.string()).optional().describe('라벨 목록'),\n components: z.array(z.string()).optional().describe('컴포넌트 이름 목록'),\n parentKey: z\n .string()\n .optional()\n .describe('상위 이슈 키 (Sub-task 생성 시)'),\n },\n async ({ projectKey, summary, issueType, description, assignee, priority, labels, components, parentKey }) => {\n const issue = await issueApi.createIssue({\n projectKey,\n summary,\n issueType,\n description,\n assignee,\n priority,\n labels,\n components,\n parentKey,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `이슈 생성 성공: ${issue.key}\\nURL: ${config.baseUrl}/browse/${issue.key}`,\n },\n ],\n };\n },\n );\n\n // 이슈 수정\n server.tool(\n 'jira_update_issue',\n 'TDE JIRA 이슈를 수정합니다.',\n {\n issueKey: z.string().describe('이슈 키'),\n summary: z.string().optional().describe('이슈 제목'),\n description: z.string().optional().describe('이슈 설명'),\n assignee: z.string().optional().describe('담당자 (빈 문자열로 배정 해제)'),\n priority: z.string().optional().describe('우선순위'),\n labels: z.array(z.string()).optional().describe('라벨 목록 (전체 교체)'),\n components: z.array(z.string()).optional().describe('컴포넌트 목록 (전체 교체)'),\n },\n async ({ issueKey, summary, description, assignee, priority, labels, components }) => {\n await issueApi.updateIssue(issueKey, {\n summary,\n description,\n assignee,\n priority,\n labels,\n components,\n });\n\n return {\n content: [{ type: 'text', text: `이슈 수정 성공: ${issueKey}` }],\n };\n },\n );\n\n // JQL 검색\n server.tool(\n 'jira_search_issues',\n 'TDE JIRA에서 JQL(JIRA Query Language)로 이슈를 검색합니다.',\n {\n jql: z.string().describe('JQL 쿼리 (예: project = PROJ AND status = Open)'),\n maxResults: z.number().default(20).describe('최대 결과 수'),\n fields: z\n .array(z.string())\n .optional()\n .describe('조회할 필드 목록'),\n },\n async ({ jql, maxResults, fields }) => {\n const result = await searchApi.searchByJql(jql, 0, maxResults, fields);\n const summary = result.issues\n .map(\n (i) =>\n `- [${i.key}] ${i.fields.summary} (${i.fields.status?.name || 'N/A'}, ${i.fields.assignee?.displayName || '미배정'})`,\n )\n .join('\\n');\n\n return {\n content: [\n {\n type: 'text',\n text: `검색 결과 (${result.issues.length}/${result.total}):\\n${summary}`,\n },\n ],\n };\n },\n );\n\n // 상태 변경 (트랜지션)\n server.tool(\n 'jira_transition_issue',\n 'TDE JIRA 이슈의 상태를 변경합니다. 가능한 트랜지션 목록 조회 또는 트랜지션 실행을 할 수 있습니다.',\n {\n issueKey: z.string().describe('이슈 키'),\n action: z\n .enum(['list', 'do'])\n .describe('작업 유형: list(가능한 트랜지션 조회), do(트랜지션 실행)'),\n transitionId: z\n .string()\n .optional()\n .describe('트랜지션 ID (do 작업 시 필수)'),\n },\n async ({ issueKey, action, transitionId }) => {\n if (action === 'list') {\n const transitions = await transitionApi.getTransitions(issueKey);\n const summary = transitions\n .map((t) => `- [${t.id}] ${t.name} → ${t.to.name}`)\n .join('\\n');\n return {\n content: [\n { type: 'text', text: `가능한 트랜지션:\\n${summary}` },\n ],\n };\n } else {\n if (!transitionId) {\n throw new Error('트랜지션 ID를 입력해주세요.');\n }\n await transitionApi.doTransition(issueKey, transitionId);\n return {\n content: [\n { type: 'text', text: `트랜지션 완료: ${issueKey}` },\n ],\n };\n }\n },\n );\n\n // 코멘트 관리\n server.tool(\n 'jira_manage_comments',\n 'TDE JIRA 이슈의 코멘트를 관리합니다. 조회, 추가, 수정, 삭제 기능을 제공합니다.',\n {\n issueKey: z.string().describe('이슈 키'),\n action: z\n .enum(['list', 'add', 'update', 'delete'])\n .describe('작업 유형'),\n body: z\n .string()\n .optional()\n .describe('코멘트 내용 (add, update 시 필수)'),\n commentId: z\n .string()\n .optional()\n .describe('코멘트 ID (update, delete 시 필수)'),\n },\n async ({ issueKey, action, body, commentId }) => {\n if (action === 'list') {\n const result = await commentApi.getComments(issueKey);\n const summary = result.comments\n .map(\n (c) =>\n `- [${c.id}] ${c.author.displayName} (${c.created}):\\n ${c.body.substring(0, 200)}`,\n )\n .join('\\n');\n return {\n content: [\n {\n type: 'text',\n text: `코멘트 목록 (${result.comments.length}/${result.total}):\\n${summary}`,\n },\n ],\n };\n } else if (action === 'add') {\n if (!body) throw new Error('코멘트 내용을 입력해주세요.');\n const comment = await commentApi.addComment(issueKey, body);\n return {\n content: [\n { type: 'text', text: `코멘트 추가 성공 (ID: ${comment.id})` },\n ],\n };\n } else if (action === 'update') {\n if (!commentId) throw new Error('코멘트 ID를 입력해주세요.');\n if (!body) throw new Error('코멘트 내용을 입력해주세요.');\n await commentApi.updateComment(issueKey, commentId, body);\n return {\n content: [{ type: 'text', text: `코멘트 수정 성공 (ID: ${commentId})` }],\n };\n } else {\n if (!commentId) throw new Error('코멘트 ID를 입력해주세요.');\n await commentApi.deleteComment(issueKey, commentId);\n return {\n content: [{ type: 'text', text: `코멘트 삭제 성공 (ID: ${commentId})` }],\n };\n }\n },\n );\n\n // 프로젝트/보드 조회\n server.tool(\n 'jira_get_projects',\n 'TDE JIRA 프로젝트 목록 또는 Agile 보드/스프린트를 조회합니다.',\n {\n action: z\n .enum(['projects', 'project', 'boards', 'sprints'])\n .describe('조회 유형'),\n projectKey: z\n .string()\n .optional()\n .describe('프로젝트 키 (project, boards 조회 시)'),\n boardId: z\n .number()\n .optional()\n .describe('보드 ID (sprints 조회 시 필수)'),\n sprintState: z\n .string()\n .optional()\n .describe('스프린트 상태 필터 (active, closed, future)'),\n },\n async ({ action, projectKey, boardId, sprintState }) => {\n if (action === 'projects') {\n const projects = await projectApi.getProjects();\n const summary = projects\n .map((p) => `- [${p.key}] ${p.name} (Lead: ${p.lead?.displayName || 'N/A'})`)\n .join('\\n');\n return {\n content: [{ type: 'text', text: `프로젝트 목록:\\n${summary}` }],\n };\n } else if (action === 'project') {\n if (!projectKey) throw new Error('프로젝트 키를 입력해주세요.');\n const project = await projectApi.getProject(projectKey);\n const issueTypes = project.issueTypes\n ?.map((t) => t.name)\n .join(', ');\n return {\n content: [\n {\n type: 'text',\n text: `프로젝트: ${project.name} (${project.key})\\nLead: ${project.lead?.displayName || 'N/A'}\\nIssue Types: ${issueTypes || 'N/A'}`,\n },\n ],\n };\n } else if (action === 'boards') {\n const result = await projectApi.getBoards(projectKey);\n const summary = result.values\n .map((b) => `- [${b.id}] ${b.name} (${b.type})`)\n .join('\\n');\n return {\n content: [{ type: 'text', text: `보드 목록:\\n${summary}` }],\n };\n } else {\n if (!boardId) throw new Error('보드 ID를 입력해주세요.');\n const result = await projectApi.getSprints(boardId, sprintState);\n const summary = result.values\n .map(\n (s) =>\n `- [${s.id}] ${s.name} (${s.state})${s.goal ? ' - ' + s.goal : ''}`,\n )\n .join('\\n');\n return {\n content: [{ type: 'text', text: `스프린트 목록:\\n${summary}` }],\n };\n }\n },\n );\n } catch (error) {\n logger.warn(\n `JIRA 설정 로드 실패 또는 도구 등록 중 오류 발생: ${(error as Error).message}`,\n );\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { GitlabProjectApi } from '../api/project.js';\nimport { GitlabMergeRequestApi } from '../api/merge-request.js';\nimport { GitlabPipelineApi } from '../api/pipeline.js';\nimport { GitlabBranchApi } from '../api/branch.js';\nimport { GitlabRepositoryApi } from '../api/repository.js';\nimport { createGitlabClient } from '../api/client.js';\nimport { loadGitlabConfig } from '../../common/config.js';\nimport { logger } from '../../common/logger.js';\n\nexport function registerGitlabTools(server: McpServer) {\n try {\n const config = loadGitlabConfig();\n const client = createGitlabClient(config);\n\n const projectApi = new GitlabProjectApi(client);\n const mrApi = new GitlabMergeRequestApi(client);\n const pipelineApi = new GitlabPipelineApi(client);\n const branchApi = new GitlabBranchApi(client);\n const repoApi = new GitlabRepositoryApi(client);\n\n // 1. 프로젝트 조회\n server.tool(\n 'gitlab_get_project',\n 'TDE GitLab 프로젝트를 조회합니다. projectId 지정 시 상세 조회, 미지정 시 목록 조회합니다.',\n {\n projectId: z\n .number()\n .optional()\n .describe('프로젝트 ID (지정 시 상세 조회)'),\n search: z.string().optional().describe('프로젝트명 검색 (목록 조회 시)'),\n owned: z.boolean().optional().describe('소유 프로젝트만 필터'),\n membership: z.boolean().optional().describe('멤버십 프로젝트만 필터'),\n },\n async ({ projectId, search, owned, membership }) => {\n if (projectId) {\n const project = await projectApi.getProject(projectId);\n const lines = [\n `ID: ${project.id}`,\n `Name: ${project.name_with_namespace}`,\n `Path: ${project.path_with_namespace}`,\n `Default Branch: ${project.default_branch}`,\n `Visibility: ${project.visibility}`,\n `Web URL: ${project.web_url}`,\n `SSH URL: ${project.ssh_url_to_repo}`,\n `HTTP URL: ${project.http_url_to_repo}`,\n `Last Activity: ${project.last_activity_at}`,\n ];\n if (project.description) {\n lines.push(`Description: ${project.description}`);\n }\n return { content: [{ type: 'text', text: lines.join('\\n') }] };\n } else {\n const projects = await projectApi.getProjects({\n search,\n owned,\n membership,\n });\n const summary = projects\n .map(\n (p) =>\n `- [${p.id}] ${p.name_with_namespace} (${p.visibility}) - ${p.web_url}`,\n )\n .join('\\n');\n return {\n content: [\n {\n type: 'text',\n text: `프로젝트 목록 (${projects.length}건):\\n${summary}`,\n },\n ],\n };\n }\n },\n );\n\n // 2. MR 조회\n server.tool(\n 'gitlab_get_merge_request',\n 'TDE GitLab Merge Request를 조회합니다. mrIid 지정 시 상세 조회, 미지정 시 목록 조회합니다.',\n {\n projectId: z.number().describe('프로젝트 ID'),\n mrIid: z.number().optional().describe('MR IID (지정 시 상세 조회)'),\n state: z\n .enum(['opened', 'closed', 'merged', 'all'])\n .optional()\n .describe('상태 필터 (목록 조회 시)'),\n includeChanges: z\n .boolean()\n .optional()\n .describe('변경 파일 포함 여부 (상세 조회 시)'),\n },\n async ({ projectId, mrIid, state, includeChanges }) => {\n if (mrIid) {\n const mr = includeChanges\n ? await mrApi.getMergeRequestChanges(projectId, mrIid)\n : await mrApi.getMergeRequest(projectId, mrIid);\n const lines = [\n `IID: !${mr.iid}`,\n `Title: ${mr.title}`,\n `State: ${mr.state}`,\n `Source: ${mr.source_branch} → Target: ${mr.target_branch}`,\n `Author: ${mr.author?.name || 'N/A'}`,\n `Assignee: ${mr.assignee?.name || '미배정'}`,\n `Merge Status: ${mr.merge_status}`,\n `Has Conflicts: ${mr.has_conflicts}`,\n `Pipeline: ${mr.pipeline?.status || 'N/A'}`,\n `Web URL: ${mr.web_url}`,\n `Created: ${mr.created_at}`,\n `Updated: ${mr.updated_at}`,\n ];\n if (mr.description) {\n lines.push('', '--- Description ---', mr.description);\n }\n if (mr.changes && mr.changes.length > 0) {\n lines.push(\n '',\n `--- Changes (${mr.changes.length}개 파일) ---`,\n ...mr.changes.map(\n (c) =>\n `- ${c.new_file ? '[NEW] ' : c.deleted_file ? '[DEL] ' : c.renamed_file ? '[REN] ' : ''}${c.new_path}`,\n ),\n );\n }\n return { content: [{ type: 'text', text: lines.join('\\n') }] };\n } else {\n const mrs = await mrApi.getMergeRequests(projectId, { state });\n const summary = mrs\n .map(\n (m) =>\n `- [!${m.iid}] ${m.title} (${m.state}, ${m.source_branch} → ${m.target_branch}) by ${m.author?.name || 'N/A'}`,\n )\n .join('\\n');\n return {\n content: [\n {\n type: 'text',\n text: `MR 목록 (${mrs.length}건):\\n${summary}`,\n },\n ],\n };\n }\n },\n );\n\n // 3. MR 생성\n server.tool(\n 'gitlab_create_merge_request',\n 'TDE GitLab에 새 Merge Request를 생성합니다.',\n {\n projectId: z.number().describe('프로젝트 ID'),\n sourceBranch: z.string().describe('소스 브랜치'),\n targetBranch: z.string().describe('타겟 브랜치'),\n title: z.string().describe('MR 제목'),\n description: z.string().optional().describe('MR 설명'),\n },\n async ({ projectId, sourceBranch, targetBranch, title, description }) => {\n const mr = await mrApi.createMergeRequest(projectId, {\n source_branch: sourceBranch,\n target_branch: targetBranch,\n title,\n description,\n });\n return {\n content: [\n {\n type: 'text',\n text: `MR 생성 성공: !${mr.iid}\\nTitle: ${mr.title}\\nURL: ${mr.web_url}`,\n },\n ],\n };\n },\n );\n\n // 4. MR 관리 (머지/닫기/재열기/코멘트)\n server.tool(\n 'gitlab_manage_merge_request',\n 'TDE GitLab MR를 관리합니다. 머지, 닫기, 재열기, 코멘트 추가 작업을 수행합니다.',\n {\n projectId: z.number().describe('프로젝트 ID'),\n mrIid: z.number().describe('MR IID'),\n action: z\n .enum(['merge', 'close', 'reopen', 'comment'])\n .describe('작업 유형'),\n comment: z.string().optional().describe('코멘트 내용 (action=comment 시 필수)'),\n squash: z.boolean().optional().describe('스쿼시 머지 (action=merge 시)'),\n removeSourceBranch: z\n .boolean()\n .optional()\n .describe('소스 브랜치 삭제 (action=merge 시)'),\n },\n async ({ projectId, mrIid, action, comment, squash, removeSourceBranch }) => {\n if (action === 'merge') {\n const mr = await mrApi.mergeMergeRequest(projectId, mrIid, {\n squash,\n should_remove_source_branch: removeSourceBranch,\n });\n return {\n content: [\n {\n type: 'text',\n text: `MR !${mrIid} 머지 성공\\nState: ${mr.state}`,\n },\n ],\n };\n } else if (action === 'close' || action === 'reopen') {\n const mr = await mrApi.updateMergeRequest(projectId, mrIid, {\n state_event: action,\n });\n const msg = action === 'close' ? '닫기' : '재열기';\n return {\n content: [\n {\n type: 'text',\n text: `MR !${mrIid} ${msg} 성공\\nState: ${mr.state}`,\n },\n ],\n };\n } else {\n if (!comment) throw new Error('코멘트 내용을 입력해주세요.');\n const note = await mrApi.addMergeRequestNote(projectId, mrIid, comment);\n return {\n content: [\n {\n type: 'text',\n text: `MR !${mrIid}에 코멘트 추가 성공 (ID: ${note.id})`,\n },\n ],\n };\n }\n },\n );\n\n // 5. 파이프라인 조회\n server.tool(\n 'gitlab_get_pipelines',\n 'TDE GitLab CI/CD 파이프라인을 조회합니다. pipelineId 지정 시 상세 조회, 미지정 시 목록 조회합니다.',\n {\n projectId: z.number().describe('프로젝트 ID'),\n pipelineId: z.number().optional().describe('파이프라인 ID (지정 시 상세 조회)'),\n status: z.string().optional().describe('상태 필터 (running, success, failed 등)'),\n ref: z.string().optional().describe('브랜치/태그 필터'),\n includeJobs: z.boolean().optional().describe('작업(Job) 목록 포함 여부'),\n },\n async ({ projectId, pipelineId, status, ref, includeJobs }) => {\n if (pipelineId) {\n const pipeline = await pipelineApi.getPipeline(projectId, pipelineId);\n const lines = [\n `ID: ${pipeline.id}`,\n `Status: ${pipeline.status}`,\n `Ref: ${pipeline.ref}`,\n `SHA: ${pipeline.sha}`,\n `Created: ${pipeline.created_at}`,\n `Duration: ${pipeline.duration ? pipeline.duration + 's' : 'N/A'}`,\n `Web URL: ${pipeline.web_url}`,\n ];\n if (includeJobs) {\n const jobs = await pipelineApi.getPipelineJobs(projectId, pipelineId);\n lines.push(\n '',\n `--- Jobs (${jobs.length}개) ---`,\n ...jobs.map(\n (j) =>\n `- [${j.stage}] ${j.name}: ${j.status} (${j.duration ? j.duration + 's' : 'N/A'})`,\n ),\n );\n }\n return { content: [{ type: 'text', text: lines.join('\\n') }] };\n } else {\n const pipelines = await pipelineApi.getPipelines(projectId, {\n status,\n ref,\n });\n const summary = pipelines\n .map(\n (p) =>\n `- [${p.id}] ${p.status} (ref: ${p.ref}, sha: ${p.sha.substring(0, 8)}) ${p.web_url}`,\n )\n .join('\\n');\n return {\n content: [\n {\n type: 'text',\n text: `파이프라인 목록 (${pipelines.length}건):\\n${summary}`,\n },\n ],\n };\n }\n },\n );\n\n // 6. 브랜치 관리\n server.tool(\n 'gitlab_manage_branches',\n 'TDE GitLab 브랜치를 관리합니다. 목록 조회, 상세 조회, 생성, 삭제 작업을 수행합니다.',\n {\n projectId: z.number().describe('프로젝트 ID'),\n action: z\n .enum(['list', 'get', 'create', 'delete'])\n .describe('작업 유형'),\n branchName: z\n .string()\n .optional()\n .describe('브랜치 이름 (get/create/delete 시 필수)'),\n ref: z.string().optional().describe('기준 ref (create 시 필수)'),\n search: z.string().optional().describe('검색 키워드 (list 시)'),\n },\n async ({ projectId, action, branchName, ref, search }) => {\n if (action === 'list') {\n const branches = await branchApi.getBranches(projectId, { search });\n const summary = branches\n .map(\n (b) =>\n `- ${b.name}${b.default ? ' [default]' : ''}${b.protected ? ' [protected]' : ''} (${b.commit.short_id}: ${b.commit.message.split('\\n')[0]})`,\n )\n .join('\\n');\n return {\n content: [\n {\n type: 'text',\n text: `브랜치 목록 (${branches.length}건):\\n${summary}`,\n },\n ],\n };\n } else if (action === 'get') {\n if (!branchName) throw new Error('브랜치 이름을 입력해주세요.');\n const branch = await branchApi.getBranch(projectId, branchName);\n const lines = [\n `Name: ${branch.name}`,\n `Default: ${branch.default}`,\n `Protected: ${branch.protected}`,\n `Merged: ${branch.merged}`,\n `Commit: ${branch.commit.id}`,\n `Message: ${branch.commit.message}`,\n `Author: ${branch.commit.author_name}`,\n `Date: ${branch.commit.authored_date}`,\n ];\n return { content: [{ type: 'text', text: lines.join('\\n') }] };\n } else if (action === 'create') {\n if (!branchName) throw new Error('브랜치 이름을 입력해주세요.');\n if (!ref) throw new Error('기준 ref를 입력해주세요.');\n const branch = await branchApi.createBranch(projectId, branchName, ref);\n return {\n content: [\n {\n type: 'text',\n text: `브랜치 생성 성공: ${branch.name} (from ${ref})`,\n },\n ],\n };\n } else {\n if (!branchName) throw new Error('브랜치 이름을 입력해주세요.');\n await branchApi.deleteBranch(projectId, branchName);\n return {\n content: [\n { type: 'text', text: `브랜치 삭제 성공: ${branchName}` },\n ],\n };\n }\n },\n );\n\n // 7. 파일/트리 조회\n server.tool(\n 'gitlab_get_file',\n 'TDE GitLab 저장소의 파일 내용 또는 디렉토리 트리를 조회합니다.',\n {\n projectId: z.number().describe('프로젝트 ID'),\n path: z.string().describe('파일 경로 또는 디렉토리 경로'),\n ref: z.string().optional().describe('브랜치/태그/커밋 (기본: 기본 브랜치)'),\n type: z\n .enum(['file', 'tree'])\n .optional()\n .describe('\"file\" (기본) 또는 \"tree\"'),\n recursive: z.boolean().optional().describe('재귀 조회 (type=tree 시)'),\n },\n async ({ projectId, path, ref, type, recursive }) => {\n if (type === 'tree') {\n const entries = await repoApi.getTree(projectId, {\n path,\n ref,\n recursive,\n });\n const summary = entries\n .map((e) => `${e.type === 'tree' ? '📁' : '📄'} ${e.path}`)\n .join('\\n');\n return {\n content: [\n {\n type: 'text',\n text: `디렉토리 트리 (${entries.length}개 항목):\\n${summary}`,\n },\n ],\n };\n } else {\n const file = await repoApi.getFile(projectId, path, ref);\n const lines = [\n `File: ${file.file_path}`,\n `Size: ${file.size} bytes`,\n `Ref: ${file.ref}`,\n `Last Commit: ${file.last_commit_id}`,\n '',\n '--- Content ---',\n file.content,\n ];\n return { content: [{ type: 'text', text: lines.join('\\n') }] };\n }\n },\n );\n } catch (error) {\n logger.warn(\n `GitLab 설정 로드 실패 또는 도구 등록 중 오류 발생: ${(error as Error).message}`,\n );\n }\n}\n"],"mappings":"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","names":["z","z","z","z","path"]}
|