@iloom/cli 0.9.1 → 0.10.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.
Files changed (222) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +179 -41
  3. package/dist/{BranchNamingService-K6XNWQ6C.js → BranchNamingService-ECJHBB67.js} +2 -2
  4. package/dist/ClaudeContextManager-QXX6ZFST.js +14 -0
  5. package/dist/ClaudeService-NJNK2SUH.js +13 -0
  6. package/dist/{GitHubService-O7T6CFAJ.js → GitHubService-MEHKHUQP.js} +4 -4
  7. package/dist/IssueTrackerFactory-NG53YX5S.js +14 -0
  8. package/dist/{LoomLauncher-3I47SUPV.js → LoomLauncher-L64HHS3T.js} +9 -9
  9. package/dist/{MetadataManager-W3C54UYT.js → MetadataManager-5QZSTKNN.js} +2 -2
  10. package/dist/{ProjectCapabilityDetector-N5L7T4IY.js → ProjectCapabilityDetector-5KSYUTBJ.js} +3 -3
  11. package/dist/{PromptTemplateManager-36YLQRHP.js → PromptTemplateManager-DULSVRRE.js} +2 -2
  12. package/dist/README.md +179 -41
  13. package/dist/{SettingsManager-QR7V2IW2.js → SettingsManager-BQDQA3FK.js} +4 -2
  14. package/dist/agents/iloom-artifact-reviewer.md +11 -0
  15. package/dist/agents/iloom-code-reviewer.md +14 -0
  16. package/dist/agents/iloom-issue-analyze-and-plan.md +55 -12
  17. package/dist/agents/iloom-issue-analyzer.md +49 -6
  18. package/dist/agents/iloom-issue-complexity-evaluator.md +47 -6
  19. package/dist/agents/iloom-issue-enhancer.md +86 -7
  20. package/dist/agents/iloom-issue-implementer.md +48 -7
  21. package/dist/agents/iloom-issue-planner.md +115 -62
  22. package/dist/{build-IC4CJRMP.js → build-5GO3XW26.js} +9 -9
  23. package/dist/{chunk-USSL2X4A.js → chunk-3D7WQM7I.js} +2 -2
  24. package/dist/chunk-4232AHNQ.js +35 -0
  25. package/dist/chunk-4232AHNQ.js.map +1 -0
  26. package/dist/{chunk-QN47QVBX.js → chunk-4WJNIR5O.js} +1 -1
  27. package/dist/chunk-4WJNIR5O.js.map +1 -0
  28. package/dist/{chunk-2JPXGGP4.js → chunk-5MWV33NN.js} +4 -4
  29. package/dist/{chunk-POU2UMWN.js → chunk-6EU6TCF6.js} +10 -10
  30. package/dist/chunk-6EU6TCF6.js.map +1 -0
  31. package/dist/{chunk-Y5O2ALDZ.js → chunk-FB47TIJG.js} +29 -11
  32. package/dist/chunk-FB47TIJG.js.map +1 -0
  33. package/dist/chunk-HEXKPKCK.js +1396 -0
  34. package/dist/chunk-HEXKPKCK.js.map +1 -0
  35. package/dist/{chunk-KAYXR544.js → chunk-J5S7DFYC.js} +2 -2
  36. package/dist/{chunk-OK7LUTRW.js → chunk-JO2LZ6EQ.js} +476 -5
  37. package/dist/chunk-JO2LZ6EQ.js.map +1 -0
  38. package/dist/{chunk-KBEIQP4G.js → chunk-KB64WNBZ.js} +43 -3
  39. package/dist/chunk-KB64WNBZ.js.map +1 -0
  40. package/dist/{chunk-Y5HSSIK2.js → chunk-KXDRI47U.js} +71 -13
  41. package/dist/chunk-KXDRI47U.js.map +1 -0
  42. package/dist/{chunk-HZXBHMVM.js → chunk-LXLMMXXY.js} +54 -14
  43. package/dist/chunk-LXLMMXXY.js.map +1 -0
  44. package/dist/{chunk-H6ST2TGP.js → chunk-MNHZB4Z2.js} +4 -4
  45. package/dist/{chunk-TL72BGP6.js → chunk-MORRVYPT.js} +2 -2
  46. package/dist/{chunk-TGRK3CHF.js → chunk-NRSWLOAZ.js} +8 -8
  47. package/dist/chunk-NRSWLOAZ.js.map +1 -0
  48. package/dist/{chunk-FO5GGFOV.js → chunk-ONQYPICO.js} +13 -5
  49. package/dist/chunk-ONQYPICO.js.map +1 -0
  50. package/dist/{chunk-7ZEHSSUP.js → chunk-P4O6EH46.js} +4 -4
  51. package/dist/chunk-QZWEJVWV.js +207 -0
  52. package/dist/chunk-QZWEJVWV.js.map +1 -0
  53. package/dist/chunk-RSYT7MVI.js +202 -0
  54. package/dist/chunk-RSYT7MVI.js.map +1 -0
  55. package/dist/{chunk-OAVJR4PM.js → chunk-RYWFS37M.js} +6 -6
  56. package/dist/chunk-RYWFS37M.js.map +1 -0
  57. package/dist/{chunk-B7U6OKUR.js → chunk-SF2P22EE.js} +11 -3
  58. package/dist/chunk-SF2P22EE.js.map +1 -0
  59. package/dist/{chunk-MZPRBNYC.js → chunk-SN3SQCFK.js} +10 -8
  60. package/dist/{chunk-MZPRBNYC.js.map → chunk-SN3SQCFK.js.map} +1 -1
  61. package/dist/{chunk-4ZIHFUPN.js → chunk-UD3WJDIV.js} +145 -107
  62. package/dist/chunk-UD3WJDIV.js.map +1 -0
  63. package/dist/{chunk-3P6J4IZZ.js → chunk-UKBAJ2QQ.js} +61 -7
  64. package/dist/chunk-UKBAJ2QQ.js.map +1 -0
  65. package/dist/{chunk-RD7OPXZK.js → chunk-UVD4CZKS.js} +3 -3
  66. package/dist/chunk-UWGVCXRF.js +207 -0
  67. package/dist/chunk-UWGVCXRF.js.map +1 -0
  68. package/dist/{chunk-JT5LZRMI.js → chunk-VECNX6VX.js} +2 -2
  69. package/dist/{chunk-TRUMP4DA.js → chunk-VG45TUYK.js} +75 -6
  70. package/dist/chunk-VG45TUYK.js.map +1 -0
  71. package/dist/{chunk-4GAJJUYS.js → chunk-VGGST52X.js} +2 -2
  72. package/dist/{chunk-4LKGCFGG.js → chunk-WWKOVDWC.js} +2 -2
  73. package/dist/{chunk-2HZX6AMR.js → chunk-WY4QBK43.js} +7 -7
  74. package/dist/chunk-WY4QBK43.js.map +1 -0
  75. package/dist/chunk-Y4YZTHZE.js +73 -0
  76. package/dist/chunk-Y4YZTHZE.js.map +1 -0
  77. package/dist/{chunk-VOGGLPG5.js → chunk-YQ57ORTV.js} +14 -1
  78. package/dist/chunk-YQ57ORTV.js.map +1 -0
  79. package/dist/{chunk-XFEK2X2D.js → chunk-YYAKPQBT.js} +73 -20
  80. package/dist/chunk-YYAKPQBT.js.map +1 -0
  81. package/dist/{chunk-NTTSUAVM.js → chunk-ZEWU5PZK.js} +2 -2
  82. package/dist/{chunk-5LVVQGB3.js → chunk-ZHPNZC75.js} +17 -17
  83. package/dist/chunk-ZHPNZC75.js.map +1 -0
  84. package/dist/{chunk-I3HMNWQQ.js → chunk-ZW2LKWWE.js} +9 -9
  85. package/dist/chunk-ZW2LKWWE.js.map +1 -0
  86. package/dist/{claude-TP2QO3BU.js → claude-P3NQR6IJ.js} +2 -2
  87. package/dist/{cleanup-D3CSRBBZ.js → cleanup-6UCPVMFG.js} +81 -32
  88. package/dist/cleanup-6UCPVMFG.js.map +1 -0
  89. package/dist/cli.js +640 -350
  90. package/dist/cli.js.map +1 -1
  91. package/dist/{commit-IWGT42XN.js → commit-L3EPY5QG.js} +23 -21
  92. package/dist/commit-L3EPY5QG.js.map +1 -0
  93. package/dist/{compile-EOWJORKO.js → compile-ZS4HYRX5.js} +9 -9
  94. package/dist/{contribute-WSJTV2RX.js → contribute-ORDDQGSL.js} +14 -6
  95. package/dist/contribute-ORDDQGSL.js.map +1 -0
  96. package/dist/{dev-server-Q6M62ATG.js → dev-server-FYZ2AQIH.js} +29 -15
  97. package/dist/dev-server-FYZ2AQIH.js.map +1 -0
  98. package/dist/{feedback-QPNDZQRV.js → feedback-TMBXSCM5.js} +15 -15
  99. package/dist/{git-W3XUIFTR.js → git-ET64COO3.js} +4 -4
  100. package/dist/hooks/iloom-hook.js +15 -0
  101. package/dist/ignite-CGOV3TD4.js +1393 -0
  102. package/dist/ignite-CGOV3TD4.js.map +1 -0
  103. package/dist/index.d.ts +397 -53
  104. package/dist/index.js +1178 -40
  105. package/dist/index.js.map +1 -1
  106. package/dist/{init-ALYWKNWG.js → init-GFQ5W7GK.js} +57 -21
  107. package/dist/init-GFQ5W7GK.js.map +1 -0
  108. package/dist/issues-T4ZZSPEG.js +179 -0
  109. package/dist/issues-T4ZZSPEG.js.map +1 -0
  110. package/dist/{lint-IHUH45OC.js → lint-6TQXDZ3T.js} +9 -9
  111. package/dist/mcp/issue-management-server.js +2472 -257
  112. package/dist/mcp/issue-management-server.js.map +1 -1
  113. package/dist/mcp/recap-server.js +144 -21
  114. package/dist/mcp/recap-server.js.map +1 -1
  115. package/dist/{neon-helpers-VVFFTLXE.js → neon-helpers-CQN2PB4S.js} +3 -3
  116. package/dist/neon-helpers-CQN2PB4S.js.map +1 -0
  117. package/dist/{open-KWOV2OFO.js → open-5QZGXQRF.js} +15 -15
  118. package/dist/open-5QZGXQRF.js.map +1 -0
  119. package/dist/{plan-BRJBFJHF.js → plan-U7ZQWLFY.js} +41 -25
  120. package/dist/plan-U7ZQWLFY.js.map +1 -0
  121. package/dist/{projects-LH362JZQ.js → projects-2UOXFLNZ.js} +4 -4
  122. package/dist/prompts/CLAUDE.md +62 -0
  123. package/dist/prompts/init-prompt.txt +386 -47
  124. package/dist/prompts/issue-prompt.txt +427 -54
  125. package/dist/prompts/plan-prompt.txt +97 -16
  126. package/dist/prompts/pr-prompt.txt +44 -1
  127. package/dist/prompts/regular-prompt.txt +42 -1
  128. package/dist/prompts/session-summary-prompt.txt +14 -0
  129. package/dist/prompts/swarm-orchestrator-prompt.txt +437 -0
  130. package/dist/{rebase-AJOJOZUG.js → rebase-DWIB77KV.js} +10 -10
  131. package/dist/{recap-GKJXMDXW.js → recap-MX63HAKV.js} +47 -19
  132. package/dist/recap-MX63HAKV.js.map +1 -0
  133. package/dist/{run-QEUVZF7J.js → run-O3TFNQFC.js} +15 -15
  134. package/dist/run-O3TFNQFC.js.map +1 -0
  135. package/dist/schema/package-iloom.schema.json +58 -0
  136. package/dist/schema/settings.schema.json +130 -15
  137. package/dist/{shell-DAAVG4YN.js → shell-G6VC2CYR.js} +14 -7
  138. package/dist/shell-G6VC2CYR.js.map +1 -0
  139. package/dist/{summary-ZKOA35PT.js → summary-FWHAX55O.js} +27 -25
  140. package/dist/summary-FWHAX55O.js.map +1 -0
  141. package/dist/{test-5GPWWO3P.js → test-F7JNJZYP.js} +9 -9
  142. package/dist/{test-git-EJUKDB7F.js → test-git-BTAOIUE2.js} +4 -4
  143. package/dist/test-jira-CHYNV33F.js +96 -0
  144. package/dist/test-jira-CHYNV33F.js.map +1 -0
  145. package/dist/{test-prefix-23TOBUXY.js → test-prefix-Q6TFSU6F.js} +4 -4
  146. package/dist/{test-webserver-CKROHFBQ.js → test-webserver-EONCG7E7.js} +6 -6
  147. package/dist/{vscode-6TOLFCI2.js → vscode-VA5X4P25.js} +7 -7
  148. package/package.json +5 -1
  149. package/dist/ClaudeContextManager-X2Y72GRL.js +0 -14
  150. package/dist/ClaudeService-7P32TTES.js +0 -13
  151. package/dist/chunk-2HZX6AMR.js.map +0 -1
  152. package/dist/chunk-3P6J4IZZ.js.map +0 -1
  153. package/dist/chunk-4ZIHFUPN.js.map +0 -1
  154. package/dist/chunk-5LVVQGB3.js.map +0 -1
  155. package/dist/chunk-B7U6OKUR.js.map +0 -1
  156. package/dist/chunk-ENGCJIYQ.js +0 -520
  157. package/dist/chunk-ENGCJIYQ.js.map +0 -1
  158. package/dist/chunk-FO5GGFOV.js.map +0 -1
  159. package/dist/chunk-HZXBHMVM.js.map +0 -1
  160. package/dist/chunk-I3HMNWQQ.js.map +0 -1
  161. package/dist/chunk-J7FJ6PUT.js +0 -121
  162. package/dist/chunk-J7FJ6PUT.js.map +0 -1
  163. package/dist/chunk-KBEIQP4G.js.map +0 -1
  164. package/dist/chunk-OAVJR4PM.js.map +0 -1
  165. package/dist/chunk-OK7LUTRW.js.map +0 -1
  166. package/dist/chunk-POU2UMWN.js.map +0 -1
  167. package/dist/chunk-QN47QVBX.js.map +0 -1
  168. package/dist/chunk-TGRK3CHF.js.map +0 -1
  169. package/dist/chunk-TRUMP4DA.js.map +0 -1
  170. package/dist/chunk-VOGGLPG5.js.map +0 -1
  171. package/dist/chunk-XFEK2X2D.js.map +0 -1
  172. package/dist/chunk-Y5HSSIK2.js.map +0 -1
  173. package/dist/chunk-Y5O2ALDZ.js.map +0 -1
  174. package/dist/cleanup-D3CSRBBZ.js.map +0 -1
  175. package/dist/commit-IWGT42XN.js.map +0 -1
  176. package/dist/contribute-WSJTV2RX.js.map +0 -1
  177. package/dist/dev-server-Q6M62ATG.js.map +0 -1
  178. package/dist/ignite-OPO6EDYT.js +0 -784
  179. package/dist/ignite-OPO6EDYT.js.map +0 -1
  180. package/dist/init-ALYWKNWG.js.map +0 -1
  181. package/dist/issues-L7TBUPXT.js +0 -116
  182. package/dist/issues-L7TBUPXT.js.map +0 -1
  183. package/dist/open-KWOV2OFO.js.map +0 -1
  184. package/dist/plan-BRJBFJHF.js.map +0 -1
  185. package/dist/recap-GKJXMDXW.js.map +0 -1
  186. package/dist/run-QEUVZF7J.js.map +0 -1
  187. package/dist/shell-DAAVG4YN.js.map +0 -1
  188. package/dist/summary-ZKOA35PT.js.map +0 -1
  189. /package/dist/{BranchNamingService-K6XNWQ6C.js.map → BranchNamingService-ECJHBB67.js.map} +0 -0
  190. /package/dist/{ClaudeContextManager-X2Y72GRL.js.map → ClaudeContextManager-QXX6ZFST.js.map} +0 -0
  191. /package/dist/{ClaudeService-7P32TTES.js.map → ClaudeService-NJNK2SUH.js.map} +0 -0
  192. /package/dist/{GitHubService-O7T6CFAJ.js.map → GitHubService-MEHKHUQP.js.map} +0 -0
  193. /package/dist/{MetadataManager-W3C54UYT.js.map → IssueTrackerFactory-NG53YX5S.js.map} +0 -0
  194. /package/dist/{LoomLauncher-3I47SUPV.js.map → LoomLauncher-L64HHS3T.js.map} +0 -0
  195. /package/dist/{ProjectCapabilityDetector-N5L7T4IY.js.map → MetadataManager-5QZSTKNN.js.map} +0 -0
  196. /package/dist/{PromptTemplateManager-36YLQRHP.js.map → ProjectCapabilityDetector-5KSYUTBJ.js.map} +0 -0
  197. /package/dist/{SettingsManager-QR7V2IW2.js.map → PromptTemplateManager-DULSVRRE.js.map} +0 -0
  198. /package/dist/{claude-TP2QO3BU.js.map → SettingsManager-BQDQA3FK.js.map} +0 -0
  199. /package/dist/{build-IC4CJRMP.js.map → build-5GO3XW26.js.map} +0 -0
  200. /package/dist/{chunk-USSL2X4A.js.map → chunk-3D7WQM7I.js.map} +0 -0
  201. /package/dist/{chunk-2JPXGGP4.js.map → chunk-5MWV33NN.js.map} +0 -0
  202. /package/dist/{chunk-KAYXR544.js.map → chunk-J5S7DFYC.js.map} +0 -0
  203. /package/dist/{chunk-H6ST2TGP.js.map → chunk-MNHZB4Z2.js.map} +0 -0
  204. /package/dist/{chunk-TL72BGP6.js.map → chunk-MORRVYPT.js.map} +0 -0
  205. /package/dist/{chunk-7ZEHSSUP.js.map → chunk-P4O6EH46.js.map} +0 -0
  206. /package/dist/{chunk-RD7OPXZK.js.map → chunk-UVD4CZKS.js.map} +0 -0
  207. /package/dist/{chunk-JT5LZRMI.js.map → chunk-VECNX6VX.js.map} +0 -0
  208. /package/dist/{chunk-4GAJJUYS.js.map → chunk-VGGST52X.js.map} +0 -0
  209. /package/dist/{chunk-4LKGCFGG.js.map → chunk-WWKOVDWC.js.map} +0 -0
  210. /package/dist/{chunk-NTTSUAVM.js.map → chunk-ZEWU5PZK.js.map} +0 -0
  211. /package/dist/{git-W3XUIFTR.js.map → claude-P3NQR6IJ.js.map} +0 -0
  212. /package/dist/{compile-EOWJORKO.js.map → compile-ZS4HYRX5.js.map} +0 -0
  213. /package/dist/{feedback-QPNDZQRV.js.map → feedback-TMBXSCM5.js.map} +0 -0
  214. /package/dist/{neon-helpers-VVFFTLXE.js.map → git-ET64COO3.js.map} +0 -0
  215. /package/dist/{lint-IHUH45OC.js.map → lint-6TQXDZ3T.js.map} +0 -0
  216. /package/dist/{projects-LH362JZQ.js.map → projects-2UOXFLNZ.js.map} +0 -0
  217. /package/dist/{rebase-AJOJOZUG.js.map → rebase-DWIB77KV.js.map} +0 -0
  218. /package/dist/{test-5GPWWO3P.js.map → test-F7JNJZYP.js.map} +0 -0
  219. /package/dist/{test-git-EJUKDB7F.js.map → test-git-BTAOIUE2.js.map} +0 -0
  220. /package/dist/{test-prefix-23TOBUXY.js.map → test-prefix-Q6TFSU6F.js.map} +0 -0
  221. /package/dist/{test-webserver-CKROHFBQ.js.map → test-webserver-EONCG7E7.js.map} +0 -0
  222. /package/dist/{vscode-6TOLFCI2.js.map → vscode-VA5X4P25.js.map} +0 -0
