tdecollab 0.1.2 → 0.2.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/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/confluence/commands/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { registerConfluenceCommands } from './confluence/commands/index.js';\nimport dotenv from 'dotenv';\n\n// Load environment variables\ndotenv.config();\n\nconst program = new Command();\n\nprogram\n .name('tdecollab')\n .description('TDE Collaboration CLI')\n .version('0.1.0');\n\n// Register module commands\nregisterConfluenceCommands(program);\n\nprogram\n .command('mcp')\n .description('Run MCP Server')\n .action(async () => {\n const { runServer } = await import('./mcp/server.js');\n await runServer();\n });\n\nprogram.parse(process.argv);\n","import { Command } from 'commander';\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 { loadConfluenceConfig } from '../../common/config.js';\nimport { logger } from '../../common/logger.js';\nimport chalk from 'chalk';\nimport Table from 'cli-table3';\n\nexport function registerConfluenceCommands(program: Command) {\n const confluenceCmd = program.command('confluence')\n .description('Confluence 관리');\n\n // 공통 초기화 함수\n const initClient = () => {\n try {\n const config = loadConfluenceConfig();\n return createConfluenceClient(config);\n } catch (e: any) {\n console.error(chalk.red(`설정 로드 실패: ${e.message}`));\n process.exit(1);\n }\n };\n\n // --- Page Commands ---\n const pageCmd = confluenceCmd.command('page').description('페이지 관리');\n\n pageCmd.command('get <pageId>')\n .description('페이지 조회')\n .option('-r, --raw', 'Raw Storage Format 출력')\n .option('-q, --quiet', '메타데이터 생략')\n .action(async (pageId, options) => {\n const client = initClient();\n const api = new ConfluenceContentApi(client);\n const storageToMd = new StorageToMarkdownConverter();\n try {\n const page = await api.getPage(pageId);\n\n if (!options.quiet) {\n console.log(chalk.bold(`Title: ${page.title}`));\n console.log(chalk.gray(`ID: ${page.id}`));\n console.log(`Space: ${page.space?.name} (${page.space?.key})`);\n console.log(`URL: ${page._links?.base}${page._links?.webui}`);\n }\n\n if (options.raw) {\n if (!options.quiet) console.log(chalk.dim('--- Content (Storage Format) ---'));\n if (page.body?.storage?.value) {\n console.log(page.body.storage.value);\n } else {\n if (!options.quiet) console.log(chalk.yellow('(No content)'));\n }\n } else {\n if (!options.quiet) console.log(chalk.dim('--- Content (Markdown) ---'));\n if (page.body?.storage?.value) {\n console.log(storageToMd.convert(page.body.storage.value));\n } else {\n if (!options.quiet) console.log(chalk.yellow('(No content)'));\n }\n }\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n pageCmd.command('create')\n .requiredOption('-s, --space <key>', '스페이스 키')\n .requiredOption('-t, --title <title>', '제목')\n .option('-c, --content <content>', '내용 (Markdown 텍스트)')\n .option('-f, --file <path>', '내용 파일 경로 (Markdown)')\n .option('-p, --parent <id>', '부모 페이지 ID')\n .description('페이지 생성')\n .action(async (options) => {\n const client = initClient();\n const api = new ConfluenceContentApi(client);\n const mdToStorage = new MarkdownToStorageConverter();\n\n try {\n let markdownContent = '';\n\n if (options.file) {\n try {\n const filePath = path.resolve(process.cwd(), options.file);\n markdownContent = fs.readFileSync(filePath, 'utf-8');\n } catch (e: any) {\n console.error(chalk.red(`파일 읽기 실패: ${e.message}`));\n process.exit(1);\n }\n } else if (options.content) {\n markdownContent = options.content;\n } else {\n console.error(chalk.red('오류: --content 또는 --file 옵션 중 하나는 필수입니다.'));\n process.exit(1);\n }\n\n const page = await api.createPage({\n spaceKey: options.space,\n title: options.title,\n body: mdToStorage.convert(markdownContent),\n parentId: options.parent\n });\n console.log(chalk.green(`페이지 생성 완료: ${page.title} (ID: ${page.id})`));\n console.log(`URL: ${page._links?.base}${page._links?.webui}`);\n } catch (e: any) {\n console.error(chalk.red(`생성 실패: ${e.message}`));\n }\n });\n\n // --- Space Commands ---\n const spaceCmd = confluenceCmd.command('space').description('스페이스 관리');\n\n spaceCmd.command('list')\n .description('스페이스 목록 조회')\n .action(async () => {\n const client = initClient();\n const api = new ConfluenceSpaceApi(client);\n try {\n const spaces = await api.getSpaces();\n const table = new Table({\n head: ['Key', 'Name', 'Type', 'ID'],\n style: { head: ['cyan'] }\n });\n spaces.forEach(s => table.push([s.key, s.name, s.type, s.id.toString()]));\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`목록 조회 실패: ${e.message}`));\n }\n });\n\n // --- Search Commands ---\n confluenceCmd.command('search <cql>')\n .description('CQL 검색')\n .action(async (cql) => {\n const client = initClient();\n const api = new ConfluenceSearchApi(client);\n try {\n const result = await api.searchByCql(cql);\n console.log(chalk.bold(`검색 결과: ${result.size}건 (총 ${result.totalSize}건)`));\n const table = new Table({\n head: ['ID', 'Title', 'Space', 'URL'],\n style: { head: ['cyan'] }\n });\n result.results.forEach(p => table.push([\n p.id,\n p.title,\n p.space?.key || '',\n `${p._links?.base}${p._links?.webui}`\n ]));\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`검색 실패: ${e.message}`));\n }\n });\n}\n"],"mappings":"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","names":["program"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/confluence/commands/index.ts","../src/jira/commands/index.ts","../src/gitlab/commands/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { registerConfluenceCommands } from './confluence/commands/index.js';\nimport { registerJiraCommands } from './jira/commands/index.js';\nimport { registerGitlabCommands } from './gitlab/commands/index.js';\nimport dotenv from 'dotenv';\n\n// Load environment variables\ndotenv.config();\n\nconst program = new Command();\n\nprogram\n .name('tdecollab')\n .description('TDE Collaboration CLI')\n .version('0.1.0');\n\n// Register module commands\nregisterConfluenceCommands(program);\nregisterJiraCommands(program);\nregisterGitlabCommands(program);\n\nprogram\n .command('mcp')\n .description('Run MCP Server')\n .action(async () => {\n const { runServer } = await import('./mcp/server.js');\n await runServer();\n });\n\nprogram.parse(process.argv);\n","import { Command } from 'commander';\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 { loadConfluenceConfig } from '../../common/config.js';\nimport { logger } from '../../common/logger.js';\nimport chalk from 'chalk';\nimport Table from 'cli-table3';\n\nexport function registerConfluenceCommands(program: Command) {\n const confluenceCmd = program.command('confluence')\n .description('Confluence 관리');\n\n // 공통 초기화 함수\n const initClient = () => {\n try {\n const config = loadConfluenceConfig();\n return createConfluenceClient(config);\n } catch (e: any) {\n console.error(chalk.red(`설정 로드 실패: ${e.message}`));\n process.exit(1);\n }\n };\n\n // --- Page Commands ---\n const pageCmd = confluenceCmd.command('page').description('페이지 관리');\n\n pageCmd.command('get <pageId>')\n .description('페이지 조회')\n .option('-r, --raw', 'Raw Storage Format 출력')\n .option('-q, --quiet', '메타데이터 생략')\n .option('-d, --download-images', '이미지 다운로드')\n .option('--image-dir <path>', '이미지 저장 디렉토리', './images')\n .option('-o, --output <file>', 'Markdown을 파일로 저장')\n .action(async (pageId, options) => {\n const client = initClient();\n const api = new ConfluenceContentApi(client);\n const config = loadConfluenceConfig();\n\n try {\n const page = await api.getPage(pageId);\n\n if (!options.quiet) {\n console.log(chalk.bold(`Title: ${page.title}`));\n console.log(chalk.gray(`ID: ${page.id}`));\n console.log(`Space: ${page.space?.name} (${page.space?.key})`);\n console.log(`URL: ${page._links?.base}${page._links?.webui}`);\n }\n\n let content = '';\n\n if (options.raw) {\n if (!options.quiet) console.log(chalk.dim('--- Content (Storage Format) ---'));\n if (page.body?.storage?.value) {\n content = page.body.storage.value;\n } else {\n if (!options.quiet) console.log(chalk.yellow('(No content)'));\n }\n } else {\n if (!options.quiet) console.log(chalk.dim('--- Content (Markdown) ---'));\n if (page.body?.storage?.value) {\n let imageUrlMap: Map<string, string> | undefined;\n\n // 이미지 다운로드 옵션이 활성화된 경우\n if (options.downloadImages) {\n const { ImageDownloader } = await import('../utils/image-downloader.js');\n const downloader = new ImageDownloader(api, {\n outputDir: path.resolve(process.cwd(), options.imageDir),\n pageId: page.id,\n baseUrl: config.baseUrl\n });\n\n console.log(chalk.blue('이미지 다운로드 중...'));\n imageUrlMap = await downloader.downloadAllImages(page.body.storage.value);\n }\n\n const storageToMd = new StorageToMarkdownConverter();\n content = storageToMd.convert(page.body.storage.value, imageUrlMap);\n } else {\n if (!options.quiet) console.log(chalk.yellow('(No content)'));\n }\n }\n\n // 파일로 저장 또는 콘솔 출력\n if (options.output) {\n const outputPath = path.resolve(process.cwd(), options.output);\n fs.writeFileSync(outputPath, content, 'utf-8');\n console.log(chalk.green(`파일 저장 완료: ${outputPath}`));\n } else {\n console.log(content);\n }\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n pageCmd.command('create')\n .requiredOption('-s, --space <key>', '스페이스 키')\n .requiredOption('-t, --title <title>', '제목')\n .option('-c, --content <content>', '내용 (Markdown 텍스트)')\n .option('-f, --file <path>', '내용 파일 경로 (Markdown)')\n .option('-p, --parent <id>', '부모 페이지 ID')\n .description('페이지 생성')\n .action(async (options) => {\n const client = initClient();\n const api = new ConfluenceContentApi(client);\n const mdToStorage = new MarkdownToStorageConverter();\n\n try {\n let markdownContent = '';\n\n if (options.file) {\n try {\n const filePath = path.resolve(process.cwd(), options.file);\n markdownContent = fs.readFileSync(filePath, 'utf-8');\n } catch (e: any) {\n console.error(chalk.red(`파일 읽기 실패: ${e.message}`));\n process.exit(1);\n }\n } else if (options.content) {\n markdownContent = options.content;\n } else {\n console.error(chalk.red('오류: --content 또는 --file 옵션 중 하나는 필수입니다.'));\n process.exit(1);\n }\n\n const page = await api.createPage({\n spaceKey: options.space,\n title: options.title,\n body: mdToStorage.convert(markdownContent),\n parentId: options.parent\n });\n console.log(chalk.green(`페이지 생성 완료: ${page.title} (ID: ${page.id})`));\n console.log(`URL: ${page._links?.base}${page._links?.webui}`);\n } catch (e: any) {\n console.error(chalk.red(`생성 실패: ${e.message}`));\n }\n });\n\n // --- Space Commands ---\n const spaceCmd = confluenceCmd.command('space').description('스페이스 관리');\n\n spaceCmd.command('list')\n .description('스페이스 목록 조회')\n .action(async () => {\n const client = initClient();\n const api = new ConfluenceSpaceApi(client);\n try {\n const spaces = await api.getSpaces();\n const table = new Table({\n head: ['Key', 'Name', 'Type', 'ID'],\n style: { head: ['cyan'] }\n });\n spaces.forEach(s => table.push([s.key, s.name, s.type, s.id.toString()]));\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`목록 조회 실패: ${e.message}`));\n }\n });\n\n // --- Search Commands ---\n confluenceCmd.command('search <cql>')\n .description('CQL 검색')\n .action(async (cql) => {\n const client = initClient();\n const api = new ConfluenceSearchApi(client);\n try {\n const result = await api.searchByCql(cql);\n console.log(chalk.bold(`검색 결과: ${result.size}건 (총 ${result.totalSize}건)`));\n const table = new Table({\n head: ['ID', 'Title', 'Space', 'URL'],\n style: { head: ['cyan'] }\n });\n result.results.forEach(p => table.push([\n p.id,\n p.title,\n p.space?.key || '',\n `${p._links?.base}${p._links?.webui}`\n ]));\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`검색 실패: ${e.message}`));\n }\n });\n}\n","import { Command } from 'commander';\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 chalk from 'chalk';\nimport Table from 'cli-table3';\n\nexport function registerJiraCommands(program: Command) {\n const jiraCmd = program.command('jira').description('JIRA 관리');\n\n const initClient = () => {\n try {\n const config = loadJiraConfig();\n return createJiraClient(config);\n } catch (e: any) {\n console.error(chalk.red(`설정 로드 실패: ${e.message}`));\n process.exit(1);\n }\n };\n\n // --- Issue Commands ---\n const issueCmd = jiraCmd.command('issue').description('이슈 관리');\n\n issueCmd\n .command('get <issueKey>')\n .description('이슈 조회')\n .action(async (issueKey) => {\n const client = initClient();\n const api = new JiraIssueApi(client);\n try {\n const issue = await api.getIssue(issueKey);\n const f = issue.fields;\n\n console.log(chalk.bold(`[${issue.key}] ${f.summary}`));\n console.log(chalk.gray(`Status: ${f.status?.name || 'N/A'}`));\n console.log(`Type: ${f.issuetype?.name || 'N/A'}`);\n console.log(`Priority: ${f.priority?.name || 'N/A'}`);\n console.log(`Assignee: ${f.assignee?.displayName || '미배정'}`);\n console.log(`Reporter: ${f.reporter?.displayName || 'N/A'}`);\n console.log(`Labels: ${f.labels?.join(', ') || '없음'}`);\n console.log(`Created: ${f.created || 'N/A'}`);\n console.log(`Updated: ${f.updated || 'N/A'}`);\n\n if (f.description) {\n console.log(chalk.dim('\\n--- Description ---'));\n console.log(f.description);\n }\n\n if (f.subtasks && f.subtasks.length > 0) {\n console.log(chalk.dim('\\n--- Subtasks ---'));\n f.subtasks.forEach((st) => {\n console.log(` - [${st.key}] ${st.fields.summary} (${st.fields.status.name})`);\n });\n }\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n issueCmd\n .command('create')\n .requiredOption('-p, --project <key>', '프로젝트 키')\n .requiredOption('-s, --summary <summary>', '이슈 제목')\n .requiredOption('-t, --type <type>', '이슈 유형 (Task, Bug, Story 등)')\n .option('-d, --description <desc>', '이슈 설명')\n .option('-a, --assignee <name>', '담당자')\n .option('--priority <priority>', '우선순위')\n .option('-l, --labels <labels>', '라벨 (쉼표 구분)')\n .option('--parent <key>', '상위 이슈 키 (Sub-task)')\n .description('이슈 생성')\n .action(async (options) => {\n const client = initClient();\n const api = new JiraIssueApi(client);\n try {\n const issue = await api.createIssue({\n projectKey: options.project,\n summary: options.summary,\n issueType: options.type,\n description: options.description,\n assignee: options.assignee,\n priority: options.priority,\n labels: options.labels?.split(',').map((l: string) => l.trim()),\n parentKey: options.parent,\n });\n const config = loadJiraConfig();\n console.log(chalk.green(`이슈 생성 완료: ${issue.key}`));\n console.log(`URL: ${config.baseUrl}/browse/${issue.key}`);\n } catch (e: any) {\n console.error(chalk.red(`생성 실패: ${e.message}`));\n }\n });\n\n issueCmd\n .command('update <issueKey>')\n .option('-s, --summary <summary>', '제목')\n .option('-d, --description <desc>', '설명')\n .option('-a, --assignee <name>', '담당자')\n .option('--priority <priority>', '우선순위')\n .option('-l, --labels <labels>', '라벨 (쉼표 구분)')\n .description('이슈 수정')\n .action(async (issueKey, options) => {\n const client = initClient();\n const api = new JiraIssueApi(client);\n try {\n await api.updateIssue(issueKey, {\n summary: options.summary,\n description: options.description,\n assignee: options.assignee,\n priority: options.priority,\n labels: options.labels?.split(',').map((l: string) => l.trim()),\n });\n console.log(chalk.green(`이슈 수정 완료: ${issueKey}`));\n } catch (e: any) {\n console.error(chalk.red(`수정 실패: ${e.message}`));\n }\n });\n\n issueCmd\n .command('transition <issueKey>')\n .option('-l, --list', '가능한 트랜지션 조회')\n .option('-t, --transition <id>', '트랜지션 실행')\n .description('이슈 상태 변경')\n .action(async (issueKey, options) => {\n const client = initClient();\n const api = new JiraTransitionApi(client);\n try {\n if (options.list || !options.transition) {\n const transitions = await api.getTransitions(issueKey);\n const table = new Table({\n head: ['ID', 'Name', 'To'],\n style: { head: ['cyan'] },\n });\n transitions.forEach((t) => table.push([t.id, t.name, t.to.name]));\n console.log(table.toString());\n } else {\n await api.doTransition(issueKey, options.transition);\n console.log(chalk.green(`트랜지션 완료: ${issueKey}`));\n }\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n // --- Search Command ---\n jiraCmd\n .command('search <jql>')\n .option('-n, --max <number>', '최대 결과 수', '20')\n .description('JQL 검색')\n .action(async (jql, options) => {\n const client = initClient();\n const api = new JiraSearchApi(client);\n try {\n const result = await api.searchByJql(jql, 0, parseInt(options.max));\n console.log(chalk.bold(`검색 결과: ${result.issues.length}건 (총 ${result.total}건)`));\n const table = new Table({\n head: ['Key', 'Summary', 'Status', 'Assignee'],\n style: { head: ['cyan'] },\n });\n result.issues.forEach((i) =>\n table.push([\n i.key,\n i.fields.summary.substring(0, 60),\n i.fields.status?.name || 'N/A',\n i.fields.assignee?.displayName || '미배정',\n ]),\n );\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`검색 실패: ${e.message}`));\n }\n });\n\n // --- Comment Commands ---\n const commentCmd = jiraCmd.command('comment').description('코멘트 관리');\n\n commentCmd\n .command('list <issueKey>')\n .description('코멘트 목록 조회')\n .action(async (issueKey) => {\n const client = initClient();\n const api = new JiraCommentApi(client);\n try {\n const result = await api.getComments(issueKey);\n result.comments.forEach((c) => {\n console.log(chalk.bold(`[${c.id}] ${c.author.displayName} (${c.created})`));\n console.log(c.body);\n console.log(chalk.dim('---'));\n });\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n commentCmd\n .command('add <issueKey> <body>')\n .description('코멘트 추가')\n .action(async (issueKey, body) => {\n const client = initClient();\n const api = new JiraCommentApi(client);\n try {\n const comment = await api.addComment(issueKey, body);\n console.log(chalk.green(`코멘트 추가 완료 (ID: ${comment.id})`));\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n // --- Project Commands ---\n const projectCmd = jiraCmd.command('project').description('프로젝트 관리');\n\n projectCmd\n .command('list')\n .description('프로젝트 목록 조회')\n .action(async () => {\n const client = initClient();\n const api = new JiraProjectApi(client);\n try {\n const projects = await api.getProjects();\n const table = new Table({\n head: ['Key', 'Name', 'Lead'],\n style: { head: ['cyan'] },\n });\n projects.forEach((p) =>\n table.push([p.key, p.name, p.lead?.displayName || 'N/A']),\n );\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n projectCmd\n .command('get <projectKey>')\n .description('프로젝트 상세 조회')\n .action(async (projectKey) => {\n const client = initClient();\n const api = new JiraProjectApi(client);\n try {\n const project = await api.getProject(projectKey);\n console.log(chalk.bold(`${project.name} (${project.key})`));\n console.log(`Lead: ${project.lead?.displayName || 'N/A'}`);\n if (project.issueTypes) {\n console.log(\n `Issue Types: ${project.issueTypes.map((t) => t.name).join(', ')}`,\n );\n }\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n // --- Board Commands ---\n const boardCmd = jiraCmd.command('board').description('Agile 보드 관리');\n\n boardCmd\n .command('list')\n .option('-p, --project <key>', '프로젝트 키')\n .description('보드 목록 조회')\n .action(async (options) => {\n const client = initClient();\n const api = new JiraProjectApi(client);\n try {\n const result = await api.getBoards(options.project);\n const table = new Table({\n head: ['ID', 'Name', 'Type'],\n style: { head: ['cyan'] },\n });\n result.values.forEach((b) => table.push([b.id.toString(), b.name, b.type]));\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n boardCmd\n .command('sprints <boardId>')\n .option('-s, --state <state>', '상태 필터 (active, closed, future)')\n .description('스프린트 목록 조회')\n .action(async (boardId, options) => {\n const client = initClient();\n const api = new JiraProjectApi(client);\n try {\n const result = await api.getSprints(parseInt(boardId), options.state);\n const table = new Table({\n head: ['ID', 'Name', 'State', 'Goal'],\n style: { head: ['cyan'] },\n });\n result.values.forEach((s) =>\n table.push([s.id.toString(), s.name, s.state, s.goal || '']),\n );\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n}\n","import { Command } from 'commander';\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 chalk from 'chalk';\nimport Table from 'cli-table3';\n\nexport function registerGitlabCommands(program: Command) {\n const gitlabCmd = program.command('gitlab').description('GitLab 관리');\n\n const initClient = () => {\n try {\n const config = loadGitlabConfig();\n return createGitlabClient(config);\n } catch (e: any) {\n console.error(chalk.red(`설정 로드 실패: ${e.message}`));\n process.exit(1);\n }\n };\n\n // --- Project Commands ---\n const projectCmd = gitlabCmd.command('project').description('프로젝트 관리');\n\n projectCmd\n .command('list')\n .option('-s, --search <query>', '프로젝트명 검색')\n .option('--owned', '소유 프로젝트만')\n .option('--membership', '멤버십 프로젝트만')\n .description('프로젝트 목록 조회')\n .action(async (options) => {\n const client = initClient();\n const api = new GitlabProjectApi(client);\n try {\n const projects = await api.getProjects({\n search: options.search,\n owned: options.owned,\n membership: options.membership,\n });\n const table = new Table({\n head: ['ID', 'Name', 'Visibility', 'Default Branch', 'Last Activity'],\n style: { head: ['cyan'] },\n });\n projects.forEach((p) =>\n table.push([\n p.id.toString(),\n p.name_with_namespace,\n p.visibility,\n p.default_branch || 'N/A',\n p.last_activity_at?.substring(0, 10) || 'N/A',\n ]),\n );\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n projectCmd\n .command('get <projectId>')\n .description('프로젝트 상세 조회')\n .action(async (projectId) => {\n const client = initClient();\n const api = new GitlabProjectApi(client);\n try {\n const p = await api.getProject(parseInt(projectId));\n console.log(chalk.bold(p.name_with_namespace));\n console.log(`ID: ${p.id}`);\n console.log(`Path: ${p.path_with_namespace}`);\n console.log(`Default Branch: ${p.default_branch}`);\n console.log(`Visibility: ${p.visibility}`);\n console.log(`Web URL: ${p.web_url}`);\n console.log(`SSH URL: ${p.ssh_url_to_repo}`);\n console.log(`HTTP URL: ${p.http_url_to_repo}`);\n console.log(`Last Activity: ${p.last_activity_at}`);\n if (p.description) console.log(`Description: ${p.description}`);\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n // --- MR Commands ---\n const mrCmd = gitlabCmd.command('mr').description('Merge Request 관리');\n\n mrCmd\n .command('list <projectId>')\n .option('-s, --state <state>', '상태 필터 (opened/closed/merged/all)', 'opened')\n .option('--scope <scope>', '범위 (created_by_me/assigned_to_me)')\n .description('MR 목록 조회')\n .action(async (projectId, options) => {\n const client = initClient();\n const api = new GitlabMergeRequestApi(client);\n try {\n const mrs = await api.getMergeRequests(parseInt(projectId), {\n state: options.state,\n scope: options.scope,\n });\n const table = new Table({\n head: ['IID', 'Title', 'State', 'Source → Target', 'Author'],\n style: { head: ['cyan'] },\n });\n mrs.forEach((m) =>\n table.push([\n `!${m.iid}`,\n m.title.substring(0, 50),\n m.state,\n `${m.source_branch} → ${m.target_branch}`,\n m.author?.name || 'N/A',\n ]),\n );\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n mrCmd\n .command('get <projectId> <mrIid>')\n .option('-c, --changes', '변경 파일 포함')\n .description('MR 상세 조회')\n .action(async (projectId, mrIid, options) => {\n const client = initClient();\n const api = new GitlabMergeRequestApi(client);\n try {\n const mr = options.changes\n ? await api.getMergeRequestChanges(parseInt(projectId), parseInt(mrIid))\n : await api.getMergeRequest(parseInt(projectId), parseInt(mrIid));\n\n console.log(chalk.bold(`[!${mr.iid}] ${mr.title}`));\n console.log(`State: ${mr.state}`);\n console.log(`Source: ${mr.source_branch} → Target: ${mr.target_branch}`);\n console.log(`Author: ${mr.author?.name || 'N/A'}`);\n console.log(`Assignee: ${mr.assignee?.name || '미배정'}`);\n console.log(`Merge Status: ${mr.merge_status}`);\n console.log(`Has Conflicts: ${mr.has_conflicts}`);\n console.log(`Pipeline: ${mr.pipeline?.status || 'N/A'}`);\n console.log(`URL: ${mr.web_url}`);\n\n if (mr.description) {\n console.log(chalk.dim('\\n--- Description ---'));\n console.log(mr.description);\n }\n\n if (mr.changes && mr.changes.length > 0) {\n console.log(chalk.dim(`\\n--- Changes (${mr.changes.length}개 파일) ---`));\n mr.changes.forEach((c) => {\n const prefix = c.new_file\n ? '[NEW]'\n : c.deleted_file\n ? '[DEL]'\n : c.renamed_file\n ? '[REN]'\n : '[MOD]';\n console.log(` ${prefix} ${c.new_path}`);\n });\n }\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n mrCmd\n .command('create <projectId>')\n .requiredOption('--source <branch>', '소스 브랜치')\n .requiredOption('--target <branch>', '타겟 브랜치')\n .requiredOption('--title <text>', 'MR 제목')\n .option('-d, --description <text>', 'MR 설명')\n .description('MR 생성')\n .action(async (projectId, options) => {\n const client = initClient();\n const api = new GitlabMergeRequestApi(client);\n try {\n const mr = await api.createMergeRequest(parseInt(projectId), {\n source_branch: options.source,\n target_branch: options.target,\n title: options.title,\n description: options.description,\n });\n console.log(chalk.green(`MR 생성 완료: !${mr.iid}`));\n console.log(`URL: ${mr.web_url}`);\n } catch (e: any) {\n console.error(chalk.red(`생성 실패: ${e.message}`));\n }\n });\n\n mrCmd\n .command('merge <projectId> <mrIid>')\n .option('--squash', '스쿼시 머지')\n .option('--remove-source-branch', '소스 브랜치 삭제')\n .description('MR 머지')\n .action(async (projectId, mrIid, options) => {\n const client = initClient();\n const api = new GitlabMergeRequestApi(client);\n try {\n const mr = await api.mergeMergeRequest(parseInt(projectId), parseInt(mrIid), {\n squash: options.squash,\n should_remove_source_branch: options.removeSourceBranch,\n });\n console.log(chalk.green(`MR !${mrIid} 머지 완료`));\n console.log(`State: ${mr.state}`);\n } catch (e: any) {\n console.error(chalk.red(`머지 실패: ${e.message}`));\n }\n });\n\n mrCmd\n .command('close <projectId> <mrIid>')\n .description('MR 닫기')\n .action(async (projectId, mrIid) => {\n const client = initClient();\n const api = new GitlabMergeRequestApi(client);\n try {\n await api.updateMergeRequest(parseInt(projectId), parseInt(mrIid), {\n state_event: 'close',\n });\n console.log(chalk.green(`MR !${mrIid} 닫기 완료`));\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n mrCmd\n .command('comment <projectId> <mrIid>')\n .requiredOption('-b, --body <text>', '코멘트 내용')\n .description('MR 코멘트 추가')\n .action(async (projectId, mrIid, options) => {\n const client = initClient();\n const api = new GitlabMergeRequestApi(client);\n try {\n const note = await api.addMergeRequestNote(\n parseInt(projectId),\n parseInt(mrIid),\n options.body,\n );\n console.log(chalk.green(`코멘트 추가 완료 (ID: ${note.id})`));\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n // --- Pipeline Commands ---\n const pipelineCmd = gitlabCmd.command('pipeline').description('파이프라인 관리');\n\n pipelineCmd\n .command('list <projectId>')\n .option('-s, --status <status>', '상태 필터')\n .option('-r, --ref <branch>', '브랜치/태그 필터')\n .description('파이프라인 목록 조회')\n .action(async (projectId, options) => {\n const client = initClient();\n const api = new GitlabPipelineApi(client);\n try {\n const pipelines = await api.getPipelines(parseInt(projectId), {\n status: options.status,\n ref: options.ref,\n });\n const table = new Table({\n head: ['ID', 'Status', 'Ref', 'SHA', 'Created'],\n style: { head: ['cyan'] },\n });\n pipelines.forEach((p) =>\n table.push([\n p.id.toString(),\n p.status,\n p.ref,\n p.sha.substring(0, 8),\n p.created_at?.substring(0, 10) || 'N/A',\n ]),\n );\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n pipelineCmd\n .command('get <projectId> <pipelineId>')\n .option('-j, --jobs', '작업 목록 포함')\n .description('파이프라인 상세 조회')\n .action(async (projectId, pipelineId, options) => {\n const client = initClient();\n const api = new GitlabPipelineApi(client);\n try {\n const p = await api.getPipeline(parseInt(projectId), parseInt(pipelineId));\n console.log(chalk.bold(`Pipeline #${p.id}`));\n console.log(`Status: ${p.status}`);\n console.log(`Ref: ${p.ref}`);\n console.log(`SHA: ${p.sha}`);\n console.log(`Duration: ${p.duration ? p.duration + 's' : 'N/A'}`);\n console.log(`URL: ${p.web_url}`);\n\n if (options.jobs) {\n const jobs = await api.getPipelineJobs(\n parseInt(projectId),\n parseInt(pipelineId),\n );\n console.log(chalk.dim(`\\n--- Jobs (${jobs.length}개) ---`));\n const table = new Table({\n head: ['Stage', 'Name', 'Status', 'Duration'],\n style: { head: ['cyan'] },\n });\n jobs.forEach((j) =>\n table.push([\n j.stage,\n j.name,\n j.status,\n j.duration ? j.duration + 's' : 'N/A',\n ]),\n );\n console.log(table.toString());\n }\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n // --- Branch Commands ---\n const branchCmd = gitlabCmd.command('branch').description('브랜치 관리');\n\n branchCmd\n .command('list <projectId>')\n .option('-s, --search <query>', '검색 키워드')\n .description('브랜치 목록 조회')\n .action(async (projectId, options) => {\n const client = initClient();\n const api = new GitlabBranchApi(client);\n try {\n const branches = await api.getBranches(parseInt(projectId), {\n search: options.search,\n });\n const table = new Table({\n head: ['Name', 'Commit', 'Message', 'Protected', 'Default'],\n style: { head: ['cyan'] },\n });\n branches.forEach((b) =>\n table.push([\n b.name,\n b.commit.short_id,\n b.commit.message.split('\\n')[0].substring(0, 40),\n b.protected ? 'Yes' : 'No',\n b.default ? 'Yes' : 'No',\n ]),\n );\n console.log(table.toString());\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n branchCmd\n .command('get <projectId> <branchName>')\n .description('브랜치 상세 조회')\n .action(async (projectId, branchName) => {\n const client = initClient();\n const api = new GitlabBranchApi(client);\n try {\n const b = await api.getBranch(parseInt(projectId), branchName);\n console.log(chalk.bold(b.name));\n console.log(`Default: ${b.default}`);\n console.log(`Protected: ${b.protected}`);\n console.log(`Merged: ${b.merged}`);\n console.log(`Commit: ${b.commit.id}`);\n console.log(`Message: ${b.commit.message}`);\n console.log(`Author: ${b.commit.author_name}`);\n console.log(`Date: ${b.commit.authored_date}`);\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n branchCmd\n .command('create <projectId>')\n .requiredOption('-n, --name <branch>', '브랜치 이름')\n .requiredOption('-r, --ref <ref>', '기준 ref')\n .description('브랜치 생성')\n .action(async (projectId, options) => {\n const client = initClient();\n const api = new GitlabBranchApi(client);\n try {\n const b = await api.createBranch(\n parseInt(projectId),\n options.name,\n options.ref,\n );\n console.log(chalk.green(`브랜치 생성 완료: ${b.name}`));\n } catch (e: any) {\n console.error(chalk.red(`생성 실패: ${e.message}`));\n }\n });\n\n branchCmd\n .command('delete <projectId> <branchName>')\n .description('브랜치 삭제')\n .action(async (projectId, branchName) => {\n const client = initClient();\n const api = new GitlabBranchApi(client);\n try {\n await api.deleteBranch(parseInt(projectId), branchName);\n console.log(chalk.green(`브랜치 삭제 완료: ${branchName}`));\n } catch (e: any) {\n console.error(chalk.red(`삭제 실패: ${e.message}`));\n }\n });\n\n // --- File Commands ---\n const fileCmd = gitlabCmd.command('file').description('파일 관리');\n\n fileCmd\n .command('get <projectId> <filePath>')\n .option('-r, --ref <ref>', '브랜치/태그/커밋')\n .description('파일 내용 조회')\n .action(async (projectId, filePath, options) => {\n const client = initClient();\n const api = new GitlabRepositoryApi(client);\n try {\n const file = await api.getFile(parseInt(projectId), filePath, options.ref);\n console.log(chalk.bold(file.file_path));\n console.log(chalk.gray(`Size: ${file.size} bytes | Ref: ${file.ref}`));\n console.log(chalk.dim('---'));\n console.log(file.content);\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n\n fileCmd\n .command('tree <projectId>')\n .option('-p, --path <dir>', '디렉토리 경로')\n .option('-r, --ref <ref>', '브랜치/태그')\n .option('--recursive', '재귀 조회')\n .description('디렉토리 트리 조회')\n .action(async (projectId, options) => {\n const client = initClient();\n const api = new GitlabRepositoryApi(client);\n try {\n const entries = await api.getTree(parseInt(projectId), {\n path: options.path,\n ref: options.ref,\n recursive: options.recursive,\n });\n entries.forEach((e) => {\n const icon = e.type === 'tree' ? '📁' : '📄';\n console.log(`${icon} ${e.path}`);\n });\n } catch (e: any) {\n console.error(chalk.red(`Error: ${e.message}`));\n }\n });\n}\n"],"mappings":"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","names":["program","chalk","Table","program","chalk","Table","program"]}
@@ -0,0 +1,123 @@
1
+ import {
2
+ logger
3
+ } from "./chunk-SJ7KPK6Q.js";
4
+
5
+ // src/confluence/utils/image-downloader.ts
6
+ import fs from "fs";
7
+ import path from "path";
8
+ var ImageDownloader = class {
9
+ constructor(api, options) {
10
+ this.api = api;
11
+ this.options = options;
12
+ }
13
+ // Storage HTML에서 이미지 참조 추출
14
+ extractImageReferences(html) {
15
+ const references = [];
16
+ const attachmentRegex = /<ac:image[^>]*>[\s\S]*?<ri:attachment\s+ri:filename="([^"]+)"[\s\S]*?<\/ac:image>/g;
17
+ let match;
18
+ while ((match = attachmentRegex.exec(html)) !== null) {
19
+ references.push({
20
+ type: "attachment",
21
+ filename: match[1],
22
+ originalTag: match[0]
23
+ });
24
+ }
25
+ const urlInAcImageRegex = /<ac:image[^>]*>[\s\S]*?<ri:url\s+ri:value="([^"]+)"[\s\S]*?<\/ac:image>/g;
26
+ while ((match = urlInAcImageRegex.exec(html)) !== null) {
27
+ references.push({
28
+ type: "url",
29
+ url: match[1],
30
+ originalTag: match[0]
31
+ });
32
+ }
33
+ const imgRegex = /<img\s+[^>]*\/?>/g;
34
+ while ((match = imgRegex.exec(html)) !== null) {
35
+ const imgTag = match[0];
36
+ const srcMatch = /src="([^"]+)"/.exec(imgTag);
37
+ const altMatch = /alt="([^"]*)"/.exec(imgTag);
38
+ if (srcMatch) {
39
+ references.push({
40
+ type: "url",
41
+ url: srcMatch[1],
42
+ originalTag: imgTag,
43
+ altText: altMatch ? altMatch[1] : ""
44
+ });
45
+ }
46
+ }
47
+ return references;
48
+ }
49
+ // 파일명 sanitize (특수문자 제거)
50
+ sanitizeFilename(filename) {
51
+ return filename.replace(/[^a-zA-Z0-9._-]/g, "_");
52
+ }
53
+ // 파일명 중복 처리
54
+ getUniqueFilename(dir, filename) {
55
+ const sanitized = this.sanitizeFilename(filename);
56
+ const ext = path.extname(sanitized);
57
+ const base = path.basename(sanitized, ext);
58
+ let counter = 1;
59
+ let uniqueName = sanitized;
60
+ while (fs.existsSync(path.join(dir, uniqueName))) {
61
+ uniqueName = `${base}_${counter}${ext}`;
62
+ counter++;
63
+ }
64
+ return uniqueName;
65
+ }
66
+ // 이미지 다운로드 및 로컬 경로 반환
67
+ async downloadImage(ref) {
68
+ try {
69
+ let buffer;
70
+ let filename;
71
+ if (ref.type === "attachment" && ref.filename) {
72
+ logger.info(`Downloading attachment: ${ref.filename}`);
73
+ const attachments = await this.api.getAttachments(this.options.pageId, ref.filename);
74
+ if (attachments.length === 0) {
75
+ logger.warn(`Attachment not found: ${ref.filename}`);
76
+ return null;
77
+ }
78
+ const attachment = attachments[0];
79
+ const downloadUrl = attachment._links.download;
80
+ const fullUrl = downloadUrl.startsWith("http") ? downloadUrl : `${this.options.baseUrl}${downloadUrl}`;
81
+ buffer = await this.api.downloadAttachment(fullUrl);
82
+ filename = ref.filename;
83
+ } else if (ref.type === "url" && ref.url) {
84
+ logger.info(`Downloading image from URL: ${ref.url}`);
85
+ const urlPath = new URL(ref.url).pathname;
86
+ filename = path.basename(urlPath) || "image.png";
87
+ buffer = await this.api.downloadAttachment(ref.url);
88
+ } else {
89
+ logger.warn(`Invalid image reference: ${JSON.stringify(ref)}`);
90
+ return null;
91
+ }
92
+ if (!fs.existsSync(this.options.outputDir)) {
93
+ fs.mkdirSync(this.options.outputDir, { recursive: true });
94
+ }
95
+ const uniqueFilename = this.getUniqueFilename(this.options.outputDir, filename);
96
+ const outputPath = path.join(this.options.outputDir, uniqueFilename);
97
+ fs.writeFileSync(outputPath, buffer);
98
+ logger.info(`Image saved: ${outputPath}`);
99
+ return outputPath;
100
+ } catch (error) {
101
+ logger.error(`Failed to download image: ${error.message}`);
102
+ return null;
103
+ }
104
+ }
105
+ // 모든 이미지 다운로드 및 매핑 반환 (원본 태그 -> 로컬 경로)
106
+ async downloadAllImages(html) {
107
+ const references = this.extractImageReferences(html);
108
+ const mapping = /* @__PURE__ */ new Map();
109
+ logger.info(`Found ${references.length} image(s) to download`);
110
+ for (const ref of references) {
111
+ const localPath = await this.downloadImage(ref);
112
+ if (localPath) {
113
+ mapping.set(ref.originalTag, localPath);
114
+ }
115
+ }
116
+ logger.info(`Successfully downloaded ${mapping.size} image(s)`);
117
+ return mapping;
118
+ }
119
+ };
120
+ export {
121
+ ImageDownloader
122
+ };
123
+ //# sourceMappingURL=image-downloader-D57KFAIQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/confluence/utils/image-downloader.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport { ConfluenceContentApi } from '../api/content.js';\nimport { logger } from '../../common/logger.js';\n\nexport interface ImageDownloadOptions {\n outputDir: string; // 이미지 저장 디렉토리\n pageId: string; // 페이지 ID\n baseUrl: string; // Confluence base URL\n}\n\nexport interface ImageReference {\n type: 'attachment' | 'url';\n filename?: string; // attachment인 경우\n url?: string; // URL인 경우\n originalTag: string; // 원본 태그\n altText?: string; // 대체 텍스트\n}\n\nexport class ImageDownloader {\n constructor(\n private api: ConfluenceContentApi,\n private options: ImageDownloadOptions,\n ) { }\n\n // Storage HTML에서 이미지 참조 추출\n extractImageReferences(html: string): ImageReference[] {\n const references: ImageReference[] = [];\n\n // 1. ac:image 태그에서 attachment 추출\n // <ac:image><ri:attachment ri:filename=\"image.png\" /></ac:image>\n const attachmentRegex =\n /<ac:image[^>]*>[\\s\\S]*?<ri:attachment\\s+ri:filename=\"([^\"]+)\"[\\s\\S]*?<\\/ac:image>/g;\n let match;\n while ((match = attachmentRegex.exec(html)) !== null) {\n references.push({\n type: 'attachment',\n filename: match[1],\n originalTag: match[0],\n });\n }\n\n // 2. ac:image 태그에서 URL 추출\n // <ac:image><ri:url ri:value=\"https://example.com/image.png\" /></ac:image>\n const urlInAcImageRegex =\n /<ac:image[^>]*>[\\s\\S]*?<ri:url\\s+ri:value=\"([^\"]+)\"[\\s\\S]*?<\\/ac:image>/g;\n while ((match = urlInAcImageRegex.exec(html)) !== null) {\n references.push({\n type: 'url',\n url: match[1],\n originalTag: match[0],\n });\n }\n\n // 3. 일반 img 태그\n // <img src=\"https://example.com/image.png\" alt=\"description\" />\n const imgRegex = /<img\\s+[^>]*\\/?>/g;\n while ((match = imgRegex.exec(html)) !== null) {\n const imgTag = match[0];\n // src 추출\n const srcMatch = /src=\"([^\"]+)\"/.exec(imgTag);\n // alt 추출\n const altMatch = /alt=\"([^\"]*)\"/.exec(imgTag);\n\n if (srcMatch) {\n references.push({\n type: 'url',\n url: srcMatch[1],\n originalTag: imgTag,\n altText: altMatch ? altMatch[1] : '',\n });\n }\n }\n\n return references;\n }\n\n // 파일명 sanitize (특수문자 제거)\n private sanitizeFilename(filename: string): string {\n return filename.replace(/[^a-zA-Z0-9._-]/g, '_');\n }\n\n // 파일명 중복 처리\n private getUniqueFilename(dir: string, filename: string): string {\n const sanitized = this.sanitizeFilename(filename);\n const ext = path.extname(sanitized);\n const base = path.basename(sanitized, ext);\n\n let counter = 1;\n let uniqueName = sanitized;\n\n while (fs.existsSync(path.join(dir, uniqueName))) {\n uniqueName = `${base}_${counter}${ext}`;\n counter++;\n }\n\n return uniqueName;\n }\n\n // 이미지 다운로드 및 로컬 경로 반환\n async downloadImage(ref: ImageReference): Promise<string | null> {\n try {\n let buffer: Buffer;\n let filename: string;\n\n if (ref.type === 'attachment' && ref.filename) {\n // Confluence attachment 다운로드\n logger.info(`Downloading attachment: ${ref.filename}`);\n const attachments = await this.api.getAttachments(this.options.pageId, ref.filename);\n\n if (attachments.length === 0) {\n logger.warn(`Attachment not found: ${ref.filename}`);\n return null;\n }\n\n const attachment = attachments[0];\n const downloadUrl = attachment._links.download;\n\n // download URL이 상대 경로인 경우 base URL 추가\n const fullUrl = downloadUrl.startsWith('http')\n ? downloadUrl\n : `${this.options.baseUrl}${downloadUrl}`;\n\n buffer = await this.api.downloadAttachment(fullUrl);\n filename = ref.filename;\n } else if (ref.type === 'url' && ref.url) {\n // 외부 URL 이미지 다운로드\n logger.info(`Downloading image from URL: ${ref.url}`);\n\n // URL에서 파일명 추출\n const urlPath = new URL(ref.url).pathname;\n filename = path.basename(urlPath) || 'image.png';\n\n // axios를 사용하여 다운로드 (api client 재사용)\n buffer = await this.api.downloadAttachment(ref.url);\n } else {\n logger.warn(`Invalid image reference: ${JSON.stringify(ref)}`);\n return null;\n }\n\n // 출력 디렉토리 생성\n if (!fs.existsSync(this.options.outputDir)) {\n fs.mkdirSync(this.options.outputDir, { recursive: true });\n }\n\n // 고유한 파일명 생성\n const uniqueFilename = this.getUniqueFilename(this.options.outputDir, filename);\n const outputPath = path.join(this.options.outputDir, uniqueFilename);\n\n // 파일 저장\n fs.writeFileSync(outputPath, buffer);\n logger.info(`Image saved: ${outputPath}`);\n\n return outputPath;\n } catch (error: any) {\n logger.error(`Failed to download image: ${error.message}`);\n return null;\n }\n }\n\n // 모든 이미지 다운로드 및 매핑 반환 (원본 태그 -> 로컬 경로)\n async downloadAllImages(html: string): Promise<Map<string, string>> {\n const references = this.extractImageReferences(html);\n const mapping = new Map<string, string>();\n\n logger.info(`Found ${references.length} image(s) to download`);\n\n for (const ref of references) {\n const localPath = await this.downloadImage(ref);\n if (localPath) {\n mapping.set(ref.originalTag, localPath);\n }\n }\n\n logger.info(`Successfully downloaded ${mapping.size} image(s)`);\n return mapping;\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runServer
4
- } from "./chunk-3TQ2OSYU.js";
5
- import "./chunk-N44NISLJ.js";
4
+ } from "./chunk-T73I3OT6.js";
5
+ import "./chunk-2IQ4QMK3.js";
6
+ import "./chunk-SJ7KPK6Q.js";
6
7
 
