tdecollab 0.3.4 → 0.3.6

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Confluence, JIRA, GitLab을 하나의 CLI / TUI / MCP 서버로 통합 제공하는 도구.
4
4
 
5
- 터미널에서 직접 사용하거나, AI 에이전트(Claude Desktop 등)와 연동하여 사용할 수 있습니다.
5
+ 터미널에서 직접 사용하거나, AI 에이전트(Claude Desktop 등)와 연동하여 사용할 수 있습니다. 또한 Obsidian 플러그인을 통해 마크다운 노트를 Confluence와 양방향으로 연동할 수 있습니다.
6
6
 
7
7
  ## 지원 서비스
8
8
 
@@ -12,21 +12,44 @@ Confluence, JIRA, GitLab을 하나의 CLI / TUI / MCP 서버로 통합 제공하
12
12
  | **JIRA** | 이슈 CRUD, JQL 검색, 상태 변경(트랜지션), 코멘트 관리, 프로젝트/보드 조회 |
13
13
  | **GitLab** | 프로젝트 조회, MR 관리, 파이프라인 조회, 브랜치 관리, 파일 조회 |
14
14
 
15
- ## 요구사항
15
+ ---
16
+
17
+ ## 1. Obsidian 플러그인
18
+
19
+ 현재 활성화된 마크다운 노트를 Confluence 페이지로 업로드하거나, 반대로 다운로드할 수 있는 Obsidian 플러그인을 제공합니다.
20
+
21
+ ### 설치 방법 (BRAT)
22
+ 1. Obsidian에서 **BRAT** 플러그인을 먼저 설치 및 활성화합니다.
23
+ 2. `BRAT: Add a beta plugin for testing` 명령을 실행합니다.
24
+ 3. **`goodjoon/tdecollab_public`** 주소를 입력하여 설치합니다.
25
+ 4. 설정에서 **TDE Collab Confluence**를 활성화합니다.
26
+
27
+ ### 사용법
28
+ - Obsidian의 명령어 팔레트(`Cmd/Ctrl + P`)를 열어 `TDE Collab`을 검색합니다.
29
+ - **Upload to Confluence**: 현재 열려있는 마크다운 노트를 Confluence 페이지로 업로드합니다.
30
+ - **Download from Confluence**: Confluence 페이지를 가져와 현재 마크다운 노트로 다운로드합니다.
31
+
32
+ ---
33
+
34
+ ## 2. CLI / TUI 및 MCP 서버
35
+
36
+ 터미널에서 직접 실행하거나 Claude Desktop 등의 MCP 클라이언트와 연동할 수 있는 Node.js 기반 도구입니다.
37
+
38
+ ### 요구사항
16
39
 
17
40
  - Node.js 20 이상
18
41
 
19
- ## 설치
42
+ ### 설치 방법
20
43
 
21
44
  ```bash
22
- # 전역 설치
45
+ # 전역 설치 (CLI/TUI 사용 시 권장)
23
46
  npm install -g tdecollab
24
47
 
25
48
  # 또는 npx로 즉시 실행 (설치 불필요)
26
49
  npx -y tdecollab --help
27
50
  ```
28
51
 
29
- ## 설정
52
+ ### 환경변수 설정
30
53
 
31
54
  각 서비스 접속에 필요한 환경변수:
32
55
 
@@ -56,10 +79,11 @@ GITLAB_PRIVATE_TOKEN=your-private-token
56
79
 
57
80
  상위 우선순위에 이미 설정된 값은 하위 설정 파일 값으로 덮어쓰지 않습니다.
58
81
 
59
- ## 사용법
82
+ ### 사용법
60
83
 
61
- ### TUI (Terminal UI) 모드
62
- ![[img_20260429004932.png]]
84
+ #### TUI (Terminal UI) 모드
85
+
86
+ ![](tdecollab-docs/assets/Monosnap%20tdecollab%202026-05-03%2014-21-27.png)
63
87
 
64
88
  인자 없이 실행하면 인터랙티브 TUI가 시작됩니다 — 메뉴 탐색, 폼 입력, 실시간 결과 확인이 한 화면에서 가능합니다.