@@ -1,32 +1,44 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ escapeJql
4
+ } from "./chunk-4232AHNQ.js";
5
+ import {
6
+ SettingsManager
7
+ } from "./chunk-YYAKPQBT.js";
8
+ import {
9
+ JiraIssueTracker,
3
10
  createLinearChildIssue,
4
11
  createLinearComment,
5
12
  createLinearIssue,
6
13
  createLinearIssueRelation,
7
14
  deleteLinearIssueRelation,
15
+ editLinearIssue,
8
16
  fetchLinearIssue,
9
17
  fetchLinearIssueComments,
10
18
  findLinearIssueRelation,
11
19
  getLinearChildIssues,
12
20
  getLinearComment,
13
21
  getLinearIssueDependencies,
14
- updateLinearComment
15
- } from "./chunk-ENGCJIYQ.js";
22
+ updateLinearComment,
23
+ updateLinearIssueState
24
+ } from "./chunk-HEXKPKCK.js";
16
25
  import {
17
26
  addSubIssue,
27
+ closeGhIssue,
18
28
  createIssue,
19
29
  createIssueComment,
20
30
  createIssueDependency,
21
31
  createPRComment,
32
+ editGhIssue,
22
33
  executeGhCommand,
23
34
  getIssueDatabaseId,
24
35
  getIssueDependencies,
25
36
  getIssueNodeId,
26
37
  getSubIssues,
27
38
  removeIssueDependency,
39
+ reopenGhIssue,
28
40
  updateIssueComment
29
- } from "./chunk-TRUMP4DA.js";
41
+ } from "./chunk-VG45TUYK.js";
30
42
  import {
31
43
  logger
32
44
  } from "./chunk-VT4PDUYT.js";
