@iloom/cli 0.11.0 → 0.12.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 (286) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +153 -13
  3. package/dist/BitBucketApiClient-J2ZSCS5N.js +10 -0
  4. package/dist/BitBucketVCSProvider-5X64IXXW.js +12 -0
  5. package/dist/{BranchNamingService-XBCO747L.js → BranchNamingService-MEK2WZUD.js} +4 -4
  6. package/dist/ClaudeContextManager-IENAE2CP.js +14 -0
  7. package/dist/ClaudeService-YIJCZUUB.js +13 -0
  8. package/dist/GitHubService-UTAYZXL3.js +12 -0
  9. package/dist/IssueTrackerFactory-2OI7YIN6.js +15 -0
  10. package/dist/{LoomLauncher-5AZU2F5I.js → LoomLauncher-3TSFW7QP.js} +10 -10
  11. package/dist/MetadataManager-V4LSJ2PB.js +10 -0
  12. package/dist/ProjectCapabilityDetector-I4J66WKF.js +11 -0
  13. package/dist/{PromptTemplateManager-T5VTLJP3.js → PromptTemplateManager-I75WKXM4.js} +3 -3
  14. package/dist/README.md +153 -13
  15. package/dist/{SettingsManager-WQ5NSGAH.js → SettingsManager-BMQCAXPP.js} +13 -5
  16. package/dist/SettingsMigrationManager-ZPARZ5KH.js +10 -0
  17. package/dist/agents/iloom-code-reviewer.md +2 -1
  18. package/dist/agents/iloom-framework-detector.md +0 -1
  19. package/dist/agents/iloom-issue-analyze-and-plan.md +4 -1
  20. package/dist/agents/iloom-issue-analyzer.md +4 -1
  21. package/dist/agents/iloom-issue-complexity-evaluator.md +4 -1
  22. package/dist/agents/iloom-issue-enhancer.md +4 -1
  23. package/dist/agents/iloom-issue-implementer.md +8 -3
  24. package/dist/agents/iloom-issue-planner.md +4 -1
  25. package/dist/agents/iloom-wave-verifier.md +186 -0
  26. package/dist/browser-VZY7F2DF.js +10 -0
  27. package/dist/build-DMWSIME6.js +27 -0
  28. package/dist/{chunk-UHIBKD73.js → chunk-35CBWAJL.js} +13 -32
  29. package/dist/{chunk-UHIBKD73.js.map → chunk-35CBWAJL.js.map} +1 -1
  30. package/dist/{chunk-YRCEOQPX.js → chunk-4JZEQBWV.js} +4 -3
  31. package/dist/chunk-4JZEQBWV.js.map +1 -0
  32. package/dist/{chunk-ET6A2JR4.js → chunk-653XBU3L.js} +111 -18
  33. package/dist/chunk-653XBU3L.js.map +1 -0
  34. package/dist/{chunk-G2MNSPA4.js → chunk-772N5WCA.js} +2 -2
  35. package/dist/{chunk-WG4MLJ6J.js → chunk-7RCUWU3I.js} +2 -2
  36. package/dist/chunk-7RCUWU3I.js.map +1 -0
  37. package/dist/{chunk-NOMQ5RFG.js → chunk-7UBEHQTP.js} +2 -2
  38. package/dist/{chunk-7NFCGKZT.js → chunk-AQUSMNBF.js} +3 -3
  39. package/dist/{chunk-IDCE26KD.js → chunk-AUYSAMXV.js} +3 -3
  40. package/dist/chunk-AYLC633W.js +406 -0
  41. package/dist/chunk-AYLC633W.js.map +1 -0
  42. package/dist/{chunk-HLDY5S4C.js → chunk-BFF27W3S.js} +3 -3
  43. package/dist/{chunk-QVAA5KHK.js → chunk-BZ7KTXPB.js} +16 -8
  44. package/dist/chunk-BZ7KTXPB.js.map +1 -0
  45. package/dist/{chunk-K7R5QY6C.js → chunk-CE676WCN.js} +2 -2
  46. package/dist/{chunk-5UFGO4ZT.js → chunk-CQHHEW2M.js} +6 -3
  47. package/dist/chunk-CQHHEW2M.js.map +1 -0
  48. package/dist/{chunk-LHDD4JHC.js → chunk-D4Q7T5KD.js} +4 -4
  49. package/dist/{chunk-RBYTXYGD.js → chunk-D75KSI3V.js} +2 -2
  50. package/dist/{chunk-Y3RX7LZT.js → chunk-DDHWZNGL.js} +18 -12
  51. package/dist/chunk-DDHWZNGL.js.map +1 -0
  52. package/dist/{chunk-5LTID2AF.js → chunk-DMSL5BAP.js} +35 -6
  53. package/dist/{chunk-5LTID2AF.js.map → chunk-DMSL5BAP.js.map} +1 -1
  54. package/dist/{chunk-SQYHPBFP.js → chunk-EGNUOALL.js} +2 -2
  55. package/dist/{chunk-LL6TOX3G.js → chunk-EQIII6GI.js} +10 -10
  56. package/dist/chunk-EQIII6GI.js.map +1 -0
  57. package/dist/{chunk-ZAXRQLK3.js → chunk-FTYWGQFM.js} +2 -2
  58. package/dist/{chunk-LE2NOUTN.js → chunk-FV4KXBGO.js} +3 -3
  59. package/dist/{chunk-XFQGI2E3.js → chunk-GWJWECZB.js} +51 -45
  60. package/dist/chunk-GWJWECZB.js.map +1 -0
  61. package/dist/{chunk-QNHZM5ZV.js → chunk-HIGWKLQR.js} +3 -3
  62. package/dist/{chunk-VMZG66UV.js → chunk-HKEXRZMU.js} +3 -3
  63. package/dist/{chunk-V4STTBQD.js → chunk-IHSA7VGI.js} +9 -9
  64. package/dist/{chunk-TEJAGQX2.js → chunk-IS46GQRA.js} +33 -33
  65. package/dist/{chunk-VNYWBHKR.js → chunk-JD3K2344.js} +3 -3
  66. package/dist/{chunk-NCPZYQ4B.js → chunk-K3QGG4O2.js} +2 -2
  67. package/dist/{chunk-QR4FU53I.js → chunk-KCZSUJUR.js} +22 -12
  68. package/dist/chunk-KCZSUJUR.js.map +1 -0
  69. package/dist/{chunk-NH3QZYE5.js → chunk-KV4NU3RP.js} +2 -2
  70. package/dist/{chunk-NDSGJZI2.js → chunk-LOAYWTJJ.js} +2 -2
  71. package/dist/{chunk-ABVMUNCD.js → chunk-M3FBM4T3.js} +64 -10
  72. package/dist/chunk-M3FBM4T3.js.map +1 -0
  73. package/dist/{chunk-GMDSYLI6.js → chunk-MY2Q3FJ3.js} +2 -2
  74. package/dist/{chunk-CV47VCMQ.js → chunk-NPVA65KS.js} +2 -2
  75. package/dist/{chunk-7OCGBJLR.js → chunk-OIVFHJOA.js} +2 -2
  76. package/dist/{chunk-7FIXNAUO.js → chunk-OKB2NEDQ.js} +66 -43
  77. package/dist/chunk-OKB2NEDQ.js.map +1 -0
  78. package/dist/{chunk-3RXYOBME.js → chunk-OPQC4OWM.js} +5 -5
  79. package/dist/{chunk-3RXYOBME.js.map → chunk-OPQC4OWM.js.map} +1 -1
  80. package/dist/chunk-P5MXXHXQ.js +284 -0
  81. package/dist/chunk-P5MXXHXQ.js.map +1 -0
  82. package/dist/{chunk-IR74O2F6.js → chunk-PDG74IJT.js} +239 -162
  83. package/dist/chunk-PDG74IJT.js.map +1 -0
  84. package/dist/{chunk-NN5RYWXA.js → chunk-PH65MFQM.js} +6 -6
  85. package/dist/{chunk-TZNNJLGT.js → chunk-PMB6TYV4.js} +6 -6
  86. package/dist/chunk-QC65IOV3.js +304 -0
  87. package/dist/chunk-QC65IOV3.js.map +1 -0
  88. package/dist/{chunk-6YVJVUR4.js → chunk-QF2DROQR.js} +3 -3
  89. package/dist/{chunk-XXFSOVL3.js → chunk-QFDM23CO.js} +4 -4
  90. package/dist/{chunk-RMLADZRY.js → chunk-R7DGN73N.js} +5 -5
  91. package/dist/{chunk-5PNZBH6V.js → chunk-V5IYLWRA.js} +2 -2
  92. package/dist/{chunk-KQFIGI37.js → chunk-VA6CWUAE.js} +7 -7
  93. package/dist/{chunk-3GTUXW26.js → chunk-VIQOQ463.js} +19 -3
  94. package/dist/chunk-VIQOQ463.js.map +1 -0
  95. package/dist/{chunk-H2SSF24U.js → chunk-VRPPI6GU.js} +17 -6
  96. package/dist/{chunk-H2SSF24U.js.map → chunk-VRPPI6GU.js.map} +1 -1
  97. package/dist/{chunk-YETJNRQM.js → chunk-WEBMMJKL.js} +2 -1
  98. package/dist/{chunk-VUUN3KE4.js → chunk-XVCGPTEQ.js} +8 -8
  99. package/dist/chunk-XVCGPTEQ.js.map +1 -0
  100. package/dist/chunk-YWNF5755.js +696 -0
  101. package/dist/chunk-YWNF5755.js.map +1 -0
  102. package/dist/{chunk-UDCI3QTS.js → chunk-ZM2AYHMO.js} +2 -2
  103. package/dist/{claude-ONQTDWV3.js → claude-ACL7G4CF.js} +4 -4
  104. package/dist/{cleanup-YOM6PQCN.js → cleanup-RLBLNQZN.js} +37 -34
  105. package/dist/{cleanup-YOM6PQCN.js.map → cleanup-RLBLNQZN.js.map} +1 -1
  106. package/dist/cli.js +290 -141
  107. package/dist/cli.js.map +1 -1
  108. package/dist/{color-VQD52LOI.js → color-AC6F2QE7.js} +3 -3
  109. package/dist/{commit-DC2Q5CDY.js → commit-RILBXFWO.js} +15 -15
  110. package/dist/{compile-4NCQECKE.js → compile-QEL5724K.js} +11 -11
  111. package/dist/{contribute-M5UWXCAV.js → contribute-EHWLYOMZ.js} +11 -11
  112. package/dist/{contribute-M5UWXCAV.js.map → contribute-EHWLYOMZ.js.map} +1 -1
  113. package/dist/{mcp/darwin-3JFFE3W2.js → darwin-5K3I4FTH.js} +2 -2
  114. package/dist/{dev-server-CYRP6M73.js → dev-server-2WSWZXJG.js} +35 -21
  115. package/dist/dev-server-2WSWZXJG.js.map +1 -0
  116. package/dist/{feedback-BMAZGKRW.js → feedback-I6ZEHEUB.js} +17 -17
  117. package/dist/{git-BXUD6CL5.js → git-I3PO6FY7.js} +6 -6
  118. package/dist/ignite-XZFYRVRJ.js +35 -0
  119. package/dist/index.d.ts +200 -16
  120. package/dist/index.js +164 -55
  121. package/dist/index.js.map +1 -1
  122. package/dist/{init-CI43GJHV.js → init-A6WRP77L.js} +18 -18
  123. package/dist/{install-deps-SRTM5U7D.js → install-deps-HXP2TM7G.js} +11 -11
  124. package/dist/{installation-detector-HF6QN7KP.js → installation-detector-PYAZ2O6U.js} +3 -3
  125. package/dist/{issues-DMRQJH7E.js → issues-SUFQJY6O.js} +69 -56
  126. package/dist/issues-SUFQJY6O.js.map +1 -0
  127. package/dist/lint-FDZC77GL.js +27 -0
  128. package/dist/{linux-RYLOP2LY.js → linux-WUGRYCJY.js} +2 -2
  129. package/dist/mcp/{chunk-PIIRD4LO.js → chunk-4HZMW2V3.js} +1 -1
  130. package/dist/mcp/{chunk-PIIRD4LO.js.map → chunk-4HZMW2V3.js.map} +1 -1
  131. package/dist/{darwin-5BHWRJ7D.js → mcp/darwin-U25WIGH6.js} +2 -2
  132. package/dist/mcp/issue-management-server.js +900 -20
  133. package/dist/mcp/issue-management-server.js.map +1 -1
  134. package/dist/mcp/{linux-JBVS4R3A.js → linux-5BXVBGSY.js} +2 -2
  135. package/dist/mcp/recap-server.js +24 -22
  136. package/dist/mcp/recap-server.js.map +1 -1
  137. package/dist/mcp/{tmux-RYBLEHUZ.js → tmux-CU26ZTNM.js} +2 -2
  138. package/dist/mcp/{wsl-4QZIQLLE.js → wsl-KI25UDOF.js} +2 -2
  139. package/dist/neon-helpers-LCZAN4U4.js +11 -0
  140. package/dist/{open-2Y7GSUTJ.js → open-US4XACLW.js} +36 -21
  141. package/dist/open-US4XACLW.js.map +1 -0
  142. package/dist/{plan-SWFPLNJE.js → plan-PL3ZB32J.js} +47 -43
  143. package/dist/{plan-SWFPLNJE.js.map → plan-PL3ZB32J.js.map} +1 -1
  144. package/dist/{projects-IUSUXD5D.js → projects-L5AHUBGA.js} +6 -6
  145. package/dist/{prompt-7LZB4PAT.js → prompt-FUU5NMJQ.js} +3 -3
  146. package/dist/prompt-FUU5NMJQ.js.map +1 -0
  147. package/dist/prompts/init-prompt.txt +160 -23
  148. package/dist/prompts/issue-prompt.txt +93 -157
  149. package/dist/prompts/plan-prompt.txt +55 -0
  150. package/dist/prompts/swarm-orchestrator-prompt.txt +78 -21
  151. package/dist/{rebase-S6OHAOOF.js → rebase-JA3RW2XO.js} +12 -12
  152. package/dist/{recap-GGVCG5VH.js → recap-5TO42HN2.js} +9 -9
  153. package/dist/{remote-MZTFHHTU.js → remote-RO4LZKT2.js} +3 -3
  154. package/dist/remote-RO4LZKT2.js.map +1 -0
  155. package/dist/{run-ST3FR75O.js → run-KKCRBRLW.js} +36 -21
  156. package/dist/run-KKCRBRLW.js.map +1 -0
  157. package/dist/schema/settings.schema.json +147 -11
  158. package/dist/{shell-W4SBQPTE.js → shell-GAB2FCXH.js} +8 -8
  159. package/dist/{summary-P2JCIIJO.js → summary-P7QE3TNW.js} +21 -19
  160. package/dist/summary-P7QE3TNW.js.map +1 -0
  161. package/dist/test-6LFB5WOO.js +27 -0
  162. package/dist/{test-git-2KFFAQ6B.js → test-git-PYJOYSED.js} +6 -6
  163. package/dist/{test-jira-FKDKG6CD.js → test-jira-SM7IU5HW.js} +8 -8
  164. package/dist/{test-prefix-GP2DAX37.js → test-prefix-HIRZBXTM.js} +6 -6
  165. package/dist/{test-tabs-YDWMWTVA.js → test-tabs-NGPTFD5T.js} +2 -2
  166. package/dist/{test-webserver-QI3QQFZ3.js → test-webserver-43PVP2JL.js} +8 -8
  167. package/dist/{tmux-7ZTA3BDI.js → tmux-6LRFH3DM.js} +2 -2
  168. package/dist/{update-XLW7R7FL.js → update-AD3GE5C4.js} +4 -4
  169. package/dist/{update-notifier-EYLAXZAA.js → update-notifier-VYDTDMSJ.js} +3 -3
  170. package/dist/update-notifier-VYDTDMSJ.js.map +1 -0
  171. package/dist/{vscode-TOGE5N67.js → vscode-HXIXRZ3A.js} +12 -12
  172. package/dist/{vscode-announcement-NIX7O2MG.js → vscode-announcement-AL3EHORH.js} +3 -3
  173. package/dist/{wsl-Y4GUTOQ7.js → wsl-4VMVT2PO.js} +2 -2
  174. package/package.json +1 -1
  175. package/dist/ClaudeContextManager-SXDCWDJA.js +0 -14
  176. package/dist/ClaudeService-6E6MCGJE.js +0 -13
  177. package/dist/GitHubService-2R5GQG4K.js +0 -12
  178. package/dist/IssueTrackerFactory-XN6MQ4UN.js +0 -14
  179. package/dist/MetadataManager-CMQQTFLQ.js +0 -10
  180. package/dist/ProjectCapabilityDetector-IC6NAFGY.js +0 -11
  181. package/dist/SettingsMigrationManager-S6J7OHUH.js +0 -10
  182. package/dist/build-OLS6J5KZ.js +0 -27
  183. package/dist/chunk-3GTUXW26.js.map +0 -1
  184. package/dist/chunk-5UFGO4ZT.js.map +0 -1
  185. package/dist/chunk-7FIXNAUO.js.map +0 -1
  186. package/dist/chunk-ABVMUNCD.js.map +0 -1
  187. package/dist/chunk-ET6A2JR4.js.map +0 -1
  188. package/dist/chunk-IR74O2F6.js.map +0 -1
  189. package/dist/chunk-LL6TOX3G.js.map +0 -1
  190. package/dist/chunk-QR4FU53I.js.map +0 -1
  191. package/dist/chunk-QVAA5KHK.js.map +0 -1
  192. package/dist/chunk-RVI6C2H5.js +0 -220
  193. package/dist/chunk-RVI6C2H5.js.map +0 -1
  194. package/dist/chunk-VUUN3KE4.js.map +0 -1
  195. package/dist/chunk-WG4MLJ6J.js.map +0 -1
  196. package/dist/chunk-XFQGI2E3.js.map +0 -1
  197. package/dist/chunk-Y3RX7LZT.js.map +0 -1
  198. package/dist/chunk-YRCEOQPX.js.map +0 -1
  199. package/dist/dev-server-CYRP6M73.js.map +0 -1
  200. package/dist/ignite-IO4LXVXJ.js +0 -35
  201. package/dist/issues-DMRQJH7E.js.map +0 -1
  202. package/dist/lint-BSWRMGPZ.js +0 -27
  203. package/dist/neon-helpers-HWIYRKOW.js +0 -11
  204. package/dist/open-2Y7GSUTJ.js.map +0 -1
  205. package/dist/run-ST3FR75O.js.map +0 -1
  206. package/dist/summary-P2JCIIJO.js.map +0 -1
  207. package/dist/test-6JH4FE2X.js +0 -27
  208. /package/dist/{BranchNamingService-XBCO747L.js.map → BitBucketApiClient-J2ZSCS5N.js.map} +0 -0
  209. /package/dist/{ClaudeContextManager-SXDCWDJA.js.map → BitBucketVCSProvider-5X64IXXW.js.map} +0 -0
  210. /package/dist/{ClaudeService-6E6MCGJE.js.map → BranchNamingService-MEK2WZUD.js.map} +0 -0
  211. /package/dist/{GitHubService-2R5GQG4K.js.map → ClaudeContextManager-IENAE2CP.js.map} +0 -0
  212. /package/dist/{IssueTrackerFactory-XN6MQ4UN.js.map → ClaudeService-YIJCZUUB.js.map} +0 -0
  213. /package/dist/{MetadataManager-CMQQTFLQ.js.map → GitHubService-UTAYZXL3.js.map} +0 -0
  214. /package/dist/{ProjectCapabilityDetector-IC6NAFGY.js.map → IssueTrackerFactory-2OI7YIN6.js.map} +0 -0
  215. /package/dist/{LoomLauncher-5AZU2F5I.js.map → LoomLauncher-3TSFW7QP.js.map} +0 -0
  216. /package/dist/{PromptTemplateManager-T5VTLJP3.js.map → MetadataManager-V4LSJ2PB.js.map} +0 -0
  217. /package/dist/{SettingsManager-WQ5NSGAH.js.map → ProjectCapabilityDetector-I4J66WKF.js.map} +0 -0
  218. /package/dist/{SettingsMigrationManager-S6J7OHUH.js.map → PromptTemplateManager-I75WKXM4.js.map} +0 -0
  219. /package/dist/{claude-ONQTDWV3.js.map → SettingsManager-BMQCAXPP.js.map} +0 -0
  220. /package/dist/{color-VQD52LOI.js.map → SettingsMigrationManager-ZPARZ5KH.js.map} +0 -0
  221. /package/dist/{darwin-5BHWRJ7D.js.map → browser-VZY7F2DF.js.map} +0 -0
  222. /package/dist/{build-OLS6J5KZ.js.map → build-DMWSIME6.js.map} +0 -0
  223. /package/dist/{chunk-G2MNSPA4.js.map → chunk-772N5WCA.js.map} +0 -0
  224. /package/dist/{chunk-NOMQ5RFG.js.map → chunk-7UBEHQTP.js.map} +0 -0
  225. /package/dist/{chunk-7NFCGKZT.js.map → chunk-AQUSMNBF.js.map} +0 -0
  226. /package/dist/{chunk-IDCE26KD.js.map → chunk-AUYSAMXV.js.map} +0 -0
  227. /package/dist/{chunk-HLDY5S4C.js.map → chunk-BFF27W3S.js.map} +0 -0
  228. /package/dist/{chunk-K7R5QY6C.js.map → chunk-CE676WCN.js.map} +0 -0
  229. /package/dist/{chunk-LHDD4JHC.js.map → chunk-D4Q7T5KD.js.map} +0 -0
  230. /package/dist/{chunk-RBYTXYGD.js.map → chunk-D75KSI3V.js.map} +0 -0
  231. /package/dist/{chunk-SQYHPBFP.js.map → chunk-EGNUOALL.js.map} +0 -0
  232. /package/dist/{chunk-ZAXRQLK3.js.map → chunk-FTYWGQFM.js.map} +0 -0
  233. /package/dist/{chunk-LE2NOUTN.js.map → chunk-FV4KXBGO.js.map} +0 -0
  234. /package/dist/{chunk-QNHZM5ZV.js.map → chunk-HIGWKLQR.js.map} +0 -0
  235. /package/dist/{chunk-VMZG66UV.js.map → chunk-HKEXRZMU.js.map} +0 -0
  236. /package/dist/{chunk-V4STTBQD.js.map → chunk-IHSA7VGI.js.map} +0 -0
  237. /package/dist/{chunk-TEJAGQX2.js.map → chunk-IS46GQRA.js.map} +0 -0
  238. /package/dist/{chunk-VNYWBHKR.js.map → chunk-JD3K2344.js.map} +0 -0
  239. /package/dist/{chunk-NCPZYQ4B.js.map → chunk-K3QGG4O2.js.map} +0 -0
  240. /package/dist/{chunk-NH3QZYE5.js.map → chunk-KV4NU3RP.js.map} +0 -0
  241. /package/dist/{chunk-NDSGJZI2.js.map → chunk-LOAYWTJJ.js.map} +0 -0
  242. /package/dist/{chunk-GMDSYLI6.js.map → chunk-MY2Q3FJ3.js.map} +0 -0
  243. /package/dist/{chunk-CV47VCMQ.js.map → chunk-NPVA65KS.js.map} +0 -0
  244. /package/dist/{chunk-7OCGBJLR.js.map → chunk-OIVFHJOA.js.map} +0 -0
  245. /package/dist/{chunk-NN5RYWXA.js.map → chunk-PH65MFQM.js.map} +0 -0
  246. /package/dist/{chunk-TZNNJLGT.js.map → chunk-PMB6TYV4.js.map} +0 -0
  247. /package/dist/{chunk-6YVJVUR4.js.map → chunk-QF2DROQR.js.map} +0 -0
  248. /package/dist/{chunk-XXFSOVL3.js.map → chunk-QFDM23CO.js.map} +0 -0
  249. /package/dist/{chunk-RMLADZRY.js.map → chunk-R7DGN73N.js.map} +0 -0
  250. /package/dist/{chunk-5PNZBH6V.js.map → chunk-V5IYLWRA.js.map} +0 -0
  251. /package/dist/{chunk-KQFIGI37.js.map → chunk-VA6CWUAE.js.map} +0 -0
  252. /package/dist/{chunk-YETJNRQM.js.map → chunk-WEBMMJKL.js.map} +0 -0
  253. /package/dist/{chunk-UDCI3QTS.js.map → chunk-ZM2AYHMO.js.map} +0 -0
  254. /package/dist/{git-BXUD6CL5.js.map → claude-ACL7G4CF.js.map} +0 -0
  255. /package/dist/{ignite-IO4LXVXJ.js.map → color-AC6F2QE7.js.map} +0 -0
  256. /package/dist/{commit-DC2Q5CDY.js.map → commit-RILBXFWO.js.map} +0 -0
  257. /package/dist/{compile-4NCQECKE.js.map → compile-QEL5724K.js.map} +0 -0
  258. /package/dist/{installation-detector-HF6QN7KP.js.map → darwin-5K3I4FTH.js.map} +0 -0
  259. /package/dist/{feedback-BMAZGKRW.js.map → feedback-I6ZEHEUB.js.map} +0 -0
  260. /package/dist/{mcp/darwin-3JFFE3W2.js.map → git-I3PO6FY7.js.map} +0 -0
  261. /package/dist/{neon-helpers-HWIYRKOW.js.map → ignite-XZFYRVRJ.js.map} +0 -0
  262. /package/dist/{init-CI43GJHV.js.map → init-A6WRP77L.js.map} +0 -0
  263. /package/dist/{install-deps-SRTM5U7D.js.map → install-deps-HXP2TM7G.js.map} +0 -0
  264. /package/dist/{prompt-7LZB4PAT.js.map → installation-detector-PYAZ2O6U.js.map} +0 -0
  265. /package/dist/{lint-BSWRMGPZ.js.map → lint-FDZC77GL.js.map} +0 -0
  266. /package/dist/{linux-RYLOP2LY.js.map → linux-WUGRYCJY.js.map} +0 -0
  267. /package/dist/{remote-MZTFHHTU.js.map → mcp/darwin-U25WIGH6.js.map} +0 -0
  268. /package/dist/mcp/{linux-JBVS4R3A.js.map → linux-5BXVBGSY.js.map} +0 -0
  269. /package/dist/mcp/{tmux-RYBLEHUZ.js.map → tmux-CU26ZTNM.js.map} +0 -0
  270. /package/dist/mcp/{wsl-4QZIQLLE.js.map → wsl-KI25UDOF.js.map} +0 -0
  271. /package/dist/{update-notifier-EYLAXZAA.js.map → neon-helpers-LCZAN4U4.js.map} +0 -0
  272. /package/dist/{projects-IUSUXD5D.js.map → projects-L5AHUBGA.js.map} +0 -0
  273. /package/dist/{rebase-S6OHAOOF.js.map → rebase-JA3RW2XO.js.map} +0 -0
  274. /package/dist/{recap-GGVCG5VH.js.map → recap-5TO42HN2.js.map} +0 -0
  275. /package/dist/{shell-W4SBQPTE.js.map → shell-GAB2FCXH.js.map} +0 -0
  276. /package/dist/{test-6JH4FE2X.js.map → test-6LFB5WOO.js.map} +0 -0
  277. /package/dist/{test-git-2KFFAQ6B.js.map → test-git-PYJOYSED.js.map} +0 -0
  278. /package/dist/{test-jira-FKDKG6CD.js.map → test-jira-SM7IU5HW.js.map} +0 -0
  279. /package/dist/{test-prefix-GP2DAX37.js.map → test-prefix-HIRZBXTM.js.map} +0 -0
  280. /package/dist/{test-tabs-YDWMWTVA.js.map → test-tabs-NGPTFD5T.js.map} +0 -0
  281. /package/dist/{test-webserver-QI3QQFZ3.js.map → test-webserver-43PVP2JL.js.map} +0 -0
  282. /package/dist/{tmux-7ZTA3BDI.js.map → tmux-6LRFH3DM.js.map} +0 -0
  283. /package/dist/{update-XLW7R7FL.js.map → update-AD3GE5C4.js.map} +0 -0
  284. /package/dist/{vscode-TOGE5N67.js.map → vscode-HXIXRZ3A.js.map} +0 -0
  285. /package/dist/{vscode-announcement-NIX7O2MG.js.map → vscode-announcement-AL3EHORH.js.map} +0 -0
  286. /package/dist/{wsl-Y4GUTOQ7.js.map → wsl-4VMVT2PO.js.map} +0 -0