65
89
 
@@ -79,9 +103,9 @@ tdecollab
79
103
 
80
104
  마지막 사용값은 `.tdecollab.json`에, 명령 히스토리는 `~/.tdecollab_history.json`에 자동 저장됩니다.
81
105
 
82
- ### CLI 명령어
106
+ #### CLI 명령어
83
107
 
84
- #### Confluence
108
+ ##### Confluence
85
109
 
86
110
  ```bash
87
111
  # 스페이스 목록
@@ -95,7 +119,7 @@ tdecollab confluence page create --space <key> --title <title> --file <path_to_m
95
119
  tdecollab confluence page update <pageId> --file <path_to_md>
96
120
  ```
97
121
 
98
- #### JIRA / GitLab
122
+ ##### JIRA / GitLab
99
123
 
100
124
  ```bash
101
125
  tdecollab jira issue get PROJ-1234
@@ -105,16 +129,16 @@ tdecollab gitlab mr list <projectId> -s opened
105
129
 
106
130
  `tdecollab <service> --help` 또는 `tdecollab <service> <command> --help`로 모든 옵션을 확인할 수 있습니다.
107
131
 
108
- ## MCP 서버 (Claude Desktop 연동)
132
+ ### MCP 서버 연동 (Claude Desktop)
109
133
 
110
134
  Claude Desktop에서 Confluence, JIRA, GitLab 도구를 사용할 수 있습니다.
111
135
 
112
- ### 설정 파일 위치
136
+ #### 설정 파일 위치
113
137
 
114
138
  - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
115
139
  - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
116
140
 
117
- ### npx 사용 (권장 — 별도 설치 불필요)
141
+ #### npx 사용 (권장 — 별도 설치 불필요)
118
142
 
119
143
  ```json
120
144
  {
@@ -136,7 +160,7 @@ Claude Desktop에서 Confluence, JIRA, GitLab 도구를 사용할 수 있습니
136
160
  }
137
161
  ```
138
162
 
139
- ### 전역 설치 후 사용
163
+ #### 전역 설치 후 사용
140
164
 
141
165
  ```bash
142
166
  npm install -g tdecollab
@@ -163,7 +187,7 @@ npm install -g tdecollab
163
187
 
164
188
  설정 후 Claude Desktop을 재시작하면 도구가 활성화됩니다.
165
189
 
166
- ### 제공 MCP 도구
190
+ #### 제공하는 MCP 도구
167
191
 
168
192
  | 서비스 | 도구 |
169
193
  |---|---|
@@ -173,6 +197,8 @@ npm install -g tdecollab
173
197
 
174
198
  자세한 도구별 파라미터는 Claude Desktop의 MCP 도구 검색 UI 또는 `tdecollab mcp` 실행 시 stderr 로그를 참조하세요.
175
199
 
200
+ ---
201
+
176
202
  ## 라이선스
177
203
 
178
- [MIT](LICENSE)
204
+ [MIT](LICENSE)
@@ -51,7 +51,7 @@ var JiraProjectApi = class {
51
51
  this.client = client;
52
52
  }
53
53
  async getProjects() {
54
- const response = await this.client.get("/rest/api/2/project");
54
+ const response = await this.client.get("rest/api/2/project");
55
55
  return response.data;
56
56
  }