@@ -429,6 +441,55 @@ var GitHubIssueManagementProvider = class {
429
441
  }
430
442
  return result;
431
443
  }
444
+ /**
445
+ * Fetch PR review comments (inline code comments on specific files/lines)
446
+ * Uses gh api with --paginate to handle PRs with many review comments
447
+ * Optionally filters by review ID
448
+ */
449
+ async getReviewComments(input) {
450
+ const { number, reviewId, repo } = input;
451
+ const prNumber = parseInt(number, 10);
452
+ if (isNaN(prNumber)) {
453
+ throw new Error(`Invalid GitHub PR number: ${number}. GitHub PR IDs must be numeric.`);
454
+ }
455
+ let numericReviewId;
456
+ if (reviewId) {
457
+ numericReviewId = parseInt(reviewId, 10);
458
+ if (isNaN(numericReviewId)) {
459
+ throw new Error(`Invalid review ID: ${reviewId}. Review IDs must be numeric.`);
460
+ }
461
+ }
462
+ const apiPath = repo ? `repos/${repo}/pulls/${prNumber}/comments` : `repos/:owner/:repo/pulls/${prNumber}/comments`;
463
+ const args = [
464
+ "api",
465
+ apiPath,
466
+ "--paginate",
467
+ "--jq",
468
+ "[.[] | {id: .id, body: .body, path: .path, line: .line, side: .side, user: .user, created_at: .created_at, updated_at: .updated_at, in_reply_to_id: .in_reply_to_id, pull_request_review_id: .pull_request_review_id}]"
469
+ ];
470
+ const raw = await executeGhCommand(args);
471
+ let comments = raw;
472
+ if (numericReviewId !== void 0) {
473
+ comments = comments.filter((c) => c.pull_request_review_id === numericReviewId);
474
+ }
475
+ const results = [];
476
+ for (const comment of comments) {
477
+ const processedBody = await processMarkdownImages(comment.body, "github");
478
+ results.push({
479
+ id: String(comment.id),
480
+ body: processedBody,
481
+ path: comment.path,
482
+ line: comment.line,
483
+ side: comment.side,
484
+ author: normalizeAuthor(comment.user),
485
+ createdAt: comment.created_at,
486
+ updatedAt: comment.updated_at ?? null,
487
+ inReplyToId: comment.in_reply_to_id ? String(comment.in_reply_to_id) : null,
488
+ pullRequestReviewId: comment.pull_request_review_id
489
+ });
490
+ }
491
+ return results;
492
+ }
432
493
  /**
433
494
  * Fetch a specific comment by ID using gh API
434
495
  * Normalizes author to FlexibleAuthor format
@@ -588,6 +649,55 @@ var GitHubIssueManagementProvider = class {
588
649
  }
589
650
  return await getSubIssues(issueNumber, repo);
590
651
  }
652
+ /**
653
+ * Close an issue
654
+ */
655
+ async closeIssue(input) {
656
+ const { number, repo } = input;
657
+ const issueNumber = parseInt(number, 10);
658
+ if (isNaN(issueNumber)) {
659
+ throw new Error(`Invalid GitHub issue number: ${number}. GitHub issue IDs must be numeric.`);
660
+ }
661
+ await closeGhIssue(issueNumber, repo);
662
+ }
663
+ /**
664
+ * Reopen a closed issue
665
+ */
666
+ async reopenIssue(input) {
667
+ const { number, repo } = input;
668
+ const issueNumber = parseInt(number, 10);
669
+ if (isNaN(issueNumber)) {
670
+ throw new Error(`Invalid GitHub issue number: ${number}. GitHub issue IDs must be numeric.`);
671
+ }
672
+ await reopenGhIssue(issueNumber, repo);
673
+ }
674
+ /**
675
+ * Edit an issue's properties
676
+ * State changes are delegated to closeIssue/reopenIssue
677
+ */
678
+ async editIssue(input) {
679
+ const { number, title, body, state, labels, repo } = input;
680
+ const issueNumber = parseInt(number, 10);
681
+ if (isNaN(issueNumber)) {
682
+ throw new Error(`Invalid GitHub issue number: ${number}. GitHub issue IDs must be numeric.`);
683
+ }
684
+ if (state === "closed") {
685
+ await this.closeIssue({ number, repo });
686
+ } else if (state === "open") {
687
+ await this.reopenIssue({ number, repo });
688
+ }
689
+ if (title !== void 0 || body !== void 0 || labels !== void 0) {
690
+ await editGhIssue(
691
+ issueNumber,
692
+ {
693
+ ...title !== void 0 && { title },
694
+ ...body !== void 0 && { body },
695
+ ...labels !== void 0 && { labels }
696
+ },
697
+ repo
698
+ );
699
+ }
700
+ }
591
701
  };
