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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 goodjoon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
# tdecollab
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Confluence, JIRA, GitLab을 하나의 CLI / TUI / MCP 서버로 통합 제공하는 도구.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
터미널에서 직접 사용하거나, AI 에이전트(Claude Desktop 등)와 연동하여 사용할 수 있습니다.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
### 지원 서비스
|
|
7
|
+
## 지원 서비스
|
|
10
8
|
|
|
11
9
|
| 서비스 | 주요 기능 |
|
|
12
10
|
|--------|----------|
|
|
13
|
-
| **Confluence** | 페이지 CRUD, Markdown↔Storage 변환, 검색, 라벨 관리, 페이지 트리 조회 |
|
|
11
|
+
| **Confluence** | 페이지 CRUD, Markdown ↔ Storage Format 변환, 검색, 라벨 관리, 페이지 트리 조회 |
|
|
14
12
|
| **JIRA** | 이슈 CRUD, JQL 검색, 상태 변경(트랜지션), 코멘트 관리, 프로젝트/보드 조회 |
|
|
15
13
|
| **GitLab** | 프로젝트 조회, MR 관리, 파이프라인 조회, 브랜치 관리, 파일 조회 |
|
|
16
14
|
|
|
@@ -20,8 +18,6 @@ tdecollab은 TDE 포털에서 제공하는 협업 도구들을 하나의 CLI와
|
|
|
20
18
|
|
|
21
19
|
## 설치
|
|
22
20
|
|
|
23
|
-
### npm에서 설치 (권장)
|
|
24
|
-
|
|
25
21
|
```bash
|
|
26
22
|
# 전역 설치
|
|
27
23
|
npm install -g tdecollab
|
|
@@ -30,30 +26,19 @@ npm install -g tdecollab
|
|
|
30
26
|
npx -y tdecollab --help
|
|
31
27
|
```
|
|
32
28
|
|
|
33
|
-
### 소스에서 빌드 (개발자용)
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
git clone <repository-url>
|
|
37
|
-
cd tdecollab
|
|
38
|
-
pnpm install
|
|
39
|
-
pnpm build
|
|
40
|
-
```
|
|
41
|
-
|
|
42
29
|
## 설정
|
|
43
30
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
tdecollab은 다음 환경변수를 통해 각 서비스에 접속합니다:
|
|
31
|
+
각 서비스 접속에 필요한 환경변수:
|
|
47
32
|
|
|
48
33
|
```env
|
|
49
34
|
# Confluence
|
|
50
35
|
CONFLUENCE_BASE_URL=https://confluence.example.com
|
|
51
|
-
CONFLUENCE_USERNAME=your-username
|
|
36
|
+
CONFLUENCE_USERNAME=your-username # Basic Auth 사용 시 (선택)
|
|
52
37
|
CONFLUENCE_API_TOKEN=your-api-token
|
|
53
38
|
|
|
54
39
|
# JIRA
|
|
55
40
|
JIRA_BASE_URL=https://jira.example.com
|
|
56
|
-
JIRA_USERNAME=your-username
|
|
41
|
+
JIRA_USERNAME=your-username # PAT 사용 시 생략 가능 (선택)
|
|
57
42
|
JIRA_API_TOKEN=your-api-token
|
|
58
43
|
|
|
59
44
|
# GitLab
|
|
@@ -61,168 +46,71 @@ GITLAB_BASE_URL=https://gitlab.example.com # 미설정 시 https://gitlab.com
|
|
|
61
46
|
GITLAB_PRIVATE_TOKEN=your-private-token
|
|
62
47
|
```
|
|
63
48
|
|
|
64
|
-
|
|
49
|
+
세 가지 설정 방법:
|
|
65
50
|
|
|
66
|
-
|
|
51
|
+
1. **`.env` 파일** — 작업 디렉토리에 `.env` 파일을 두면 자동 로드됩니다.
|
|
52
|
+
2. **셸 환경변수** — `export CONFLUENCE_BASE_URL=...` 후 `tdecollab` 실행
|
|
53
|
+
3. **MCP 서버 설정** — Claude Desktop 설정 파일의 `env` 섹션에 추가 (아래 MCP 서버 섹션 참조)
|
|
67
54
|
|
|
68
|
-
|
|
69
|
-
# 프로젝트 루트에 .env 파일 생성
|
|
70
|
-
echo "CONFLUENCE_BASE_URL=https://confluence.example.com" > .env
|
|
71
|
-
echo "CONFLUENCE_API_TOKEN=your-token" >> .env
|
|
72
|
-
```
|
|
55
|
+
## 사용법
|
|
73
56
|
|
|
74
|
-
|
|
57
|
+
### TUI (Terminal UI) 모드
|
|
58
|
+
![[img_20260429004932.png]]
|
|
59
|
+
|
|
60
|
+
인자 없이 실행하면 인터랙티브 TUI가 시작됩니다 — 메뉴 탐색, 폼 입력, 실시간 결과 확인이 한 화면에서 가능합니다.
|
|
75
61
|
|
|
76
62
|
```bash
|
|
77
|
-
|
|
78
|
-
export CONFLUENCE_API_TOKEN=your-token
|
|
79
|
-
tdecollab confluence space list
|
|
63
|
+
tdecollab
|
|
80
64
|
```
|
|
81
65
|
|
|
82
|
-
|
|
66
|
+
| 단축키 | 동작 |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `↑↓` `Tab` `Shift+Tab` | 메뉴/필드 이동 |
|
|
69
|
+
| `↵` | 메뉴 펼치기 / 경로 선택창 / 토글 |
|
|
70
|
+
| `Ctrl+R` | 폼 실행 |
|
|
71
|
+
| `Ctrl+S` | 입력값을 프리셋으로 저장 |
|
|
72
|
+
| `Esc` | 뒤로 |
|
|
73
|
+
| `q` | 종료 |
|
|
74
|
+
| `j/k` `Ctrl+D/U` `Ctrl+F/B` `g/G` | 결과 마크다운 뷰 vim 스타일 스크롤 |
|
|
83
75
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
## 사용법
|
|
76
|
+
마지막 사용값은 `.tdecollab.json`에, 명령 히스토리는 `~/.tdecollab_history.json`에 자동 저장됩니다.
|
|
87
77
|
|
|
88
78
|
### CLI 명령어
|
|
89
79
|
|
|
90
80
|
#### Confluence
|
|
91
81
|
|
|
92
82
|
```bash
|
|
93
|
-
# 스페이스 목록
|
|
83
|
+
# 스페이스 목록
|
|
94
84
|
tdecollab confluence space list
|
|
95
85
|
|
|
96
|
-
#
|
|
97
|
-
tdecollab confluence page get <pageId>
|
|
98
|
-
tdecollab confluence page get <pageId> --raw # Storage Format 출력
|
|
99
|
-
tdecollab confluence page get <pageId> --quiet # 메타데이터 생략
|
|
100
|
-
tdecollab confluence page get <pageId> --raw --quiet > page.html
|
|
101
|
-
|
|
102
|
-
# 이미지 다운로드와 함께 페이지 조회
|
|
103
|
-
tdecollab confluence page get <pageId> --download-images # 이미지를 ./images에 다운로드
|
|
104
|
-
tdecollab confluence page get <pageId> -d --image-dir ./my-images # 커스텀 디렉토리에 다운로드
|
|
105
|
-
tdecollab confluence page get <pageId> -d -o page.md # Markdown 파일로 저장
|
|
106
|
-
tdecollab confluence page get <pageId> -d --image-dir ./assets -o page.md # 이미지와 함께 저장
|
|
107
|
-
|
|
108
|
-
# 페이지 생성
|
|
109
|
-
tdecollab confluence page create --space <key> --title <title> --content "Markdown 내용"
|
|
110
|
-
tdecollab confluence page create --space <key> --title <title> --file <path>
|
|
111
|
-
|
|
112
|
-
# 페이지 검색 (CQL)
|
|
113
|
-
tdecollab confluence search "title ~ 'guide'"
|
|
114
|
-
tdecollab confluence search "space = MYSPACE AND type = page"
|
|
115
|
-
```
|
|
86
|
+
# 페이지를 Markdown으로 다운로드 (이미지 포함)
|
|
87
|
+
tdecollab confluence page get <pageId> -d --image-dir ./assets -o page.md
|
|
116
88
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
# 이슈 관리
|
|
121
|
-
tdecollab jira issue get <issueKey> # 이슈 상세 조회
|
|
122
|
-
tdecollab jira issue create -p PROJ -s "제목" -t Task # 이슈 생성
|
|
123
|
-
tdecollab jira issue update <issueKey> -s "새 제목" # 이슈 수정
|
|
124
|
-
tdecollab jira issue transition <issueKey> -l # 가능한 트랜지션 조회
|
|
125
|
-
tdecollab jira issue transition <issueKey> -t <id> # 트랜지션 실행
|
|
126
|
-
|
|
127
|
-
# JQL 검색
|
|
128
|
-
tdecollab jira search "project = PROJ AND status = Open"
|
|
129
|
-
tdecollab jira search "assignee = currentUser()" -n 50
|
|
130
|
-
|
|
131
|
-
# 코멘트 관리
|
|
132
|
-
tdecollab jira comment list <issueKey>
|
|
133
|
-
tdecollab jira comment add <issueKey> "코멘트 내용"
|
|
134
|
-
|
|
135
|
-
# 프로젝트/보드
|
|
136
|
-
tdecollab jira project list
|
|
137
|
-
tdecollab jira project get <projectKey>
|
|
138
|
-
tdecollab jira board list [-p <projectKey>]
|
|
139
|
-
tdecollab jira board sprints <boardId> [-s active]
|
|
89
|
+
# 마크다운 파일로 페이지 생성/수정 (로컬 이미지 자동 업로드)
|
|
90
|
+
tdecollab confluence page create --space <key> --title <title> --file <path_to_md>
|
|
91
|
+
tdecollab confluence page update <pageId> --file <path_to_md>
|
|
140
92
|
```
|
|
141
93
|
|
|
142
|
-
#### GitLab
|
|
94
|
+
#### JIRA / GitLab
|
|
143
95
|
|
|
144
96
|
```bash
|
|
145
|
-
|
|
146
|
-
tdecollab
|
|
147
|
-
tdecollab gitlab
|
|
148
|
-
|
|
149
|
-
# Merge Request
|
|
150
|
-
tdecollab gitlab mr list <projectId> [-s opened|closed|merged|all]
|
|
151
|
-
tdecollab gitlab mr get <projectId> <mrIid> [--changes]
|
|
152
|
-
tdecollab gitlab mr create <projectId> --source <branch> --target <branch> --title <text>
|
|
153
|
-
tdecollab gitlab mr merge <projectId> <mrIid> [--squash] [--remove-source-branch]
|
|
154
|
-
tdecollab gitlab mr close <projectId> <mrIid>
|
|
155
|
-
tdecollab gitlab mr comment <projectId> <mrIid> -b "코멘트 내용"
|
|
156
|
-
|
|
157
|
-
# 파이프라인
|
|
158
|
-
tdecollab gitlab pipeline list <projectId> [--status <status>] [--ref <branch>]
|
|
159
|
-
tdecollab gitlab pipeline get <projectId> <pipelineId> [--jobs]
|
|
160
|
-
|
|
161
|
-
# 브랜치
|
|
162
|
-
tdecollab gitlab branch list <projectId> [--search <query>]
|
|
163
|
-
tdecollab gitlab branch get <projectId> <branchName>
|
|
164
|
-
tdecollab gitlab branch create <projectId> --name <branch> --ref <ref>
|
|
165
|
-
tdecollab gitlab branch delete <projectId> <branchName>
|
|
166
|
-
|
|
167
|
-
# 파일/저장소
|
|
168
|
-
tdecollab gitlab file get <projectId> <filePath> [--ref <ref>]
|
|
169
|
-
tdecollab gitlab file tree <projectId> [--path <dir>] [--ref <ref>] [--recursive]
|
|
97
|
+
tdecollab jira issue get PROJ-1234
|
|
98
|
+
tdecollab jira search "assignee = currentUser() AND status != Done"
|
|
99
|
+
tdecollab gitlab mr list <projectId> -s opened
|
|
170
100
|
```
|
|
171
101
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
MCP
|
|
175
|
-
|
|
176
|
-
#### Confluence (9개)
|
|
177
|
-
|
|
178
|
-
| 도구 | 설명 |
|
|
179
|
-
|------|------|
|
|
180
|
-
| `confluence_get_page` | 페이지 상세 조회 (Markdown 변환) |
|
|
181
|
-
| `confluence_create_page` | 새 페이지 생성 (Markdown → Storage Format 자동 변환) |
|
|
182
|
-
| `confluence_update_page` | 페이지 수정 |
|
|
183
|
-
| `confluence_delete_page` | 페이지 삭제 |
|
|
184
|
-
| `confluence_search_pages` | CQL로 페이지 검색 |
|
|
185
|
-
| `confluence_get_spaces` | 스페이스 목록 조회 |
|
|
186
|
-
| `confluence_get_page_tree` | 하위 페이지(자식 페이지) 목록 조회 |
|
|
187
|
-
| `confluence_manage_labels` | 페이지 라벨 조회/추가/삭제 |
|
|
188
|
-
| `confluence_convert_content` | Markdown ↔ Storage Format 양방향 변환 |
|
|
189
|
-
|
|
190
|
-
#### JIRA (7개)
|
|
191
|
-
|
|
192
|
-
| 도구 | 설명 |
|
|
193
|
-
|------|------|
|
|
194
|
-
| `jira_get_issue` | 이슈 상세 조회 |
|
|
195
|
-
| `jira_create_issue` | 새 이슈 생성 |
|
|
196
|
-
| `jira_update_issue` | 이슈 수정 |
|
|
197
|
-
| `jira_search_issues` | JQL로 이슈 검색 |
|
|
198
|
-
| `jira_transition_issue` | 이슈 상태 변경 (트랜지션 조회/실행) |
|
|
199
|
-
| `jira_manage_comments` | 코멘트 조회/추가/수정/삭제 |
|
|
200
|
-
| `jira_get_projects` | 프로젝트/보드/스프린트 조회 |
|
|
201
|
-
|
|
202
|
-
#### GitLab (7개)
|
|
203
|
-
|
|
204
|
-
| 도구 | 설명 |
|
|
205
|
-
|------|------|
|
|
206
|
-
| `gitlab_get_project` | 프로젝트 목록 또는 상세 조회 |
|
|
207
|
-
| `gitlab_get_merge_request` | MR 목록 또는 상세 조회 (변경 파일 포함 가능) |
|
|
208
|
-
| `gitlab_create_merge_request` | 새 Merge Request 생성 |
|
|
209
|
-
| `gitlab_manage_merge_request` | MR 머지/닫기/재열기/코멘트 추가 |
|
|
210
|
-
| `gitlab_get_pipelines` | 파이프라인 목록 또는 상세 조회 (Job 포함 가능) |
|
|
211
|
-
| `gitlab_manage_branches` | 브랜치 목록/상세/생성/삭제 |
|
|
212
|
-
| `gitlab_get_file` | 파일 내용 또는 디렉토리 트리 조회 |
|
|
213
|
-
|
|
214
|
-
### MCP 서버 (Claude Desktop 연동)
|
|
102
|
+
`tdecollab <service> --help` 또는 `tdecollab <service> <command> --help`로 모든 옵션을 확인할 수 있습니다.
|
|
103
|
+
|
|
104
|
+
## MCP 서버 (Claude Desktop 연동)
|
|
215
105
|
|
|
216
106
|
Claude Desktop에서 Confluence, JIRA, GitLab 도구를 사용할 수 있습니다.
|
|
217
107
|
|
|
218
|
-
|
|
108
|
+
### 설정 파일 위치
|
|
219
109
|
|
|
220
110
|
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
221
111
|
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
222
112
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
별도 설치 없이 최신 버전을 자동으로 실행합니다:
|
|
113
|
+
### npx 사용 (권장 — 별도 설치 불필요)
|
|
226
114
|
|
|
227
115
|
```json
|
|
228
116
|
{
|
|
@@ -244,7 +132,7 @@ Claude Desktop에서 Confluence, JIRA, GitLab 도구를 사용할 수 있습니
|
|
|
244
132
|
}
|
|
245
133
|
```
|
|
246
134
|
|
|
247
|
-
|
|
135
|
+
### 전역 설치 후 사용
|
|
248
136
|
|
|
249
137
|
```bash
|
|
250
138
|
npm install -g tdecollab
|
|
@@ -258,29 +146,6 @@ npm install -g tdecollab
|
|
|
258
146
|
"args": ["mcp"],
|
|
259
147
|
"env": {
|
|
260
148
|
"CONFLUENCE_BASE_URL": "https://confluence.example.com",
|
|
261
|
-
"CONFLUENCE_USERNAME": "your-username",
|
|
262
|
-
"CONFLUENCE_API_TOKEN": "your-api-token",
|
|
263
|
-
"JIRA_BASE_URL": "https://jira.example.com",
|
|
264
|
-
"JIRA_API_TOKEN": "your-jira-token",
|
|
265
|
-
"GITLAB_BASE_URL": "https://gitlab.example.com",
|
|
266
|
-
"GITLAB_PRIVATE_TOKEN": "your-gitlab-token"
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
#### 로컬 개발 버전 사용
|
|
274
|
-
|
|
275
|
-
```json
|
|
276
|
-
{
|
|
277
|
-
"mcpServers": {
|
|
278
|
-
"tdecollab-dev": {
|
|
279
|
-
"command": "node",
|
|
280
|
-
"args": ["/absolute/path/to/tdecollab/dist/index.js"],
|
|
281
|
-
"env": {
|
|
282
|
-
"CONFLUENCE_BASE_URL": "https://confluence.example.com",
|
|
283
|
-
"CONFLUENCE_USERNAME": "your-username",
|
|
284
149
|
"CONFLUENCE_API_TOKEN": "your-api-token",
|
|
285
150
|
"JIRA_BASE_URL": "https://jira.example.com",
|
|
286
151
|
"JIRA_API_TOKEN": "your-jira-token",
|
|
@@ -292,87 +157,18 @@ npm install -g tdecollab
|
|
|
292
157
|
}
|
|
293
158
|
```
|
|
294
159
|
|
|
295
|
-
설정 후 Claude Desktop을 재시작하면
|
|
296
|
-
|
|
297
|
-
## 개발
|
|
298
|
-
|
|
299
|
-
```bash
|
|
300
|
-
# 개발 모드 (MCP 서버)
|
|
301
|
-
pnpm dev
|
|
302
|
-
|
|
303
|
-
# CLI 실행
|
|
304
|
-
pnpm cli -- confluence page get 12345
|
|
305
|
-
|
|
306
|
-
# 테스트
|
|
307
|
-
pnpm test
|
|
308
|
-
|
|
309
|
-
# 빌드
|
|
310
|
-
pnpm build
|
|
160
|
+
설정 후 Claude Desktop을 재시작하면 도구가 활성화됩니다.
|
|
311
161
|
|
|
312
|
-
|
|
313
|
-
pnpm format
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
## 프로젝트 구조
|
|
317
|
-
|
|
318
|
-
```
|
|
319
|
-
tools/ # (기존 src/) 사내 시스템 연계용 Tool & MCP
|
|
320
|
-
├── index.ts # MCP 서버 엔트리포인트
|
|
321
|
-
├── cli.ts # CLI 엔트리포인트
|
|
322
|
-
├── common/ # 공통 모듈 (인증, HTTP, 설정, 에러)
|
|
323
|
-
├── confluence/ # Confluence 모듈 (api/tools/commands/converters)
|
|
324
|
-
├── jira/ # JIRA 모듈 (api/tools/commands)
|
|
325
|
-
├── gitlab/ # GitLab 모듈 (api/tools/commands)
|
|
326
|
-
└── mcp/ # MCP 서버 코어
|
|
327
|
-
|
|
328
|
-
backend/ # Agentic PRD Harness 백엔드 (Python/FastAPI)
|
|
329
|
-
├── app/
|
|
330
|
-
│ ├── api/ # 엔드포인트 및 라우터
|
|
331
|
-
│ ├── core/ # 비즈니스 로직, 데이터베이스, AI 연동
|
|
332
|
-
│ ├── models/ # 데이터 모델 (SQLAlchemy)
|
|
333
|
-
│ └── webhooks/ # GitLab Webhook 연동
|
|
334
|
-
└── tests/
|
|
335
|
-
|
|
336
|
-
frontend/ # Agentic PRD Harness 프론트엔드 (React/Next.js)
|
|
337
|
-
├── src/
|
|
338
|
-
│ ├── components/ # UI 컴포넌트 (shadcn/ui)
|
|
339
|
-
│ ├── pages/ # 웹 페이지
|
|
340
|
-
│ └── services/ # 백엔드 API 호출
|
|
341
|
-
└── tests/
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
## 실행 방법 (Agentic PRD Harness)
|
|
345
|
-
|
|
346
|
-
새롭게 추가된 기획 문서 관리 및 개발 연동 웹 UI를 실행하는 방법입니다.
|
|
347
|
-
|
|
348
|
-
### 1. 필수 요구사항
|
|
349
|
-
- Node.js 20+
|
|
350
|
-
- Python 3.11+
|
|
351
|
-
- pnpm
|
|
352
|
-
|
|
353
|
-
### 2. 초기 셋업
|
|
354
|
-
가상환경(venv)을 생성하고 프론트엔드/백엔드 패키지를 모두 설치합니다.
|
|
355
|
-
```bash
|
|
356
|
-
make setup
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
### 3. 서버 실행
|
|
360
|
-
MCP, 백엔드(FastAPI), 프론트엔드(Next.js)를 동시에 실행합니다.
|
|
361
|
-
```bash
|
|
362
|
-
make dev
|
|
363
|
-
```
|
|
364
|
-
- **Frontend URL**: [http://localhost:3000](http://localhost:3000)
|
|
365
|
-
- **Backend API Docs**: [http://localhost:8000/docs](http://localhost:8000/docs)
|
|
162
|
+
### 제공 MCP 도구
|
|
366
163
|
|
|
164
|
+
| 서비스 | 도구 |
|
|
165
|
+
|---|---|
|
|
166
|
+
| **Confluence (9)** | `confluence_get_page`, `confluence_create_page`, `confluence_update_page`, `confluence_delete_page`, `confluence_search_pages`, `confluence_get_spaces`, `confluence_get_page_tree`, `confluence_manage_labels`, `confluence_convert_content` |
|
|
167
|
+
| **JIRA (7)** | `jira_get_issue`, `jira_create_issue`, `jira_update_issue`, `jira_search_issues`, `jira_transition_issue`, `jira_manage_comments`, `jira_get_projects` |
|
|
168
|
+
| **GitLab (7)** | `gitlab_get_project`, `gitlab_get_merge_request`, `gitlab_create_merge_request`, `gitlab_manage_merge_request`, `gitlab_get_pipelines`, `gitlab_manage_branches`, `gitlab_get_file` |
|
|
367
169
|
|
|
368
|
-
|
|
170
|
+
자세한 도구별 파라미터는 Claude Desktop의 MCP 도구 검색 UI 또는 `tdecollab mcp` 실행 시 stderr 로그를 참조하세요.
|
|
369
171
|
|
|
370
|
-
|
|
172
|
+
## 라이선스
|
|
371
173
|
|
|
372
|
-
|
|
373
|
-
- [인증 및 설정](tdecollab-docs/auth-and-config.md)
|
|
374
|
-
- [MCP 서버 설계](tdecollab-docs/mcp-server-design.md)
|
|
375
|
-
- [npm 패키지 등록(Publish) 가이드](tdecollab-docs/npm-publish-guide.md)
|
|
376
|
-
- Confluence: [API 스펙](tdecollab-docs/confluence/api-spec.md) | [기능 정의](tdecollab-docs/confluence/features.md) | [MCP 도구](tdecollab-docs/confluence/mcp-tools.md)
|
|
377
|
-
- JIRA: [API 스펙](tdecollab-docs/jira/api-spec.md) | [기능 정의](tdecollab-docs/jira/features.md) | [MCP 도구](tdecollab-docs/jira/mcp-tools.md)
|
|
378
|
-
- GitLab: [API 스펙](tdecollab-docs/gitlab/api-spec.md) | [기능 정의](tdecollab-docs/gitlab/features.md) | [MCP 도구](tdecollab-docs/gitlab/mcp-tools.md)
|
|
174
|
+
[MIT](LICENSE)
|
|
@@ -304,6 +304,14 @@ function loadConfluenceConfig() {
|
|
|
304
304
|
inlineCodeStyle
|
|
305
305
|
};
|
|
306
306
|
}
|
|
307
|
+
function loadAIConfig() {
|
|
308
|
+
return {
|
|
309
|
+
openaiApiKey: process.env.OPENAI_API_KEY,
|
|
310
|
+
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
|
|
311
|
+
defaultProvider: process.env.AI_PROVIDER || "openai",
|
|
312
|
+
defaultModel: process.env.AI_MODEL || "gpt-4o"
|
|
313
|
+
};
|
|
314
|
+
}
|
|
307
315
|
function loadJiraConfig() {
|
|
308
316
|
const baseUrl = getEnvOrThrow("JIRA_BASE_URL", "JIRA \uAE30\uBCF8 URL");
|
|
309
317
|
const username = process.env.JIRA_USERNAME;
|
|
@@ -604,110 +612,11 @@ var JiraSearchApi = class {
|
|
|
604
612
|
}
|
|
605
613
|
};
|
|
606
614
|
|
|
607
|
-
// tools/jira/api/transition.ts
|
|
608
|
-
var JiraTransitionApi = class {
|
|
609
|
-
constructor(client) {
|
|
610
|
-
this.client = client;
|
|
611
|
-
}
|
|
612
|
-
async getTransitions(issueKey) {
|
|
613
|
-
const response = await this.client.get(`/rest/api/2/issue/${issueKey}/transitions`);
|
|
614
|
-
return response.data.transitions;
|
|
615
|
-
}
|
|
616
|
-
async doTransition(issueKey, transitionId, fields) {
|
|
617
|
-
const data = {
|
|
618
|
-
transition: { id: transitionId }
|
|
619
|
-
};
|
|
620
|
-
if (fields) {
|
|
621
|
-
data.fields = fields;
|
|
622
|
-
}
|
|
623
|
-
await this.client.post(`/rest/api/2/issue/${issueKey}/transitions`, data);
|
|
624
|
-
}
|
|
625
|
-
};
|
|
626
|
-
|
|
627
|
-
// tools/jira/api/comment.ts
|
|
628
|
-
var JiraCommentApi = class {
|
|
629
|
-
constructor(client) {
|
|
630
|
-
this.client = client;
|
|
631
|
-
}
|
|
632
|
-
async getComments(issueKey, startAt = 0, maxResults = 50) {
|
|
633
|
-
const response = await this.client.get(`/rest/api/2/issue/${issueKey}/comment`, {
|
|
634
|
-
params: { startAt, maxResults }
|
|
635
|
-
});
|
|
636
|
-
return response.data;
|
|
637
|
-
}
|
|
638
|
-
async addComment(issueKey, body) {
|
|
639
|
-
const response = await this.client.post(`/rest/api/2/issue/${issueKey}/comment`, { body });
|
|
640
|
-
return response.data;
|
|
641
|
-
}
|
|
642
|
-
async updateComment(issueKey, commentId, body) {
|
|
643
|
-
const response = await this.client.put(
|
|
644
|
-
`/rest/api/2/issue/${issueKey}/comment/${commentId}`,
|
|
645
|
-
{ body }
|
|
646
|
-
);
|
|
647
|
-
return response.data;
|
|
648
|
-
}
|
|
649
|
-
async deleteComment(issueKey, commentId) {
|
|
650
|
-
await this.client.delete(`/rest/api/2/issue/${issueKey}/comment/${commentId}`);
|
|
651
|
-
}
|
|
652
|
-
};
|
|
653
|
-
|
|
654
|
-
// tools/jira/api/project.ts
|
|
655
|
-
var JiraProjectApi = class {
|
|
656
|
-
constructor(client) {
|
|
657
|
-
this.client = client;
|
|
658
|
-
}
|
|
659
|
-
async getProjects() {
|
|
660
|
-
const response = await this.client.get("/rest/api/2/project");
|
|
661
|
-
return response.data;
|
|
662
|
-
}
|
|
663
|
-
async getProject(projectKey) {
|
|
664
|
-
const response = await this.client.get(`/rest/api/2/project/${projectKey}`);
|
|
665
|
-
return response.data;
|
|
666
|
-
}
|
|
667
|
-
async getBoards(projectKeyOrId, type) {
|
|
668
|
-
const params = {};
|
|
669
|
-
if (projectKeyOrId) params.projectKeyOrId = projectKeyOrId;
|
|
670
|
-
if (type) params.type = type;
|
|
671
|
-
const response = await this.client.get("/rest/agile/1.0/board", { params });
|
|
672
|
-
return response.data;
|
|
673
|
-
}
|
|
674
|
-
async getSprints(boardId, state) {
|
|
675
|
-
const params = {};
|
|
676
|
-
if (state) params.state = state;
|
|
677
|
-
const response = await this.client.get(`/rest/agile/1.0/board/${boardId}/sprint`, {
|
|
678
|
-
params
|
|
679
|
-
});
|
|
680
|
-
return response.data;
|
|
681
|
-
}
|
|
682
|
-
};
|
|
683
|
-
|
|
684
615
|
// tools/jira/api/client.ts
|
|
685
616
|
function createJiraClient(config) {
|
|
686
617
|
return createHttpClient(config);
|
|
687
618
|
}
|
|
688
619
|
|
|
689
|
-
// tools/gitlab/api/project.ts
|
|
690
|
-
var GitlabProjectApi = class {
|
|
691
|
-
constructor(client) {
|
|
692
|
-
this.client = client;
|
|
693
|
-
}
|
|
694
|
-
async getProjects(params) {
|
|
695
|
-
const response = await this.client.get("/projects", {
|
|
696
|
-
params: {
|
|
697
|
-
search: params?.search,
|
|
698
|
-
owned: params?.owned,
|
|
699
|
-
membership: params?.membership,
|
|
700
|
-
per_page: params?.perPage || 20
|
|
701
|
-
}
|
|
702
|
-
});
|
|
703
|
-
return response.data;
|
|
704
|
-
}
|
|
705
|
-
async getProject(projectId) {
|
|
706
|
-
const response = await this.client.get(`/projects/${encodeURIComponent(projectId)}`);
|
|
707
|
-
return response.data;
|
|
708
|
-
}
|
|
709
|
-
};
|
|
710
|
-
|
|
711
620
|
// tools/gitlab/api/merge-request.ts
|
|
712
621
|
var GitlabMergeRequestApi = class {
|
|
713
622
|
constructor(client) {
|
|
@@ -804,70 +713,6 @@ var GitlabPipelineApi = class {
|
|
|
804
713
|
}
|
|
805
714
|
};
|
|
806
715
|
|
|
807
|
-
// tools/gitlab/api/branch.ts
|
|
808
|
-
var GitlabBranchApi = class {
|
|
809
|
-
constructor(client) {
|
|
810
|
-
this.client = client;
|
|
811
|
-
}
|
|
812
|
-
async getBranches(projectId, params) {
|
|
813
|
-
const response = await this.client.get(`/projects/${projectId}/repository/branches`, {
|
|
814
|
-
params: {
|
|
815
|
-
search: params?.search,
|
|
816
|
-
per_page: params?.perPage || 20
|
|
817
|
-
}
|
|
818
|
-
});
|
|
819
|
-
return response.data;
|
|
820
|
-
}
|
|
821
|
-
async getBranch(projectId, branchName) {
|
|
822
|
-
const response = await this.client.get(
|
|
823
|
-
`/projects/${projectId}/repository/branches/${encodeURIComponent(branchName)}`
|
|
824
|
-
);
|
|
825
|
-
return response.data;
|
|
826
|
-
}
|
|
827
|
-
async createBranch(projectId, branchName, ref) {
|
|
828
|
-
const response = await this.client.post(`/projects/${projectId}/repository/branches`, {
|
|
829
|
-
branch: branchName,
|
|
830
|
-
ref
|
|
831
|
-
});
|
|
832
|
-
return response.data;
|
|
833
|
-
}
|
|
834
|
-
async deleteBranch(projectId, branchName) {
|
|
835
|
-
await this.client.delete(
|
|
836
|
-
`/projects/${projectId}/repository/branches/${encodeURIComponent(branchName)}`
|
|
837
|
-
);
|
|
838
|
-
}
|
|
839
|
-
};
|
|
840
|
-
|
|
841
|
-
// tools/gitlab/api/repository.ts
|
|
842
|
-
var GitlabRepositoryApi = class {
|
|
843
|
-
constructor(client) {
|
|
844
|
-
this.client = client;
|
|
845
|
-
}
|
|
846
|
-
async getFile(projectId, filePath, ref) {
|
|
847
|
-
const encodedPath = encodeURIComponent(filePath);
|
|
848
|
-
const response = await this.client.get(
|
|
849
|
-
`/projects/${projectId}/repository/files/${encodedPath}`,
|
|
850
|
-
{ params: { ref: ref || "HEAD" } }
|
|
851
|
-
);
|
|
852
|
-
const file = response.data;
|
|
853
|
-
if (file.encoding === "base64") {
|
|
854
|
-
file.content = Buffer.from(file.content, "base64").toString("utf-8");
|
|
855
|
-
}
|
|
856
|
-
return file;
|
|
857
|
-
}
|
|
858
|
-
async getTree(projectId, params) {
|
|
859
|
-
const response = await this.client.get(`/projects/${projectId}/repository/tree`, {
|
|
860
|
-
params: {
|
|
861
|
-
path: params?.path,
|
|
862
|
-
ref: params?.ref,
|
|
863
|
-
recursive: params?.recursive,
|
|
864
|
-
per_page: params?.perPage || 100
|
|
865
|
-
}
|
|
866
|
-
});
|
|
867
|
-
return response.data;
|
|
868
|
-
}
|
|
869
|
-
};
|
|
870
|
-
|
|
871
716
|
// tools/gitlab/api/client.ts
|
|
872
717
|
function createGitlabClient(config) {
|
|
873
718
|
const client = createHttpClient({
|
|
@@ -884,21 +729,16 @@ export {
|
|
|
884
729
|
ConfluenceSearchApi,
|
|
885
730
|
createConfluenceClient,
|
|
886
731
|
loadConfluenceConfig,
|
|
732
|
+
loadAIConfig,
|
|
887
733
|
loadJiraConfig,
|
|
888
734
|
loadGitlabConfig,
|
|
889
735
|
MarkdownToStorageConverter,
|
|
890
736
|
StorageToMarkdownConverter,
|
|
891
737
|
JiraIssueApi,
|
|
892
738
|
JiraSearchApi,
|
|
893
|
-
JiraTransitionApi,
|
|
894
|
-
JiraCommentApi,
|
|
895
|
-
JiraProjectApi,
|
|
896
739
|
createJiraClient,
|
|
897
|
-
GitlabProjectApi,
|
|
898
740
|
GitlabMergeRequestApi,
|
|
899
741
|
GitlabPipelineApi,
|
|
900
|
-
GitlabBranchApi,
|
|
901
|
-
GitlabRepositoryApi,
|
|
902
742
|
createGitlabClient
|
|
903
743
|
};
|
|
904
|
-
//# sourceMappingURL=chunk-
|
|
744
|
+
//# sourceMappingURL=chunk-6AFNYE7N.js.map
|