57
57
  async getProject(projectKey) {
@@ -62,7 +62,7 @@ var JiraProjectApi = class {
62
62
  const params = {};
63
63
  if (projectKeyOrId) params.projectKeyOrId = projectKeyOrId;
64
64
  if (type) params.type = type;
65
- const response = await this.client.get("/rest/agile/1.0/board", { params });
65
+ const response = await this.client.get("rest/agile/1.0/board", { params });
66
66
  return response.data;
67
67
  }
68
68
  async getSprints(boardId, state) {
@@ -81,7 +81,7 @@ var GitlabProjectApi = class {
81
81
  this.client = client;
82
82
  }
83
83
  async getProjects(params) {
84
- const response = await this.client.get("/projects", {
84
+ const response = await this.client.get("projects", {
85
85
  params: {
86
86
  search: params?.search,
87
87
  owned: params?.owned,
@@ -169,4 +169,4 @@ export {
169
169
  GitlabBranchApi,
170
170
  GitlabRepositoryApi
171
171
  };
172
- //# sourceMappingURL=chunk-JI2YUE7N.js.map
172
+ //# sourceMappingURL=chunk-4QW3PXPJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../tools/jira/api/transition.ts","../tools/jira/api/comment.ts","../tools/jira/api/project.ts","../tools/gitlab/api/project.ts","../tools/gitlab/api/branch.ts","../tools/gitlab/api/repository.ts"],"sourcesContent":["import { AxiosInstance } from 'axios';\nimport { JiraTransition } from '../types.js';\n\nexport class JiraTransitionApi {\n constructor(private client: AxiosInstance) {}\n\n async getTransitions(issueKey: string): Promise<JiraTransition[]> {\n const response = await this.client.get(`/rest/api/2/issue/${issueKey}/transitions`);\n return response.data.transitions;\n }\n\n async doTransition(\n issueKey: string,\n transitionId: string,\n fields?: Record<string, unknown>,\n ): Promise<void> {\n const data: Record<string, unknown> = {\n transition: { id: transitionId },\n };\n if (fields) {\n data.fields = fields;\n }\n await this.client.post(`/rest/api/2/issue/${issueKey}/transitions`, data);\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { JiraComment } from '../types.js';\n\nexport class JiraCommentApi {\n constructor(private client: AxiosInstance) {}\n\n async getComments(\n issueKey: string,\n startAt = 0,\n maxResults = 50,\n ): Promise<{ comments: JiraComment[]; total: number; startAt: number; maxResults: number }> {\n const response = await this.client.get(`/rest/api/2/issue/${issueKey}/comment`, {\n params: { startAt, maxResults },\n });\n return response.data;\n }\n\n async addComment(issueKey: string, body: string): Promise<JiraComment> {\n const response = await this.client.post(`/rest/api/2/issue/${issueKey}/comment`, { body });\n return response.data;\n }\n\n async updateComment(issueKey: string, commentId: string, body: string): Promise<JiraComment> {\n const response = await this.client.put(\n `/rest/api/2/issue/${issueKey}/comment/${commentId}`,\n { body },\n );\n return response.data;\n }\n\n async deleteComment(issueKey: string, commentId: string): Promise<void> {\n await this.client.delete(`/rest/api/2/issue/${issueKey}/comment/${commentId}`);\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { JiraProject, JiraBoard, JiraSprint } from '../types.js';\n\nexport class JiraProjectApi {\n constructor(private client: AxiosInstance) {}\n\n async getProjects(): Promise<JiraProject[]> {\n const response = await this.client.get('rest/api/2/project');\n return response.data;\n }\n\n async getProject(projectKey: string): Promise<JiraProject> {\n const response = await this.client.get(`/rest/api/2/project/${projectKey}`);\n return response.data;\n }\n\n async getBoards(\n projectKeyOrId?: string,\n type?: string,\n ): Promise<{ values: JiraBoard[]; total: number }> {\n const params: Record<string, string> = {};\n if (projectKeyOrId) params.projectKeyOrId = projectKeyOrId;\n if (type) params.type = type;\n const response = await this.client.get('rest/agile/1.0/board', { params });\n return response.data;\n }\n\n async getSprints(\n boardId: number,\n state?: string,\n ): Promise<{ values: JiraSprint[]; total: number }> {\n const params: Record<string, string> = {};\n if (state) params.state = state;\n const response = await this.client.get(`/rest/agile/1.0/board/${boardId}/sprint`, {\n params,\n });\n return response.data;\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { GitlabProject } from '../types.js';\n\nexport class GitlabProjectApi {\n constructor(private client: AxiosInstance) {}\n\n async getProjects(params?: {\n search?: string;\n owned?: boolean;\n membership?: boolean;\n perPage?: number;\n }): Promise<GitlabProject[]> {\n const response = await this.client.get('projects', {\n params: {\n search: params?.search,\n owned: params?.owned,\n membership: params?.membership,\n per_page: params?.perPage || 20,\n },\n });\n return response.data;\n }\n\n async getProject(projectId: number | string): Promise<GitlabProject> {\n const response = await this.client.get(`/projects/${encodeURIComponent(projectId)}`);\n return response.data;\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { GitlabBranch } from '../types.js';\n\nexport class GitlabBranchApi {\n constructor(private client: AxiosInstance) {}\n\n async getBranches(\n projectId: number,\n params?: { search?: string; perPage?: number },\n ): Promise<GitlabBranch[]> {\n const response = await this.client.get(`/projects/${projectId}/repository/branches`, {\n params: {\n search: params?.search,\n per_page: params?.perPage || 20,\n },\n });\n return response.data;\n }\n\n async getBranch(projectId: number, branchName: string): Promise<GitlabBranch> {\n const response = await this.client.get(\n `/projects/${projectId}/repository/branches/${encodeURIComponent(branchName)}`,\n );\n return response.data;\n }\n\n async createBranch(\n projectId: number,\n branchName: string,\n ref: string,\n ): Promise<GitlabBranch> {\n const response = await this.client.post(`/projects/${projectId}/repository/branches`, {\n branch: branchName,\n ref,\n });\n return response.data;\n }\n\n async deleteBranch(projectId: number, branchName: string): Promise<void> {\n await this.client.delete(\n `/projects/${projectId}/repository/branches/${encodeURIComponent(branchName)}`,\n );\n }\n}\n","import { AxiosInstance } from 'axios';\nimport { GitlabRepositoryFile, GitlabTreeEntry } from '../types.js';\n\nexport class GitlabRepositoryApi {\n constructor(private client: AxiosInstance) {}\n\n async getFile(\n projectId: number,\n filePath: string,\n ref?: string,\n ): Promise<GitlabRepositoryFile> {\n const encodedPath = encodeURIComponent(filePath);\n const response = await this.client.get(\n `/projects/${projectId}/repository/files/${encodedPath}`,\n { params: { ref: ref || 'HEAD' } },\n );\n const file: GitlabRepositoryFile = response.data;\n // Base64 디코딩\n if (file.encoding === 'base64') {\n file.content = Buffer.from(file.content, 'base64').toString('utf-8');\n }\n return file;\n }\n\n async getTree(\n projectId: number,\n params?: { path?: string; ref?: string; recursive?: boolean; perPage?: number },\n ): Promise<GitlabTreeEntry[]> {\n const response = await this.client.get(`/projects/${projectId}/repository/tree`, {\n params: {\n path: params?.path,\n ref: params?.ref,\n recursive: params?.recursive,\n per_page: params?.perPage || 100,\n },\n });\n return response.data;\n }\n}\n"],"mappings":"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","names":[]}
@@ -5,7 +5,7 @@ import {
5
5
  JiraCommentApi,
6
6
  JiraProjectApi,
7
7
  JiraTransitionApi
8
- } from "./chunk-JI2YUE7N.js";
8
+ } from "./chunk-4QW3PXPJ.js";
9
9
  import {
10
10
  ConfluenceContentApi,
11
11
  ConfluenceSearchApi,
@@ -24,7 +24,7 @@ import {
24
24
  loadGitlabConfig,
25
25
  loadJiraConfig,
26
26
  tryBuildJiraIssueMap
27
- } from "./chunk-5OB3KU5D.js";
27
+ } from "./chunk-SIKUIQKX.js";
28
28
  import {
29
29
  logger
30
30
  } from "./chunk-IFYMZLQI.js";
@@ -1107,4 +1107,4 @@ async function runServer() {
1107
1107
  export {
1108
1108
  runServer
1109
1109
  };
1110
- //# sourceMappingURL=chunk-4DPCLTF4.js.map
1110
+ //# sourceMappingURL=chunk-6GCKWJJ7.js.map