592
702
 
593
703
  // src/utils/linear-markup-converter.ts
@@ -940,19 +1050,380 @@ var LinearIssueManagementProvider = class {
940
1050
  const { number } = input;
941
1051
  return await getLinearChildIssues(number);
942
1052
  }
1053
+ /**
1054
+ * Close an issue by transitioning to "Done" state
1055
+ */
1056
+ async closeIssue(input) {
1057
+ const { number } = input;
1058
+ await updateLinearIssueState(number, "Done");
1059
+ }
1060
+ /**
1061
+ * Reopen a closed issue by transitioning to "Todo" state
1062
+ */
1063
+ async reopenIssue(input) {
1064
+ const { number } = input;
1065
+ await updateLinearIssueState(number, "Todo");
1066
+ }
1067
+ /**
1068
+ * Edit an issue's properties
1069
+ * State changes are delegated to closeIssue/reopenIssue
1070
+ */
1071
+ async editIssue(input) {
1072
+ const { number, title, body, state } = input;
1073
+ if (state === "closed") {
1074
+ await this.closeIssue({ number });
1075
+ } else if (state === "open") {
1076
+ await this.reopenIssue({ number });
1077
+ }
1078
+ if (title !== void 0 || body !== void 0) {
1079
+ await editLinearIssue(number, {
1080
+ ...title !== void 0 && { title },
1081
+ ...body !== void 0 && { description: body }
1082
+ });
1083
+ }
1084
+ }
1085
+ };
1086
+
1087
+ // src/mcp/JiraIssueManagementProvider.ts
1088
+ function normalizeAuthor2(author) {
1089
+ if (!author) return null;
1090
+ return {
1091
+ id: author.accountId ?? author.emailAddress ?? "unknown",
1092
+ displayName: author.displayName ?? author.emailAddress ?? "Unknown",
1093
+ ...author.emailAddress && { email: author.emailAddress },
1094
+ ...author.accountId && { accountId: author.accountId }
1095
+ };
1096
+ }
1097
+ var getJiraTrackerConfig = (settings) => {
1098
+ var _a;
1099
+ const jiraSettings = (_a = settings.issueManagement) == null ? void 0 : _a.jira;
1100
+ if ((jiraSettings == null ? void 0 : jiraSettings.host) && (jiraSettings == null ? void 0 : jiraSettings.username) && (jiraSettings == null ? void 0 : jiraSettings.apiToken) && (jiraSettings == null ? void 0 : jiraSettings.projectKey)) {
1101
+ const config = {
1102
+ host: jiraSettings.host,
1103
+ username: jiraSettings.username,
1104
+ apiToken: jiraSettings.apiToken,
1105
+ projectKey: jiraSettings.projectKey
1106
+ };
1107
+ if (jiraSettings.transitionMappings) {
1108
+ config.transitionMappings = jiraSettings.transitionMappings;
1109
+ }
1110
+ if (jiraSettings.defaultIssueType) {
1111
+ config.defaultIssueType = jiraSettings.defaultIssueType;
1112
+ }
1113
+ if (jiraSettings.defaultSubtaskType) {
1114
+ config.defaultSubtaskType = jiraSettings.defaultSubtaskType;
1115
+ }
1116
+ return config;
1117
+ }
1118
+ if (process.env.JIRA_HOST && process.env.JIRA_USERNAME && process.env.JIRA_API_TOKEN && process.env.JIRA_PROJECT_KEY) {
1119
+ const config = {
1120
+ host: process.env.JIRA_HOST,
1121
+ username: process.env.JIRA_USERNAME,
1122
+ apiToken: process.env.JIRA_API_TOKEN,
1123
+ projectKey: process.env.JIRA_PROJECT_KEY
1124
+ };
1125
+ if (process.env.JIRA_TRANSITION_MAPPINGS) {
1126
+ try {
1127
+ config.transitionMappings = JSON.parse(process.env.JIRA_TRANSITION_MAPPINGS);
1128
+ } catch {
1129
+ throw new Error("Invalid JSON in JIRA_TRANSITION_MAPPINGS environment variable");
1130
+ }
1131
+ }
1132
+ if (process.env.JIRA_DEFAULT_ISSUE_TYPE) {
1133
+ config.defaultIssueType = process.env.JIRA_DEFAULT_ISSUE_TYPE;
1134
+ }
1135
+ if (process.env.JIRA_DEFAULT_SUBTASK_TYPE) {
1136
+ config.defaultSubtaskType = process.env.JIRA_DEFAULT_SUBTASK_TYPE;
1137
+ }
1138
+ return config;
1139
+ }
1140
+ throw new Error(
1141
+ "Missing required Jira settings: issueManagement.jira.{host, username, apiToken, projectKey} or corresponding environment variables"
1142
+ );
1143
+ };
1144
+ var JiraIssueManagementProvider = class _JiraIssueManagementProvider {
1145
+ constructor(settings) {
1146
+ this.providerName = "jira";
1147
+ this.issuePrefix = "";
1148
+ const config = getJiraTrackerConfig(settings);
1149
+ this.tracker = new JiraIssueTracker(config);
1150
+ this.projectKey = config.projectKey;
1151
+ }
1152
+ /**
1153
+ * Static factory for convenience when settings aren't pre-loaded
1154
+ */
1155
+ static async create() {
1156
+ const settingsManager = new SettingsManager();
1157
+ const settings = await settingsManager.loadSettings();
1158
+ return new _JiraIssueManagementProvider(settings);
1159
+ }
1160
+ /**
1161
+ * Fetch issue details using JiraIssueTracker
1162
+ */
1163
+ async getIssue(input) {
1164
+ const { number, includeComments = true } = input;
1165
+ const issue = await this.tracker.getIssue(number);
1166
+ const issueExt = issue;
1167
+ const result = {
1168
+ id: issueExt.id ?? String(issue.number),
1169
+ title: issue.title,
1170
+ body: issue.body,
1171
+ state: issue.state,
1172
+ url: issue.url,
1173
+ provider: "jira",
1174
+ author: normalizeAuthor2(issueExt.author),
1175
+ number: issue.number,
1176
+ key: issueExt.key,
1177
+ // Preserve Jira-specific fields
1178
+ ...issueExt.issueType && { issueType: issueExt.issueType },
1179
+ ...issueExt.priority && { priority: issueExt.priority },
1180
+ ...issueExt.status && { status: issueExt.status }
1181
+ };
1182
+ if (issue.labels && issue.labels.length > 0) {
1183
+ result.labels = issue.labels.map((label) => ({ name: label }));
1184
+ }
1185
+ if (issue.assignees && issue.assignees.length > 0) {
1186
+ result.assignees = issue.assignees.map((name) => ({
1187
+ id: name,
1188
+ displayName: name
1189
+ }));
1190
+ }
1191
+ if (includeComments) {
1192
+ const comments = await this.tracker.getComments(number);
1193
+ result.comments = comments.map((comment) => ({
1194
+ id: comment.id,
1195
+ body: comment.body,
1196
+ author: normalizeAuthor2(comment.author),
1197
+ createdAt: comment.createdAt,
1198
+ updatedAt: comment.updatedAt
1199
+ }));
1200
+ }
1201
+ return result;
1202
+ }
1203
+ /**
1204
+ * Fetch a specific comment by ID
1205
+ */
1206
+ async getComment(input) {
1207
+ const { commentId, number } = input;
1208
+ const comments = await this.tracker.getComments(number);
1209
+ const comment = comments.find((c) => c.id === commentId);
1210
+ if (!comment) {
1211
+ throw new Error(`Comment ${commentId} not found on issue ${number}`);
1212
+ }
1213
+ return {
1214
+ id: comment.id,
1215
+ body: comment.body,
1216
+ author: normalizeAuthor2(comment.author),
1217
+ created_at: comment.createdAt,
1218
+ updated_at: comment.updatedAt
1219
+ };
1220
+ }
1221
+ /**
1222
+ * Create a new comment on an issue
1223
+ */
1224
+ async createComment(input) {
1225
+ const { number, body } = input;
1226
+ const normalizedKey = this.tracker.normalizeIdentifier(number);
1227
+ const comment = await this.tracker.addComment(normalizedKey, body);
1228
+ return {
1229
+ id: comment.id,
1230
+ url: `${this.tracker.getConfig().host}/browse/${normalizedKey}?focusedCommentId=${comment.id}`,
1231
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
1232
+ };
1233
+ }
1234
+ /**
1235
+ * Update an existing comment
1236
+ */
1237
+ async updateComment(input) {
1238
+ const { commentId, number, body } = input;
1239
+ const normalizedKey = this.tracker.normalizeIdentifier(number);
1240
+ await this.tracker.updateComment(normalizedKey, commentId, body);
1241
+ return {
1242
+ id: commentId,
1243
+ url: `${this.tracker.getConfig().host}/browse/${normalizedKey}?focusedCommentId=${commentId}`,
1244
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
1245
+ };
1246
+ }
1247
+ /**
1248
+ * Create a new issue
1249
+ */
1250
+ async createIssue(input) {
1251
+ const { title, body } = input;
1252
+ const issue = await this.tracker.createIssue(title, body);
1253
+ const result = {
1254
+ id: String(issue.number),
1255
+ url: issue.url
1256
+ };
1257
+ if (typeof issue.number === "number") {
1258
+ result.number = issue.number;
1259
+ }
1260
+ return result;
1261
+ }
1262
+ /**
1263
+ * Fetch pull request details
1264
+ * Jira does not have pull requests - throw like Linear does
1265
+ */
1266
+ async getPR(_input) {
1267
+ throw new Error(
1268
+ "Jira does not support pull requests. PRs exist only on GitHub. Use the GitHub provider for PR operations."
1269
+ );
1270
+ }
1271
+ /**
1272
+ * Create a child issue linked to a parent issue
1273
+ * Uses Jira's parent field to create a subtask
1274
+ */
1275
+ async createChildIssue(input) {
1276
+ const { parentId, title, body } = input;
1277
+ const parentKey = this.tracker.normalizeIdentifier(parentId);
1278
+ const jiraIssue = await this.tracker.getApiClient().createIssueWithParent(
1279
+ this.projectKey,
1280
+ title,
1281
+ body,
1282
+ parentKey,
1283
+ this.tracker.getConfig().defaultSubtaskType
1284
+ );
1285
+ return {
1286
+ id: jiraIssue.key,
1287
+ url: `${this.tracker.getConfig().host}/browse/${jiraIssue.key}`
1288
+ };
1289
+ }
1290
+ /**
1291
+ * Create a blocking dependency between two issues
1292
+ * Uses Jira issue links with "Blocks" link type
1293
+ */
1294
+ async createDependency(input) {
1295
+ const blockingKey = this.tracker.normalizeIdentifier(input.blockingIssue);
1296
+ const blockedKey = this.tracker.normalizeIdentifier(input.blockedIssue);
1297
+ await this.tracker.getApiClient().createIssueLink(blockingKey, blockedKey, "Blocks");
1298
+ }
1299
+ /**
1300
+ * Get dependencies for an issue
1301
+ * Parses issue links of type "Blocks"
1302
+ */
1303
+ async getDependencies(input) {
1304
+ const issueKey = this.tracker.normalizeIdentifier(input.number);
1305
+ const host = this.tracker.getConfig().host;
1306
+ const issue = await this.tracker.getApiClient().getIssue(issueKey);
1307
+ const links = issue.fields.issuelinks ?? [];
1308
+ const blocking = [];
1309
+ const blockedBy = [];
1310
+ for (const link of links) {
1311
+ if (link.type.name !== "Blocks") continue;
1312
+ if (link.inwardIssue) {
1313
+ blockedBy.push({
1314
+ id: link.inwardIssue.key,
1315
+ title: link.inwardIssue.fields.summary,
1316
+ url: `${host}/browse/${link.inwardIssue.key}`,
1317
+ state: link.inwardIssue.fields.status.name.toLowerCase()
1318
+ });
1319
+ }
1320
+ if (link.outwardIssue) {
1321
+ blocking.push({
1322
+ id: link.outwardIssue.key,
1323
+ title: link.outwardIssue.fields.summary,
1324
+ url: `${host}/browse/${link.outwardIssue.key}`,
1325
+ state: link.outwardIssue.fields.status.name.toLowerCase()
1326
+ });
1327
+ }
1328
+ }
1329
+ if (input.direction === "blocking") {
1330
+ return { blocking, blockedBy: [] };
1331
+ }
1332
+ if (input.direction === "blocked_by") {
1333
+ return { blocking: [], blockedBy };
1334
+ }
1335
+ return { blocking, blockedBy };
1336
+ }
1337
+ /**
1338
+ * Remove a blocking dependency between two issues
1339
+ * Finds the matching "Blocks" link and deletes it
1340
+ */
1341
+ async removeDependency(input) {
1342
+ const blockingKey = this.tracker.normalizeIdentifier(input.blockingIssue);
1343
+ const blockedKey = this.tracker.normalizeIdentifier(input.blockedIssue);
1344
+ const issue = await this.tracker.getApiClient().getIssue(blockedKey);
1345
+ const links = issue.fields.issuelinks ?? [];
1346
+ const matchingLink = links.find(
1347
+ (link) => {
1348
+ var _a;
1349
+ return link.type.name === "Blocks" && ((_a = link.inwardIssue) == null ? void 0 : _a.key) === blockingKey;
1350
+ }
1351
+ );
1352
+ if (!matchingLink) {
1353
+ throw new Error(
1354
+ `No "Blocks" dependency found from ${blockingKey} to ${blockedKey}`
1355
+ );
1356
+ }
1357
+ await this.tracker.getApiClient().deleteIssueLink(matchingLink.id);
1358
+ }
1359
+ /**
1360
+ * Get child issues of a parent issue
1361
+ * Uses JQL search: parent = KEY
1362
+ */
1363
+ async getChildIssues(input) {
1364
+ const parentKey = this.tracker.normalizeIdentifier(input.number);
1365
+ const host = this.tracker.getConfig().host;
1366
+ const issues = await this.tracker.getApiClient().searchIssues(`parent = "${escapeJql(parentKey)}"`);
1367
+ return issues.map((issue) => ({
1368
+ id: issue.key,
1369
+ title: issue.fields.summary,
1370
+ url: `${host}/browse/${issue.key}`,
1371
+ state: issue.fields.status.name.toLowerCase()
1372
+ }));
1373
+ }
1374
+ /**
1375
+ * Close an issue by transitioning to "Done" state
1376
+ */
1377
+ async closeIssue(input) {
1378
+ const issueKey = this.tracker.normalizeIdentifier(input.number);
1379
+ await this.tracker.closeIssue(issueKey);
1380
+ }
1381
+ /**
1382
+ * Reopen a closed issue
1383
+ */
1384
+ async reopenIssue(input) {
1385
+ const issueKey = this.tracker.normalizeIdentifier(input.number);
1386
+ await this.tracker.reopenIssue(issueKey);
1387
+ }
1388
+ /**
1389
+ * Edit an issue's properties
1390
+ * State changes are delegated to closeIssue/reopenIssue
1391
+ */
1392
+ async editIssue(input) {
1393
+ const { number, title, body, state } = input;
1394
+ if (state === "closed") {
1395
+ await this.closeIssue({ number });
1396
+ } else if (state === "open") {
1397
+ await this.reopenIssue({ number });
1398
+ }
1399
+ if (title !== void 0 || body !== void 0) {
1400
+ const issueKey = this.tracker.normalizeIdentifier(number);
1401
+ await this.tracker.getApiClient().updateIssue(issueKey, {
1402
+ ...title !== void 0 && { summary: title },
1403
+ ...body !== void 0 && { description: body }
1404
+ });
1405
+ }
1406
+ }
943
1407
  };
