tdecollab 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-SJ7KPK6Q.js";
3
+ } from "./chunk-IFYMZLQI.js";
4
4
 
5
- // src/confluence/api/content.ts
5
+ // tools/confluence/api/content.ts
6
6
  var ConfluenceContentApi = class {
7
7
  constructor(client) {
8
8
  this.client = client;
@@ -85,7 +85,40 @@ var ConfluenceContentApi = class {
85
85
  const data = labels.map((name) => ({ prefix: "global", name }));
86
86
  await this.client.post(`/rest/api/content/${id}/label`, data);
87
87
  }
88
- // Attachment 관련 메서드
88
+ // Attachment 관련 메서드 (upsert: 기존 파일이 있으면 업데이트, 없으면 신규 업로드)
89
+ async uploadAttachment(pageId, filename, fileContent, contentType) {
90
+ const FormData = (await import("form-data")).default;
91
+ const existingAttachments = await this.getAttachments(pageId, filename);
92
+ const existing = existingAttachments.find((a) => a.title === filename);
93
+ const form = new FormData();
94
+ form.append("file", fileContent, {
95
+ filename,
96
+ contentType: contentType || "application/octet-stream"
97
+ });
98
+ const headers = {
99
+ ...form.getHeaders(),
100
+ "X-Atlassian-Token": "nocheck",
101
+ "Accept": "application/json"
102
+ };
103
+ let response;
104
+ if (existing) {
105
+ response = await this.client.post(
106
+ `/rest/api/content/${pageId}/child/attachment/${existing.id}/data`,
107
+ form,
108
+ { headers }
109
+ );
110
+ } else {
111
+ response = await this.client.post(
112
+ `/rest/api/content/${pageId}/child/attachment`,
113
+ form,
114
+ { headers }
115
+ );
116
+ }
117
+ if (response.data && response.data.results && response.data.results.length > 0) {
118
+ return response.data.results[0];
119
+ }
120
+ return response.data;
121
+ }
89
122
  async getAttachments(pageId, filename) {
90
123
  const response = await this.client.get(`/rest/api/content/${pageId}/child/attachment`, {
91
124
  params: {
@@ -103,7 +136,7 @@ var ConfluenceContentApi = class {
103
136
  }
104
137
  };
105
138
 
106
- // src/confluence/api/space.ts
139
+ // tools/confluence/api/space.ts
107
140
  var ConfluenceSpaceApi = class {
108
141
  constructor(client) {
109
142
  this.client = client;
@@ -120,7 +153,7 @@ var ConfluenceSpaceApi = class {
120
153
  }
121
154
  };
122
155
 
123
- // src/confluence/api/search.ts
156
+ // tools/confluence/api/search.ts
124
157
  var ConfluenceSearchApi = class {
125
158
  constructor(client) {
126
159
  this.client = client;
@@ -139,10 +172,10 @@ var ConfluenceSearchApi = class {
139
172
  }
140
173
  };
141
174
 
142
- // src/common/http-client.ts
175
+ // tools/common/http-client.ts
143
176
  import axios from "axios";
144
177
 
145
- // src/common/errors.ts
178
+ // tools/common/errors.ts
146
179
  var TdeCollabError = class extends Error {
147
180
  constructor(message) {
148
181
  super(message);
@@ -173,7 +206,7 @@ var ConflictError = class extends TdeCollabError {
173
206
  }
174
207
  };
175
208
 
176
- // src/common/http-client.ts
209
+ // tools/common/http-client.ts
177
210
  function createHttpClient(config) {
178
211
  const client = axios.create({
179
212
  baseURL: config.baseUrl,
@@ -184,19 +217,25 @@ function createHttpClient(config) {
184
217
  }
185
218
  });
186
219
  client.interceptors.request.use((reqConfig) => {
187
- if (config.auth.username && config.auth.token) {
220
+ if (config.auth.token && !reqConfig.headers.Authorization && !reqConfig.headers["PRIVATE-TOKEN"]) {
221
+ reqConfig.headers.Authorization = `Bearer ${config.auth.token}`;
222
+ } else if (config.auth.username && config.auth.token && !reqConfig.headers.Authorization) {
188
223
  const token = Buffer.from(`${config.auth.username}:${config.auth.token}`).toString("base64");
189
224
  reqConfig.headers.Authorization = `Basic ${token}`;
190
- } else if (config.auth.token) {
191
- if (!reqConfig.headers.Authorization && !reqConfig.headers["PRIVATE-TOKEN"]) {
192
- reqConfig.headers.Authorization = `Bearer ${config.auth.token}`;
193
- }
194
225
  }
226
+ logger.debug(`[HTTP Request] ${reqConfig.method?.toUpperCase()} ${reqConfig.url}`, {
227
+ headers: reqConfig.headers,
228
+ params: reqConfig.params,
229
+ data: reqConfig.data
230
+ });
195
231
  return reqConfig;
196
232
  });
197
233
  client.interceptors.response.use(
198
234
  (response) => {
199
- logger.debug(`[HTTP] ${response.status} ${response.config.method?.toUpperCase()} ${response.config.url}`);
235
+ logger.debug(`[HTTP Response] ${response.status} ${response.config.method?.toUpperCase()} ${response.config.url}`, {
236
+ headers: response.headers,
237
+ data: response.data
238
+ });
200
239
  return response;
201
240
  },
202
241
  (error) => {
@@ -205,7 +244,11 @@ function createHttpClient(config) {
205
244
  const method = error.config?.method?.toUpperCase();
206
245
  const url = error.config?.url;
207
246
  const message = error.response.data?.message || error.message;
208
- logger.error(`[HTTP] ${status} ${method} ${url} - ${message}`);
247
+ logger.error(`[HTTP Error] ${status} ${method} ${url}`, {
248
+ message,
249
+ responseData: error.response.data,
250
+ requestHeaders: error.config?.headers
251
+ });
209
252
  if (status === 401 || status === 403) {
210
253
  throw new AuthError(`\uC778\uC99D \uC2E4\uD328: ${message}`);
211
254
  }
@@ -228,101 +271,12 @@ function createHttpClient(config) {
228
271
  return client;
229
272
  }
230
273
 
231
- // src/confluence/api/client.ts
274
+ // tools/confluence/api/client.ts
232
275
  function createConfluenceClient(config) {
233
276
  return createHttpClient(config);
234
277
  }
235
278
 
236
- // src/confluence/converters/md-to-storage.ts
237
- import MarkdownIt from "markdown-it";
238
- var MarkdownToStorageConverter = class {
239
- md;
240
- constructor() {
241
- this.md = new MarkdownIt({
242
- html: true,
243
- linkify: true,
244
- breaks: true
245
- });
246
- this.md.renderer.rules.fence = (tokens, idx) => {
247
- const token = tokens[idx];
248
- const code = token.content.trim();
249
- const lang = token.info.trim();
250
- return `<ac:structured-macro ac:name="code" ac:schema-version="1">
251
- <ac:parameter ac:name="language">${lang || "text"}</ac:parameter>
252
- <ac:plain-text-body><![CDATA[${code}]]></ac:plain-text-body>
253
- </ac:structured-macro>`;
254
- };
255
- }
256
- convert(markdown) {
257
- return this.md.render(markdown);
258
- }
259
- };
260
-
261
- // src/confluence/converters/storage-to-md.ts
262
- var StorageToMarkdownConverter = class {
263
- convert(storageHtml, imageUrlMap) {
264
- let md = storageHtml;
265
- if (imageUrlMap && imageUrlMap.size > 0) {
266
- imageUrlMap.forEach((localPath, originalTag) => {
267
- const filename = localPath.split("/").pop() || "image";
268
- const altText = filename.replace(/\.[^.]+$/, "");
269
- const markdownImage = `![${altText}](${localPath})`;
270
- md = md.replace(originalTag, markdownImage);
271
- });
272
- }
273
- md = md.replace(
274
- /<ac:image[^>]*>[\s\S]*?<ri:attachment\s+ri:filename="([^"]+)"[\s\S]*?<\/ac:image>/g,
275
- (match, filename) => {
276
- return `![${filename}](attachment:${filename})`;
277
- }
278
- );
279
- md = md.replace(
280
- /<ac:image[^>]*>[\s\S]*?<ri:url\s+ri:value="([^"]+)"[\s\S]*?<\/ac:image>/g,
281
- (match, url) => {
282
- const filename = url.split("/").pop() || "image";
283
- return `![${filename}](${url})`;
284
- }
285
- );
286
- md = md.replace(
287
- /<img\s+[^>]*\/?>/g,
288
- (match) => {
289
- const srcMatch = /src="([^"]+)"/.exec(match);
290
- const altMatch = /alt="([^"]*)"/.exec(match);
291
- if (srcMatch) {
292
- const src = srcMatch[1];
293
- const altText = altMatch ? altMatch[1] : src.split("/").pop() || "image";
294
- return `![${altText}](${src})`;
295
- }
296
- return match;
297
- }
298
- );
299
- md = md.replace(/<ac:structured-macro[^>]*ac:name="code"[^>]*>[\s\S]*?<ac:parameter[^>]*ac:name="language">([^<]*)<\/ac:parameter>[\s\S]*?<ac:plain-text-body><!\[CDATA\[([\s\S]*?)\]\]><\/ac:plain-text-body>[\s\S]*?<\/ac:structured-macro>/g, (match, lang, code) => {
300
- return `\`\`\`${lang}
301
- ${code}
302
- \`\`\``;
303
- });
304
- md = md.replace(/<h1>(.*?)<\/h1>/g, "# $1\n");
305
- md = md.replace(/<h2>(.*?)<\/h2>/g, "## $1\n");
306
- md = md.replace(/<h3>(.*?)<\/h3>/g, "### $1\n");
307
- md = md.replace(/<p>(.*?)<\/p>/g, "$1\n\n");
308
- md = md.replace(/<strong>(.*?)<\/strong>/g, "**$1**");
309
- md = md.replace(/<b>(.*?)<\/b>/g, "**$1**");
310
- md = md.replace(/<em>(.*?)<\/em>/g, "*$1*");
311
- md = md.replace(/<i>(.*?)<\/i>/g, "*$1*");
312
- md = md.replace(/<ul>([\s\S]*?)<\/ul>/g, (match, content) => {
313
- return content.replace(/<li>(.*?)<\/li>/g, "- $1\n");
314
- });
315
- md = md.replace(/<ol>([\s\S]*?)<\/ol>/g, (match, content) => {
316
- let i = 1;
317
- return content.replace(/<li>(.*?)<\/li>/g, () => `${i++}. $1
318
- `);
319
- });
320
- md = md.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&").replace(/&quot;/g, '"');
321
- return md.trim();
322
- }
323
- };
324
-
325
- // src/common/config.ts
279
+ // tools/common/config.ts
326
280
  import dotenv from "dotenv";
327
281
  dotenv.config();
328
282
  function getEnvOrThrow(key, description) {
@@ -337,20 +291,31 @@ function getEnvOrThrow(key, description) {
337
291
  function loadConfluenceConfig() {
338
292
  const baseUrl = getEnvOrThrow("CONFLUENCE_BASE_URL", "Confluence \uAE30\uBCF8 URL");
339
293
  const username = process.env.CONFLUENCE_USERNAME;
340
- const token = getEnvOrThrow("CONFLUENCE_API_TOKEN", "Confluence API \uD1A0\uD070");
294
+ const token = getEnvOrThrow("CONFLUENCE_API_TOKEN", "Confluence PAT \uD1A0\uD070");
295
+ const mermaidMacroName = process.env.CONFLUENCE_MERMAID_MACRO_NAME || "mermaiddiagram";
296
+ const inlineCodeStyle = process.env.CONFLUENCE_INLINE_CODE_STYLE || "color: #d04437; font-weight: bold;";
341
297
  return {
342
298
  baseUrl,
343
299
  auth: {
344
300
  username,
345
301
  token
346
- // API 토큰은 일반적으로 패스워드 필드에 사용되지만, 여기서는 token으로 저장하여 범용성 확보
347
- }
302
+ },
303
+ mermaidMacroName,
304
+ inlineCodeStyle
305
+ };
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"
348
313
  };
349
314
  }
350
315
  function loadJiraConfig() {
351
316
  const baseUrl = getEnvOrThrow("JIRA_BASE_URL", "JIRA \uAE30\uBCF8 URL");
352
317
  const username = process.env.JIRA_USERNAME;
353
- const token = getEnvOrThrow("JIRA_API_TOKEN", "JIRA API \uD1A0\uD070");
318
+ const token = getEnvOrThrow("JIRA_API_TOKEN", "JIRA PAT \uD1A0\uD070");
354
319
  return {
355
320
  baseUrl,
356
321
  auth: {
@@ -370,7 +335,205 @@ function loadGitlabConfig() {
370
335
  };
371
336
  }
372
337
 
373
- // src/jira/api/issue.ts
338
+ // tools/confluence/converters/md-to-storage.ts
339
+ import MarkdownIt from "markdown-it";
340
+ var MarkdownToStorageConverter = class {
341
+ md;
342
+ mermaidMacroName;
343
+ inlineCodeStyle;
344
+ constructor() {
345
+ const config = loadConfluenceConfig();
346
+ this.mermaidMacroName = config.mermaidMacroName;
347
+ this.inlineCodeStyle = config.inlineCodeStyle;
348
+ this.md = new MarkdownIt({
349
+ html: true,
350
+ linkify: true,
351
+ breaks: true,
352
+ xhtmlOut: true
353
+ // Confluence XML 파서와의 호환성을 위해 XHTML 출력 활성화
354
+ });
355
+ this.md.renderer.rules.fence = (tokens, idx) => {
356
+ const token = tokens[idx];
357
+ const code = token.content.trim();
358
+ const lang = token.info.trim().toLowerCase();
359
+ if (lang === "mermaid") {
360
+ return `<ac:structured-macro ac:name="${this.mermaidMacroName}" ac:schema-version="1">
361
+ <ac:plain-text-body><![CDATA[${code}]]></ac:plain-text-body>
362
+ </ac:structured-macro>`;
363
+ }
364
+ if (lang === "plantuml") {
365
+ return `<ac:structured-macro ac:name="plantuml" ac:schema-version="1">
366
+ <ac:parameter ac:name="atlassian-macro-output-type">INLINE</ac:parameter>
367
+ <ac:plain-text-body><![CDATA[${code}]]></ac:plain-text-body>
368
+ </ac:structured-macro>`;
369
+ }
370
+ return `<ac:structured-macro ac:name="code" ac:schema-version="1">
371
+ <ac:parameter ac:name="language">${lang || "text"}</ac:parameter>
372
+ <ac:plain-text-body><![CDATA[${code}]]></ac:plain-text-body>
373
+ </ac:structured-macro>`;
374
+ };
375
+ this.md.renderer.rules.image = (tokens, idx, options, env, self) => {
376
+ const token = tokens[idx];
377
+ const src = token.attrGet("src") || "";
378
+ const alt = token.content || "";
379
+ const isExternal = src.startsWith("http://") || src.startsWith("https://");
380
+ const altAttr = alt ? ` ac:alt="${this.md.utils.escapeHtml(alt)}"` : "";
381
+ if (isExternal) {
382
+ return `<ac:image${altAttr}><ri:url ri:value="${src}" /></ac:image>`;
383
+ } else {
384
+ const filename = src.split("/").pop() || src;
385
+ return `<ac:image${altAttr}><ri:attachment ri:filename="${filename}" /></ac:image>`;
386
+ }
387
+ };
388
+ this.md.renderer.rules.code_inline = (tokens, idx) => {
389
+ const token = tokens[idx];
390
+ const content = this.md.utils.escapeHtml(token.content);
391
+ return `<code style="${this.inlineCodeStyle}">${content}</code>`;
392
+ };
393
+ }
394
+ convert(markdown) {
395
+ return this.md.render(markdown);
396
+ }
397
+ extractLocalImages(markdown) {
398
+ const tokens = this.md.parse(markdown, {});
399
+ const localImages = /* @__PURE__ */ new Set();
400
+ const walk = (tokens2) => {
401
+ for (const token of tokens2) {
402
+ if (token.type === "image") {
403
+ const src = token.attrGet("src") || "";
404
+ if (!src.startsWith("http://") && !src.startsWith("https://")) {
405
+ localImages.add(src);
406
+ }
407
+ }
408
+ if (token.children) {
409
+ walk(token.children);
410
+ }
411
+ }
412
+ };
413
+ walk(tokens);
414
+ return Array.from(localImages);
415
+ }
416
+ };
417
+
418
+ // tools/confluence/converters/storage-to-md.ts
419
+ import TurndownService from "turndown";
420
+ import { gfm } from "turndown-plugin-gfm";
421
+ import { JSDOM } from "jsdom";
422
+ var StorageToMarkdownConverter = class {
423
+ turndown;
424
+ constructor() {
425
+ this.turndown = new TurndownService({
426
+ headingStyle: "atx",
427
+ hr: "---",
428
+ bulletListMarker: "-",
429
+ codeBlockStyle: "fenced"
430
+ });
431
+ this.turndown.use(gfm);
432
+ this.setupRules();
433
+ }
434
+ setupRules() {
435
+ this.turndown.addRule("tables", {
436
+ filter: ["table"],
437
+ replacement: (content, node) => {
438
+ const element = node;
439
+ const rows = Array.from(element.rows);
440
+ if (rows.length === 0) return "";
441
+ let mdTable = "\n\n";
442
+ rows.forEach((row, index) => {
443
+ const cells = Array.from(row.cells);
444
+ const cellContents = cells.map((cell) => {
445
+ return this.turndown.turndown(cell.innerHTML).replace(/\n/g, " ").trim();
446
+ });
447
+ mdTable += `| ${cellContents.join(" | ")} |
448
+ `;
449
+ if (index === 0) {
450
+ const separators = cells.map((cell) => {
451
+ const style = cell.getAttribute("style") || "";
452
+ const align = style.match(/text-align:\s*(\w+)/i)?.[1]?.toLowerCase();
453
+ if (align === "center") return ":---:";
454
+ if (align === "right") return "---:";
455
+ if (align === "left") return ":---";
456
+ return "---";
457
+ });
458
+ mdTable += `| ${separators.join(" | ")} |
459
+ `;
460
+ }
461
+ });
462
+ return mdTable + "\n";
463
+ }
464
+ });
465
+ this.turndown.addRule("confluenceMacro", {
466
+ filter: (node) => {
467
+ return node.nodeName === "DIV" && node.getAttribute("data-macro-name-tag") !== null;
468
+ },
469
+ replacement: (content, node) => {
470
+ const element = node;
471
+ const macroName = element.getAttribute("data-macro-name");
472
+ if (macroName === "code") {
473
+ const lang = element.querySelector('[data-macro-param-name="language"]')?.textContent || "text";
474
+ let body = element.querySelector("[data-macro-body]")?.textContent || "";
475
+ body = body.replace(/__CDATA_START__/g, "").replace(/__CDATA_END__/g, "");
476
+ return `
477
+ \`\`\`${lang}
478
+ ${body.trim()}
479
+ \`\`\`
480
+ `;
481
+ }
482
+ if (macroName === "mermaid" || macroName === "mermaiddiagram" || macroName === "capable-mermaid" || macroName === "mermaid-macro") {
483
+ let body = element.querySelector("[data-macro-body]")?.textContent || "";
484
+ body = body.replace(/__CDATA_START__/g, "").replace(/__CDATA_END__/g, "");
485
+ return `
486
+ \`\`\`mermaid
487
+ ${body.trim()}
488
+ \`\`\`
489
+ `;
490
+ }
491
+ if (macroName === "plantuml") {
492
+ let body = element.querySelector("[data-macro-body]")?.textContent || "";
493
+ body = body.replace(/__CDATA_START__/g, "").replace(/__CDATA_END__/g, "");
494
+ return `
495
+ \`\`\`plantuml
496
+ ${body.trim()}
497
+ \`\`\`
498
+ `;
499
+ }
500
+ return `
501
+ <!-- Macro: ${macroName} -->
502
+ `;
503
+ }
504
+ });
505
+ }
506
+ convert(storageHtml, imageUrlMap) {
507
+ if (!storageHtml) return "";
508
+ let processedHtml = storageHtml.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/gi, (match, p1) => {
509
+ return `__CDATA_START__${p1}__CDATA_END__`;
510
+ }).replace(/<ac:structured-macro\s+ac:name="([^"]*)"/gi, '<div data-macro-name-tag data-macro-name="$1"').replace(/<\/ac:structured-macro>/gi, "</div>").replace(/<ac:parameter\s+ac:name="([^"]*)"/gi, '<div data-macro-param-tag data-macro-param-name="$1"').replace(/<\/ac:parameter>/gi, "</div>").replace(/<ac:plain-text-body>/gi, "<pre data-macro-body>").replace(/<\/ac:plain-text-body>/gi, "</pre>").replace(/<ac:image([^>]*)>[\s\S]*?<ri:attachment\s+ri:filename="([^"]*)"\s*\/?>[\s\S]*?<\/ac:image>/gi, (match, attrs, filename) => {
511
+ const altMatch = attrs.match(/ac:alt="([^"]*)"/i);
512
+ const alt = altMatch ? altMatch[1] : filename;
513
+ return `<img src="${filename}" alt="${alt}" />`;
514
+ }).replace(/<ac:image([^>]*)>[\s\S]*?<ri:url\s+ri:value="([^"]*)"\s*\/?>[\s\S]*?<\/ac:image>/gi, (match, attrs, url) => {
515
+ const altMatch = attrs.match(/ac:alt="([^"]*)"/i);
516
+ const alt = altMatch ? altMatch[1] : "";
517
+ return `<img src="${url}" alt="${alt}" />`;
518
+ });
519
+ const dom = new JSDOM(processedHtml);
520
+ const document = dom.window.document;
521
+ if (imageUrlMap && imageUrlMap.size > 0) {
522
+ const images = document.querySelectorAll("img");
523
+ images.forEach((img) => {
524
+ const src = img.getAttribute("src");
525
+ if (src && imageUrlMap.has(src)) {
526
+ img.setAttribute("src", imageUrlMap.get(src));
527
+ }
528
+ });
529
+ }
530
+ let markdown = this.turndown.turndown(document.body.innerHTML).trim();
531
+ markdown = markdown.replace(/^(#{1,6}\s.*?)\\\./gm, "$1.");
532
+ return markdown + "\n";
533
+ }
534
+ };
535
+
536
+ // tools/jira/api/issue.ts
374
537
  var JiraIssueApi = class {
375
538
  constructor(client) {
376
539
  this.client = client;
@@ -430,7 +593,7 @@ var JiraIssueApi = class {
430
593
  }
431
594
  };
432
595
 
433
- // src/jira/api/search.ts
596
+ // tools/jira/api/search.ts
434
597
  var JiraSearchApi = class {
435
598
  constructor(client) {
436
599
  this.client = client;
@@ -449,111 +612,12 @@ var JiraSearchApi = class {
449
612
  }
450
613
  };
451
614
 
452
- // src/jira/api/transition.ts
453
- var JiraTransitionApi = class {
454
- constructor(client) {
455
- this.client = client;
456
- }
457
- async getTransitions(issueKey) {
458
- const response = await this.client.get(`/rest/api/2/issue/${issueKey}/transitions`);
459
- return response.data.transitions;
460
- }
461
- async doTransition(issueKey, transitionId, fields) {
462
- const data = {
463
- transition: { id: transitionId }
464
- };
465
- if (fields) {
466
- data.fields = fields;
467
- }
468
- await this.client.post(`/rest/api/2/issue/${issueKey}/transitions`, data);
469
- }
470
- };
471
-
472
- // src/jira/api/comment.ts
473
- var JiraCommentApi = class {
474
- constructor(client) {
475
- this.client = client;
476
- }
477
- async getComments(issueKey, startAt = 0, maxResults = 50) {
478
- const response = await this.client.get(`/rest/api/2/issue/${issueKey}/comment`, {
479
- params: { startAt, maxResults }
480
- });
481
- return response.data;
482
- }
483
- async addComment(issueKey, body) {
484
- const response = await this.client.post(`/rest/api/2/issue/${issueKey}/comment`, { body });
485
- return response.data;
486
- }
487
- async updateComment(issueKey, commentId, body) {
488
- const response = await this.client.put(
489
- `/rest/api/2/issue/${issueKey}/comment/${commentId}`,
490
- { body }
491
- );
492
- return response.data;
493
- }
494
- async deleteComment(issueKey, commentId) {
495
- await this.client.delete(`/rest/api/2/issue/${issueKey}/comment/${commentId}`);
496
- }
497
- };
498
-
499
- // src/jira/api/project.ts
500
- var JiraProjectApi = class {
501
- constructor(client) {
502
- this.client = client;
503
- }
504
- async getProjects() {
505
- const response = await this.client.get("/rest/api/2/project");
506
- return response.data;
507
- }
508
- async getProject(projectKey) {
509
- const response = await this.client.get(`/rest/api/2/project/${projectKey}`);
510
- return response.data;
511
- }
512
- async getBoards(projectKeyOrId, type) {
513
- const params = {};
514
- if (projectKeyOrId) params.projectKeyOrId = projectKeyOrId;
515
- if (type) params.type = type;
516
- const response = await this.client.get("/rest/agile/1.0/board", { params });
517
- return response.data;
518
- }
519
- async getSprints(boardId, state) {
520
- const params = {};
521
- if (state) params.state = state;
522
- const response = await this.client.get(`/rest/agile/1.0/board/${boardId}/sprint`, {
523
- params
524
- });
525
- return response.data;
526
- }
527
- };
528
-
529
- // src/jira/api/client.ts
615
+ // tools/jira/api/client.ts
530
616
  function createJiraClient(config) {
531
617
  return createHttpClient(config);
532
618
  }
533
619
 
534
- // src/gitlab/api/project.ts
535
- var GitlabProjectApi = class {
536
- constructor(client) {
537
- this.client = client;
538
- }
539
- async getProjects(params) {
540
- const response = await this.client.get("/projects", {
541
- params: {
542
- search: params?.search,
543
- owned: params?.owned,
544
- membership: params?.membership,
545
- per_page: params?.perPage || 20
546
- }
547
- });
548
- return response.data;
549
- }
550
- async getProject(projectId) {
551
- const response = await this.client.get(`/projects/${encodeURIComponent(projectId)}`);
552
- return response.data;
553
- }
554
- };
555
-
556
- // src/gitlab/api/merge-request.ts
620
+ // tools/gitlab/api/merge-request.ts
557
621
  var GitlabMergeRequestApi = class {
558
622
  constructor(client) {
559
623
  this.client = client;
@@ -614,7 +678,7 @@ var GitlabMergeRequestApi = class {
614
678
  }
615
679
  };
616
680
 
617
- // src/gitlab/api/pipeline.ts
681
+ // tools/gitlab/api/pipeline.ts
618
682
  var GitlabPipelineApi = class {
619
683
  constructor(client) {
620
684
  this.client = client;
@@ -649,71 +713,7 @@ var GitlabPipelineApi = class {
649
713
  }
650
714
  };
651
715
 
652
- // src/gitlab/api/branch.ts
653
- var GitlabBranchApi = class {
654
- constructor(client) {
655
- this.client = client;
656
- }
657
- async getBranches(projectId, params) {
658
- const response = await this.client.get(`/projects/${projectId}/repository/branches`, {
659
- params: {
660
- search: params?.search,
661
- per_page: params?.perPage || 20
662
- }
663
- });
664
- return response.data;
665
- }
666
- async getBranch(projectId, branchName) {
667
- const response = await this.client.get(
668
- `/projects/${projectId}/repository/branches/${encodeURIComponent(branchName)}`
669
- );
670
- return response.data;
671
- }
672
- async createBranch(projectId, branchName, ref) {
673
- const response = await this.client.post(`/projects/${projectId}/repository/branches`, {
674
- branch: branchName,
675
- ref
676
- });
677
- return response.data;
678
- }
679
- async deleteBranch(projectId, branchName) {
680
- await this.client.delete(
681
- `/projects/${projectId}/repository/branches/${encodeURIComponent(branchName)}`
682
- );
683
- }
684
- };
685
-
686
- // src/gitlab/api/repository.ts
687
- var GitlabRepositoryApi = class {
688
- constructor(client) {
689
- this.client = client;
690
- }
691
- async getFile(projectId, filePath, ref) {
692
- const encodedPath = encodeURIComponent(filePath);
693
- const response = await this.client.get(
694
- `/projects/${projectId}/repository/files/${encodedPath}`,
695
- { params: { ref: ref || "HEAD" } }
696
- );
697
- const file = response.data;
698
- if (file.encoding === "base64") {
699
- file.content = Buffer.from(file.content, "base64").toString("utf-8");
700
- }
701
- return file;
702
- }
703
- async getTree(projectId, params) {
704
- const response = await this.client.get(`/projects/${projectId}/repository/tree`, {
705
- params: {
706
- path: params?.path,
707
- ref: params?.ref,
708
- recursive: params?.recursive,
709
- per_page: params?.perPage || 100
710
- }
711
- });
712
- return response.data;
713
- }
714
- };
715
-
716
- // src/gitlab/api/client.ts
716
+ // tools/gitlab/api/client.ts
717
717
  function createGitlabClient(config) {
718
718
  const client = createHttpClient({
719
719
  ...config,
@@ -728,22 +728,17 @@ export {
728
728
  ConfluenceSpaceApi,
729
729
  ConfluenceSearchApi,
730
730
  createConfluenceClient,
731
- MarkdownToStorageConverter,
732
- StorageToMarkdownConverter,
733
731
  loadConfluenceConfig,
732
+ loadAIConfig,
734
733
  loadJiraConfig,
735
734
  loadGitlabConfig,
735
+ MarkdownToStorageConverter,
736
+ StorageToMarkdownConverter,
736
737
  JiraIssueApi,
737
738
  JiraSearchApi,
738
- JiraTransitionApi,
739
- JiraCommentApi,
740
- JiraProjectApi,
741
739
  createJiraClient,
742
- GitlabProjectApi,
743
740
  GitlabMergeRequestApi,
744
741
  GitlabPipelineApi,
745
- GitlabBranchApi,
746
- GitlabRepositoryApi,
747
742
  createGitlabClient
748
743
  };
749
- //# sourceMappingURL=chunk-2IQ4QMK3.js.map
744
+ //# sourceMappingURL=chunk-6AFNYE7N.js.map