@@ -0,0 +1,186 @@
1
+ ---
2
+ name: iloom-wave-verifier
3
+ description: Wave verification agent that checks must-have criteria from child issues after each swarm wave, invokes fix skills for failures, and reports structured results.\n\nExamples:\n<example>\nContext: Orchestrator wants to verify that wave 1 work meets acceptance criteria\nuser: "Verify must-haves for issues #101, #102, #103 from wave 1"\nassistant: "I'll check all must-have criteria from those issues against the codebase and report results."\n<commentary>\nThe orchestrator needs wave verification after a completed wave, so use the iloom-wave-verifier agent.\n</commentary>\n</example>\n<example>\nContext: Swarm orchestrator needs to gate the next wave on verification passing\nuser: "Run wave verification for child issues #45, #46 before proceeding to wave 2"\nassistant: "I'll verify all must-haves for the specified issues, fix any failures, and return a structured report."\n<commentary>\nWave gating requires verification of completed work, so use the iloom-wave-verifier agent.\n</commentary>\n</example>
4
+ model: opus
5
+ color: red
6
+ ---
7
+
8
+ {{#if SWARM_MODE}}
9
+ ## Swarm Mode
10
+
11
+ **You are running in swarm mode as part of an autonomous workflow.**
12
+
13
+ - **No human interaction**: Do NOT pause for user input or present options for decision. Make your best judgment and proceed.
14
+ - **Concise output**: Return structured verification results suitable for the orchestrator.
15
+ - **No state to done**: Do NOT call `recap.set_loom_state` with state `done` — only the swarm worker may do that after committing.
16
+ {{/if}}
17
+
18
+ # Wave Verifier Agent
19
+
20
+ You are a wave verification agent. Your job is to check must-have criteria from completed child issues against the codebase, fix failures by invoking the implementer skill, and return a structured pass/fail report.
21
+
22
+ ## MANDATORY FIRST STEP
23
+
24
+ 1. `cd` to your assigned worktree path (from your invocation prompt)
25
+ 2. Call `recap.set_loom_state({ state: "in_progress", worktreePath: "<your-worktree-path>" })`
26
+ 3. Parse the child issue numbers from your invocation prompt
27
+
28
+ ## Core Workflow
29
+
30
+ ### Step 1: Parse Must-Haves from Child Issues
31
+
32
+ For each child issue number provided in your prompt:
33
+
34
+ 1. Call `mcp__issue_management__get_issue` to fetch the issue body and title
35
+ 2. Extract the `## Must-Haves` section from the body
36
+ 3. Parse each line into structured criteria:
37
+ - `exists: <file-path>` → Check that file exists at the given path
38
+ - `substantive: <file-path> — <description>` → Check file has expected content matching description
39
+ - `wired: <file-path> — <description>` → Check code is integrated into the app as described
40
+
41
+ **Must-Haves format expected in child issue bodies:**
42
+
43
+ ```
44
+ ## Must-Haves
45
+ - exists: src/components/Foo.tsx
46
+ - substantive: src/components/Foo.tsx — exports a default React component with Props interface
47
+ - wired: src/App.tsx — imports and renders Foo component in the main layout
48
+ ```
49
+
50
+ If a child issue has no `## Must-Haves` section, skip it and note in the report: "Issue #NNN: No must-haves defined — skipped."
51
+
52
+ ### Step 2: Verify Each Must-Have
53
+
54
+ For each parsed must-have criterion, run the appropriate check:
55
+
56
+ **`exists` checks:**
57
+ - Use the Glob tool to check if the file exists at the specified path
58
+ - PASS if file is found, FAIL if not found
59
+
60
+ **`substantive` checks:**
61
+ - Use the Read tool to read the file at the specified path
62
+ - If the file does not exist, FAIL immediately with detail "File not found"
63
+ - Analyze the file content against the description (e.g., expected exports, key functions, class names, proper structure)
64
+ - PASS if content meaningfully satisfies the description, FAIL if the file is empty, a stub, or missing the expected content
65
+ - Use judgment: a file that exports a placeholder comment is a FAIL; a file that exports the expected construct is a PASS
66
+
67
+ **`wired` checks:**
68
+ - Use the Grep tool to search for imports, references, or usage of the subject file from the rest of the codebase
69
+ - Read relevant files if you need to verify the integration described (e.g., check that the import is actually used, not just present)
70
+ - PASS if evidence of integration as described is found, FAIL if no integration evidence exists
71
+
72
+ Record each result as:
73
+
74
+ ```
75
+ {
76
+ issueNumber: string,
77
+ issueTitle: string,
78
+ criterion: string, // the raw criterion line, e.g. "src/Foo.tsx — exports default component"
79
+ type: 'exists' | 'substantive' | 'wired',
80
+ filePath: string,
81
+ status: 'pass' | 'fail',
82
+ detail: string // brief reason, e.g. "File found" or "No exports found in file"
83
+ }
84
+ ```
85
+
86
+ ### Step 3: Fix Failures (if any)
87
+
88
+ If any must-haves FAILED, invoke the fix skill to address them:
89
+
90
+ 1. Group failures by child issue number
91
+ 2. For each group of failures for a single issue, invoke the fix skill:
92
+
93
+ **Fix skill invocation:**
94
+
95
+ CRITICAL: Skills run with `context: fork` and start at the project root. You MUST include the child worktree path so the forked agent works in the correct location.
96
+
97
+ ```
98
+ /iloom-swarm-issue-implementer "Your working directory is /path/to/child/worktree. cd there before doing any work. Implement the following missing must-haves for issue #NNN '[issue title]'. DO NOT create your own issue comment.
99
+
100
+ The following must-have criteria FAILED verification:
101
+ 1. [exists] src/components/Foo.tsx — File does not exist
102
+ 2. [substantive] src/components/Foo.tsx — Expected: exports a default React component with Props interface. Found: file is empty
103
+ 3. [wired] src/App.tsx — Expected: imports and renders Foo component. Found: no import of Foo found
104
+
105
+ Fix ONLY these specific failures. Do not add scope beyond what is listed above."
106
+ ```
107
+
108
+ **Fix prompt construction:** The fix prompt MUST include:
109
+ - Issue number and title for context
110
+ - Specific must-have failures and what was expected
111
+ - File paths and descriptions from each failed criterion
112
+ - Clear instruction: "DO NOT create your own issue comment"
113
+ - Instruction to fix ONLY the listed failures without adding scope
114
+
115
+ **Output handling:**
116
+ The skill runs inline and returns its result directly. Check the skill's output for success/failure indicators.
117
+
118
+ 3. Run fix skill invocations sequentially (one per issue group), waiting for each to complete before starting the next
119
+ 4. Record fix action results: which issue, which failures were targeted, and whether the skill reported success
120
+
121
+ ### Step 4: Re-Verify (Single Pass Only)
122
+
123
+ After ALL fix skill invocations have completed:
124
+
125
+ 1. Re-run the exact same verification checks from Step 2, but ONLY for the criteria that previously FAILED
126
+ 2. Update the result records with new status (pass/fail) and updated detail
127
+ 3. **Do NOT invoke additional fix skills** — this is a single re-verification pass
128
+ 4. If a criterion still fails after the fix attempt, record `status: 'fail'` and note "Still failing after fix attempt"
129
+
130
+ ### Step 5: Return Structured Report
131
+
132
+ Return the verification report in this exact format:
133
+
134
+ ---
135
+
136
+ ## Wave Verification Report
137
+
138
+ ### Summary
139
+ - **Total must-haves checked:** N
140
+ - **Passed (initial):** N
141
+ - **Failed (initial):** N
142
+ - **Fixed after re-verification:** N
143
+ - **Still failing:** N
144
+
145
+ ### Results by Issue
146
+
147
+ #### Issue #NNN: [issue title]
148
+
149
+ | Must-Have | Type | Initial | After Fix |
150
+ |-----------|------|---------|-----------|
151
+ | `src/Foo.tsx` | exists | ✅ PASS | — |
152
+ | `src/Foo.tsx` — exports default component | substantive | ❌ FAIL | ✅ PASS |
153
+ | `src/App.tsx` — imports Foo | wired | ✅ PASS | — |
154
+
155
+ #### Issue #NNN: [issue title]
156
+
157
+ | Must-Have | Type | Initial | After Fix |
158
+ |-----------|------|---------|-----------|
159
+ | `src/Bar.tsx` | exists | ❌ FAIL | ❌ FAIL |
160
+
161
+ ### Fix Actions Taken
162
+
163
+ - **Issue #NNN**: Invoked fix skill for: `src/Foo.tsx` (substantive)
164
+ - Fix result: Success — re-verification passed
165
+
166
+ - **Issue #NNN**: Invoked fix skill for: `src/Bar.tsx` (exists)
167
+ - Fix result: Partial — file created but still failing
168
+
169
+ *(If no fix skills were invoked: "None — all must-haves passed on initial verification.")*
170
+
171
+ ### Overall Status: [ALL_PASSED | PARTIALLY_FIXED | FAILURES_REMAIN]
172
+
173
+ - **ALL_PASSED**: All must-haves passed initial verification (no fix skills needed)
174
+ - **PARTIALLY_FIXED**: Some failures were fixed but others remain
175
+ - **FAILURES_REMAIN**: One or more must-haves are still failing after re-verification
176
+
177
+ ---
178
+
179
+ ### State Transitions
180
+
181
+ Call `recap.set_loom_state` at these workflow boundaries, **always passing your child worktree path** as the `worktreePath` parameter (e.g., `{ state: "done", worktreePath: "<your-worktree-path>" }`). Without `worktreePath`, the call defaults to the epic's metadata — which is wrong for verification workers.
182
+ - `in_progress` — At workflow start (Mandatory First Step)
183
+ - `done` — After returning the verification report (regardless of whether must-haves passed or failed — the verifier's job is complete)
184
+ - `failed` — On any unrecoverable error
185
+
186
+ **IMPORTANT:** Return the full report text as your output so the orchestrator can log it and determine whether to proceed to the next wave.
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ detectPlatform,
4
+ openBrowser
5
+ } from "./chunk-WEBMMJKL.js";
6
+ export {
7
+ detectPlatform,
8
+ openBrowser
9
+ };
10
+ //# sourceMappingURL=browser-VZY7F2DF.js.map
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ScriptCommandBase
4
+ } from "./chunk-IHSA7VGI.js";
5
+ import "./chunk-ZM2AYHMO.js";
6
+ import "./chunk-VIQOQ463.js";
7
+ import "./chunk-FV4KXBGO.js";
8
+ import "./chunk-K3QGG4O2.js";
9
+ import "./chunk-OPQC4OWM.js";
10
+ import "./chunk-653XBU3L.js";
11
+ import "./chunk-4JZEQBWV.js";
12
+ import "./chunk-FTYWGQFM.js";
13
+ import "./chunk-VRPPI6GU.js";
14
+
15
+ // src/commands/build.ts
16
+ var BuildCommand = class extends ScriptCommandBase {
17
+ getScriptName() {
18
+ return "build";
19
+ }
20
+ getScriptDisplayName() {
21
+ return "Build";
22
+ }
23
+ };
24
+ export {
25
+ BuildCommand
26
+ };
27
+ //# sourceMappingURL=build-DMWSIME6.js.map
@@ -6,16 +6,19 @@ import {
6
6
  fetchLinearIssue,
7
7
  getLinearChildIssues,
8
8
  updateLinearIssueState
9
- } from "./chunk-5LTID2AF.js";
9
+ } from "./chunk-DMSL5BAP.js";
10
10
  import {
11
11
  GitHubService
12
- } from "./chunk-LHDD4JHC.js";
12
+ } from "./chunk-D4Q7T5KD.js";
13
13
  import {
14
14
  promptConfirmation
15
- } from "./chunk-CV47VCMQ.js";
15
+ } from "./chunk-NPVA65KS.js";
16
+ import {
17
+ redactSensitiveFields
18
+ } from "./chunk-653XBU3L.js";
16
19
  import {
17
20
  getLogger
18
- } from "./chunk-ZAXRQLK3.js";
21
+ } from "./chunk-FTYWGQFM.js";
19
22
 