7
8
  // src/index.ts
8
9
  runServer().catch((error) => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runServer } from './mcp/server.js';\n\n\nrunServer().catch((error) => {\n console.error('Fatal error in MCP Server entry point:', error);\n process.exit(1);\n});\n"],"mappings":";;;;;;;AAIA,UAAU,EAAE,MAAM,CAAC,UAAU;AACzB,UAAQ,MAAM,0CAA0C,KAAK;AAC7D,UAAQ,KAAK,CAAC;AAClB,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runServer } from './mcp/server.js';\n\n\nrunServer().catch((error) => {\n console.error('Fatal error in MCP Server entry point:', error);\n process.exit(1);\n});\n"],"mappings":";;;;;;;;AAIA,UAAU,EAAE,MAAM,CAAC,UAAU;AACzB,UAAQ,MAAM,0CAA0C,KAAK;AAC7D,UAAQ,KAAK,CAAC;AAClB,CAAC;","names":[]}
@@ -0,0 +1,9 @@
1
+ import {
2
+ runServer
3
+ } from "./chunk-T73I3OT6.js";
4
+ import "./chunk-2IQ4QMK3.js";
5
+ import "./chunk-SJ7KPK6Q.js";
6
+ export {
7
+ runServer
8
+ };
9
+ //# sourceMappingURL=server-HS774DWY.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tdecollab",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Confluence, Jira, GitLab CLI 및 MCP 통합 도구",
5
5
  "keywords": [
6
6
  "mcp",
@@ -51,4 +51,4 @@
51
51
  "engines": {
52
52
  "node": ">=20.0.0"
53
53
  }
54
- }
54
+ }