944
1408
 
945
1409
  // src/mcp/IssueManagementProviderFactory.ts
946
1410
  var IssueManagementProviderFactory = class {
947
1411
  /**
948
1412
  * Create an issue management provider based on the provider type
1413
+ * @param provider - The provider type (github, linear, jira)
1414
+ * @param settings - Required for Jira provider, optional for others
949
1415
  */
950
- static create(provider) {
1416
+ static create(provider, settings) {
951
1417
  switch (provider) {
952
1418
  case "github":
953
1419
  return new GitHubIssueManagementProvider();
954
1420
  case "linear":
955
1421
  return new LinearIssueManagementProvider();
1422
+ case "jira":
1423
+ if (!settings) {
1424
+ throw new Error("Settings required for Jira provider");
1425
+ }
1426
+ return new JiraIssueManagementProvider(settings);
956
1427
  default:
957
1428
  throw new Error(`Unsupported issue management provider: ${provider}`);
958
1429
  }
@@ -962,4 +1433,4 @@ var IssueManagementProviderFactory = class {
962
1433
  export {
963
1434
  IssueManagementProviderFactory
964
1435
  };
965
- //# sourceMappingURL=chunk-OK7LUTRW.js.map
1436
+ //# sourceMappingURL=chunk-JO2LZ6EQ.js.map