20
23
  // src/lib/LinearService.ts
21
24
  var LinearService = class {
@@ -206,10 +209,10 @@ var IssueTrackerFactory = class {
206
209
  * @throws Error if provider type is not supported
207
210
  */
208
211
  static create(settings) {
209
- var _a, _b, _c;
212
+ var _a, _b;
210
213
  const provider = ((_a = settings.issueManagement) == null ? void 0 : _a.provider) ?? "github";
211
214
  getLogger().debug(`IssueTrackerFactory: Creating tracker for provider "${provider}"`);
212
- getLogger().debug(`IssueTrackerFactory: issueManagement settings:`, JSON.stringify(settings.issueManagement, null, 2));
215
+ getLogger().debug(`IssueTrackerFactory: issueManagement settings:`, JSON.stringify(redactSensitiveFields(settings.issueManagement), null, 2));
213
216
  switch (provider) {
214
217
  case "github":
215
218
  getLogger().debug("IssueTrackerFactory: Creating GitHubService");
@@ -226,34 +229,12 @@ var IssueTrackerFactory = class {
226
229
  if (linearSettings == null ? void 0 : linearSettings.apiToken) {
227
230
  linearConfig.apiToken = linearSettings.apiToken;
228
231
  }
229
- getLogger().debug(`IssueTrackerFactory: Creating LinearService with config:`, JSON.stringify(linearConfig, null, 2));
232
+ getLogger().debug(`IssueTrackerFactory: Creating LinearService with config:`, JSON.stringify(redactSensitiveFields(linearConfig), null, 2));
230
233
  return new LinearService(linearConfig);
231
234
  }
232
235
  case "jira": {
233
- const jiraSettings = (_c = settings.issueManagement) == null ? void 0 : _c.jira;
234
- if (!(jiraSettings == null ? void 0 : jiraSettings.host)) {
235
- throw new Error("Jira host is required. Configure issueManagement.jira.host in .iloom/settings.json");
236
- }
237
- if (!(jiraSettings == null ? void 0 : jiraSettings.username)) {
238
- throw new Error("Jira username is required. Configure issueManagement.jira.username in .iloom/settings.json");
239
- }
240
- if (!(jiraSettings == null ? void 0 : jiraSettings.apiToken)) {
241
- throw new Error("Jira API token is required. Configure issueManagement.jira.apiToken in .iloom/settings.local.json");
242
- }
243
- if (!(jiraSettings == null ? void 0 : jiraSettings.projectKey)) {
244
- throw new Error("Jira project key is required. Configure issueManagement.jira.projectKey in .iloom/settings.json");
245
- }
246
- const jiraConfig = {
247
- host: jiraSettings.host,
248
- username: jiraSettings.username,
249
- apiToken: jiraSettings.apiToken,
250
- projectKey: jiraSettings.projectKey
251
- };
252
- if (jiraSettings.transitionMappings) {
253
- jiraConfig.transitionMappings = jiraSettings.transitionMappings;
254
- }
255
- getLogger().debug(`IssueTrackerFactory: Creating JiraIssueTracker for host: ${jiraSettings.host}`);
256
- return new JiraIssueTracker(jiraConfig);
236
+ getLogger().debug(`IssueTrackerFactory: Creating JiraIssueTracker from settings`);
237
+ return JiraIssueTracker.fromSettings(settings);
257
238
  }
258
239
  default:
259
240
  throw new Error(`Unsupported issue tracker provider: ${provider}`);
@@ -275,4 +256,4 @@ var IssueTrackerFactory = class {
275
256
  export {
276
257
  IssueTrackerFactory
277
258
  };
278
- //# sourceMappingURL=chunk-UHIBKD73.js.map
259
+ //# sourceMappingURL=chunk-35CBWAJL.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/LinearService.ts","../src/lib/IssueTrackerFactory.ts"],"sourcesContent":["/**\n * LinearService - IssueTracker implementation for Linear\n * Implements issue tracking operations using the @linear/sdk\n */\n\nimport type { Issue, PullRequest, IssueTrackerInputDetection } from '../types/index.js'\nimport type { LinearIssue } from '../types/linear.js'\nimport { LinearServiceError } from '../types/linear.js'\nimport {\n fetchLinearIssue,\n createLinearIssue,\n updateLinearIssueState,\n getLinearChildIssues,\n} from '../utils/linear.js'\nimport { promptConfirmation } from '../utils/prompt.js'\nimport type { IssueTracker } from './IssueTracker.js'\nimport { getLogger } from '../utils/logger-context.js'\n\n/**\n * Linear service configuration options\n */\nexport interface LinearServiceConfig {\n /** Linear team key (e.g., \"ENG\", \"PLAT\") */\n teamId?: string\n /** Branch naming template (e.g., \"feat/{{key}}__{{title}}\") */\n branchFormat?: string\n /** Linear API token (lin_api_...). If provided, sets process.env.LINEAR_API_TOKEN */\n apiToken?: string\n}\n\n/**\n * Linear implementation of IssueTracker interface\n */\nexport class LinearService implements IssueTracker {\n // IssueTracker interface implementation\n readonly providerName = 'linear'\n readonly supportsPullRequests = false // Linear doesn't have pull requests\n\n private config: LinearServiceConfig\n private prompter: (message: string) => Promise<boolean>\n\n constructor(\n config?: LinearServiceConfig,\n options?: { prompter?: (message: string) => Promise<boolean> },\n ) {\n this.config = config ?? {}\n this.prompter = options?.prompter ?? promptConfirmation\n\n // Set API token from config if provided (follows mcp.ts pattern)\n if (this.config.apiToken) {\n process.env.LINEAR_API_TOKEN = this.config.apiToken\n }\n }\n\n /**\n * Detect if input matches Linear identifier format (TEAM-NUMBER)\n * @param input - User input string\n * @param _repo - Repository (unused for Linear)\n * @returns Detection result with type and identifier\n */\n public async detectInputType(\n input: string,\n _repo?: string,\n ): Promise<IssueTrackerInputDetection> {\n getLogger().debug(`LinearService.detectInputType called with input: \"${input}\"`)\n\n // Pattern: TEAM-NUMBER (e.g., ENG-123, PLAT-456)\n // Requires at least 2 letters before dash to avoid conflict with PR-123 format\n const linearPattern = /^([A-Z]{2,}-\\d+)$/i\n const match = input.match(linearPattern)\n\n if (!match?.[1]) {\n getLogger().debug(`LinearService: Input \"${input}\" does not match Linear pattern`)\n return { type: 'unknown', identifier: null, rawInput: input }\n }\n\n const identifier = match[1].toUpperCase()\n getLogger().debug(`LinearService: Matched Linear identifier: ${identifier}`)\n\n // Validate the issue exists in Linear\n getLogger().debug(`LinearService: Checking if ${identifier} is a valid Linear issue via SDK`)\n const issue = await this.isValidIssue(identifier)\n\n if (issue) {\n getLogger().debug(`LinearService: Issue ${identifier} found: \"${issue.title}\"`)\n return { type: 'issue', identifier, rawInput: input }\n }\n\n // Not found\n getLogger().debug(`LinearService: Issue ${identifier} NOT found by SDK`)\n return { type: 'unknown', identifier: null, rawInput: input }\n }\n\n /**\n * Fetch a Linear issue by identifier\n * @param identifier - Linear issue identifier (string or number)\n * @param _repo - Repository (unused for Linear)\n * @returns Generic Issue type\n * @throws LinearServiceError if issue not found\n */\n public async fetchIssue(identifier: string | number, _repo?: string): Promise<Issue> {\n const linearIssue = await fetchLinearIssue(String(identifier))\n return this.mapLinearIssueToIssue(linearIssue)\n }\n\n /**\n * Check if an issue identifier is valid (silent validation)\n * @param identifier - Linear issue identifier\n * @param _repo - Repository (unused for Linear)\n * @returns Issue if valid, false if not found\n */\n public async isValidIssue(identifier: string | number, _repo?: string): Promise<Issue | false> {\n try {\n return await this.fetchIssue(identifier)\n } catch (error) {\n // Return false for NOT_FOUND errors (expected during detection)\n if (error instanceof LinearServiceError && error.code === 'NOT_FOUND') {\n return false\n }\n // Re-throw unexpected errors\n throw error\n }\n }\n\n /**\n * Validate issue state and prompt user if closed\n * @param issue - Issue to validate\n * @throws LinearServiceError if user cancels due to closed issue\n */\n public async validateIssueState(issue: Issue): Promise<void> {\n if (issue.state === 'closed') {\n const shouldContinue = await this.prompter(\n `Issue ${issue.number} is closed. Continue anyway?`,\n )\n\n if (!shouldContinue) {\n throw new LinearServiceError('INVALID_STATE', 'User cancelled due to closed issue')\n }\n }\n }\n\n /**\n * Create a new Linear issue\n * @param title - Issue title\n * @param body - Issue description (markdown)\n * @param _repository - Repository (unused for Linear)\n * @param labels - Optional label names\n * @returns Created issue identifier and URL\n * @throws LinearServiceError if teamId not configured or creation fails\n */\n public async createIssue(\n title: string,\n body: string,\n _repository?: string,\n labels?: string[],\n ): Promise<{ number: string | number; url: string }> {\n // Require teamId configuration\n if (!this.config.teamId) {\n throw new LinearServiceError(\n 'INVALID_STATE',\n 'Linear teamId not configured. Run `il init` to configure Linear settings.',\n )\n }\n\n getLogger().info(`Creating Linear issue in team ${this.config.teamId}: ${title}`)\n\n const result = await createLinearIssue(title, body, this.config.teamId, labels)\n\n return {\n number: result.identifier,\n url: result.url,\n }\n }\n\n /**\n * Get the web URL for a Linear issue\n * @param identifier - Linear issue identifier\n * @param _repo - Repository (unused for Linear)\n * @returns Issue URL\n */\n public async getIssueUrl(identifier: string | number, _repo?: string): Promise<string> {\n const issue = await this.fetchIssue(identifier)\n return issue.url\n }\n\n /**\n * Fetch child issues of a Linear parent issue\n * @param parentIdentifier - Linear issue identifier (e.g., \"ENG-123\")\n * @param _repo - Repository (unused for Linear)\n * @returns Array of child issues\n */\n public async getChildIssues(parentIdentifier: string, _repo?: string): Promise<Array<{ id: string; title: string; url: string; state: string }>> {\n return getLinearChildIssues(parentIdentifier, this.config.apiToken ? { apiToken: this.config.apiToken } : undefined)\n }\n\n /**\n * Move a Linear issue to \"In Progress\" state\n * @param identifier - Linear issue identifier\n * @throws LinearServiceError if state update fails\n */\n public async moveIssueToInProgress(identifier: string | number): Promise<void> {\n getLogger().info(`Moving Linear issue ${identifier} to In Progress`)\n await updateLinearIssueState(String(identifier), 'In Progress')\n }\n\n /**\n * Move a Linear issue to \"In Review\" state\n * @param identifier - Linear issue identifier\n * @throws LinearServiceError if state update fails\n */\n public async moveIssueToReadyForReview(identifier: string | number): Promise<void> {\n getLogger().info(`Moving Linear issue ${identifier} to In Review`)\n await updateLinearIssueState(String(identifier), 'In Review')\n }\n\n /**\n * Normalize identifier to canonical form (uppercase for Linear keys)\n * @param identifier - Linear issue identifier (e.g., \"eng-123\" or \"ENG-123\")\n * @returns Uppercase identifier (e.g., \"ENG-123\")\n */\n public normalizeIdentifier(identifier: string | number): string {\n return String(identifier).toUpperCase()\n }\n\n /**\n * Extract issue context for AI prompts\n * @param entity - Issue (Linear doesn't have PRs)\n * @returns Formatted context string\n */\n public extractContext(entity: Issue | PullRequest): string {\n // Linear doesn't have PRs, always an issue\n const issue = entity as Issue\n return `Linear Issue ${issue.number}: ${issue.title}\\nState: ${issue.state}\\n\\n${issue.body}`\n }\n\n /**\n * Map Linear API issue to generic Issue type\n * @param linear - Linear issue from SDK\n * @returns Generic Issue type\n */\n private mapLinearIssueToIssue(linear: LinearIssue): Issue {\n return {\n number: linear.identifier, // Keep as string (e.g., \"ENG-123\")\n title: linear.title,\n body: linear.description ?? '',\n state: linear.state ? (linear.state.toLowerCase().includes('done') || linear.state.toLowerCase().includes('completed') || linear.state.toLowerCase().includes('canceled') ? 'closed' : 'open') : 'open',\n labels: [],\n assignees: [],\n url: linear.url,\n }\n }\n}\n","// IssueTrackerFactory - creates appropriate IssueTracker based on settings\n// Follows pattern from database provider instantiation\n\nimport type { IssueTracker } from './IssueTracker.js'\nimport { GitHubService } from './GitHubService.js'\nimport { LinearService, type LinearServiceConfig } from './LinearService.js'\nimport { JiraIssueTracker, type JiraTrackerConfig } from './providers/jira/index.js'\nimport type { IloomSettings } from './SettingsManager.js'\nimport { getLogger } from '../utils/logger-context.js'\n\nexport type IssueTrackerProviderType = 'github' | 'linear' | 'jira'\n\n/**\n * Factory for creating IssueTracker instances based on settings\n * Provides a single point of provider instantiation\n *\n * Usage:\n * const tracker = IssueTrackerFactory.create(settings, { useClaude: true })\n * const issue = await tracker.fetchIssue(123)\n */\nexport class IssueTrackerFactory {\n\t/**\n\t * Create an IssueTracker instance based on settings configuration\n\t * Defaults to GitHub if no provider specified\n\t *\n\t * @param settings - iloom settings containing issueManagement.provider\n\t * @returns IssueTracker instance configured for the specified provider\n\t * @throws Error if provider type is not supported\n\t */\n\tstatic create(settings: IloomSettings): IssueTracker {\n\t\tconst provider = settings.issueManagement?.provider ?? 'github'\n\n\t\tgetLogger().debug(`IssueTrackerFactory: Creating tracker for provider \"${provider}\"`)\n\t\tgetLogger().debug(`IssueTrackerFactory: issueManagement settings:`, JSON.stringify(settings.issueManagement, null, 2))\n\n\t\tswitch (provider) {\n\t\t\tcase 'github':\n\t\t\t\tgetLogger().debug('IssueTrackerFactory: Creating GitHubService')\n\t\t\t\treturn new GitHubService()\n\t\t\tcase 'linear': {\n\t\t\t\tconst linearSettings = settings.issueManagement?.linear\n\t\t\t\tconst linearConfig: LinearServiceConfig = {}\n\n\t\t\t\tif (linearSettings?.teamId) {\n\t\t\t\t\tlinearConfig.teamId = linearSettings.teamId\n\t\t\t\t}\n\t\t\t\tif (linearSettings?.branchFormat) {\n\t\t\t\t\tlinearConfig.branchFormat = linearSettings.branchFormat\n\t\t\t\t}\n\t\t\t\tif (linearSettings?.apiToken) {\n\t\t\t\t\tlinearConfig.apiToken = linearSettings.apiToken\n\t\t\t\t}\n\n\t\t\t\tgetLogger().debug(`IssueTrackerFactory: Creating LinearService with config:`, JSON.stringify(linearConfig, null, 2))\n\t\t\t\treturn new LinearService(linearConfig)\n\t\t\t}\n\t\t\tcase 'jira': {\n\t\t\t\tconst jiraSettings = settings.issueManagement?.jira\n\t\t\t\t\n\t\t\t\tif (!jiraSettings?.host) {\n\t\t\t\t\tthrow new Error('Jira host is required. Configure issueManagement.jira.host in .iloom/settings.json')\n\t\t\t\t}\n\t\t\t\tif (!jiraSettings?.username) {\n\t\t\t\t\tthrow new Error('Jira username is required. Configure issueManagement.jira.username in .iloom/settings.json')\n\t\t\t\t}\n\t\t\t\tif (!jiraSettings?.apiToken) {\n\t\t\t\t\tthrow new Error('Jira API token is required. Configure issueManagement.jira.apiToken in .iloom/settings.local.json')\n\t\t\t\t}\n\t\t\t\tif (!jiraSettings?.projectKey) {\n\t\t\t\t\tthrow new Error('Jira project key is required. Configure issueManagement.jira.projectKey in .iloom/settings.json')\n\t\t\t\t}\n\n\t\t\t\tconst jiraConfig: JiraTrackerConfig = {\n\t\t\t\t\thost: jiraSettings.host,\n\t\t\t\t\tusername: jiraSettings.username,\n\t\t\t\t\tapiToken: jiraSettings.apiToken,\n\t\t\t\t\tprojectKey: jiraSettings.projectKey,\n\t\t\t\t}\n\n\t\t\t\tif (jiraSettings.transitionMappings) {\n\t\t\t\t\tjiraConfig.transitionMappings = jiraSettings.transitionMappings\n\t\t\t\t}\n\n\t\t\t\tgetLogger().debug(`IssueTrackerFactory: Creating JiraIssueTracker for host: ${jiraSettings.host}`)\n\t\t\t\treturn new JiraIssueTracker(jiraConfig)\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unsupported issue tracker provider: ${provider}`)\n\t\t}\n\t}\n\n\t/**\n\t * Get the configured provider name from settings\n\t * Defaults to 'github' if not configured\n\t *\n\t * @param settings - iloom settings\n\t * @returns Provider type string\n\t */\n\tstatic getProviderName(settings: IloomSettings): IssueTrackerProviderType {\n\t\treturn (settings.issueManagement?.provider ?? 'github') as IssueTrackerProviderType\n\t}\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/lib/LinearService.ts","../src/lib/IssueTrackerFactory.ts"],"sourcesContent":["/**\n * LinearService - IssueTracker implementation for Linear\n * Implements issue tracking operations using the @linear/sdk\n */\n\nimport type { Issue, PullRequest, IssueTrackerInputDetection } from '../types/index.js'\nimport type { LinearIssue } from '../types/linear.js'\nimport { LinearServiceError } from '../types/linear.js'\nimport {\n fetchLinearIssue,\n createLinearIssue,\n updateLinearIssueState,\n getLinearChildIssues,\n} from '../utils/linear.js'\nimport { promptConfirmation } from '../utils/prompt.js'\nimport type { IssueTracker } from './IssueTracker.js'\nimport { getLogger } from '../utils/logger-context.js'\n\n/**\n * Linear service configuration options\n */\nexport interface LinearServiceConfig {\n /** Linear team key (e.g., \"ENG\", \"PLAT\") */\n teamId?: string\n /** Branch naming template (e.g., \"feat/{{key}}__{{title}}\") */\n branchFormat?: string\n /** Linear API token (lin_api_...). If provided, sets process.env.LINEAR_API_TOKEN */\n apiToken?: string\n}\n\n/**\n * Linear implementation of IssueTracker interface\n */\nexport class LinearService implements IssueTracker {\n // IssueTracker interface implementation\n readonly providerName = 'linear'\n readonly supportsPullRequests = false // Linear doesn't have pull requests\n\n private config: LinearServiceConfig\n private prompter: (message: string) => Promise<boolean>\n\n constructor(\n config?: LinearServiceConfig,\n options?: { prompter?: (message: string) => Promise<boolean> },\n ) {\n this.config = config ?? {}\n this.prompter = options?.prompter ?? promptConfirmation\n\n // Set API token from config if provided (follows mcp.ts pattern)\n if (this.config.apiToken) {\n process.env.LINEAR_API_TOKEN = this.config.apiToken\n }\n }\n\n /**\n * Detect if input matches Linear identifier format (TEAM-NUMBER)\n * @param input - User input string\n * @param _repo - Repository (unused for Linear)\n * @returns Detection result with type and identifier\n */\n public async detectInputType(\n input: string,\n _repo?: string,\n ): Promise<IssueTrackerInputDetection> {\n getLogger().debug(`LinearService.detectInputType called with input: \"${input}\"`)\n\n // Pattern: TEAM-NUMBER (e.g., ENG-123, PLAT-456)\n // Requires at least 2 letters before dash to avoid conflict with PR-123 format\n const linearPattern = /^([A-Z]{2,}-\\d+)$/i\n const match = input.match(linearPattern)\n\n if (!match?.[1]) {\n getLogger().debug(`LinearService: Input \"${input}\" does not match Linear pattern`)\n return { type: 'unknown', identifier: null, rawInput: input }\n }\n\n const identifier = match[1].toUpperCase()\n getLogger().debug(`LinearService: Matched Linear identifier: ${identifier}`)\n\n // Validate the issue exists in Linear\n getLogger().debug(`LinearService: Checking if ${identifier} is a valid Linear issue via SDK`)\n const issue = await this.isValidIssue(identifier)\n\n if (issue) {\n getLogger().debug(`LinearService: Issue ${identifier} found: \"${issue.title}\"`)\n return { type: 'issue', identifier, rawInput: input }\n }\n\n // Not found\n getLogger().debug(`LinearService: Issue ${identifier} NOT found by SDK`)\n return { type: 'unknown', identifier: null, rawInput: input }\n }\n\n /**\n * Fetch a Linear issue by identifier\n * @param identifier - Linear issue identifier (string or number)\n * @param _repo - Repository (unused for Linear)\n * @returns Generic Issue type\n * @throws LinearServiceError if issue not found\n */\n public async fetchIssue(identifier: string | number, _repo?: string): Promise<Issue> {\n const linearIssue = await fetchLinearIssue(String(identifier))\n return this.mapLinearIssueToIssue(linearIssue)\n }\n\n /**\n * Check if an issue identifier is valid (silent validation)\n * @param identifier - Linear issue identifier\n * @param _repo - Repository (unused for Linear)\n * @returns Issue if valid, false if not found\n */\n public async isValidIssue(identifier: string | number, _repo?: string): Promise<Issue | false> {\n try {\n return await this.fetchIssue(identifier)\n } catch (error) {\n // Return false for NOT_FOUND errors (expected during detection)\n if (error instanceof LinearServiceError && error.code === 'NOT_FOUND') {\n return false\n }\n // Re-throw unexpected errors\n throw error\n }\n }\n\n /**\n * Validate issue state and prompt user if closed\n * @param issue - Issue to validate\n * @throws LinearServiceError if user cancels due to closed issue\n */\n public async validateIssueState(issue: Issue): Promise<void> {\n if (issue.state === 'closed') {\n const shouldContinue = await this.prompter(\n `Issue ${issue.number} is closed. Continue anyway?`,\n )\n\n if (!shouldContinue) {\n throw new LinearServiceError('INVALID_STATE', 'User cancelled due to closed issue')\n }\n }\n }\n\n /**\n * Create a new Linear issue\n * @param title - Issue title\n * @param body - Issue description (markdown)\n * @param _repository - Repository (unused for Linear)\n * @param labels - Optional label names\n * @returns Created issue identifier and URL\n * @throws LinearServiceError if teamId not configured or creation fails\n */\n public async createIssue(\n title: string,\n body: string,\n _repository?: string,\n labels?: string[],\n ): Promise<{ number: string | number; url: string }> {\n // Require teamId configuration\n if (!this.config.teamId) {\n throw new LinearServiceError(\n 'INVALID_STATE',\n 'Linear teamId not configured. Run `il init` to configure Linear settings.',\n )\n }\n\n getLogger().info(`Creating Linear issue in team ${this.config.teamId}: ${title}`)\n\n const result = await createLinearIssue(title, body, this.config.teamId, labels)\n\n return {\n number: result.identifier,\n url: result.url,\n }\n }\n\n /**\n * Get the web URL for a Linear issue\n * @param identifier - Linear issue identifier\n * @param _repo - Repository (unused for Linear)\n * @returns Issue URL\n */\n public async getIssueUrl(identifier: string | number, _repo?: string): Promise<string> {\n const issue = await this.fetchIssue(identifier)\n return issue.url\n }\n\n /**\n * Fetch child issues of a Linear parent issue\n * @param parentIdentifier - Linear issue identifier (e.g., \"ENG-123\")\n * @param _repo - Repository (unused for Linear)\n * @returns Array of child issues\n */\n public async getChildIssues(parentIdentifier: string, _repo?: string): Promise<Array<{ id: string; title: string; url: string; state: string }>> {\n return getLinearChildIssues(parentIdentifier, this.config.apiToken ? { apiToken: this.config.apiToken } : undefined)\n }\n\n /**\n * Move a Linear issue to \"In Progress\" state\n * @param identifier - Linear issue identifier\n * @throws LinearServiceError if state update fails\n */\n public async moveIssueToInProgress(identifier: string | number): Promise<void> {\n getLogger().info(`Moving Linear issue ${identifier} to In Progress`)\n await updateLinearIssueState(String(identifier), 'In Progress')\n }\n\n /**\n * Move a Linear issue to \"In Review\" state\n * @param identifier - Linear issue identifier\n * @throws LinearServiceError if state update fails\n */\n public async moveIssueToReadyForReview(identifier: string | number): Promise<void> {\n getLogger().info(`Moving Linear issue ${identifier} to In Review`)\n await updateLinearIssueState(String(identifier), 'In Review')\n }\n\n /**\n * Normalize identifier to canonical form (uppercase for Linear keys)\n * @param identifier - Linear issue identifier (e.g., \"eng-123\" or \"ENG-123\")\n * @returns Uppercase identifier (e.g., \"ENG-123\")\n */\n public normalizeIdentifier(identifier: string | number): string {\n return String(identifier).toUpperCase()\n }\n\n /**\n * Extract issue context for AI prompts\n * @param entity - Issue (Linear doesn't have PRs)\n * @returns Formatted context string\n */\n public extractContext(entity: Issue | PullRequest): string {\n // Linear doesn't have PRs, always an issue\n const issue = entity as Issue\n return `Linear Issue ${issue.number}: ${issue.title}\\nState: ${issue.state}\\n\\n${issue.body}`\n }\n\n /**\n * Map Linear API issue to generic Issue type\n * @param linear - Linear issue from SDK\n * @returns Generic Issue type\n */\n private mapLinearIssueToIssue(linear: LinearIssue): Issue {\n return {\n number: linear.identifier, // Keep as string (e.g., \"ENG-123\")\n title: linear.title,\n body: linear.description ?? '',\n state: linear.state ? (linear.state.toLowerCase().includes('done') || linear.state.toLowerCase().includes('completed') || linear.state.toLowerCase().includes('canceled') ? 'closed' : 'open') : 'open',\n labels: [],\n assignees: [],\n url: linear.url,\n }\n }\n}\n","// IssueTrackerFactory - creates appropriate IssueTracker based on settings\n// Follows pattern from database provider instantiation\n\nimport type { IssueTracker } from './IssueTracker.js'\nimport { GitHubService } from './GitHubService.js'\nimport { LinearService, type LinearServiceConfig } from './LinearService.js'\nimport { JiraIssueTracker } from './providers/jira/index.js'\nimport { type IloomSettings, redactSensitiveFields } from './SettingsManager.js'\nimport { getLogger } from '../utils/logger-context.js'\n\nexport type IssueTrackerProviderType = 'github' | 'linear' | 'jira'\n\n/**\n * Factory for creating IssueTracker instances based on settings\n * Provides a single point of provider instantiation\n *\n * Usage:\n * const tracker = IssueTrackerFactory.create(settings, { useClaude: true })\n * const issue = await tracker.fetchIssue(123)\n */\nexport class IssueTrackerFactory {\n\t/**\n\t * Create an IssueTracker instance based on settings configuration\n\t * Defaults to GitHub if no provider specified\n\t *\n\t * @param settings - iloom settings containing issueManagement.provider\n\t * @returns IssueTracker instance configured for the specified provider\n\t * @throws Error if provider type is not supported\n\t */\n\tstatic create(settings: IloomSettings): IssueTracker {\n\t\tconst provider = settings.issueManagement?.provider ?? 'github'\n\n\t\tgetLogger().debug(`IssueTrackerFactory: Creating tracker for provider \"${provider}\"`)\n\t\tgetLogger().debug(`IssueTrackerFactory: issueManagement settings:`, JSON.stringify(redactSensitiveFields(settings.issueManagement), null, 2))\n\n\t\tswitch (provider) {\n\t\t\tcase 'github':\n\t\t\t\tgetLogger().debug('IssueTrackerFactory: Creating GitHubService')\n\t\t\t\treturn new GitHubService()\n\t\t\tcase 'linear': {\n\t\t\t\tconst linearSettings = settings.issueManagement?.linear\n\t\t\t\tconst linearConfig: LinearServiceConfig = {}\n\n\t\t\t\tif (linearSettings?.teamId) {\n\t\t\t\t\tlinearConfig.teamId = linearSettings.teamId\n\t\t\t\t}\n\t\t\t\tif (linearSettings?.branchFormat) {\n\t\t\t\t\tlinearConfig.branchFormat = linearSettings.branchFormat\n\t\t\t\t}\n\t\t\t\tif (linearSettings?.apiToken) {\n\t\t\t\t\tlinearConfig.apiToken = linearSettings.apiToken\n\t\t\t\t}\n\n\t\t\t\tgetLogger().debug(`IssueTrackerFactory: Creating LinearService with config:`, JSON.stringify(redactSensitiveFields(linearConfig), null, 2))\n\t\t\t\treturn new LinearService(linearConfig)\n\t\t\t}\n\t\t\tcase 'jira': {\n\t\t\t\tgetLogger().debug(`IssueTrackerFactory: Creating JiraIssueTracker from settings`)\n\t\t\t\treturn JiraIssueTracker.fromSettings(settings)\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unsupported issue tracker provider: ${provider}`)\n\t\t}\n\t}\n\n\t/**\n\t * Get the configured provider name from settings\n\t * Defaults to 'github' if not configured\n\t *\n\t * @param settings - iloom settings\n\t * @returns Provider type string\n\t */\n\tstatic getProviderName(settings: IloomSettings): IssueTrackerProviderType {\n\t\treturn (settings.issueManagement?.provider ?? 'github') as IssueTrackerProviderType\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getLogger
4
- } from "./chunk-ZAXRQLK3.js";
4
+ } from "./chunk-FTYWGQFM.js";
5
5
 
6
6
  // src/lib/MetadataManager.ts
7
7
  import path from "path";
@@ -40,7 +40,8 @@ var MetadataManager = class {
40
40
  parentLoom: data.parentLoom ?? null,
41
41
  childIssues: data.childIssues ?? [],
42
42
  dependencyMap: data.dependencyMap ?? {},
43
- mcpConfigPath: data.mcpConfigPath ?? null
43
+ mcpConfigPath: data.mcpConfigPath ?? null,
44
+ swarmTeamName: data.swarmTeamName ?? null
44
45
  };
45
46
  }
46
47
  /**
@@ -329,4 +330,4 @@ var MetadataManager = class {
329
330
  export {
330
331
  MetadataManager
331
332
  };
332
- //# sourceMappingURL=chunk-YRCEOQPX.js.map
333
+ //# sourceMappingURL=chunk-4JZEQBWV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/MetadataManager.ts"],"sourcesContent":["import path from 'path'\nimport os from 'os'\nimport fs from 'fs-extra'\nimport { getLogger } from '../utils/logger-context.js'\nimport type { ProjectCapability } from '../types/loom.js'\nimport type { ComplexityOverride, OneShotMode } from '../types/index.js'\n\nexport type SwarmState = 'pending' | 'in_progress' | 'code_review' | 'done' | 'failed'\n\n/**\n * Schema for metadata JSON file\n * Stored in ~/.config/iloom-ai/looms/\n */\nexport interface MetadataFile {\n description: string\n created_at?: string\n version: number\n // Additional metadata fields (v2)\n branchName?: string\n worktreePath?: string\n issueType?: 'branch' | 'issue' | 'pr' | 'epic'\n issueKey?: string // Canonical, properly-cased issue key (e.g., \"PROJ-123\")\n issue_numbers?: string[]\n pr_numbers?: string[]\n issueTracker?: string\n colorHex?: string // Stored hex color (e.g., \"#dcebff\") - robust against palette changes\n sessionId?: string // Claude Code session ID for resume support\n projectPath?: string // Main worktree path (project root) - enables project identification\n issueUrls?: Record<string, string> // Map of issue ID to URL in the issue tracker\n prUrls?: Record<string, string> // Map of PR number to URL in the issue tracker\n draftPrNumber?: number // Draft PR number if draft-pr mode was used\n oneShot?: OneShotMode // One-shot automation mode stored during loom creation\n complexity?: ComplexityOverride // Complexity override stored during loom creation\n capabilities?: ProjectCapability[] // Detected project capabilities\n state?: SwarmState // Swarm mode lifecycle state\n childIssueNumbers?: string[] // Child issue numbers for epic looms\n parentLoom?: {\n type: 'issue' | 'pr' | 'branch' | 'epic'\n identifier: string | number\n branchName: string\n worktreePath: string\n databaseBranch?: string\n }\n // Epic/swarm child issue data (populated during spin setup)\n childIssues?: Array<{\n number: string // Prefixed: \"#123\" for GitHub, \"ENG-123\" for Linear\n title: string\n body: string\n url: string\n }>\n dependencyMap?: Record<string, string[]> // issueNumber -> array of blocking issueNumbers\n mcpConfigPath?: string // Path to per-loom MCP config file (for swarm claude -p commands)\n swarmTeamName?: string // Unique team name for swarm orchestrator (persisted for re-runs)\n}\n\n/**\n * Input for writing metadata (all fields except version and created_at)\n * Note: issueTracker is required because every loom should have an associated\n * issue tracker provider (defaults to 'github' via IssueTrackerFactory)\n */\nexport interface WriteMetadataInput {\n description: string\n branchName: string\n worktreePath: string\n issueType: 'branch' | 'issue' | 'pr' | 'epic'\n issueKey?: string // Canonical, properly-cased issue key (e.g., \"PROJ-123\")\n issue_numbers: string[]\n pr_numbers: string[]\n issueTracker: string\n colorHex: string // Hex color (e.g., \"#dcebff\") - robust against palette changes\n sessionId: string // Claude Code session ID for resume support (required for new looms)\n projectPath: string // Main worktree path (project root) - required for new looms\n issueUrls: Record<string, string> // Map of issue ID to URL in the issue tracker\n prUrls: Record<string, string> // Map of PR number to URL in the issue tracker\n draftPrNumber?: number // Draft PR number for draft-pr mode\n oneShot?: OneShotMode // One-shot automation mode to persist\n complexity?: ComplexityOverride // Complexity override to persist\n capabilities: ProjectCapability[] // Detected project capabilities (required for new looms)\n state?: SwarmState // Swarm mode lifecycle state\n childIssueNumbers?: string[] // Child issue numbers for epic looms\n parentLoom?: {\n type: 'issue' | 'pr' | 'branch' | 'epic'\n identifier: string | number\n branchName: string\n worktreePath: string\n databaseBranch?: string\n }\n // Epic/swarm child issue data (populated during spin setup)\n childIssues?: Array<{\n number: string // Prefixed: \"#123\" for GitHub, \"ENG-123\" for Linear\n title: string\n body: string\n url: string\n }>\n dependencyMap?: Record<string, string[]> // issueNumber -> array of blocking issueNumbers\n mcpConfigPath?: string // Path to per-loom MCP config file (for swarm claude -p commands)\n swarmTeamName?: string // Unique team name for swarm orchestrator (persisted for re-runs)\n}\n\n/**\n * Result of reading metadata for a worktree\n */\nexport interface LoomMetadata {\n status?: 'active' | 'finished'\n finishedAt?: string | null\n description: string\n created_at: string | null\n branchName: string | null\n worktreePath: string | null\n issueType: 'branch' | 'issue' | 'pr' | 'epic' | null\n issueKey: string | null // Canonical, properly-cased issue key (e.g., \"PROJ-123\")\n issue_numbers: string[]\n pr_numbers: string[]\n issueTracker: string | null\n colorHex: string | null // Hex color (e.g., \"#dcebff\") - robust against palette changes\n sessionId: string | null // Claude Code session ID (null for legacy looms)\n projectPath: string | null // Main worktree path (null for legacy looms)\n issueUrls: Record<string, string> // Map of issue ID to URL ({} for legacy looms)\n prUrls: Record<string, string> // Map of PR number to URL ({} for legacy looms)\n draftPrNumber: number | null // Draft PR number (null if not draft mode)\n oneShot: OneShotMode | null // One-shot mode (null for legacy looms)\n complexity: ComplexityOverride | null // Complexity override (null when not overridden)\n capabilities: ProjectCapability[] // Detected project capabilities (empty for legacy looms)\n state: SwarmState | null // Swarm mode lifecycle state (null for non-swarm looms)\n childIssueNumbers: string[] // Child issue numbers for epic looms (empty for non-epic looms)\n parentLoom: {\n type: 'issue' | 'pr' | 'branch' | 'epic'\n identifier: string | number\n branchName: string\n worktreePath: string\n databaseBranch?: string\n } | null\n // Epic/swarm child issue data (empty arrays/objects for non-epic looms)\n childIssues: Array<{\n number: string\n title: string\n body: string\n url: string\n }>\n dependencyMap: Record<string, string[]>\n mcpConfigPath: string | null // Path to per-loom MCP config file (null for non-swarm looms)\n swarmTeamName: string | null // Unique team name for swarm orchestrator (null for non-swarm looms)\n}\n\n/**\n * MetadataManager: Manage loom metadata persistence\n *\n * Stores loom metadata in ~/.config/iloom-ai/looms/ directory.\n * Each worktree gets a JSON file named by slugifying its absolute path.\n *\n * Per spec section 2.2:\n * - Filename derived from worktree absolute path\n * - Path separators replaced with double underscores\n * - Non-alphanumeric chars (except _ and -) replaced with hyphens\n */\nexport class MetadataManager {\n private readonly loomsDir: string\n private readonly finishedDir: string\n\n constructor() {\n this.loomsDir = path.join(os.homedir(), '.config', 'iloom-ai', 'looms')\n this.finishedDir = path.join(this.loomsDir, 'finished')\n }\n\n /**\n * Convert MetadataFile to LoomMetadata with default values for optional fields\n */\n private toMetadata(data: MetadataFile): LoomMetadata {\n return {\n description: data.description,\n created_at: data.created_at ?? null,\n branchName: data.branchName ?? null,\n worktreePath: data.worktreePath ?? null,\n issueType: data.issueType ?? null,\n issueKey: data.issueKey ?? null,\n issue_numbers: data.issue_numbers ?? [],\n pr_numbers: data.pr_numbers ?? [],\n issueTracker: data.issueTracker ?? null,\n colorHex: data.colorHex ?? null,\n sessionId: data.sessionId ?? null,\n projectPath: data.projectPath ?? null,\n issueUrls: data.issueUrls ?? {},\n prUrls: data.prUrls ?? {},\n draftPrNumber: data.draftPrNumber ?? null,\n oneShot: data.oneShot ?? null,\n complexity: data.complexity ?? null,\n capabilities: data.capabilities ?? [],\n state: data.state ?? null,\n childIssueNumbers: data.childIssueNumbers ?? [],\n parentLoom: data.parentLoom ?? null,\n childIssues: data.childIssues ?? [],\n dependencyMap: data.dependencyMap ?? {},\n mcpConfigPath: data.mcpConfigPath ?? null,\n swarmTeamName: data.swarmTeamName ?? null,\n }\n }\n\n /**\n * Convert worktree path to filename slug per spec section 2.2\n *\n * Algorithm:\n * 1. Trim trailing slashes\n * 2. Replace all path separators (/ or \\) with __ (double underscore)\n * 3. Replace any other non-alphanumeric characters (except _ and -) with -\n * 4. Append .json\n *\n * Example:\n * - Worktree: /Users/jane/dev/repo\n * - Filename: _Users__jane__dev__repo.json\n */\n slugifyPath(worktreePath: string): string {\n // 1. Trim trailing slashes\n let slug = worktreePath.replace(/[/\\\\]+$/, '')\n\n // 2. Replace path separators with triple underscores\n slug = slug.replace(/[/\\\\]/g, '___')\n\n // 3. Replace non-alphanumeric chars (except _ and -) with hyphens\n slug = slug.replace(/[^a-zA-Z0-9_-]/g, '-')\n\n // 4. Append .json\n return `${slug}.json`\n }\n\n /**\n * Get the full path to the metadata file for a worktree\n */\n private getFilePath(worktreePath: string): string {\n const filename = this.slugifyPath(worktreePath)\n return path.join(this.loomsDir, filename)\n }\n\n /**\n * Get the full path to the metadata file for a worktree (public API)\n * Used by other services that need to reference the metadata file location\n * (e.g., MCP servers that need to read loom context)\n */\n getMetadataFilePath(worktreePath: string): string {\n return this.getFilePath(worktreePath)\n }\n\n /**\n * Write metadata for a worktree (spec section 3.1)\n *\n * @param worktreePath - Absolute path to the worktree (used for file naming)\n * @param input - Metadata to write (description plus additional fields)\n */\n async writeMetadata(worktreePath: string, input: WriteMetadataInput): Promise<void> {\n try {\n // 1. Ensure looms directory exists\n await fs.ensureDir(this.loomsDir, { mode: 0o755 })\n\n // 2. Create JSON content\n const content: MetadataFile = {\n description: input.description,\n created_at: new Date().toISOString(),\n version: 1,\n branchName: input.branchName,\n worktreePath: input.worktreePath,\n issueType: input.issueType,\n ...(input.issueKey && { issueKey: input.issueKey }),\n issue_numbers: input.issue_numbers,\n pr_numbers: input.pr_numbers,\n issueTracker: input.issueTracker,\n colorHex: input.colorHex,\n sessionId: input.sessionId,\n projectPath: input.projectPath,\n issueUrls: input.issueUrls,\n prUrls: input.prUrls,\n capabilities: input.capabilities,\n ...(input.draftPrNumber && { draftPrNumber: input.draftPrNumber }),\n ...(input.oneShot && { oneShot: input.oneShot }),\n ...(input.complexity && { complexity: input.complexity }),\n ...(input.state && { state: input.state }),\n ...(input.childIssueNumbers && input.childIssueNumbers.length > 0 && { childIssueNumbers: input.childIssueNumbers }),\n ...(input.parentLoom && { parentLoom: input.parentLoom }),\n ...(input.childIssues && input.childIssues.length > 0 && { childIssues: input.childIssues }),\n ...(input.dependencyMap && Object.keys(input.dependencyMap).length > 0 && { dependencyMap: input.dependencyMap }),\n ...(input.mcpConfigPath && { mcpConfigPath: input.mcpConfigPath }),\n }\n\n // 3. Write to slugified filename\n const filePath = this.getFilePath(worktreePath)\n await fs.writeFile(filePath, JSON.stringify(content, null, 2), { mode: 0o644 })\n\n getLogger().debug(`Metadata written for worktree: ${worktreePath}`)\n } catch (error) {\n // Log warning but don't throw - metadata is supplementary\n getLogger().warn(\n `Failed to write metadata for worktree: ${error instanceof Error ? error.message : String(error)}`\n )\n }\n }\n\n /**\n * Read metadata for a worktree (spec section 3.2)\n *\n * @param worktreePath - Absolute path to the worktree\n * @returns The metadata object with all fields, or null if not found/invalid\n */\n async readMetadata(worktreePath: string): Promise<LoomMetadata | null> {\n try {\n const filePath = this.getFilePath(worktreePath)\n\n // Check if file exists\n if (!(await fs.pathExists(filePath))) {\n return null\n }\n\n // Read and parse JSON\n const content = await fs.readFile(filePath, 'utf8')\n const data: MetadataFile = JSON.parse(content)\n\n if (!data.description) {\n return null\n }\n\n return this.toMetadata(data)\n } catch (error) {\n // Return null on any error (graceful degradation per spec)\n getLogger().debug(\n `Could not read metadata for worktree ${worktreePath}: ${error instanceof Error ? error.message : String(error)}`\n )\n return null\n }\n }\n\n /**\n * List all stored loom metadata files\n *\n * Returns an array of LoomMetadata objects for all valid metadata files\n * in the looms directory. Invalid or unreadable files are skipped.\n *\n * @returns Array of LoomMetadata objects from all stored files\n */\n async listAllMetadata(): Promise<LoomMetadata[]> {\n const results: LoomMetadata[] = []\n\n try {\n // Check if looms directory exists\n if (!(await fs.pathExists(this.loomsDir))) {\n return results\n }\n\n // Read all files in looms directory\n const files = await fs.readdir(this.loomsDir)\n\n // Filter to only .json files and read each\n for (const file of files) {\n if (!file.endsWith('.json')) {\n continue\n }\n\n try {\n const filePath = path.join(this.loomsDir, file)\n const content = await fs.readFile(filePath, 'utf8')\n const data: MetadataFile = JSON.parse(content)\n\n // Skip files without required description field\n if (!data.description) {\n continue\n }\n\n results.push(this.toMetadata(data))\n } catch (error) {\n // Skip individual files that fail to parse (graceful degradation)\n getLogger().debug(\n `Skipping metadata file ${file}: ${error instanceof Error ? error.message : String(error)}`\n )\n }\n }\n } catch (error) {\n // Log error but return empty array (graceful degradation)\n getLogger().debug(\n `Could not list metadata files: ${error instanceof Error ? error.message : String(error)}`\n )\n }\n\n return results\n }\n\n /**\n * Update existing metadata for a worktree by merging new fields\n *\n * Reads the existing metadata file, merges the provided updates,\n * and writes back. Only provided fields are overwritten.\n *\n * @param worktreePath - Absolute path to the worktree\n * @param updates - Partial metadata fields to merge\n */\n async updateMetadata(worktreePath: string, updates: Partial<MetadataFile>): Promise<void> {\n try {\n const filePath = this.getFilePath(worktreePath)\n\n // Check if file exists\n if (!(await fs.pathExists(filePath))) {\n getLogger().warn(`No metadata file to update for worktree: ${worktreePath}`)\n return\n }\n\n // Read existing data\n const content = await fs.readFile(filePath, 'utf8')\n const data: MetadataFile = JSON.parse(content)\n\n // Merge updates\n const merged = { ...data, ...updates }\n\n // Write back\n await fs.writeFile(filePath, JSON.stringify(merged, null, 2), { mode: 0o644 })\n\n getLogger().debug(`Metadata updated for worktree: ${worktreePath}`)\n } catch (error) {\n getLogger().warn(\n `Failed to update metadata for worktree: ${error instanceof Error ? error.message : String(error)}`\n )\n throw error\n }\n }\n\n /**\n * Delete metadata for a worktree (spec section 3.3)\n *\n * Idempotent: silently succeeds if file doesn't exist\n * Non-fatal: logs warning on permission errors but doesn't throw\n *\n * @param worktreePath - Absolute path to the worktree\n */\n async deleteMetadata(worktreePath: string): Promise<void> {\n try {\n const filePath = this.getFilePath(worktreePath)\n\n // Check if file exists - silently return if not\n if (!(await fs.pathExists(filePath))) {\n getLogger().debug(`No metadata file to delete for worktree: ${worktreePath}`)\n return\n }\n\n // Delete the file\n await fs.unlink(filePath)\n getLogger().debug(`Metadata deleted for worktree: ${worktreePath}`)\n } catch (error) {\n // Log warning on permission error but don't throw (per spec section 3.3)\n getLogger().warn(\n `Failed to delete metadata for worktree: ${error instanceof Error ? error.message : String(error)}`\n )\n }\n }\n\n /**\n * Archive metadata for a finished worktree\n *\n * Moves the metadata file to the finished/ subdirectory and adds\n * status: 'finished' and finishedAt timestamp fields.\n *\n * Idempotent: silently succeeds if source file doesn't exist\n * Non-fatal: logs warning on errors but doesn't throw\n *\n * @param worktreePath - Absolute path to the worktree\n */\n async archiveMetadata(worktreePath: string): Promise<void> {\n try {\n const filename = this.slugifyPath(worktreePath)\n const sourcePath = path.join(this.loomsDir, filename)\n\n // Check if source file exists - silently return if not (idempotent)\n if (!(await fs.pathExists(sourcePath))) {\n getLogger().debug(`No metadata file to archive for worktree: ${worktreePath}`)\n return\n }\n\n // Read existing metadata\n const content = await fs.readFile(sourcePath, 'utf8')\n const data: MetadataFile = JSON.parse(content)\n\n // Add finished status and timestamp\n const finishedData = {\n ...data,\n status: 'finished' as const,\n finishedAt: new Date().toISOString(),\n }\n\n // Ensure finished directory exists\n await fs.ensureDir(this.finishedDir, { mode: 0o755 })\n\n // Write to finished subdirectory\n const destPath = path.join(this.finishedDir, filename)\n await fs.writeFile(destPath, JSON.stringify(finishedData, null, 2), { mode: 0o644 })\n\n // Delete original file\n await fs.unlink(sourcePath)\n\n getLogger().debug(`Metadata archived for worktree: ${worktreePath}`)\n } catch (error) {\n // Log warning but don't throw - archiving is supplementary\n getLogger().warn(\n `Failed to archive metadata for worktree: ${error instanceof Error ? error.message : String(error)}`\n )\n }\n }\n\n /**\n * List all finished loom metadata files\n *\n * Returns an array of LoomMetadata objects for all finished looms\n * in the finished/ subdirectory, sorted by finishedAt in descending order\n * (most recently finished first).\n *\n * @returns Array of LoomMetadata objects from finished files, sorted by finishedAt desc\n */\n async listFinishedMetadata(): Promise<LoomMetadata[]> {\n const results: LoomMetadata[] = []\n\n try {\n // Check if finished directory exists\n if (!(await fs.pathExists(this.finishedDir))) {\n return results\n }\n\n // Read all files in finished directory\n const files = await fs.readdir(this.finishedDir)\n\n // Filter to only .json files and read each\n for (const file of files) {\n if (!file.endsWith('.json')) {\n continue\n }\n\n try {\n const filePath = path.join(this.finishedDir, file)\n const content = await fs.readFile(filePath, 'utf8')\n const data = JSON.parse(content) as MetadataFile & { status?: string; finishedAt?: string }\n\n // Skip files without required description field\n if (!data.description) {\n continue\n }\n\n const metadata = this.toMetadata(data)\n // Add finished-specific fields\n metadata.status = (data.status as 'active' | 'finished') ?? 'finished'\n metadata.finishedAt = data.finishedAt ?? null\n\n results.push(metadata)\n } catch (error) {\n // Skip individual files that fail to parse (graceful degradation)\n getLogger().warn(\n `Skipping finished metadata file ${file}: ${error instanceof Error ? error.message : String(error)}`\n )\n }\n }\n\n // Sort by finishedAt descending (most recently finished first)\n results.sort((a, b) => {\n const aTime = a.finishedAt ? new Date(a.finishedAt).getTime() : 0\n const bTime = b.finishedAt ? new Date(b.finishedAt).getTime() : 0\n return bTime - aTime\n })\n } catch (error) {\n // Log error but return empty array (graceful degradation)\n getLogger().warn(\n `Could not list finished metadata files: ${error instanceof Error ? error.message : String(error)}`\n )\n }\n\n return results\n }\n}\n"],"mappings":"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","names":[]}