@iloom/cli 0.9.2 → 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 (220) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +159 -40
  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-TGWJN4V4.js → GitHubService-MEHKHUQP.js} +4 -4
  7. package/dist/IssueTrackerFactory-NG53YX5S.js +14 -0
  8. package/dist/{LoomLauncher-73NXL2CL.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 +159 -40
  13. package/dist/{SettingsManager-AW3JTJHD.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-THZI572G.js → build-5GO3XW26.js} +9 -9
  23. package/dist/{chunk-NUACL52E.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-A7NJF73J.js → chunk-5MWV33NN.js} +4 -4
  29. package/dist/{chunk-3I4ONZRT.js → chunk-6EU6TCF6.js} +10 -10
  30. package/dist/chunk-6EU6TCF6.js.map +1 -0
  31. package/dist/{chunk-CWRI4JC3.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-ULSWCPQG.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-OFDN5NKS.js → chunk-KXDRI47U.js} +69 -12
  41. package/dist/chunk-KXDRI47U.js.map +1 -0
  42. package/dist/{chunk-R4YWBGY6.js → chunk-LXLMMXXY.js} +54 -14
  43. package/dist/chunk-LXLMMXXY.js.map +1 -0
  44. package/dist/{chunk-AR5QKYNE.js → chunk-MNHZB4Z2.js} +4 -4
  45. package/dist/{chunk-TL72BGP6.js → chunk-MORRVYPT.js} +2 -2
  46. package/dist/{chunk-KJTVU3HZ.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-Z2TWEXR7.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-6IIL5M2L.js → chunk-SN3SQCFK.js} +10 -8
  60. package/dist/{chunk-6IIL5M2L.js.map → chunk-SN3SQCFK.js.map} +1 -1
  61. package/dist/{chunk-SOSQILHO.js → chunk-UD3WJDIV.js} +92 -82
  62. package/dist/chunk-UD3WJDIV.js.map +1 -0
  63. package/dist/{chunk-KXGQYLFZ.js → chunk-UKBAJ2QQ.js} +61 -7
  64. package/dist/chunk-UKBAJ2QQ.js.map +1 -0
  65. package/dist/{chunk-W6DP5RVR.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-NWMORW3U.js → chunk-VECNX6VX.js} +2 -2
  69. package/dist/{chunk-4CO6KG5S.js → chunk-VG45TUYK.js} +53 -7
  70. package/dist/{chunk-4CO6KG5S.js.map → chunk-VG45TUYK.js.map} +1 -1
  71. package/dist/{chunk-TC7APDKU.js → chunk-VGGST52X.js} +2 -2
  72. package/dist/{chunk-4LKGCFGG.js → chunk-WWKOVDWC.js} +2 -2
  73. package/dist/{chunk-YKFCCV6S.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-RI2YL6TK.js → chunk-YYAKPQBT.js} +65 -18
  80. package/dist/chunk-YYAKPQBT.js.map +1 -0
  81. package/dist/{chunk-IZIYLYPK.js → chunk-ZEWU5PZK.js} +2 -2
  82. package/dist/{chunk-VPTAX5TR.js → chunk-ZHPNZC75.js} +12 -12
  83. package/dist/chunk-ZHPNZC75.js.map +1 -0
  84. package/dist/{chunk-DGG2VY7B.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-PJRIFFU4.js → cleanup-6UCPVMFG.js} +81 -32
  88. package/dist/cleanup-6UCPVMFG.js.map +1 -0
  89. package/dist/cli.js +638 -349
  90. package/dist/cli.js.map +1 -1
  91. package/dist/{commit-IVP3M4HG.js → commit-L3EPY5QG.js} +21 -20
  92. package/dist/commit-L3EPY5QG.js.map +1 -0
  93. package/dist/{compile-R2J65HBQ.js → compile-ZS4HYRX5.js} +9 -9
  94. package/dist/{contribute-VDZXHK5Y.js → contribute-ORDDQGSL.js} +14 -6
  95. package/dist/contribute-ORDDQGSL.js.map +1 -0
  96. package/dist/{dev-server-7F622OEO.js → dev-server-FYZ2AQIH.js} +29 -15
  97. package/dist/dev-server-FYZ2AQIH.js.map +1 -0
  98. package/dist/{feedback-E7VET7CL.js → feedback-TMBXSCM5.js} +15 -15
  99. package/dist/{git-2QDQ2X2S.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 +382 -53
  104. package/dist/index.js +1167 -36
  105. package/dist/index.js.map +1 -1
  106. package/dist/{init-676DHF6R.js → init-GFQ5W7GK.js} +57 -21
  107. package/dist/init-GFQ5W7GK.js.map +1 -0
  108. package/dist/{issues-PJSOLOBJ.js → issues-T4ZZSPEG.js} +61 -20
  109. package/dist/issues-T4ZZSPEG.js.map +1 -0
  110. package/dist/{lint-CJM7BAIM.js → lint-6TQXDZ3T.js} +9 -9
  111. package/dist/mcp/issue-management-server.js +2471 -256
  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-544H7JF5.js → open-5QZGXQRF.js} +15 -15
  118. package/dist/open-5QZGXQRF.js.map +1 -0
  119. package/dist/{plan-Q7ELXDLC.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 +347 -26
  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-YND35CIE.js → rebase-DWIB77KV.js} +10 -10
  131. package/dist/{recap-3W7COH7D.js → recap-MX63HAKV.js} +47 -19
  132. package/dist/recap-MX63HAKV.js.map +1 -0
  133. package/dist/{run-QUXJKDQQ.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 +115 -15
  137. package/dist/{shell-QGECBLST.js → shell-G6VC2CYR.js} +14 -7
  138. package/dist/shell-G6VC2CYR.js.map +1 -0
  139. package/dist/{summary-G2T4452H.js → summary-FWHAX55O.js} +27 -25
  140. package/dist/summary-FWHAX55O.js.map +1 -0
  141. package/dist/{test-EA5NQFDC.js → test-F7JNJZYP.js} +9 -9
  142. package/dist/{test-git-M7LSLEFL.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-64NAAUON.js → test-prefix-Q6TFSU6F.js} +4 -4
  146. package/dist/{test-webserver-OK6Z5FJM.js → test-webserver-EONCG7E7.js} +6 -6
  147. package/dist/{vscode-AR5NNXXI.js → vscode-VA5X4P25.js} +7 -7
  148. package/package.json +5 -1
  149. package/dist/ClaudeContextManager-HR5JQKAI.js +0 -14
  150. package/dist/ClaudeService-TK7FMC2X.js +0 -13
  151. package/dist/chunk-3I4ONZRT.js.map +0 -1
  152. package/dist/chunk-B7U6OKUR.js.map +0 -1
  153. package/dist/chunk-CWRI4JC3.js.map +0 -1
  154. package/dist/chunk-DGG2VY7B.js.map +0 -1
  155. package/dist/chunk-FJDRTVJX.js +0 -520
  156. package/dist/chunk-FJDRTVJX.js.map +0 -1
  157. package/dist/chunk-FO5GGFOV.js.map +0 -1
  158. package/dist/chunk-KBEIQP4G.js.map +0 -1
  159. package/dist/chunk-KJTVU3HZ.js.map +0 -1
  160. package/dist/chunk-KXGQYLFZ.js.map +0 -1
  161. package/dist/chunk-OFDN5NKS.js.map +0 -1
  162. package/dist/chunk-QN47QVBX.js.map +0 -1
  163. package/dist/chunk-R4YWBGY6.js.map +0 -1
  164. package/dist/chunk-RI2YL6TK.js.map +0 -1
  165. package/dist/chunk-SOSQILHO.js.map +0 -1
  166. package/dist/chunk-ULSWCPQG.js.map +0 -1
  167. package/dist/chunk-VOGGLPG5.js.map +0 -1
  168. package/dist/chunk-VPTAX5TR.js.map +0 -1
  169. package/dist/chunk-WHI5KEOX.js +0 -121
  170. package/dist/chunk-WHI5KEOX.js.map +0 -1
  171. package/dist/chunk-YKFCCV6S.js.map +0 -1
  172. package/dist/chunk-Z2TWEXR7.js.map +0 -1
  173. package/dist/cleanup-PJRIFFU4.js.map +0 -1
  174. package/dist/commit-IVP3M4HG.js.map +0 -1
  175. package/dist/contribute-VDZXHK5Y.js.map +0 -1
  176. package/dist/dev-server-7F622OEO.js.map +0 -1
  177. package/dist/ignite-IW35CDBD.js +0 -784
  178. package/dist/ignite-IW35CDBD.js.map +0 -1
  179. package/dist/init-676DHF6R.js.map +0 -1
  180. package/dist/issues-PJSOLOBJ.js.map +0 -1
  181. package/dist/open-544H7JF5.js.map +0 -1
  182. package/dist/plan-Q7ELXDLC.js.map +0 -1
  183. package/dist/recap-3W7COH7D.js.map +0 -1
  184. package/dist/run-QUXJKDQQ.js.map +0 -1
  185. package/dist/shell-QGECBLST.js.map +0 -1
  186. package/dist/summary-G2T4452H.js.map +0 -1
  187. /package/dist/{BranchNamingService-K6XNWQ6C.js.map → BranchNamingService-ECJHBB67.js.map} +0 -0
  188. /package/dist/{ClaudeContextManager-HR5JQKAI.js.map → ClaudeContextManager-QXX6ZFST.js.map} +0 -0
  189. /package/dist/{ClaudeService-TK7FMC2X.js.map → ClaudeService-NJNK2SUH.js.map} +0 -0
  190. /package/dist/{GitHubService-TGWJN4V4.js.map → GitHubService-MEHKHUQP.js.map} +0 -0
  191. /package/dist/{MetadataManager-W3C54UYT.js.map → IssueTrackerFactory-NG53YX5S.js.map} +0 -0
  192. /package/dist/{LoomLauncher-73NXL2CL.js.map → LoomLauncher-L64HHS3T.js.map} +0 -0
  193. /package/dist/{ProjectCapabilityDetector-N5L7T4IY.js.map → MetadataManager-5QZSTKNN.js.map} +0 -0
  194. /package/dist/{PromptTemplateManager-36YLQRHP.js.map → ProjectCapabilityDetector-5KSYUTBJ.js.map} +0 -0
  195. /package/dist/{SettingsManager-AW3JTJHD.js.map → PromptTemplateManager-DULSVRRE.js.map} +0 -0
  196. /package/dist/{claude-TP2QO3BU.js.map → SettingsManager-BQDQA3FK.js.map} +0 -0
  197. /package/dist/{build-THZI572G.js.map → build-5GO3XW26.js.map} +0 -0
  198. /package/dist/{chunk-NUACL52E.js.map → chunk-3D7WQM7I.js.map} +0 -0
  199. /package/dist/{chunk-A7NJF73J.js.map → chunk-5MWV33NN.js.map} +0 -0
  200. /package/dist/{chunk-KAYXR544.js.map → chunk-J5S7DFYC.js.map} +0 -0
  201. /package/dist/{chunk-AR5QKYNE.js.map → chunk-MNHZB4Z2.js.map} +0 -0
  202. /package/dist/{chunk-TL72BGP6.js.map → chunk-MORRVYPT.js.map} +0 -0
  203. /package/dist/{chunk-7ZEHSSUP.js.map → chunk-P4O6EH46.js.map} +0 -0
  204. /package/dist/{chunk-W6DP5RVR.js.map → chunk-UVD4CZKS.js.map} +0 -0
  205. /package/dist/{chunk-NWMORW3U.js.map → chunk-VECNX6VX.js.map} +0 -0
  206. /package/dist/{chunk-TC7APDKU.js.map → chunk-VGGST52X.js.map} +0 -0
  207. /package/dist/{chunk-4LKGCFGG.js.map → chunk-WWKOVDWC.js.map} +0 -0
  208. /package/dist/{chunk-IZIYLYPK.js.map → chunk-ZEWU5PZK.js.map} +0 -0
  209. /package/dist/{git-2QDQ2X2S.js.map → claude-P3NQR6IJ.js.map} +0 -0
  210. /package/dist/{compile-R2J65HBQ.js.map → compile-ZS4HYRX5.js.map} +0 -0
  211. /package/dist/{feedback-E7VET7CL.js.map → feedback-TMBXSCM5.js.map} +0 -0
  212. /package/dist/{neon-helpers-VVFFTLXE.js.map → git-ET64COO3.js.map} +0 -0
  213. /package/dist/{lint-CJM7BAIM.js.map → lint-6TQXDZ3T.js.map} +0 -0
  214. /package/dist/{projects-LH362JZQ.js.map → projects-2UOXFLNZ.js.map} +0 -0
  215. /package/dist/{rebase-YND35CIE.js.map → rebase-DWIB77KV.js.map} +0 -0
  216. /package/dist/{test-EA5NQFDC.js.map → test-F7JNJZYP.js.map} +0 -0
  217. /package/dist/{test-git-M7LSLEFL.js.map → test-git-BTAOIUE2.js.map} +0 -0
  218. /package/dist/{test-prefix-64NAAUON.js.map → test-prefix-Q6TFSU6F.js.map} +0 -0
  219. /package/dist/{test-webserver-OK6Z5FJM.js.map → test-webserver-EONCG7E7.js.map} +0 -0
  220. /package/dist/{vscode-AR5NNXXI.js.map → vscode-VA5X4P25.js.map} +0 -0
@@ -1,520 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- logger
4
- } from "./chunk-VT4PDUYT.js";
5
-
6
- // src/utils/linear.ts
7
- import { LinearClient, IssueRelationType } from "@linear/sdk";
8
-
9
- // src/types/linear.ts
10
- var LinearServiceError = class _LinearServiceError extends Error {
11
- constructor(code, message, details) {
12
- super(message);
13
- this.code = code;
14
- this.details = details;
15
- this.name = "LinearServiceError";
16
- if (Error.captureStackTrace) {
17
- Error.captureStackTrace(this, _LinearServiceError);
18
- }
19
- }
20
- };
21
-
22
- // src/utils/linear.ts
23
- function slugifyTitle(title, maxLength = 50) {
24
- const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
25
- if (slug.length <= maxLength) {
26
- return slug;
27
- }
28
- const parts = slug.split("-");
29
- let result = "";
30
- for (const part of parts) {
31
- const candidate = result ? `${result}-${part}` : part;
32
- if (candidate.length > maxLength) {
33
- break;
34
- }
35
- result = candidate;
36
- }
37
- return result || slug.slice(0, maxLength);
38
- }
39
- function buildLinearIssueUrl(identifier, title) {
40
- const base = `https://linear.app/issue/${identifier}`;
41
- if (title) {
42
- const slug = slugifyTitle(title);
43
- return slug ? `${base}/${slug}` : base;
44
- }
45
- return base;
46
- }
47
- function getLinearApiToken() {
48
- const token = process.env.LINEAR_API_TOKEN;
49
- if (!token) {
50
- throw new LinearServiceError(
51
- "UNAUTHORIZED",
52
- "LINEAR_API_TOKEN not set. Configure in settings.local.json or set environment variable."
53
- );
54
- }
55
- return token;
56
- }
57
- function createLinearClient(apiToken) {
58
- const token = apiToken ?? getLinearApiToken();
59
- return new LinearClient({ apiKey: token });
60
- }
61
- function handleLinearError(error, context) {
62
- logger.debug(`${context}: Handling error`, { error });
63
- const errorMessage = error instanceof Error ? error.message : String(error);
64
- if (errorMessage.includes("not found") || errorMessage.includes("Not found")) {
65
- throw new LinearServiceError("NOT_FOUND", "Linear issue or resource not found", { error });
66
- }
67
- if (errorMessage.includes("unauthorized") || errorMessage.includes("Unauthorized") || errorMessage.includes("Invalid API key")) {
68
- throw new LinearServiceError(
69
- "UNAUTHORIZED",
70
- "Linear authentication failed. Check LINEAR_API_TOKEN.",
71
- { error }
72
- );
73
- }
74
- if (errorMessage.includes("rate limit")) {
75
- throw new LinearServiceError("RATE_LIMITED", "Linear API rate limit exceeded", { error });
76
- }
77
- throw new LinearServiceError("CLI_ERROR", `Linear SDK error: ${errorMessage}`, { error });
78
- }
79
- async function fetchLinearIssue(identifier) {
80
- try {
81
- logger.debug(`Fetching Linear issue: ${identifier}`);
82
- const client = createLinearClient();
83
- const issue = await client.issue(identifier);
84
- if (!issue) {
85
- throw new LinearServiceError("NOT_FOUND", `Linear issue ${identifier} not found`);
86
- }
87
- const result = {
88
- id: issue.id,
89
- identifier: issue.identifier,
90
- title: issue.title,
91
- url: issue.url,
92
- createdAt: issue.createdAt.toISOString(),
93
- updatedAt: issue.updatedAt.toISOString()
94
- };
95
- if (issue.description) {
96
- result.description = issue.description;
97
- }
98
- if (issue.state) {
99
- const state = await issue.state;
100
- if (state == null ? void 0 : state.name) {
101
- result.state = state.name;
102
- }
103
- }
104
- return result;
105
- } catch (error) {
106
- if (error instanceof LinearServiceError) {
107
- throw error;
108
- }
109
- handleLinearError(error, "fetchLinearIssue");
110
- }
111
- }
112
- async function createLinearIssue(title, body, teamKey, _labels) {
113
- try {
114
- logger.debug(`Creating Linear issue in team ${teamKey}: ${title}`);
115
- const client = createLinearClient();
116
- const teams = await client.teams();
117
- const team = teams.nodes.find((t) => t.key === teamKey);
118
- if (!team) {
119
- throw new LinearServiceError("NOT_FOUND", `Linear team ${teamKey} not found`);
120
- }
121
- const issueInput = {
122
- teamId: team.id,
123
- title
124
- };
125
- if (body) {
126
- issueInput.description = body;
127
- }
128
- const payload = await client.createIssue(issueInput);
129
- const issue = await payload.issue;
130
- if (!issue) {
131
- throw new LinearServiceError("CLI_ERROR", "Failed to create Linear issue");
132
- }
133
- const url = issue.url ?? buildLinearIssueUrl(issue.identifier, title);
134
- return {
135
- identifier: issue.identifier,
136
- url
137
- };
138
- } catch (error) {
139
- if (error instanceof LinearServiceError) {
140
- throw error;
141
- }
142
- handleLinearError(error, "createLinearIssue");
143
- }
144
- }
145
- async function createLinearChildIssue(title, body, teamKey, parentId, _labels) {
146
- try {
147
- logger.debug(`Creating Linear child issue in team ${teamKey}: ${title}`);
148
- const client = createLinearClient();
149
- const teams = await client.teams();
150
- const team = teams.nodes.find((t) => t.key === teamKey);
151
- if (!team) {
152
- throw new LinearServiceError("NOT_FOUND", `Linear team ${teamKey} not found`);
153
- }
154
- const issueInput = {
155
- teamId: team.id,
156
- title,
157
- parentId
158
- // UUID of parent issue
159
- };
160
- if (body) {
161
- issueInput.description = body;
162
- }
163
- const payload = await client.createIssue(issueInput);
164
- const issue = await payload.issue;
165
- if (!issue) {
166
- throw new LinearServiceError("CLI_ERROR", "Failed to create Linear child issue");
167
- }
168
- const url = issue.url ?? buildLinearIssueUrl(issue.identifier, title);
169
- return {
170
- identifier: issue.identifier,
171
- url
172
- };
173
- } catch (error) {
174
- if (error instanceof LinearServiceError) {
175
- throw error;
176
- }
177
- handleLinearError(error, "createLinearChildIssue");
178
- }
179
- }
180
- async function createLinearComment(identifier, body) {
181
- try {
182
- logger.debug(`Creating comment on Linear issue ${identifier}`);
183
- const client = createLinearClient();
184
- const issue = await client.issue(identifier);
185
- if (!issue) {
186
- throw new LinearServiceError("NOT_FOUND", `Linear issue ${identifier} not found`);
187
- }
188
- const payload = await client.createComment({
189
- issueId: issue.id,
190
- body
191
- });
192
- const comment = await payload.comment;
193
- if (!comment) {
194
- throw new LinearServiceError("CLI_ERROR", "Failed to create Linear comment");
195
- }
196
- return {
197
- id: comment.id,
198
- body: comment.body,
199
- createdAt: comment.createdAt.toISOString(),
200
- updatedAt: comment.updatedAt.toISOString(),
201
- url: comment.url
202
- };
203
- } catch (error) {
204
- if (error instanceof LinearServiceError) {
205
- throw error;
206
- }
207
- handleLinearError(error, "createLinearComment");
208
- }
209
- }
210
- async function updateLinearIssueState(identifier, stateName) {
211
- try {
212
- logger.debug(`Updating Linear issue ${identifier} state to: ${stateName}`);
213
- const client = createLinearClient();
214
- const issue = await client.issue(identifier);
215
- if (!issue) {
216
- throw new LinearServiceError("NOT_FOUND", `Linear issue ${identifier} not found`);
217
- }
218
- const team = await issue.team;
219
- if (!team) {
220
- throw new LinearServiceError("CLI_ERROR", "Issue has no team");
221
- }
222
- const states = await team.states();
223
- const state = states.nodes.find((s) => s.name === stateName);
224
- if (!state) {
225
- throw new LinearServiceError(
226
- "NOT_FOUND",
227
- `State "${stateName}" not found in team ${team.key}`
228
- );
229
- }
230
- await client.updateIssue(issue.id, {
231
- stateId: state.id
232
- });
233
- } catch (error) {
234
- if (error instanceof LinearServiceError) {
235
- throw error;
236
- }
237
- handleLinearError(error, "updateLinearIssueState");
238
- }
239
- }
240
- async function getLinearComment(commentId) {
241
- try {
242
- logger.debug(`Fetching Linear comment: ${commentId}`);
243
- const client = createLinearClient();
244
- const comment = await client.comment({ id: commentId });
245
- if (!comment) {
246
- throw new LinearServiceError("NOT_FOUND", `Linear comment ${commentId} not found`);
247
- }
248
- return {
249
- id: comment.id,
250
- body: comment.body,
251
- createdAt: comment.createdAt.toISOString(),
252
- updatedAt: comment.updatedAt.toISOString(),
253
- url: comment.url
254
- };
255
- } catch (error) {
256
- if (error instanceof LinearServiceError) {
257
- throw error;
258
- }
259
- handleLinearError(error, "getLinearComment");
260
- }
261
- }
262
- async function updateLinearComment(commentId, body) {
263
- try {
264
- logger.debug(`Updating Linear comment: ${commentId}`);
265
- const client = createLinearClient();
266
- const payload = await client.updateComment(commentId, { body });
267
- const comment = await payload.comment;
268
- if (!comment) {
269
- throw new LinearServiceError("CLI_ERROR", "Failed to update Linear comment");
270
- }
271
- return {
272
- id: comment.id,
273
- body: comment.body,
274
- createdAt: comment.createdAt.toISOString(),
275
- updatedAt: comment.updatedAt.toISOString(),
276
- url: comment.url
277
- };
278
- } catch (error) {
279
- if (error instanceof LinearServiceError) {
280
- throw error;
281
- }
282
- handleLinearError(error, "updateLinearComment");
283
- }
284
- }
285
- async function fetchLinearIssueComments(identifier) {
286
- try {
287
- logger.debug(`Fetching comments for Linear issue: ${identifier}`);
288
- const client = createLinearClient();
289
- const issue = await client.issue(identifier);
290
- if (!issue) {
291
- throw new LinearServiceError("NOT_FOUND", `Linear issue ${identifier} not found`);
292
- }
293
- const comments = await issue.comments({ first: 100 });
294
- return comments.nodes.map((comment) => ({
295
- id: comment.id,
296
- body: comment.body,
297
- createdAt: comment.createdAt.toISOString(),
298
- updatedAt: comment.updatedAt.toISOString(),
299
- url: comment.url
300
- }));
301
- } catch (error) {
302
- if (error instanceof LinearServiceError) {
303
- throw error;
304
- }
305
- handleLinearError(error, "fetchLinearIssueComments");
306
- }
307
- }
308
- async function getLinearChildIssues(identifier, options) {
309
- try {
310
- logger.debug(`Fetching child issues for Linear issue: ${identifier}`);
311
- const client = createLinearClient(options == null ? void 0 : options.apiToken);
312
- const issue = await client.issue(identifier);
313
- if (!issue) {
314
- throw new LinearServiceError("NOT_FOUND", `Linear issue ${identifier} not found`);
315
- }
316
- const children = await issue.children({ first: 100 });
317
- const results = await Promise.all(
318
- children.nodes.map(async (child) => {
319
- const stateObj = await child.state;
320
- const state = (stateObj == null ? void 0 : stateObj.name) ?? "unknown";
321
- return {
322
- id: child.identifier,
323
- title: child.title,
324
- url: child.url,
325
- state
326
- };
327
- })
328
- );
329
- return results;
330
- } catch (error) {
331
- if (error instanceof LinearServiceError) {
332
- throw error;
333
- }
334
- handleLinearError(error, "getLinearChildIssues");
335
- }
336
- }
337
- async function createLinearIssueRelation(blockingIssueId, blockedIssueId) {
338
- try {
339
- logger.debug(`Creating Linear issue relation: ${blockingIssueId} blocks ${blockedIssueId}`);
340
- const client = createLinearClient();
341
- const payload = await client.createIssueRelation({
342
- issueId: blockingIssueId,
343
- relatedIssueId: blockedIssueId,
344
- type: IssueRelationType.Blocks
345
- });
346
- if (!payload.success) {
347
- throw new LinearServiceError("CLI_ERROR", "Failed to create Linear issue relation");
348
- }
349
- } catch (error) {
350
- if (error instanceof LinearServiceError) {
351
- throw error;
352
- }
353
- handleLinearError(error, "createLinearIssueRelation");
354
- }
355
- }
356
- async function getLinearIssueDependencies(identifier, direction) {
357
- try {
358
- logger.debug(`Fetching Linear issue dependencies: ${identifier} (direction: ${direction})`);
359
- const client = createLinearClient();
360
- const issue = await client.issue(identifier);
361
- if (!issue) {
362
- throw new LinearServiceError("NOT_FOUND", `Linear issue ${identifier} not found`);
363
- }
364
- const [relations, inverseRelations] = await Promise.all([
365
- issue.relations(),
366
- issue.inverseRelations()
367
- ]);
368
- const blocking = [];
369
- const blockedBy = [];
370
- const buildDependencyResult = async (relatedIssue) => {
371
- if (!relatedIssue) return null;
372
- const stateObj = await relatedIssue.state;
373
- const state = (stateObj == null ? void 0 : stateObj.name) ?? "unknown";
374
- return {
375
- id: relatedIssue.identifier,
376
- title: relatedIssue.title,
377
- url: relatedIssue.url,
378
- state
379
- };
380
- };
381
- if (direction === "blocking" || direction === "both") {
382
- const blockingRelations = relations.nodes.filter(
383
- (r) => r.type === IssueRelationType.Blocks
384
- );
385
- const relatedIssuePromises = blockingRelations.map((r) => r.relatedIssue).filter((p) => p !== void 0);
386
- const relatedIssues = await Promise.all(relatedIssuePromises);
387
- const blockingResults = await Promise.all(
388
- relatedIssues.map((issue2) => buildDependencyResult(issue2))
389
- );
390
- blocking.push(...blockingResults.filter((r) => r !== null));
391
- }
392
- if (direction === "blocked_by" || direction === "both") {
393
- const blockedByRelations = inverseRelations.nodes.filter(
394
- (r) => r.type === IssueRelationType.Blocks
395
- );
396
- const sourceIssuePromises = blockedByRelations.map((r) => r.issue).filter((p) => p !== void 0);
397
- const sourceIssues = await Promise.all(sourceIssuePromises);
398
- const blockedByResults = await Promise.all(
399
- sourceIssues.map((issue2) => buildDependencyResult(issue2))
400
- );
401
- blockedBy.push(...blockedByResults.filter((r) => r !== null));
402
- }
403
- return { blocking, blockedBy };
404
- } catch (error) {
405
- if (error instanceof LinearServiceError) {
406
- throw error;
407
- }
408
- handleLinearError(error, "getLinearIssueDependencies");
409
- }
410
- }
411
- async function deleteLinearIssueRelation(relationId) {
412
- try {
413
- logger.debug(`Deleting Linear issue relation: ${relationId}`);
414
- const client = createLinearClient();
415
- const payload = await client.deleteIssueRelation(relationId);
416
- if (!payload.success) {
417
- throw new LinearServiceError("CLI_ERROR", "Failed to delete Linear issue relation");
418
- }
419
- } catch (error) {
420
- if (error instanceof LinearServiceError) {
421
- throw error;
422
- }
423
- handleLinearError(error, "deleteLinearIssueRelation");
424
- }
425
- }
426
- async function fetchLinearIssueList(teamKey, options) {
427
- try {
428
- const limit = (options == null ? void 0 : options.limit) ?? 100;
429
- logger.debug(`Fetching Linear issue list for team ${teamKey}`, { limit });
430
- const client = createLinearClient(options == null ? void 0 : options.apiToken);
431
- const teams = await client.teams();
432
- const team = teams.nodes.find((t) => t.key === teamKey);
433
- if (!team) {
434
- throw new LinearServiceError("NOT_FOUND", `Linear team ${teamKey} not found`);
435
- }
436
- const issues = await team.issues({
437
- first: limit,
438
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- PaginationOrderBy is a const enum incompatible with isolatedModules
439
- orderBy: "updatedAt",
440
- filter: {
441
- state: {
442
- type: {
443
- nin: ["completed", "canceled"]
444
- }
445
- }
446
- }
447
- });
448
- const results = await Promise.all(
449
- issues.nodes.map(async (issue) => {
450
- const stateObj = await issue.state;
451
- const state = (stateObj == null ? void 0 : stateObj.name) ?? "unknown";
452
- return {
453
- id: issue.identifier,
454
- title: issue.title,
455
- updatedAt: issue.updatedAt.toISOString(),
456
- url: issue.url,
457
- state
458
- };
459
- })
460
- );
461
- return results;
462
- } catch (error) {
463
- if (error instanceof LinearServiceError) {
464
- throw error;
465
- }
466
- handleLinearError(error, "fetchLinearIssueList");
467
- }
468
- }
469
- async function findLinearIssueRelation(blockingIdentifier, blockedIdentifier) {
470
- try {
471
- logger.debug(`Finding Linear issue relation: ${blockingIdentifier} blocks ${blockedIdentifier}`);
472
- const client = createLinearClient();
473
- const blockingIssue = await client.issue(blockingIdentifier);
474
- if (!blockingIssue) {
475
- throw new LinearServiceError("NOT_FOUND", `Linear issue ${blockingIdentifier} not found`);
476
- }
477
- const blockedIssue = await client.issue(blockedIdentifier);
478
- if (!blockedIssue) {
479
- throw new LinearServiceError("NOT_FOUND", `Linear issue ${blockedIdentifier} not found`);
480
- }
481
- const relations = await blockingIssue.relations();
482
- const blockingRelations = relations.nodes.filter(
483
- (r) => r.type === IssueRelationType.Blocks
484
- );
485
- const relationsWithIssues = await Promise.all(
486
- blockingRelations.map(async (relation) => ({
487
- relation,
488
- relatedIssue: await relation.relatedIssue
489
- }))
490
- );
491
- const matchingRelation = relationsWithIssues.find(
492
- ({ relatedIssue }) => (relatedIssue == null ? void 0 : relatedIssue.id) === blockedIssue.id
493
- );
494
- return (matchingRelation == null ? void 0 : matchingRelation.relation.id) ?? null;
495
- } catch (error) {
496
- if (error instanceof LinearServiceError) {
497
- throw error;
498
- }
499
- handleLinearError(error, "findLinearIssueRelation");
500
- }
501
- }
502
-
503
- export {
504
- LinearServiceError,
505
- fetchLinearIssue,
506
- createLinearIssue,
507
- createLinearChildIssue,
508
- createLinearComment,
509
- updateLinearIssueState,
510
- getLinearComment,
511
- updateLinearComment,
512
- fetchLinearIssueComments,
513
- getLinearChildIssues,
514
- createLinearIssueRelation,
515
- getLinearIssueDependencies,
516
- deleteLinearIssueRelation,
517
- fetchLinearIssueList,
518
- findLinearIssueRelation
519
- };
520
- //# sourceMappingURL=chunk-FJDRTVJX.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/linear.ts","../src/types/linear.ts"],"sourcesContent":["/**\n * Linear SDK utilities\n * Wrapper functions for the @linear/sdk\n */\n\nimport { LinearClient, IssueRelationType } from '@linear/sdk'\nimport type { LinearIssue, LinearComment } from '../types/linear.js'\nimport { LinearServiceError } from '../types/linear.js'\nimport { logger } from './logger.js'\n\n/**\n * Slugify a title for use in Linear URLs\n * Converts to lowercase, replaces non-alphanumeric with hyphens, truncates to reasonable length\n * @param title - Issue title\n * @param maxLength - Maximum slug length (default: 50)\n * @returns Slugified title\n */\nexport function slugifyTitle(title: string, maxLength: number = 50): string {\n // Convert to lowercase, replace non-alphanumeric chars with hyphens\n const slug = title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '') // trim leading/trailing hyphens\n\n // If already short enough, return as-is\n if (slug.length <= maxLength) {\n return slug\n }\n\n // Split by hyphens and rebuild until we hit the limit\n const parts = slug.split('-')\n let result = ''\n for (const part of parts) {\n const candidate = result ? `${result}-${part}` : part\n if (candidate.length > maxLength) {\n break\n }\n result = candidate\n }\n\n return result || slug.slice(0, maxLength) // fallback if first part is too long\n}\n\n/**\n * Build a Linear issue URL with optional title slug\n * @param identifier - Issue identifier (e.g., \"ENG-123\")\n * @param title - Optional issue title for slug\n * @returns Linear URL\n */\nexport function buildLinearIssueUrl(identifier: string, title?: string): string {\n const base = `https://linear.app/issue/${identifier}`\n if (title) {\n const slug = slugifyTitle(title)\n return slug ? `${base}/${slug}` : base\n }\n return base\n}\n\n/**\n * Get Linear API token from environment\n * @returns API token\n * @throws LinearServiceError if token not found\n */\nfunction getLinearApiToken(): string {\n const token = process.env.LINEAR_API_TOKEN\n if (!token) {\n throw new LinearServiceError(\n 'UNAUTHORIZED',\n 'LINEAR_API_TOKEN not set. Configure in settings.local.json or set environment variable.',\n )\n }\n return token\n}\n\n/**\n * Create a Linear SDK client instance\n * @param apiToken - Optional API token (takes precedence over env var)\n * @returns Configured LinearClient\n */\nfunction createLinearClient(apiToken?: string): LinearClient {\n const token = apiToken ?? getLinearApiToken()\n return new LinearClient({ apiKey: token })\n}\n\n/**\n * Handle SDK errors and convert to LinearServiceError\n * @param error - Error from SDK\n * @param context - Context string for debugging\n * @throws LinearServiceError\n */\nfunction handleLinearError(error: unknown, context: string): never {\n logger.debug(`${context}: Handling error`, { error })\n\n // SDK errors typically have a message property\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n // Map common error patterns\n if (errorMessage.includes('not found') || errorMessage.includes('Not found')) {\n throw new LinearServiceError('NOT_FOUND', 'Linear issue or resource not found', { error })\n }\n\n if (\n errorMessage.includes('unauthorized') ||\n errorMessage.includes('Unauthorized') ||\n errorMessage.includes('Invalid API key')\n ) {\n throw new LinearServiceError(\n 'UNAUTHORIZED',\n 'Linear authentication failed. Check LINEAR_API_TOKEN.',\n { error },\n )\n }\n\n if (errorMessage.includes('rate limit')) {\n throw new LinearServiceError('RATE_LIMITED', 'Linear API rate limit exceeded', { error })\n }\n\n // Generic SDK error\n throw new LinearServiceError('CLI_ERROR', `Linear SDK error: ${errorMessage}`, { error })\n}\n\n/**\n * Fetch a Linear issue by identifier\n * @param identifier - Linear issue identifier (e.g., \"ENG-123\")\n * @returns Linear issue details\n * @throws LinearServiceError if issue not found or SDK error\n */\nexport async function fetchLinearIssue(identifier: string): Promise<LinearIssue> {\n try {\n logger.debug(`Fetching Linear issue: ${identifier}`)\n const client = createLinearClient()\n const issue = await client.issue(identifier)\n\n if (!issue) {\n throw new LinearServiceError('NOT_FOUND', `Linear issue ${identifier} not found`)\n }\n\n // Convert SDK issue to our LinearIssue type\n const result: LinearIssue = {\n id: issue.id,\n identifier: issue.identifier,\n title: issue.title,\n url: issue.url,\n createdAt: issue.createdAt.toISOString(),\n updatedAt: issue.updatedAt.toISOString(),\n }\n\n // Add optional fields if present\n if (issue.description) {\n result.description = issue.description\n }\n\n if (issue.state) {\n const state = await issue.state\n if (state?.name) {\n result.state = state.name\n }\n }\n\n return result\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'fetchLinearIssue')\n }\n}\n\n/**\n * Create a new Linear issue\n * @param title - Issue title\n * @param body - Issue description (markdown)\n * @param teamKey - Team key (e.g., \"ENG\", \"PLAT\")\n * @param labels - Optional label names to apply\n * @returns Created issue identifier and URL\n * @throws LinearServiceError on creation failure\n */\nexport async function createLinearIssue(\n title: string,\n body: string,\n teamKey: string,\n _labels?: string[],\n): Promise<{ identifier: string; url: string }> {\n try {\n logger.debug(`Creating Linear issue in team ${teamKey}: ${title}`)\n const client = createLinearClient()\n\n // Get team by key\n const teams = await client.teams()\n const team = teams.nodes.find((t) => t.key === teamKey)\n\n if (!team) {\n throw new LinearServiceError('NOT_FOUND', `Linear team ${teamKey} not found`)\n }\n\n // Create issue\n const issueInput: { teamId: string; title: string; description?: string } = {\n teamId: team.id,\n title,\n }\n\n if (body) {\n issueInput.description = body\n }\n\n const payload = await client.createIssue(issueInput)\n\n const issue = await payload.issue\n\n if (!issue) {\n throw new LinearServiceError('CLI_ERROR', 'Failed to create Linear issue')\n }\n\n // Construct URL\n const url = issue.url ?? buildLinearIssueUrl(issue.identifier, title)\n\n return {\n identifier: issue.identifier,\n url,\n }\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'createLinearIssue')\n }\n}\n\n/**\n * Create a child issue linked to a parent issue\n * Linear supports atomic creation with parentId field\n * @param title - Issue title\n * @param body - Issue description (markdown)\n * @param teamKey - Team key (e.g., \"ENG\")\n * @param parentId - Parent issue UUID (from issue.id, not identifier)\n * @param labels - Optional label names to apply\n * @returns Created issue identifier and URL\n * @throws LinearServiceError on creation failure\n */\nexport async function createLinearChildIssue(\n title: string,\n body: string,\n teamKey: string,\n parentId: string,\n _labels?: string[],\n): Promise<{ identifier: string; url: string }> {\n try {\n logger.debug(`Creating Linear child issue in team ${teamKey}: ${title}`)\n const client = createLinearClient()\n\n // Get team by key\n const teams = await client.teams()\n const team = teams.nodes.find((t) => t.key === teamKey)\n\n if (!team) {\n throw new LinearServiceError('NOT_FOUND', `Linear team ${teamKey} not found`)\n }\n\n // Create issue with parentId for atomic parent-child relationship\n const issueInput: { teamId: string; title: string; description?: string; parentId: string } = {\n teamId: team.id,\n title,\n parentId, // UUID of parent issue\n }\n\n if (body) {\n issueInput.description = body\n }\n\n const payload = await client.createIssue(issueInput)\n\n const issue = await payload.issue\n\n if (!issue) {\n throw new LinearServiceError('CLI_ERROR', 'Failed to create Linear child issue')\n }\n\n // Construct URL\n const url = issue.url ?? buildLinearIssueUrl(issue.identifier, title)\n\n return {\n identifier: issue.identifier,\n url,\n }\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'createLinearChildIssue')\n }\n}\n\n/**\n * Create a comment on a Linear issue\n * @param identifier - Linear issue identifier (e.g., \"ENG-123\")\n * @param body - Comment body (markdown)\n * @returns Created comment details\n * @throws LinearServiceError on creation failure\n */\nexport async function createLinearComment(\n identifier: string,\n body: string,\n): Promise<LinearComment> {\n try {\n logger.debug(`Creating comment on Linear issue ${identifier}`)\n const client = createLinearClient()\n\n // Get issue by identifier to get its ID\n const issue = await client.issue(identifier)\n if (!issue) {\n throw new LinearServiceError('NOT_FOUND', `Linear issue ${identifier} not found`)\n }\n\n // Create comment using issue ID\n const payload = await client.createComment({\n issueId: issue.id,\n body,\n })\n\n const comment = await payload.comment\n\n if (!comment) {\n throw new LinearServiceError('CLI_ERROR', 'Failed to create Linear comment')\n }\n\n return {\n id: comment.id,\n body: comment.body,\n createdAt: comment.createdAt.toISOString(),\n updatedAt: comment.updatedAt.toISOString(),\n url: comment.url,\n }\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'createLinearComment')\n }\n}\n\n/**\n * Update a Linear issue's workflow state\n * @param identifier - Linear issue identifier (e.g., \"ENG-123\")\n * @param stateName - Target state name (e.g., \"In Progress\", \"Done\")\n * @throws LinearServiceError on update failure\n */\nexport async function updateLinearIssueState(\n identifier: string,\n stateName: string,\n): Promise<void> {\n try {\n logger.debug(`Updating Linear issue ${identifier} state to: ${stateName}`)\n const client = createLinearClient()\n\n // Get issue by identifier\n const issue = await client.issue(identifier)\n if (!issue) {\n throw new LinearServiceError('NOT_FOUND', `Linear issue ${identifier} not found`)\n }\n\n // Get team to find state\n const team = await issue.team\n if (!team) {\n throw new LinearServiceError('CLI_ERROR', 'Issue has no team')\n }\n\n // Find state by name\n const states = await team.states()\n const state = states.nodes.find((s) => s.name === stateName)\n\n if (!state) {\n throw new LinearServiceError(\n 'NOT_FOUND',\n `State \"${stateName}\" not found in team ${team.key}`,\n )\n }\n\n // Update issue state\n await client.updateIssue(issue.id, {\n stateId: state.id,\n })\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'updateLinearIssueState')\n }\n}\n\n/**\n * Get a specific comment by ID\n * @param commentId - Linear comment UUID\n * @returns Comment details\n * @throws LinearServiceError if comment not found\n */\nexport async function getLinearComment(commentId: string): Promise<LinearComment> {\n try {\n logger.debug(`Fetching Linear comment: ${commentId}`)\n const client = createLinearClient()\n const comment = await client.comment({ id: commentId })\n\n if (!comment) {\n throw new LinearServiceError('NOT_FOUND', `Linear comment ${commentId} not found`)\n }\n\n return {\n id: comment.id,\n body: comment.body,\n createdAt: comment.createdAt.toISOString(),\n updatedAt: comment.updatedAt.toISOString(),\n url: comment.url,\n }\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'getLinearComment')\n }\n}\n\n/**\n * Update an existing comment\n * @param commentId - Linear comment UUID\n * @param body - New comment body (markdown)\n * @returns Updated comment details\n * @throws LinearServiceError on update failure\n */\nexport async function updateLinearComment(\n commentId: string,\n body: string,\n): Promise<LinearComment> {\n try {\n logger.debug(`Updating Linear comment: ${commentId}`)\n const client = createLinearClient()\n\n const payload = await client.updateComment(commentId, { body })\n const comment = await payload.comment\n\n if (!comment) {\n throw new LinearServiceError('CLI_ERROR', 'Failed to update Linear comment')\n }\n\n return {\n id: comment.id,\n body: comment.body,\n createdAt: comment.createdAt.toISOString(),\n updatedAt: comment.updatedAt.toISOString(),\n url: comment.url,\n }\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'updateLinearComment')\n }\n}\n\n/**\n * Fetch all comments for a Linear issue\n * @param identifier - Linear issue identifier (e.g., \"ENG-123\")\n * @returns Array of comments\n * @throws LinearServiceError on fetch failure\n */\nexport async function fetchLinearIssueComments(identifier: string): Promise<LinearComment[]> {\n try {\n logger.debug(`Fetching comments for Linear issue: ${identifier}`)\n const client = createLinearClient()\n\n // Get issue by identifier\n const issue = await client.issue(identifier)\n if (!issue) {\n throw new LinearServiceError('NOT_FOUND', `Linear issue ${identifier} not found`)\n }\n\n // Fetch comments\n const comments = await issue.comments({ first: 100 })\n\n return comments.nodes.map((comment) => ({\n id: comment.id,\n body: comment.body,\n createdAt: comment.createdAt.toISOString(),\n updatedAt: comment.updatedAt.toISOString(),\n url: comment.url,\n }))\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'fetchLinearIssueComments')\n }\n}\n\n/**\n * Get child issues of a parent Linear issue\n * @param identifier - Linear issue identifier (e.g., \"ENG-123\")\n * @param options - Optional settings\n * @param options.apiToken - Optional API token (takes precedence over env var)\n * @returns Array of child issues\n * @throws LinearServiceError on fetch failure\n */\nexport async function getLinearChildIssues(\n identifier: string,\n options?: { apiToken?: string },\n): Promise<Array<{ id: string; title: string; url: string; state: string }>> {\n try {\n logger.debug(`Fetching child issues for Linear issue: ${identifier}`)\n const client = createLinearClient(options?.apiToken)\n\n // Get issue by identifier\n const issue = await client.issue(identifier)\n if (!issue) {\n throw new LinearServiceError('NOT_FOUND', `Linear issue ${identifier} not found`)\n }\n\n // Fetch child issues\n const children = await issue.children({ first: 100 })\n\n // Build results, fetching state in parallel\n const results = await Promise.all(\n children.nodes.map(async (child) => {\n const stateObj = await child.state\n const state = stateObj?.name ?? 'unknown'\n\n return {\n id: child.identifier,\n title: child.title,\n url: child.url,\n state,\n }\n }),\n )\n\n return results\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'getLinearChildIssues')\n }\n}\n\n// Linear Issue Dependency Operations\n\n/**\n * Dependency result for Linear issues\n */\nexport interface LinearDependencyResult {\n id: string\n title: string\n url: string\n state: string\n}\n\n/**\n * Create a blocking relationship between two issues\n * @param blockingIssueId - UUID of the issue that blocks (the blocker)\n * @param blockedIssueId - UUID of the issue being blocked\n * @throws LinearServiceError on creation failure\n */\nexport async function createLinearIssueRelation(\n blockingIssueId: string,\n blockedIssueId: string,\n): Promise<void> {\n try {\n logger.debug(`Creating Linear issue relation: ${blockingIssueId} blocks ${blockedIssueId}`)\n const client = createLinearClient()\n\n // Create a \"blocks\" relation from blockingIssue to blockedIssue\n // In Linear, the relation is created on the blocking issue pointing to the blocked issue\n const payload = await client.createIssueRelation({\n issueId: blockingIssueId,\n relatedIssueId: blockedIssueId,\n type: IssueRelationType.Blocks,\n })\n\n if (!payload.success) {\n throw new LinearServiceError('CLI_ERROR', 'Failed to create Linear issue relation')\n }\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'createLinearIssueRelation')\n }\n}\n\n/**\n * Get dependencies for a Linear issue\n * @param identifier - Linear issue identifier (e.g., \"ENG-123\")\n * @param direction - 'blocking' for issues this blocks, 'blocked_by' for blockers, 'both' for all\n * @returns Object with blocking and blockedBy arrays\n * @throws LinearServiceError on fetch failure\n */\nexport async function getLinearIssueDependencies(\n identifier: string,\n direction: 'blocking' | 'blocked_by' | 'both',\n): Promise<{ blocking: LinearDependencyResult[]; blockedBy: LinearDependencyResult[] }> {\n try {\n logger.debug(`Fetching Linear issue dependencies: ${identifier} (direction: ${direction})`)\n const client = createLinearClient()\n\n // Get issue by identifier\n const issue = await client.issue(identifier)\n if (!issue) {\n throw new LinearServiceError('NOT_FOUND', `Linear issue ${identifier} not found`)\n }\n\n // Fetch relations and inverse relations in parallel\n const [relations, inverseRelations] = await Promise.all([\n issue.relations(),\n issue.inverseRelations(),\n ])\n\n const blocking: LinearDependencyResult[] = []\n const blockedBy: LinearDependencyResult[] = []\n\n // Helper to build dependency result from a resolved issue\n const buildDependencyResult = async (\n relatedIssue: { identifier: string; title: string; url: string; state: unknown } | null | undefined,\n ): Promise<LinearDependencyResult | null> => {\n if (!relatedIssue) return null\n\n const stateObj = await (relatedIssue.state as Promise<{ name?: string } | null | undefined>)\n const state = stateObj?.name ?? 'unknown'\n\n return {\n id: relatedIssue.identifier,\n title: relatedIssue.title,\n url: relatedIssue.url,\n state,\n }\n }\n\n // Process blocking relations (this issue blocks the related issue)\n // relations with type 'blocks' mean this issue blocks the related issue\n if (direction === 'blocking' || direction === 'both') {\n const blockingRelations = relations.nodes.filter(\n (r) => r.type === IssueRelationType.Blocks,\n )\n // Resolve all related issues in parallel, then build results\n // Filter out undefined relatedIssue before Promise.all (LinearFetch<Issue> | undefined)\n const relatedIssuePromises = blockingRelations\n .map((r) => r.relatedIssue)\n .filter((p): p is NonNullable<typeof p> => p !== undefined)\n const relatedIssues = await Promise.all(relatedIssuePromises)\n const blockingResults = await Promise.all(\n relatedIssues.map((issue) => buildDependencyResult(issue)),\n )\n blocking.push(...blockingResults.filter((r): r is LinearDependencyResult => r !== null))\n }\n\n // Process blocked by relations (the related issue blocks this issue)\n // inverseRelations with type 'blocks' mean the related issue blocks this issue\n if (direction === 'blocked_by' || direction === 'both') {\n const blockedByRelations = inverseRelations.nodes.filter(\n (r) => r.type === IssueRelationType.Blocks,\n )\n // Resolve all source issues in parallel, then build results\n // Filter out undefined issue before Promise.all (LinearFetch<Issue> | undefined)\n const sourceIssuePromises = blockedByRelations\n .map((r) => r.issue)\n .filter((p): p is NonNullable<typeof p> => p !== undefined)\n const sourceIssues = await Promise.all(sourceIssuePromises)\n const blockedByResults = await Promise.all(\n sourceIssues.map((issue) => buildDependencyResult(issue)),\n )\n blockedBy.push(...blockedByResults.filter((r): r is LinearDependencyResult => r !== null))\n }\n\n return { blocking, blockedBy }\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'getLinearIssueDependencies')\n }\n}\n\n/**\n * Delete an issue relation by ID\n * @param relationId - UUID of the relation to delete\n * @throws LinearServiceError on deletion failure\n */\nexport async function deleteLinearIssueRelation(relationId: string): Promise<void> {\n try {\n logger.debug(`Deleting Linear issue relation: ${relationId}`)\n const client = createLinearClient()\n\n const payload = await client.deleteIssueRelation(relationId)\n\n if (!payload.success) {\n throw new LinearServiceError('CLI_ERROR', 'Failed to delete Linear issue relation')\n }\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'deleteLinearIssueRelation')\n }\n}\n\n// Issue List Operations (for il issues command)\n\nexport interface LinearIssueListItem {\n id: string\n title: string\n updatedAt: string\n url: string\n state: string\n}\n\n/**\n * Fetch a list of active Linear issues for a team, sorted by recently updated\n * @param teamKey - Team key (e.g., \"ENG\", \"PLAT\")\n * @param options - Fetch options\n * @param options.limit - Maximum number of issues to return (default: 100)\n * @param options.apiToken - Optional API token (takes precedence over env var)\n * @returns Array of issues\n * @throws LinearServiceError on fetch failure\n */\nexport async function fetchLinearIssueList(\n teamKey: string,\n options?: { limit?: number; apiToken?: string },\n): Promise<LinearIssueListItem[]> {\n try {\n const limit = options?.limit ?? 100\n\n logger.debug(`Fetching Linear issue list for team ${teamKey}`, { limit })\n const client = createLinearClient(options?.apiToken)\n\n // Get team by key\n const teams = await client.teams()\n const team = teams.nodes.find((t) => t.key === teamKey)\n\n if (!team) {\n throw new LinearServiceError('NOT_FOUND', `Linear team ${teamKey} not found`)\n }\n\n // Fetch issues: filter out completed and canceled states, order by updatedAt\n const issues = await team.issues({\n first: limit,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- PaginationOrderBy is a const enum incompatible with isolatedModules\n orderBy: 'updatedAt' as any,\n filter: {\n state: {\n type: {\n nin: ['completed', 'canceled'],\n },\n },\n },\n })\n\n // Build results, resolving state names in parallel\n const results = await Promise.all(\n issues.nodes.map(async (issue) => {\n const stateObj = await issue.state\n const state = stateObj?.name ?? 'unknown'\n\n return {\n id: issue.identifier,\n title: issue.title,\n updatedAt: issue.updatedAt.toISOString(),\n url: issue.url,\n state,\n }\n }),\n )\n\n return results\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'fetchLinearIssueList')\n }\n}\n\n/**\n * Find the relation ID between two issues for removal\n * @param blockingIdentifier - Identifier of the blocking issue\n * @param blockedIdentifier - Identifier of the blocked issue\n * @returns The relation ID if found, null otherwise\n * @throws LinearServiceError on fetch failure\n */\nexport async function findLinearIssueRelation(\n blockingIdentifier: string,\n blockedIdentifier: string,\n): Promise<string | null> {\n try {\n logger.debug(`Finding Linear issue relation: ${blockingIdentifier} blocks ${blockedIdentifier}`)\n const client = createLinearClient()\n\n // Get the blocking issue\n const blockingIssue = await client.issue(blockingIdentifier)\n if (!blockingIssue) {\n throw new LinearServiceError('NOT_FOUND', `Linear issue ${blockingIdentifier} not found`)\n }\n\n // Get the blocked issue to get its ID\n const blockedIssue = await client.issue(blockedIdentifier)\n if (!blockedIssue) {\n throw new LinearServiceError('NOT_FOUND', `Linear issue ${blockedIdentifier} not found`)\n }\n\n // Find the relation from blockingIssue that blocks blockedIssue\n const relations = await blockingIssue.relations()\n\n // Filter to only 'blocks' relations and fetch related issues in parallel\n const blockingRelations = relations.nodes.filter(\n (r) => r.type === IssueRelationType.Blocks,\n )\n\n const relationsWithIssues = await Promise.all(\n blockingRelations.map(async (relation) => ({\n relation,\n relatedIssue: await relation.relatedIssue,\n })),\n )\n\n const matchingRelation = relationsWithIssues.find(\n ({ relatedIssue }) => relatedIssue?.id === blockedIssue.id,\n )\n\n return matchingRelation?.relation.id ?? null\n } catch (error) {\n if (error instanceof LinearServiceError) {\n throw error\n }\n handleLinearError(error, 'findLinearIssueRelation')\n }\n}\n","/**\n * Linear API response types (from @linear/sdk)\n */\n\n/**\n * Linear issue response from SDK\n */\nexport interface LinearIssue {\n /** Linear internal UUID */\n id: string\n /** Issue identifier in TEAM-NUMBER format (e.g., ENG-123) */\n identifier: string\n /** Issue title */\n title: string\n /** Issue description (markdown) */\n description?: string\n /** Current workflow state name */\n state?: string\n /** Linear web URL */\n url: string\n /** Creation timestamp (ISO string) */\n createdAt: string\n /** Last update timestamp (ISO string) */\n updatedAt: string\n}\n\n/**\n * Linear comment response from SDK\n */\nexport interface LinearComment {\n /** Comment UUID */\n id: string\n /** Comment body (markdown) */\n body: string\n /** Creation timestamp (ISO string) */\n createdAt: string\n /** Last update timestamp (ISO string) */\n updatedAt: string\n /** Comment URL */\n url: string\n}\n\n/**\n * Linear error codes\n */\nexport type LinearErrorCode =\n | 'NOT_FOUND'\n | 'UNAUTHORIZED'\n | 'INVALID_STATE'\n | 'RATE_LIMITED'\n | 'CLI_NOT_FOUND'\n | 'CLI_ERROR'\n\n/**\n * Linear error details\n */\nexport interface LinearError {\n code: LinearErrorCode\n message: string\n details?: unknown\n}\n\n/**\n * Custom error class for Linear operations\n */\nexport class LinearServiceError extends Error {\n constructor(\n public code: LinearErrorCode,\n message: string,\n public details?: unknown,\n ) {\n super(message)\n this.name = 'LinearServiceError'\n // Maintain proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, LinearServiceError)\n }\n }\n}\n"],"mappings":"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","names":["issue"]}