opkg 0.9.2 → 0.9.4

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 (404) hide show
  1. package/.claude/agents/code-reviewer.md +171 -0
  2. package/.claude/commands/commit-push-pr.md +20 -0
  3. package/.claude/commands/{specs/read.md → read-specs.md} +1 -1
  4. package/.claude/commands/{specs/update.md → update-specs.md} +4 -0
  5. package/.claude/skills/code-review-excellence/SKILL.md +538 -0
  6. package/README.md +2 -2
  7. package/package.json +3 -1
  8. package/packages/cli/dist/add-IJAPFHIX.js +624 -0
  9. package/packages/cli/dist/add-IJAPFHIX.js.map +7 -0
  10. package/packages/cli/dist/add-LLUNFLJI.js +624 -0
  11. package/packages/cli/dist/add-LLUNFLJI.js.map +7 -0
  12. package/packages/cli/dist/add-U44SL3OR.js +624 -0
  13. package/packages/cli/dist/add-U44SL3OR.js.map +7 -0
  14. package/packages/cli/dist/chunk-23VBP5L6.js +371 -0
  15. package/packages/cli/dist/chunk-23VBP5L6.js.map +7 -0
  16. package/packages/cli/dist/chunk-2SVHLF5C.js +1419 -0
  17. package/packages/cli/dist/chunk-2SVHLF5C.js.map +7 -0
  18. package/packages/cli/dist/chunk-37256POU.js +99 -0
  19. package/packages/cli/dist/chunk-37256POU.js.map +7 -0
  20. package/packages/cli/dist/chunk-3PZRVA6O.js +196 -0
  21. package/packages/cli/dist/chunk-3PZRVA6O.js.map +7 -0
  22. package/packages/cli/dist/chunk-427DCURL.js +155 -0
  23. package/packages/cli/dist/chunk-427DCURL.js.map +7 -0
  24. package/packages/cli/dist/chunk-4B5HJLP2.js +48 -0
  25. package/packages/cli/dist/chunk-4B5HJLP2.js.map +7 -0
  26. package/packages/cli/dist/chunk-4OWT3YEG.js +413 -0
  27. package/packages/cli/dist/chunk-4OWT3YEG.js.map +7 -0
  28. package/packages/cli/dist/chunk-4RIBTBXI.js +568 -0
  29. package/packages/cli/dist/chunk-4RIBTBXI.js.map +7 -0
  30. package/packages/cli/dist/chunk-4X2EJHJN.js +63 -0
  31. package/packages/cli/dist/chunk-4X2EJHJN.js.map +7 -0
  32. package/packages/cli/dist/chunk-6CYW66HD.js +1136 -0
  33. package/packages/cli/dist/chunk-6CYW66HD.js.map +7 -0
  34. package/packages/cli/dist/chunk-6DITYAFA.js +172 -0
  35. package/packages/cli/dist/chunk-6DITYAFA.js.map +7 -0
  36. package/packages/cli/dist/chunk-7KEAKEVZ.js +568 -0
  37. package/packages/cli/dist/chunk-7KEAKEVZ.js.map +7 -0
  38. package/packages/cli/dist/chunk-ABFUD25D.js +61 -0
  39. package/packages/cli/dist/chunk-ABFUD25D.js.map +7 -0
  40. package/packages/cli/dist/chunk-AR7GJCG6.js +274 -0
  41. package/packages/cli/dist/chunk-AR7GJCG6.js.map +7 -0
  42. package/packages/cli/dist/chunk-AYTGQCXH.js +86 -0
  43. package/packages/cli/dist/chunk-AYTGQCXH.js.map +7 -0
  44. package/packages/cli/dist/chunk-BROJ6OUT.js +631 -0
  45. package/packages/cli/dist/chunk-BROJ6OUT.js.map +7 -0
  46. package/packages/cli/dist/chunk-BVVSU7QD.js +23 -0
  47. package/packages/cli/dist/chunk-BVVSU7QD.js.map +7 -0
  48. package/packages/cli/dist/chunk-C6FY55UP.js +108 -0
  49. package/packages/cli/dist/chunk-C6FY55UP.js.map +7 -0
  50. package/packages/cli/dist/chunk-CVA64SXK.js +1136 -0
  51. package/packages/cli/dist/chunk-CVA64SXK.js.map +7 -0
  52. package/packages/cli/dist/chunk-D3O7LY2Q.js +1151 -0
  53. package/packages/cli/dist/chunk-D3O7LY2Q.js.map +7 -0
  54. package/packages/cli/dist/chunk-D6LEPODL.js +413 -0
  55. package/packages/cli/dist/chunk-D6LEPODL.js.map +7 -0
  56. package/packages/cli/dist/chunk-DEC24S7E.js +186 -0
  57. package/packages/cli/dist/chunk-DEC24S7E.js.map +7 -0
  58. package/packages/cli/dist/chunk-FMVVJH5M.js +371 -0
  59. package/packages/cli/dist/chunk-FMVVJH5M.js.map +7 -0
  60. package/packages/cli/dist/chunk-GDVFS3YP.js +130 -0
  61. package/packages/cli/dist/chunk-GDVFS3YP.js.map +7 -0
  62. package/packages/cli/dist/chunk-GEP2G5HF.js +31 -0
  63. package/packages/cli/dist/chunk-GEP2G5HF.js.map +7 -0
  64. package/packages/cli/dist/chunk-GSWHZBT2.js +62 -0
  65. package/packages/cli/dist/chunk-GSWHZBT2.js.map +7 -0
  66. package/packages/cli/dist/chunk-HTYHJA3B.js +61 -0
  67. package/packages/cli/dist/chunk-HTYHJA3B.js.map +7 -0
  68. package/packages/cli/dist/chunk-HYKYECAE.js +222 -0
  69. package/packages/cli/dist/chunk-HYKYECAE.js.map +7 -0
  70. package/packages/cli/dist/chunk-I7FEAHB4.js +100 -0
  71. package/packages/cli/dist/chunk-I7FEAHB4.js.map +7 -0
  72. package/packages/cli/dist/chunk-IHVZ5AUJ.js +107 -0
  73. package/packages/cli/dist/chunk-IHVZ5AUJ.js.map +7 -0
  74. package/packages/cli/dist/chunk-KI7FDU3H.js +99 -0
  75. package/packages/cli/dist/chunk-KI7FDU3H.js.map +7 -0
  76. package/packages/cli/dist/chunk-L5GRJQBS.js +32 -0
  77. package/packages/cli/dist/chunk-L5GRJQBS.js.map +7 -0
  78. package/packages/cli/dist/chunk-LHEAUDJL.js +302 -0
  79. package/packages/cli/dist/chunk-LHEAUDJL.js.map +7 -0
  80. package/packages/cli/dist/chunk-MIURCESJ.js +48 -0
  81. package/packages/cli/dist/chunk-MIURCESJ.js.map +7 -0
  82. package/packages/cli/dist/chunk-N43IXOND.js +732 -0
  83. package/packages/cli/dist/chunk-N43IXOND.js.map +7 -0
  84. package/packages/cli/dist/chunk-OUZRMGPV.js +274 -0
  85. package/packages/cli/dist/chunk-OUZRMGPV.js.map +7 -0
  86. package/packages/cli/dist/chunk-PSQXKAL4.js +371 -0
  87. package/packages/cli/dist/chunk-PSQXKAL4.js.map +7 -0
  88. package/packages/cli/dist/chunk-PUDRKDVZ.js +1419 -0
  89. package/packages/cli/dist/chunk-PUDRKDVZ.js.map +7 -0
  90. package/packages/cli/dist/chunk-RAKMX654.js +631 -0
  91. package/packages/cli/dist/chunk-RAKMX654.js.map +7 -0
  92. package/packages/cli/dist/chunk-RSFLK2TP.js +195 -0
  93. package/packages/cli/dist/chunk-RSFLK2TP.js.map +7 -0
  94. package/packages/cli/dist/chunk-S26PR2BS.js +99 -0
  95. package/packages/cli/dist/chunk-S26PR2BS.js.map +7 -0
  96. package/packages/cli/dist/chunk-U7FW7SXX.js +568 -0
  97. package/packages/cli/dist/chunk-U7FW7SXX.js.map +7 -0
  98. package/packages/cli/dist/chunk-VKM6K5TN.js +413 -0
  99. package/packages/cli/dist/chunk-VKM6K5TN.js.map +7 -0
  100. package/packages/cli/dist/chunk-VKNJG4JN.js +253 -0
  101. package/packages/cli/dist/chunk-VKNJG4JN.js.map +7 -0
  102. package/packages/cli/dist/chunk-VQ2KY6CK.js +113 -0
  103. package/packages/cli/dist/chunk-VQ2KY6CK.js.map +7 -0
  104. package/packages/cli/dist/chunk-VQDTXLOX.js +1312 -0
  105. package/packages/cli/dist/chunk-VQDTXLOX.js.map +7 -0
  106. package/packages/cli/dist/chunk-VXNS3X5O.js +60 -0
  107. package/packages/cli/dist/chunk-VXNS3X5O.js.map +7 -0
  108. package/packages/cli/dist/chunk-WF7H2YDU.js +376 -0
  109. package/packages/cli/dist/chunk-WF7H2YDU.js.map +7 -0
  110. package/packages/cli/dist/chunk-WNRXZLWW.js +266 -0
  111. package/packages/cli/dist/chunk-WNRXZLWW.js.map +7 -0
  112. package/packages/cli/dist/chunk-WT4VVCXM.js +1121 -0
  113. package/packages/cli/dist/chunk-WT4VVCXM.js.map +7 -0
  114. package/packages/cli/dist/configure-3AZUMDJZ.js +107 -0
  115. package/packages/cli/dist/configure-3AZUMDJZ.js.map +7 -0
  116. package/packages/cli/dist/configure-D722JQOD.js +107 -0
  117. package/packages/cli/dist/configure-D722JQOD.js.map +7 -0
  118. package/packages/cli/dist/configure-IU5H7XD6.js +107 -0
  119. package/packages/cli/dist/configure-IU5H7XD6.js.map +7 -0
  120. package/packages/cli/dist/file-format-detector-PXCIAKTK.js +22 -0
  121. package/packages/cli/dist/file-format-detector-PXCIAKTK.js.map +7 -0
  122. package/packages/cli/dist/index.js +17 -17
  123. package/packages/cli/dist/install-EZNWMLJR.js +7581 -0
  124. package/packages/cli/dist/install-EZNWMLJR.js.map +7 -0
  125. package/packages/cli/dist/install-F5ANFUBX.js +7577 -0
  126. package/packages/cli/dist/install-F5ANFUBX.js.map +7 -0
  127. package/packages/cli/dist/install-JSXEPPC2.js +7104 -0
  128. package/packages/cli/dist/install-JSXEPPC2.js.map +7 -0
  129. package/packages/cli/dist/install-QHEBX7JH.js +7101 -0
  130. package/packages/cli/dist/install-QHEBX7JH.js.map +7 -0
  131. package/packages/cli/dist/list-DMOUATYI.js +327 -0
  132. package/packages/cli/dist/list-DMOUATYI.js.map +7 -0
  133. package/packages/cli/dist/list-UESSCB7Y.js +327 -0
  134. package/packages/cli/dist/list-UESSCB7Y.js.map +7 -0
  135. package/packages/cli/dist/list-XR7RSJFS.js +327 -0
  136. package/packages/cli/dist/list-XR7RSJFS.js.map +7 -0
  137. package/packages/cli/dist/login-EYZ2SOYZ.js +150 -0
  138. package/packages/cli/dist/login-EYZ2SOYZ.js.map +7 -0
  139. package/packages/cli/dist/login-JWCSTAEU.js +150 -0
  140. package/packages/cli/dist/login-JWCSTAEU.js.map +7 -0
  141. package/packages/cli/dist/login-NRKHXZKM.js +150 -0
  142. package/packages/cli/dist/login-NRKHXZKM.js.map +7 -0
  143. package/packages/cli/dist/logout-HDMYRXIE.js +40 -0
  144. package/packages/cli/dist/logout-HDMYRXIE.js.map +7 -0
  145. package/packages/cli/dist/logout-SYHXCVCQ.js +40 -0
  146. package/packages/cli/dist/logout-SYHXCVCQ.js.map +7 -0
  147. package/packages/cli/dist/logout-X3XUUOH5.js +40 -0
  148. package/packages/cli/dist/logout-X3XUUOH5.js.map +7 -0
  149. package/packages/cli/dist/new-3LTFKDTQ.js +277 -0
  150. package/packages/cli/dist/new-3LTFKDTQ.js.map +7 -0
  151. package/packages/cli/dist/new-F46OSD72.js +277 -0
  152. package/packages/cli/dist/new-F46OSD72.js.map +7 -0
  153. package/packages/cli/dist/new-OPCCLNL2.js +277 -0
  154. package/packages/cli/dist/new-OPCCLNL2.js.map +7 -0
  155. package/packages/cli/dist/package-marker-detector-T5O5YD2E.js +80 -0
  156. package/packages/cli/dist/package-marker-detector-T5O5YD2E.js.map +7 -0
  157. package/packages/cli/dist/package-yml-QWZIJDYU.js +16 -0
  158. package/packages/cli/dist/package-yml-QWZIJDYU.js.map +7 -0
  159. package/packages/cli/dist/plugin-naming-YP2I4NPA.js +29 -0
  160. package/packages/cli/dist/plugin-naming-YP2I4NPA.js.map +7 -0
  161. package/packages/cli/dist/publish-4H43PCSG.js +619 -0
  162. package/packages/cli/dist/publish-4H43PCSG.js.map +7 -0
  163. package/packages/cli/dist/publish-RULKLNUX.js +619 -0
  164. package/packages/cli/dist/publish-RULKLNUX.js.map +7 -0
  165. package/packages/cli/dist/publish-URWY2P3E.js +619 -0
  166. package/packages/cli/dist/publish-URWY2P3E.js.map +7 -0
  167. package/packages/cli/dist/remove-BD52BHR2.js +542 -0
  168. package/packages/cli/dist/remove-BD52BHR2.js.map +7 -0
  169. package/packages/cli/dist/remove-G5NRC7LD.js +542 -0
  170. package/packages/cli/dist/remove-G5NRC7LD.js.map +7 -0
  171. package/packages/cli/dist/remove-TC3FQUYQ.js +542 -0
  172. package/packages/cli/dist/remove-TC3FQUYQ.js.map +7 -0
  173. package/packages/cli/dist/resource-discoverer-4X4RY43E.js +17 -0
  174. package/packages/cli/dist/resource-discoverer-4X4RY43E.js.map +7 -0
  175. package/packages/cli/dist/save-24TESYKI.js +1728 -0
  176. package/packages/cli/dist/save-24TESYKI.js.map +7 -0
  177. package/packages/cli/dist/save-N3QWF2WN.js +1728 -0
  178. package/packages/cli/dist/save-N3QWF2WN.js.map +7 -0
  179. package/packages/cli/dist/save-P2U67DTV.js +1728 -0
  180. package/packages/cli/dist/save-P2U67DTV.js.map +7 -0
  181. package/packages/cli/dist/search-ABROK3UO.js +157 -0
  182. package/packages/cli/dist/search-ABROK3UO.js.map +7 -0
  183. package/packages/cli/dist/search-WVFXFNAV.js +157 -0
  184. package/packages/cli/dist/search-WVFXFNAV.js.map +7 -0
  185. package/packages/cli/dist/search-YQN2Q2SO.js +157 -0
  186. package/packages/cli/dist/search-YQN2Q2SO.js.map +7 -0
  187. package/packages/cli/dist/set-DCWF73F6.js +251 -0
  188. package/packages/cli/dist/set-DCWF73F6.js.map +7 -0
  189. package/packages/cli/dist/set-GJEG2F6Y.js +251 -0
  190. package/packages/cli/dist/set-GJEG2F6Y.js.map +7 -0
  191. package/packages/cli/dist/set-NGM2FIKF.js +251 -0
  192. package/packages/cli/dist/set-NGM2FIKF.js.map +7 -0
  193. package/packages/cli/dist/uninstall-3CJQMTYH.js +539 -0
  194. package/packages/cli/dist/uninstall-3CJQMTYH.js.map +7 -0
  195. package/packages/cli/dist/uninstall-Q3CP4UN5.js +539 -0
  196. package/packages/cli/dist/uninstall-Q3CP4UN5.js.map +7 -0
  197. package/packages/cli/dist/uninstall-QU5OMEEC.js +539 -0
  198. package/packages/cli/dist/uninstall-QU5OMEEC.js.map +7 -0
  199. package/packages/cli/dist/unpublish-GHJQYC4S.js +245 -0
  200. package/packages/cli/dist/unpublish-GHJQYC4S.js.map +7 -0
  201. package/packages/cli/dist/unpublish-L2CYMK4B.js +245 -0
  202. package/packages/cli/dist/unpublish-L2CYMK4B.js.map +7 -0
  203. package/packages/cli/dist/unpublish-VBTNTMS5.js +245 -0
  204. package/packages/cli/dist/unpublish-VBTNTMS5.js.map +7 -0
  205. package/packages/cli/dist/view-MXRBMXOG.js +488 -0
  206. package/packages/cli/dist/view-MXRBMXOG.js.map +7 -0
  207. package/packages/cli/dist/view-NMND7SAW.js +488 -0
  208. package/packages/cli/dist/view-NMND7SAW.js.map +7 -0
  209. package/packages/cli/dist/view-RPQRDSYB.js +488 -0
  210. package/packages/cli/dist/view-RPQRDSYB.js.map +7 -0
  211. package/packages/cli/package.json +2 -0
  212. package/packages/core/dist/constants/index.d.ts +9 -0
  213. package/packages/core/dist/constants/index.d.ts.map +1 -1
  214. package/packages/core/dist/constants/index.js +12 -0
  215. package/packages/core/dist/constants/index.js.map +1 -1
  216. package/packages/core/dist/core/dependency-resolver/index.d.ts +2 -10
  217. package/packages/core/dist/core/dependency-resolver/index.d.ts.map +1 -1
  218. package/packages/core/dist/core/dependency-resolver/index.js +3 -14
  219. package/packages/core/dist/core/dependency-resolver/index.js.map +1 -1
  220. package/packages/core/dist/core/install/base-detector.d.ts +2 -1
  221. package/packages/core/dist/core/install/base-detector.d.ts.map +1 -1
  222. package/packages/core/dist/core/install/base-detector.js +54 -1
  223. package/packages/core/dist/core/install/base-detector.js.map +1 -1
  224. package/packages/core/dist/core/install/conflicts/file-conflict-resolver.d.ts +7 -5
  225. package/packages/core/dist/core/install/conflicts/file-conflict-resolver.d.ts.map +1 -1
  226. package/packages/core/dist/core/install/conflicts/file-conflict-resolver.js +25 -9
  227. package/packages/core/dist/core/install/conflicts/file-conflict-resolver.js.map +1 -1
  228. package/packages/core/dist/core/install/flow-index-installer.d.ts +2 -1
  229. package/packages/core/dist/core/install/flow-index-installer.d.ts.map +1 -1
  230. package/packages/core/dist/core/install/flow-index-installer.js +19 -4
  231. package/packages/core/dist/core/install/flow-index-installer.js.map +1 -1
  232. package/packages/core/dist/core/install/input-classifier-base.js +3 -3
  233. package/packages/core/dist/core/install/input-classifier-base.js.map +1 -1
  234. package/packages/core/dist/core/install/install-reporting.d.ts.map +1 -1
  235. package/packages/core/dist/core/install/install-reporting.js +7 -9
  236. package/packages/core/dist/core/install/install-reporting.js.map +1 -1
  237. package/packages/core/dist/core/install/list-handler.d.ts.map +1 -1
  238. package/packages/core/dist/core/install/list-handler.js +3 -0
  239. package/packages/core/dist/core/install/list-handler.js.map +1 -1
  240. package/packages/core/dist/core/install/marketplace-handler.d.ts.map +1 -1
  241. package/packages/core/dist/core/install/marketplace-handler.js.map +1 -1
  242. package/packages/core/dist/core/install/operations/conflict-handler.d.ts +2 -1
  243. package/packages/core/dist/core/install/operations/conflict-handler.d.ts.map +1 -1
  244. package/packages/core/dist/core/install/operations/conflict-handler.js +2 -2
  245. package/packages/core/dist/core/install/operations/conflict-handler.js.map +1 -1
  246. package/packages/core/dist/core/install/operations/installation-executor.d.ts +3 -0
  247. package/packages/core/dist/core/install/operations/installation-executor.d.ts.map +1 -1
  248. package/packages/core/dist/core/install/operations/installation-executor.js +39 -22
  249. package/packages/core/dist/core/install/operations/installation-executor.js.map +1 -1
  250. package/packages/core/dist/core/install/orchestrator/orchestrator.d.ts +7 -3
  251. package/packages/core/dist/core/install/orchestrator/orchestrator.d.ts.map +1 -1
  252. package/packages/core/dist/core/install/orchestrator/orchestrator.js +193 -93
  253. package/packages/core/dist/core/install/orchestrator/orchestrator.js.map +1 -1
  254. package/packages/core/dist/core/install/orchestrator/strategies/git-strategy.d.ts +1 -0
  255. package/packages/core/dist/core/install/orchestrator/strategies/git-strategy.d.ts.map +1 -1
  256. package/packages/core/dist/core/install/orchestrator/strategies/git-strategy.js +11 -24
  257. package/packages/core/dist/core/install/orchestrator/strategies/git-strategy.js.map +1 -1
  258. package/packages/core/dist/core/install/orchestrator/strategies/path-strategy.d.ts +2 -0
  259. package/packages/core/dist/core/install/orchestrator/strategies/path-strategy.d.ts.map +1 -1
  260. package/packages/core/dist/core/install/orchestrator/strategies/path-strategy.js +14 -14
  261. package/packages/core/dist/core/install/orchestrator/strategies/path-strategy.js.map +1 -1
  262. package/packages/core/dist/core/install/orchestrator/strategies/registry-strategy.d.ts +7 -0
  263. package/packages/core/dist/core/install/orchestrator/strategies/registry-strategy.d.ts.map +1 -1
  264. package/packages/core/dist/core/install/orchestrator/strategies/registry-strategy.js +28 -0
  265. package/packages/core/dist/core/install/orchestrator/strategies/registry-strategy.js.map +1 -1
  266. package/packages/core/dist/core/install/orchestrator/types.d.ts +2 -0
  267. package/packages/core/dist/core/install/orchestrator/types.d.ts.map +1 -1
  268. package/packages/core/dist/core/install/path-package-loader.d.ts.map +1 -1
  269. package/packages/core/dist/core/install/path-package-loader.js +20 -1
  270. package/packages/core/dist/core/install/path-package-loader.js.map +1 -1
  271. package/packages/core/dist/core/install/platform-resolution.d.ts +3 -0
  272. package/packages/core/dist/core/install/platform-resolution.d.ts.map +1 -1
  273. package/packages/core/dist/core/install/platform-resolution.js +5 -2
  274. package/packages/core/dist/core/install/platform-resolution.js.map +1 -1
  275. package/packages/core/dist/core/install/preprocessing/context-population.d.ts +18 -0
  276. package/packages/core/dist/core/install/preprocessing/context-population.d.ts.map +1 -0
  277. package/packages/core/dist/core/install/preprocessing/context-population.js +36 -0
  278. package/packages/core/dist/core/install/preprocessing/context-population.js.map +1 -0
  279. package/packages/core/dist/core/install/preprocessing/convenience-preprocessor.d.ts +23 -0
  280. package/packages/core/dist/core/install/preprocessing/convenience-preprocessor.d.ts.map +1 -1
  281. package/packages/core/dist/core/install/preprocessing/convenience-preprocessor.js +44 -0
  282. package/packages/core/dist/core/install/preprocessing/convenience-preprocessor.js.map +1 -1
  283. package/packages/core/dist/core/install/sources/git-source.d.ts.map +1 -1
  284. package/packages/core/dist/core/install/sources/git-source.js +67 -4
  285. package/packages/core/dist/core/install/sources/git-source.js.map +1 -1
  286. package/packages/core/dist/core/install/sources/path-source.d.ts.map +1 -1
  287. package/packages/core/dist/core/install/sources/path-source.js +8 -0
  288. package/packages/core/dist/core/install/sources/path-source.js.map +1 -1
  289. package/packages/core/dist/core/install/strategies/flow-based-strategy.d.ts.map +1 -1
  290. package/packages/core/dist/core/install/strategies/flow-based-strategy.js +12 -5
  291. package/packages/core/dist/core/install/strategies/flow-based-strategy.js.map +1 -1
  292. package/packages/core/dist/core/install/strategies/types.d.ts +11 -1
  293. package/packages/core/dist/core/install/strategies/types.d.ts.map +1 -1
  294. package/packages/core/dist/core/install/unified/context-builders.d.ts +5 -0
  295. package/packages/core/dist/core/install/unified/context-builders.d.ts.map +1 -1
  296. package/packages/core/dist/core/install/unified/context-builders.js +12 -0
  297. package/packages/core/dist/core/install/unified/context-builders.js.map +1 -1
  298. package/packages/core/dist/core/install/unified/context-helpers.d.ts +0 -4
  299. package/packages/core/dist/core/install/unified/context-helpers.d.ts.map +1 -1
  300. package/packages/core/dist/core/install/unified/context-helpers.js +0 -24
  301. package/packages/core/dist/core/install/unified/context-helpers.js.map +1 -1
  302. package/packages/core/dist/core/install/unified/index.d.ts +1 -1
  303. package/packages/core/dist/core/install/unified/index.d.ts.map +1 -1
  304. package/packages/core/dist/core/install/unified/index.js +1 -1
  305. package/packages/core/dist/core/install/unified/index.js.map +1 -1
  306. package/packages/core/dist/core/install/unified/multi-context-pipeline.d.ts +6 -0
  307. package/packages/core/dist/core/install/unified/multi-context-pipeline.d.ts.map +1 -1
  308. package/packages/core/dist/core/install/unified/multi-context-pipeline.js +11 -4
  309. package/packages/core/dist/core/install/unified/multi-context-pipeline.js.map +1 -1
  310. package/packages/core/dist/core/install/unified/phases/conflicts.d.ts.map +1 -1
  311. package/packages/core/dist/core/install/unified/phases/conflicts.js +1 -1
  312. package/packages/core/dist/core/install/unified/phases/conflicts.js.map +1 -1
  313. package/packages/core/dist/core/install/unified/phases/execute.d.ts.map +1 -1
  314. package/packages/core/dist/core/install/unified/phases/execute.js +5 -5
  315. package/packages/core/dist/core/install/unified/phases/execute.js.map +1 -1
  316. package/packages/core/dist/core/install/unified/phases/load-package.js +3 -3
  317. package/packages/core/dist/core/install/unified/phases/load-package.js.map +1 -1
  318. package/packages/core/dist/core/install/unified/phases/report.js +1 -1
  319. package/packages/core/dist/core/install/unified/phases/report.js.map +1 -1
  320. package/packages/core/dist/core/install/unified/pipeline.d.ts.map +1 -1
  321. package/packages/core/dist/core/install/unified/pipeline.js +7 -10
  322. package/packages/core/dist/core/install/unified/pipeline.js.map +1 -1
  323. package/packages/core/dist/core/install/wave-resolver/content-root-cache.d.ts +24 -0
  324. package/packages/core/dist/core/install/wave-resolver/content-root-cache.d.ts.map +1 -0
  325. package/packages/core/dist/core/install/wave-resolver/content-root-cache.js +71 -0
  326. package/packages/core/dist/core/install/wave-resolver/content-root-cache.js.map +1 -0
  327. package/packages/core/dist/core/install/wave-resolver/context-builder.d.ts +39 -0
  328. package/packages/core/dist/core/install/wave-resolver/context-builder.d.ts.map +1 -0
  329. package/packages/core/dist/core/install/wave-resolver/context-builder.js +148 -0
  330. package/packages/core/dist/core/install/wave-resolver/context-builder.js.map +1 -0
  331. package/packages/core/dist/core/install/wave-resolver/fetcher.d.ts +49 -0
  332. package/packages/core/dist/core/install/wave-resolver/fetcher.d.ts.map +1 -0
  333. package/packages/core/dist/core/install/wave-resolver/fetcher.js +221 -0
  334. package/packages/core/dist/core/install/wave-resolver/fetcher.js.map +1 -0
  335. package/packages/core/dist/core/install/wave-resolver/index-updater.d.ts +23 -0
  336. package/packages/core/dist/core/install/wave-resolver/index-updater.d.ts.map +1 -0
  337. package/packages/core/dist/core/install/wave-resolver/index-updater.js +87 -0
  338. package/packages/core/dist/core/install/wave-resolver/index-updater.js.map +1 -0
  339. package/packages/core/dist/core/install/wave-resolver/index-write-collector.d.ts +101 -0
  340. package/packages/core/dist/core/install/wave-resolver/index-write-collector.d.ts.map +1 -0
  341. package/packages/core/dist/core/install/wave-resolver/index-write-collector.js +194 -0
  342. package/packages/core/dist/core/install/wave-resolver/index-write-collector.js.map +1 -0
  343. package/packages/core/dist/core/install/wave-resolver/index.d.ts +17 -0
  344. package/packages/core/dist/core/install/wave-resolver/index.d.ts.map +1 -0
  345. package/packages/core/dist/core/install/wave-resolver/index.js +16 -0
  346. package/packages/core/dist/core/install/wave-resolver/index.js.map +1 -0
  347. package/packages/core/dist/core/install/wave-resolver/manifest-reader.d.ts +34 -0
  348. package/packages/core/dist/core/install/wave-resolver/manifest-reader.d.ts.map +1 -0
  349. package/packages/core/dist/core/install/wave-resolver/manifest-reader.js +112 -0
  350. package/packages/core/dist/core/install/wave-resolver/manifest-reader.js.map +1 -0
  351. package/packages/core/dist/core/install/wave-resolver/types.d.ts +210 -0
  352. package/packages/core/dist/core/install/wave-resolver/types.d.ts.map +1 -0
  353. package/packages/core/dist/core/install/wave-resolver/types.js +6 -0
  354. package/packages/core/dist/core/install/wave-resolver/types.js.map +1 -0
  355. package/packages/core/dist/core/install/wave-resolver/version-solver.d.ts +65 -0
  356. package/packages/core/dist/core/install/wave-resolver/version-solver.d.ts.map +1 -0
  357. package/packages/core/dist/core/install/wave-resolver/version-solver.js +166 -0
  358. package/packages/core/dist/core/install/wave-resolver/version-solver.js.map +1 -0
  359. package/packages/core/dist/core/install/wave-resolver/wave-engine.d.ts +16 -0
  360. package/packages/core/dist/core/install/wave-resolver/wave-engine.d.ts.map +1 -0
  361. package/packages/core/dist/core/install/wave-resolver/wave-engine.js +337 -0
  362. package/packages/core/dist/core/install/wave-resolver/wave-engine.js.map +1 -0
  363. package/packages/core/dist/core/install/wave-resolver/wave-installer.d.ts +50 -0
  364. package/packages/core/dist/core/install/wave-resolver/wave-installer.d.ts.map +1 -0
  365. package/packages/core/dist/core/install/wave-resolver/wave-installer.js +246 -0
  366. package/packages/core/dist/core/install/wave-resolver/wave-installer.js.map +1 -0
  367. package/packages/core/dist/core/ports/buffered-output.d.ts +36 -0
  368. package/packages/core/dist/core/ports/buffered-output.d.ts.map +1 -0
  369. package/packages/core/dist/core/ports/buffered-output.js +89 -0
  370. package/packages/core/dist/core/ports/buffered-output.js.map +1 -0
  371. package/packages/core/dist/core/ports/resolve.d.ts +0 -13
  372. package/packages/core/dist/core/ports/resolve.d.ts.map +1 -1
  373. package/packages/core/dist/core/ports/resolve.js +0 -28
  374. package/packages/core/dist/core/ports/resolve.js.map +1 -1
  375. package/packages/core/dist/core/remove/removal-confirmation.d.ts +4 -1
  376. package/packages/core/dist/core/remove/removal-confirmation.d.ts.map +1 -1
  377. package/packages/core/dist/core/remove/removal-confirmation.js +5 -4
  378. package/packages/core/dist/core/remove/removal-confirmation.js.map +1 -1
  379. package/packages/core/dist/core/remove/remove-from-source-pipeline.d.ts.map +1 -1
  380. package/packages/core/dist/core/remove/remove-from-source-pipeline.js +1 -10
  381. package/packages/core/dist/core/remove/remove-from-source-pipeline.js.map +1 -1
  382. package/packages/core/dist/core/uninstall/uninstall-executor.js +1 -1
  383. package/packages/core/dist/core/uninstall/uninstall-executor.js.map +1 -1
  384. package/packages/core/dist/core/uninstall/uninstall-reporter.d.ts +2 -2
  385. package/packages/core/dist/core/uninstall/uninstall-reporter.d.ts.map +1 -1
  386. package/packages/core/dist/core/uninstall/uninstall-reporter.js +4 -4
  387. package/packages/core/dist/core/uninstall/uninstall-reporter.js.map +1 -1
  388. package/packages/core/dist/index.d.ts +1 -1
  389. package/packages/core/dist/index.d.ts.map +1 -1
  390. package/packages/core/dist/types/execution-context.d.ts +40 -10
  391. package/packages/core/dist/types/execution-context.d.ts.map +1 -1
  392. package/packages/core/dist/utils/concurrency-pool.d.ts +34 -0
  393. package/packages/core/dist/utils/concurrency-pool.d.ts.map +1 -0
  394. package/packages/core/dist/utils/concurrency-pool.js +58 -0
  395. package/packages/core/dist/utils/concurrency-pool.js.map +1 -0
  396. package/packages/core/dist/utils/plugin-naming.d.ts +11 -3
  397. package/packages/core/dist/utils/plugin-naming.d.ts.map +1 -1
  398. package/packages/core/dist/utils/plugin-naming.js +27 -7
  399. package/packages/core/dist/utils/plugin-naming.js.map +1 -1
  400. package/plans/wave-resolver.md +254 -0
  401. package/.claude/agents/essentials/code-simplifier.md +0 -52
  402. package/.claude/commands/essentials/cleanup.md +0 -1
  403. package/.claude/commands/essentials/review.md +0 -8
  404. package/.claude/commands/git/commit.md +0 -5
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../core/src/core/platforms.ts", "../../core/src/core/platform/platform-mapper.ts", "../../core/src/core/platform/platform-file.ts", "../../core/src/utils/jsonc.ts", "../../core/src/core/flows/switch-resolver.ts", "../../core/src/utils/path-comparison.ts", "../../core/src/core/universal-patterns.ts"],
4
+ "sourcesContent": ["/**\n * Platform Management Module\n * Centralized platform definitions, directory mappings, and file patterns\n * for all 13 supported AI coding platforms\n * \n * Now supports flow-based configurations for declarative transformations.\n */\n\nimport { join, relative } from \"path\"\nimport { exists, ensureDir } from \"../utils/fs.js\"\nimport { logger } from \"../utils/logger.js\"\nimport { getPathLeaf } from \"../utils/path-normalization.js\"\nimport {\n DIR_PATTERNS,\n FILE_PATTERNS,\n} from \"../constants/index.js\"\nimport { mapPlatformFileToUniversal } from \"./platform/platform-mapper.js\"\nimport { parseUniversalPath } from \"./platform/platform-file.js\"\nimport { readJsoncFileSync, readJsoncOrJson } from \"../utils/jsonc.js\"\nimport * as os from \"os\"\nimport type { Flow, SwitchExpression } from \"../types/flows.js\"\nimport type { GlobalFlowsConfig } from \"../types/platform-flows.js\"\nimport type { Platform, PlatformDefinition, PlatformDetectionResult, PlatformPaths, PlatformDirectoryPaths } from \"../types/platform.js\"\nexport type { Platform, PlatformDefinition, PlatformDetectionResult, PlatformPaths, PlatformDirectoryPaths }\nimport { validateSwitchExpression } from \"./flows/switch-resolver.js\"\nimport { \n matchesAnyPattern, \n extractSubdirectoriesFromPatterns \n} from \"./universal-patterns.js\"\n\n// PlatformDefinition is now imported from ../types/platform.js\n\n// Types for JSONC config structure (array format)\ninterface PlatformConfig {\n name: string\n rootDir?: string // Optional now, use detection instead\n rootFile?: string // Optional now, use detection instead\n detection?: string[] // Array of glob patterns for detection\n export?: Flow[] // Export flows: Package \u2192 Workspace (install, apply)\n import?: Flow[] // Import flows: Workspace \u2192 Package (save)\n aliases?: string[]\n enabled?: boolean\n description?: string\n variables?: Record<string, any>\n}\n\ntype PlatformsConfig = Record<string, PlatformConfig | GlobalFlowsConfig>\n\nexport interface PlatformsState {\n config: PlatformsConfig\n globalExportFlows?: Flow[] // Global export flows applied to all platforms\n globalImportFlows?: Flow[] // Global import flows applied to all platforms\n defs: Record<Platform, PlatformDefinition>\n dirLookup: Record<string, Platform>\n aliasLookup: Record<string, Platform>\n universalPatterns: Set<string> // All 'from' patterns from export flows (source of truth)\n universalSubdirs: Set<string> // Derived from patterns for backward compatibility\n rootFiles: string[]\n allPlatforms: Platform[]\n enabledPlatforms: Platform[]\n}\n\n/**\n * Check if a config entry is a global flows config\n */\nfunction isGlobalFlowsConfig(cfg: PlatformConfig | GlobalFlowsConfig): cfg is GlobalFlowsConfig {\n return ('export' in cfg || 'import' in cfg) && !('name' in cfg) && !('rootDir' in cfg)\n}\n\n/**\n * Create platform definitions from a PlatformsConfig object\n * Export/import flows configuration (no legacy subdirs support)\n * Assumes config is already validated.\n * @param config - The merged platforms configuration\n */\nfunction createPlatformDefinitions(\n config: PlatformsConfig\n): Record<Platform, PlatformDefinition> {\n const result: Record<Platform, PlatformDefinition> = {}\n\n for (const [id, cfg] of Object.entries(config)) {\n // Skip special keys\n if (id === '$schema') continue\n \n // Skip global config entry\n if (id === 'global') continue\n \n // Type guard for platform config\n if (isGlobalFlowsConfig(cfg)) continue\n \n // Now we know cfg is PlatformConfig\n const platformConfig = cfg as PlatformConfig\n const platformId = id as Platform\n\n result[platformId] = {\n id: platformId,\n name: platformConfig.name,\n rootDir: platformConfig.rootDir,\n rootFile: platformConfig.rootFile,\n detection: platformConfig.detection,\n export: platformConfig.export || [],\n import: platformConfig.import || [],\n aliases: platformConfig.aliases,\n enabled: platformConfig.enabled !== false,\n description: platformConfig.description,\n variables: platformConfig.variables,\n }\n }\n\n return result\n}\n\nconst BUILT_IN_CONFIG: PlatformsConfig =\n readJsoncFileSync<PlatformsConfig>(\"platforms.jsonc\")\n\nconst builtinErrors = validatePlatformsConfig(BUILT_IN_CONFIG)\nif (builtinErrors.length > 0) {\n throw new Error(`Built-in platforms.jsonc validation failed:\\n - ${builtinErrors.join('\\n - ')}`)\n}\n\n/**\n * Merge two PlatformsConfig objects, handling per-platform fields and subdirs arrays properly.\n * Adds new platforms from override; merges existing with override preferences.\n */\nexport function mergePlatformsConfig(base: PlatformsConfig, override: PlatformsConfig): PlatformsConfig {\n const merged: PlatformsConfig = { ...base }\n\n for (const [platformId, overridePlat] of Object.entries(override)) {\n // Skip special keys\n if (platformId === '$schema') {\n merged[platformId] = overridePlat\n continue\n }\n\n const basePlat = base[platformId]\n if (!basePlat) {\n merged[platformId] = overridePlat\n continue\n }\n\n // Handle global config separately\n if (platformId === 'global') {\n if (isGlobalFlowsConfig(overridePlat)) {\n merged[platformId] = overridePlat // Replace global config entirely\n }\n continue\n }\n\n // Type guard for platform config\n if (isGlobalFlowsConfig(overridePlat) || isGlobalFlowsConfig(basePlat)) {\n merged[platformId] = overridePlat\n continue\n }\n\n // Now we know both are PlatformConfig\n const overrideCfg = overridePlat as PlatformConfig\n const baseCfg = basePlat as PlatformConfig\n\n merged[platformId] = {\n name: overrideCfg.name ?? baseCfg.name,\n rootDir: overrideCfg.rootDir ?? baseCfg.rootDir,\n rootFile: overrideCfg.rootFile ?? baseCfg.rootFile,\n detection: overrideCfg.detection ?? baseCfg.detection, // replace array\n aliases: overrideCfg.aliases ?? baseCfg.aliases, // replace array\n enabled: overrideCfg.enabled ?? baseCfg.enabled,\n description: overrideCfg.description ?? baseCfg.description,\n variables: overrideCfg.variables ?? baseCfg.variables,\n export: overrideCfg.export ?? baseCfg.export, // replace array (no merge)\n import: overrideCfg.import ?? baseCfg.import, // replace array (no merge)\n }\n }\n\n return merged\n}\n\n/**\n * Validate a PlatformsConfig object and return any validation errors.\n * Export/import flows configuration (no legacy subdirs support).\n * @param config - The config to validate\n * @returns Array of error messages; empty if valid\n */\nexport function validatePlatformsConfig(config: PlatformsConfig): string[] {\n const errors: string[] = []\n\n for (const [platformId, platConfig] of Object.entries(config)) {\n // Skip special keys\n if (platformId === '$schema') {\n continue\n }\n\n // Skip global config - validate separately\n if (platformId === 'global') {\n if (isGlobalFlowsConfig(platConfig)) {\n errors.push(...validateGlobalFlowsConfig(platConfig))\n }\n continue\n }\n\n // Type guard for platform config\n if (isGlobalFlowsConfig(platConfig)) {\n errors.push(`Platform '${platformId}': Cannot use global flows config format for platform entry`)\n continue\n }\n\n // Now we know platConfig is PlatformConfig\n const cfg = platConfig as PlatformConfig\n\n // rootDir is now optional if detection is provided\n if (!cfg.detection && (!cfg.rootDir || cfg.rootDir.trim() === '')) {\n errors.push(`Platform '${platformId}': Must define either 'detection' array or 'rootDir'`)\n }\n if (!cfg.name || cfg.name.trim() === '') {\n errors.push(`Platform '${platformId}': Missing or empty name`)\n }\n\n // Validate export flows\n if (cfg.export !== undefined) {\n if (!Array.isArray(cfg.export)) {\n errors.push(`Platform '${platformId}': export must be array or undefined`)\n } else {\n errors.push(...validateFlows(cfg.export, `${platformId}.export`))\n }\n }\n\n // Validate import flows\n if (cfg.import !== undefined) {\n if (!Array.isArray(cfg.import)) {\n errors.push(`Platform '${platformId}': import must be array or undefined`)\n } else {\n errors.push(...validateFlows(cfg.import, `${platformId}.import`))\n }\n }\n\n // Validate that export or import or rootFile or detection is present\n const hasExport = cfg.export && cfg.export.length > 0;\n const hasImport = cfg.import && cfg.import.length > 0;\n const hasDetection = cfg.detection && cfg.detection.length > 0;\n if (!hasExport && !hasImport && !cfg.rootFile && !hasDetection) {\n errors.push(`Platform '${platformId}': Must define at least one of 'export', 'import', 'detection', or 'rootFile'`)\n }\n\n if (cfg.aliases !== undefined && (!Array.isArray(cfg.aliases) || cfg.aliases.some((a: any) => typeof a !== 'string'))) {\n errors.push(`Platform '${platformId}': aliases must be array of strings or undefined`)\n }\n if (typeof cfg.enabled !== 'boolean' && cfg.enabled !== undefined) {\n errors.push(`Platform '${platformId}': enabled must be boolean or undefined`)\n }\n if (cfg.variables !== undefined && (typeof cfg.variables !== 'object' || Array.isArray(cfg.variables))) {\n errors.push(`Platform '${platformId}': variables must be object or undefined`)\n }\n }\n\n return errors\n}\n\n/**\n * Extract pattern string from flow field (handles string, array, and pattern object)\n */\nfunction extractPatternString(field: any): string | null {\n if (typeof field === 'string') {\n return field;\n }\n if (typeof field === 'object' && field !== null) {\n if ('pattern' in field) {\n return field.pattern;\n }\n if ('$switch' in field) {\n return null; // Skip switch expressions\n }\n }\n if (Array.isArray(field) && field.length > 0) {\n return extractPatternString(field[0]);\n }\n return null;\n}\n\n/**\n * Validate global flows configuration\n */\nfunction validateGlobalFlowsConfig(config: GlobalFlowsConfig): string[] {\n const errors: string[] = []\n \n if (config.export !== undefined) {\n if (!Array.isArray(config.export)) {\n errors.push(`Global config: export must be array or undefined`)\n } else {\n errors.push(...validateFlows(config.export, 'global.export'))\n }\n }\n \n if (config.import !== undefined) {\n if (!Array.isArray(config.import)) {\n errors.push(`Global config: import must be array or undefined`)\n } else {\n errors.push(...validateFlows(config.import, 'global.import'))\n }\n }\n \n if (config.description !== undefined && typeof config.description !== 'string') {\n errors.push(`Global config: description must be string or undefined`)\n }\n \n return errors\n}\n\n/**\n * Validate an array of flows\n */\n/**\n * Check if a value is a switch expression\n */\nfunction isSwitchExpression(value: any): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n '$switch' in value\n );\n}\n\n/**\n * Check if a value is a pattern object (with pattern and optional schema)\n */\nfunction isPatternObject(value: any): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'pattern' in value &&\n typeof value.pattern === 'string'\n );\n}\n\n/**\n * Validate a pattern object\n */\nfunction validatePatternObject(value: any, context: string): string[] {\n const errors: string[] = [];\n \n if (typeof value.pattern !== 'string' || value.pattern.trim() === '') {\n errors.push(`${context}: pattern must be non-empty string`);\n }\n \n if ('schema' in value && typeof value.schema !== 'string') {\n errors.push(`${context}: schema must be string if provided`);\n }\n \n return errors;\n}\n\nfunction validateFlows(flows: Flow[], context: string): string[] {\n const errors: string[] = []\n \n for (let i = 0; i < flows.length; i++) {\n const flow = flows[i]\n \n // Required fields\n if (!flow.from) {\n errors.push(`${context}, flows[${i}]: Missing 'from' field`)\n } else if (typeof flow.from === 'string') {\n if (flow.from.trim() === '') {\n errors.push(`${context}, flows[${i}]: 'from' cannot be empty`)\n }\n } else if (Array.isArray(flow.from)) {\n if (flow.from.length === 0) {\n errors.push(`${context}, flows[${i}]: 'from' array cannot be empty`)\n }\n flow.from.forEach((p, j) => {\n if (typeof p === 'string') {\n if (p.trim() === '') {\n errors.push(`${context}, flows[${i}]: 'from' array item ${j} cannot be empty string`)\n }\n } else if (isPatternObject(p)) {\n errors.push(...validatePatternObject(p, `${context}, flows[${i}].from[${j}]`))\n } else {\n errors.push(`${context}, flows[${i}]: 'from' array item ${j} must be string or pattern object`)\n }\n })\n } else if (isSwitchExpression(flow.from)) {\n // Switch expression validation happens elsewhere\n } else if (isPatternObject(flow.from)) {\n errors.push(...validatePatternObject(flow.from, `${context}, flows[${i}].from`))\n } else {\n errors.push(`${context}, flows[${i}]: 'from' must be string, array, pattern object, or $switch expression`)\n }\n \n if (!flow.to) {\n errors.push(`${context}, flows[${i}]: Missing 'to' field`)\n } else if (typeof flow.to === 'string') {\n if (flow.to.trim() === '') {\n errors.push(`${context}, flows[${i}]: 'to' cannot be empty`)\n }\n } else if (isSwitchExpression(flow.to)) {\n // Validate switch expression structure\n const switchValidation = validateSwitchExpression(flow.to as any);\n if (!switchValidation.valid) {\n switchValidation.errors.forEach(err => {\n errors.push(`${context}, flows[${i}]: ${err}`);\n });\n }\n } else if (isPatternObject(flow.to)) {\n errors.push(...validatePatternObject(flow.to, `${context}, flows[${i}].to`))\n } else if (typeof flow.to === 'object') {\n // Multi-target flows - validate each target\n for (const [targetPath, targetFlow] of Object.entries(flow.to)) {\n if (typeof targetPath !== 'string' || targetPath.trim() === '') {\n errors.push(`${context}, flows[${i}].to: target path cannot be empty`)\n }\n }\n } else {\n errors.push(`${context}, flows[${i}]: 'to' must be string, pattern object, switch expression, or multi-target object`)\n }\n \n // Validate merge strategy\n if (flow.merge !== undefined) {\n const validMerges = ['replace', 'shallow', 'deep', 'composite']\n if (!validMerges.includes(flow.merge)) {\n errors.push(`${context}, flows[${i}]: Invalid merge strategy '${flow.merge}'. Must be one of: ${validMerges.join(', ')}`)\n }\n }\n \n // Validate legacy 'pipe' (still supported in platforms.jsonc for compatibility)\n const pipe = (flow as any).pipe\n if (pipe !== undefined) {\n if (!Array.isArray(pipe)) {\n errors.push(`${context}, flows[${i}]: 'pipe' must be array`)\n } else if (pipe.some((p: any) => typeof p !== 'string' || p.trim() === '')) {\n errors.push(`${context}, flows[${i}]: 'pipe' must be array of strings`)\n }\n }\n \n // Validate map pipeline (must be array)\n if (flow.map !== undefined && !Array.isArray(flow.map)) {\n errors.push(`${context}, flows[${i}]: 'map' must be array of operations`)\n }\n \n // Validate pick/omit\n if (flow.pick !== undefined && !Array.isArray(flow.pick)) {\n errors.push(`${context}, flows[${i}]: 'pick' must be array or undefined`)\n }\n if (flow.omit !== undefined && !Array.isArray(flow.omit)) {\n errors.push(`${context}, flows[${i}]: 'omit' must be array or undefined`)\n }\n \n // Validate embed\n if (flow.embed !== undefined && (typeof flow.embed !== 'string' || flow.embed.trim() === '')) {\n errors.push(`${context}, flows[${i}]: 'embed' must be non-empty string or undefined`)\n }\n }\n \n return errors\n}\n\nconst GLOBAL_DIR = join(os.homedir(), \".openpackage\")\n\nconst stateCache = new Map<string | null, PlatformsState>()\n\n/**\n * Clear the platforms cache. Useful for testing.\n * @param cwd Optional path to clear cache for. If not provided, clears all cache.\n */\nexport function clearPlatformsCache(targetDir?: string): void {\n if (targetDir !== undefined) {\n stateCache.delete(targetDir)\n } else {\n stateCache.clear()\n }\n}\n\nexport function getPlatformsState(targetDir?: string | null): PlatformsState {\n const key = targetDir ?? null\n if (stateCache.has(key)) {\n return stateCache.get(key)!\n }\n\n let config: PlatformsConfig\n\n if (key === null) {\n // Global\n const globalFile =\n readJsoncOrJson(join(GLOBAL_DIR, \"platforms.jsonc\")) ??\n readJsoncOrJson(join(GLOBAL_DIR, \"platforms.json\")) as PlatformsConfig | undefined\n config = globalFile\n ? mergePlatformsConfig(BUILT_IN_CONFIG, globalFile)\n : BUILT_IN_CONFIG\n\n const errors = validatePlatformsConfig(config)\n if (errors.length > 0) {\n throw new Error(`Global platforms config validation failed:\\n - ${errors.join('\\n - ')}`)\n }\n } else {\n // Local\n const globalState = getPlatformsState(null)\n const globalConfig = globalState.config\n\n const localDir = join(key, DIR_PATTERNS.OPENPACKAGE)\n const localFile =\n readJsoncOrJson(join(localDir, \"platforms.jsonc\")) ??\n readJsoncOrJson(join(localDir, \"platforms.json\")) as PlatformsConfig | undefined\n config = localFile\n ? mergePlatformsConfig(globalConfig, localFile)\n : globalConfig\n\n const errors = validatePlatformsConfig(config)\n if (errors.length > 0) {\n throw new Error(`Local platforms config validation failed in ${key}:\\n - ${errors.join('\\n - ')}`)\n }\n }\n\n // Extract global flows if present\n const globalConfig = config['global']\n const globalExportFlows = (globalConfig && isGlobalFlowsConfig(globalConfig)) \n ? globalConfig.export \n : undefined\n const globalImportFlows = (globalConfig && isGlobalFlowsConfig(globalConfig)) \n ? globalConfig.import \n : undefined\n\n // Create definitions and compute state\n const defs = createPlatformDefinitions(config)\n\n const dirLookup: Record<string, Platform> = {}\n const aliasLookup: Record<string, Platform> = {}\n const universalPatterns = new Set<string>()\n const rootFiles: string[] = []\n const allPlatforms: Platform[] = []\n\n // Collect all universal patterns from platform export flows\n for (const def of Object.values(defs)) {\n allPlatforms.push(def.id)\n if (def.rootDir) {\n dirLookup[def.rootDir] = def.id\n }\n for (const alias of def.aliases ?? []) {\n aliasLookup[alias.toLowerCase()] = def.id\n }\n \n // Collect all 'from' patterns from export flows\n if (def.export && def.export.length > 0) {\n for (const flow of def.export) {\n // Extract pattern string using helper\n const pattern = extractPatternString(flow.from);\n if (pattern) {\n universalPatterns.add(pattern);\n }\n }\n }\n \n if (def.rootFile) {\n rootFiles.push(def.rootFile)\n }\n }\n\n // Add patterns from global export flows\n if (globalExportFlows && globalExportFlows.length > 0) {\n for (const flow of globalExportFlows) {\n // Extract pattern string using helper\n const pattern = extractPatternString(flow.from);\n if (pattern) {\n universalPatterns.add(pattern);\n }\n }\n }\n\n // Derive subdirectories from patterns (backward compatibility)\n const universalSubdirs = extractSubdirectoriesFromPatterns(universalPatterns)\n\n const enabledPlatforms = allPlatforms.filter((p: string) => defs[p].enabled)\n\n const state: PlatformsState = {\n config,\n globalExportFlows,\n globalImportFlows,\n defs,\n dirLookup,\n aliasLookup,\n universalPatterns,\n universalSubdirs,\n rootFiles,\n allPlatforms,\n enabledPlatforms\n }\n\n stateCache.set(key, state)\n return state\n}\n\nexport function getPlatformDefinitions(\n targetDir?: string\n): Record<Platform, PlatformDefinition> {\n return getPlatformsState(targetDir).defs\n}\n\n/**\n * Get global export flows that apply to all platforms (install/apply)\n */\nexport function getGlobalExportFlows(targetDir?: string): Flow[] | undefined {\n return getPlatformsState(targetDir).globalExportFlows\n}\n\n/**\n * Get global import flows that apply to all platforms (save)\n */\nexport function getGlobalImportFlows(targetDir?: string): Flow[] | undefined {\n return getPlatformsState(targetDir).globalImportFlows\n}\n\n/**\n * Check if a platform uses flow-based configuration (export or import)\n */\nexport function platformUsesFlows(platform: Platform, targetDir?: string): boolean {\n try {\n const def = getPlatformDefinition(platform, targetDir)\n const hasExport = def.export !== undefined && def.export.length > 0\n const hasImport = def.import !== undefined && def.import.length > 0\n return hasExport || hasImport\n } catch (error) {\n // Platform not found - return false\n return false\n }\n}\n\n/**\n * Get all universal path patterns from flow definitions.\n * These patterns define which files are considered universal package content.\n * This is the source of truth for determining what belongs in a package.\n * \n * @param targetDir - Optional target directory for local config overrides\n * @returns Set of glob patterns from all platform flows\n * \n * @example\n * // Returns: Set([\"rules/**\\/*.md\", \"mcp.jsonc\", \"commands/*.md\", ...])\n * const patterns = getAllUniversalPatterns()\n */\nexport function getAllUniversalPatterns(targetDir?: string): Set<string> {\n return new Set(getPlatformsState(targetDir).universalPatterns)\n}\n\n/**\n * Check if a file path matches any universal pattern from flows.\n * This is the primary method for determining if a file is universal content.\n * \n * @param filePath - File path to check (normalized, no leading slash)\n * @param targetDir - Optional target directory for local config overrides\n * @returns true if path matches any universal pattern\n * \n * @example\n * matchesUniversalPattern(\"mcp.jsonc\") // true (if defined in flows)\n * matchesUniversalPattern(\"rules/typescript.md\") // true\n * matchesUniversalPattern(\"random-file.txt\") // false\n */\nexport function matchesUniversalPattern(filePath: string, targetDir?: string): boolean {\n const patterns = getAllUniversalPatterns(targetDir)\n return matchesAnyPattern(filePath, patterns)\n}\n\n/**\n * Get lookup map from platform directory name to platform ID.\n */\nexport function getPlatformDirLookup(targetDir?: string): Record<string, Platform> {\n return getPlatformsState(targetDir).dirLookup\n}\n\n/**\n * Get lookup map from platform alias to platform ID.\n */\nexport function getPlatformAliasLookup(targetDir?: string): Record<string, Platform> {\n return getPlatformsState(targetDir).aliasLookup\n}\n\n/**\n * Get all known platform root files.\n */\nexport function getPlatformRootFiles(targetDir?: string): string[] {\n return getPlatformsState(targetDir).rootFiles\n}\n\n\n\n// PlatformDetectionResult, PlatformPaths, PlatformDirectoryPaths are now imported from ../types/platform.js\n\n/**\n * Get platform definition by name\n * @throws Error if platform not found\n */\nexport function getPlatformDefinition(\n name: Platform,\n targetDir?: string\n): PlatformDefinition {\n const state = getPlatformsState(targetDir)\n const def = state.defs[name]\n if (!def) {\n throw new Error(`Unknown platform: ${name}`)\n }\n return def\n}\n\n/**\n * Derive the root directory from platform flows.\n * Extracts the common root directory from export flow 'to' patterns.\n * Falls back to platform ID if no flows defined.\n * \n * @param definition - Platform definition\n * @returns Root directory path (e.g., '.claude', '.cursor')\n */\nexport function deriveRootDirFromFlows(definition: PlatformDefinition): string {\n // If rootDir is explicitly defined, use it\n if (definition.rootDir) {\n return definition.rootDir;\n }\n \n // Helper to extract path from switch expression (uses default if available)\n const extractPathFromSwitch = (switchExpr: any): string | null => {\n if (isSwitchExpression(switchExpr)) {\n // Use default if available, otherwise first case value\n return switchExpr.$switch.default || (switchExpr.$switch.cases[0]?.value);\n }\n return null;\n };\n \n // Try to extract from export flows\n if (definition.export && definition.export.length > 0) {\n for (const flow of definition.export) {\n let toPattern: string | null = null;\n \n if (typeof flow.to === 'string') {\n toPattern = flow.to;\n } else if (isSwitchExpression(flow.to)) {\n toPattern = extractPathFromSwitch(flow.to);\n } else {\n toPattern = Object.keys(flow.to)[0];\n }\n \n if (toPattern) {\n // Extract root directory from pattern (e.g., \".claude/rules/**/*.md\" -> \".claude\")\n const match = toPattern.match(/^(\\.[^/]+)/);\n if (match) {\n return match[1];\n }\n }\n }\n }\n \n // Try to extract from import flows\n if (definition.import && definition.import.length > 0) {\n for (const flow of definition.import) {\n let fromPattern: string | null = null;\n \n if (typeof flow.from === 'string') {\n fromPattern = flow.from;\n } else if (Array.isArray(flow.from)) {\n fromPattern = flow.from[0];\n } else if (isSwitchExpression(flow.from)) {\n fromPattern = extractPathFromSwitch(flow.from);\n }\n \n if (fromPattern) {\n // Extract root directory from pattern\n const match = fromPattern.match(/^(\\.[^/]+)/);\n if (match) {\n return match[1];\n }\n }\n }\n }\n \n // Fallback to platform ID prefixed with dot\n return `.${definition.id}`;\n}\n\n/**\n * Get all platforms\n */\nexport function getAllPlatforms(\n options?: { includeDisabled?: boolean },\n targetDir?: string\n): Platform[] {\n const state = getPlatformsState(targetDir)\n if (options?.includeDisabled) {\n return state.allPlatforms\n }\n return state.enabledPlatforms\n}\n\nexport function resolvePlatformName(\n input: string | undefined,\n targetDir?: string\n): Platform | undefined {\n if (!input) {\n return undefined\n }\n\n const state = getPlatformsState(targetDir)\n const normalized = input.toLowerCase()\n if (normalized in state.defs) {\n return normalized as Platform\n }\n\n return state.aliasLookup[normalized]\n}\n\n/**\n * Resolve a frontmatter/platform key (id or alias, case-insensitive) to a canonical platform id.\n * Returns null when the key is not a known platform or alias.\n */\nexport function resolvePlatformKey(\n key: string,\n targetDir?: string\n): Platform | null {\n if (!key) return null\n\n const normalized = key.toLowerCase()\n const state = getPlatformsState(targetDir)\n\n if (normalized in state.defs) {\n return normalized as Platform\n }\n\n return state.aliasLookup[normalized] ?? null\n}\n\n/**\n * Internal helper to build directory paths for a single platform definition.\n */\nfunction buildDirectoryPaths(\n definition: PlatformDefinition, \n targetDir: string\n): PlatformPaths {\n const subdirsPaths: Record<string, string> = {}\n \n // Build from export flows (the flows that define workspace structure)\n if (definition.export && definition.export.length > 0) {\n for (const flow of definition.export) {\n // Extract pattern from 'from' field\n const fromPattern = extractPatternString(flow.from);\n if (!fromPattern) continue;\n \n const firstComponent = fromPattern.split('/')[0]\n \n // Skip if it's a file (contains extension) or already exists\n if (firstComponent && !firstComponent.includes('.') && !subdirsPaths[firstComponent]) {\n // Extract platform subdir from 'to' pattern\n const toPattern = typeof flow.to === 'string' ? flow.to : Object.values(flow.to)[0]\n \n if (typeof toPattern === 'string') {\n // Get the directory part of the target path\n const targetPath = toPattern.split('/').slice(0, -1).join('/')\n \n if (targetPath) {\n subdirsPaths[firstComponent] = join(targetDir, targetPath)\n }\n }\n }\n }\n }\n\n const rootDir = deriveRootDirFromFlows(definition);\n \n return {\n rootDir: join(targetDir, rootDir),\n rootFile: definition.rootFile ? join(targetDir, definition.rootFile) : undefined,\n subdirs: subdirsPaths\n }\n}\n\n/**\n * Get platform directory paths for a given target directory\n */\nexport function getPlatformDirectoryPaths(targetDir: string): PlatformDirectoryPaths {\n const state = getPlatformsState(targetDir)\n const paths: PlatformDirectoryPaths = {}\n\n for (const platform of state.enabledPlatforms) {\n paths[platform] = buildDirectoryPaths(state.defs[platform], targetDir)\n }\n\n return paths\n}\n\n/**\n * Get directory paths for a specific platform.\n * @throws Error if platform unknown\n */\nexport function getPlatformDirectoryPathsForPlatform(\n platform: Platform,\n targetDir: string\n): PlatformPaths {\n const state = getPlatformsState(targetDir)\n const definition = state.defs[platform]\n if (!definition) {\n throw new Error(`Unknown platform: ${platform}`)\n }\n return buildDirectoryPaths(definition, targetDir)\n}\n\n/**\n * Detect all platforms present in a directory\n * Checks both platform directories (.platform/) and unique root files (e.g., CLAUDE.md)\n * AGENTS.md is skipped as it's universal/ambiguous.\n */\nexport async function detectAllPlatforms(\n targetDir: string\n): Promise<PlatformDetectionResult[]> {\n const state = getPlatformsState(targetDir)\n const detectionPromises = state.enabledPlatforms.map(\n async (platform) => {\n const definition = state.defs[platform]\n \n // Use new detection array if available\n if (definition.detection && definition.detection.length > 0) {\n // Check if any detection pattern matches\n for (const pattern of definition.detection) {\n const testPath = join(targetDir, pattern)\n if (await exists(testPath)) {\n return {\n name: platform,\n detected: true,\n }\n }\n }\n \n return {\n name: platform,\n detected: false,\n }\n }\n \n // Legacy detection using rootDir/rootFile\n let detected = false\n \n if (definition.rootDir) {\n const rootDirPath = join(targetDir, definition.rootDir)\n detected = await exists(rootDirPath)\n }\n \n if (!detected && definition.rootFile && definition.rootFile !== FILE_PATTERNS.AGENTS_MD) {\n const rootFilePath = join(targetDir, definition.rootFile)\n detected = await exists(rootFilePath)\n }\n\n return {\n name: platform,\n detected,\n }\n }\n )\n\n return await Promise.all(detectionPromises)\n}\n\n/**\n * Get detected platforms only\n */\nexport async function getDetectedPlatforms(cwd: string): Promise<Platform[]> {\n const results = await detectAllPlatforms(cwd)\n return results\n .filter((result) => result.detected)\n .map((result) => result.name)\n}\n\n/**\n * Validate platform directory structure\n */\nexport async function validatePlatformStructure(\n cwd: string,\n platform: Platform\n): Promise<{ valid: boolean; issues: string[] }> {\n const state = getPlatformsState(cwd)\n const definition = state.defs[platform]\n if (!definition) {\n throw new Error(`Unknown platform: ${platform}`)\n }\n\n const issues: string[] = []\n\n // Check detection patterns if available\n if (definition.detection && definition.detection.length > 0) {\n // Detection patterns are used for source detection, not validation\n // Skip validation for now\n } else if (definition.rootFile) {\n // Legacy rootFile validation\n const rootFilePath = join(cwd, definition.rootFile)\n if (!(await exists(rootFilePath))) {\n issues.push(`Root file does not exist: ${rootFilePath}`)\n }\n }\n\n // TODO: Optionally check flow-based directories exist\n // (may not be necessary since flows handle missing directories gracefully)\n\n return {\n valid: issues.length === 0,\n issues,\n }\n}\n\n/**\n * Get file extensions allowed in a specific universal subdir for a platform\n * @param universalSubdir - The universal subdirectory name (e.g., 'rules', 'commands', or custom)\n * @returns Allowed extensions or empty array if subdir not supported\n */\nexport function getPlatformSubdirExts(\n platform: Platform,\n universalSubdir: string,\n targetDir?: string\n): string[] {\n const state = getPlatformsState(targetDir)\n const definition = state.defs[platform]\n if (!definition) {\n throw new Error(`Unknown platform: ${platform}`)\n }\n \n // Check export flows\n if (definition.export && definition.export.length > 0) {\n const extensions = new Set<string>()\n \n for (const flow of definition.export) {\n // Extract pattern from 'from' field\n const fromPattern = extractPatternString(flow.from);\n if (!fromPattern) continue;\n \n // Check if this flow matches the universal subdir\n if (fromPattern.startsWith(`${universalSubdir}/`)) {\n // Extract extension from the 'from' pattern\n const extMatch = fromPattern.match(/\\.[^./]+$/)\n if (extMatch) {\n extensions.add(extMatch[0])\n }\n \n // Also check 'to' pattern for extension changes\n const toPattern = typeof flow.to === 'string' ? flow.to : Object.values(flow.to)[0]\n if (typeof toPattern === 'string') {\n const toExtMatch = toPattern.match(/\\.[^./]+$/)\n if (toExtMatch) {\n extensions.add(toExtMatch[0])\n }\n }\n }\n }\n \n if (extensions.size > 0) {\n return Array.from(extensions)\n }\n }\n \n logger.warn(`Platform ${platform} does not support universal subdir '${universalSubdir}'`)\n return []\n}\n\n/**\n * Get all universal subdirs that exist for a platform\n */\nexport function getPlatformUniversalSubdirs(\n targetDir: string,\n platform: Platform\n): Array<{ dir: string; label: string; leaf: string }> {\n const paths = getPlatformDirectoryPathsForPlatform(platform, targetDir)\n const subdirs: Array<{ dir: string; label: string; leaf: string }> = []\n\n for (const [label, dir] of Object.entries(paths.subdirs)) {\n subdirs.push({\n dir,\n label,\n leaf: getPathLeaf(dir),\n })\n }\n\n return subdirs\n}\n\n/**\n * Check if a normalized path represents a universal subdir\n */\nexport function isUniversalSubdirPath(normalizedPath: string, targetDir?: string): boolean {\n const state = getPlatformsState(targetDir)\n for (const subdir of state.universalSubdirs) {\n if (\n normalizedPath.startsWith(`${subdir}/`) ||\n normalizedPath === subdir ||\n normalizedPath.startsWith(`${DIR_PATTERNS.OPENPACKAGE}/${subdir}/`) ||\n normalizedPath === `${DIR_PATTERNS.OPENPACKAGE}/${subdir}`\n ) {\n return true\n }\n }\n return false\n}\n\n/**\n * Check if a value is a valid platform ID.\n */\nexport function isPlatformId(\n value: string | undefined,\n targetDir?: string\n): value is Platform {\n if (!value) return false\n return value in getPlatformsState(targetDir).defs\n}\n\n/**\n * Infer platform from workspace file information.\n * Attempts multiple strategies to determine the platform:\n * 1. Maps full path to universal path (if platform can be inferred from path structure)\n * 2. Checks if source directory or registry path indicates workspace install content\n * 3. Looks up platform from source directory using PLATFORM_DIR_LOOKUP\n * 4. Parses registry path for platform suffix (e.g., file.cursor.md)\n *\n * @param fullPath - Full absolute path to the file\n * @param sourceDir - Source directory name (e.g., '.cursor', 'ai')\n * @param registryPath - Registry path (e.g., 'rules/file.md')\n * @param targetDir - Optional target directory for local platform config overrides\n * @returns Platform ID, 'ai', or undefined if cannot be determined\n */\nexport function inferPlatformFromWorkspaceFile(\n fullPath: string,\n sourceDir: string,\n registryPath: string,\n targetDir?: string\n): Platform | undefined {\n // First try to get platform from full path using existing mapper\n const mapping = mapPlatformFileToUniversal(fullPath, targetDir)\n if (mapping?.platform) {\n return mapping.platform\n }\n\n // Look up platform from source directory\n const fromSource = getPlatformDirLookup(targetDir)[sourceDir]\n if (fromSource) {\n return fromSource\n }\n \n // Fallback: derive platform root dirs from flows\n const state = getPlatformsState(targetDir)\n for (const [platformId, def] of Object.entries(state.defs)) {\n const derivedRoot = deriveRootDirFromFlows(def)\n if (derivedRoot === sourceDir) {\n return platformId as Platform\n }\n }\n\n // Fallback: check registry path for platform suffix\n const parsed = parseUniversalPath(registryPath, { allowPlatformSuffix: true })\n if (parsed?.platformSuffix && isPlatformId(parsed.platformSuffix, targetDir)) {\n return parsed.platformSuffix\n }\n\n return undefined\n}\n", "import { join, basename, dirname, extname, relative, resolve } from 'path';\nimport { realpathSync } from 'fs';\nimport type { Platform, PlatformPaths, PlatformDefinition } from '../../types/platform.js';\nimport {\n getPlatformDefinition,\n getDetectedPlatforms,\n getAllPlatforms,\n getPlatformDirectoryPathsForPlatform\n} from '../platforms.js';\nimport type { Flow } from '../../types/flows.js';\nimport { logger } from '../../utils/logger.js';\nimport { type UniversalSubdir } from '../../constants/index.js';\nimport { normalizePathForProcessing, findSubpathIndex } from '../../utils/path-normalization.js';\n\n/**\n * Extract pattern string from a flow pattern value\n * Handles both string patterns and FlowPattern objects with { pattern, schema }\n */\nfunction extractPatternString(pattern: string | { pattern: string; schema?: string }): string {\n if (typeof pattern === 'string') {\n return pattern;\n }\n return pattern.pattern;\n}\n\n/**\n * Extract all \"from\" pattern strings from a flow's from field.\n * Handles string, array, pattern object, and $switch expressions.\n * For $switch: extracts patterns from both cases and default.\n */\nfunction extractFromPatternsFromFlow(flow: Flow): string[] {\n const from = flow.from;\n if (typeof from === 'string') {\n return [from];\n }\n if (Array.isArray(from)) {\n return from.map((p) => extractPatternString(typeof p === 'string' ? p : p as { pattern: string }));\n }\n if (typeof from === 'object' && from !== null && 'pattern' in from) {\n return [extractPatternString(from as { pattern: string })];\n }\n if (typeof from === 'object' && from !== null && '$switch' in from) {\n const sw = (from as { $switch: { cases?: Array<{ value: unknown }>; default?: unknown } }).$switch;\n const patterns: string[] = [];\n if (sw.cases) {\n for (const c of sw.cases) {\n const v = c.value;\n if (typeof v === 'string') patterns.push(v);\n else if (typeof v === 'object' && v !== null && 'pattern' in v) patterns.push((v as { pattern: string }).pattern);\n }\n }\n if (sw.default !== undefined) {\n const d = sw.default;\n if (typeof d === 'string') patterns.push(d);\n else if (typeof d === 'object' && d !== null && 'pattern' in d) patterns.push((d as { pattern: string }).pattern);\n }\n return patterns;\n }\n return [];\n}\n\n/**\n * Result of mapping a universal path to a platform path.\n *\n * IMPORTANT CONTRACT:\n * - `relDir` / `relFile` are **workspace-relative** paths (to be joined with the workspace `cwd`)\n *\n * Do NOT return absolute paths from this mapper: most call sites treat mapping outputs as\n * relative and prefix them with `cwd` (via `path.join`), which would create duplicated roots.\n */\nexport interface PlatformPathMapping {\n /** Workspace-relative directory path (e.g. `.cursor/rules`) */\n relDir: string;\n /** Workspace-relative file path (e.g. `.cursor/rules/foo.mdc`) */\n relFile: string;\n}\n\n/**\n * Normalize platform names from command line input\n */\nexport function normalizePlatforms(platforms?: string[]): string[] | undefined {\n if (!platforms || platforms.length === 0) {\n return undefined;\n }\n \n return platforms.map(p => p.toLowerCase());\n}\n\n/**\n * Resolve the target directory for a registry-relative path within a package directory.\n *\n * This is intentionally simple: it preserves the directory structure of the registry path.\n * (Platform-specific mapping is handled elsewhere via flows.)\n */\nexport function resolveTargetDirectory(packageDir: string, registryPath: string): string {\n const normalized = registryPath.replace(/\\\\/g, '/').replace(/^\\/+/, '');\n const parts = normalized.split('/');\n if (parts.length <= 1) {\n return packageDir;\n }\n return join(packageDir, parts.slice(0, -1).join('/'));\n}\n\n/**\n * Resolve the final target file path given a target directory and a registry-relative path.\n */\nexport function resolveTargetFilePath(targetDir: string, registryPath: string): string {\n const normalized = registryPath.replace(/\\\\/g, '/').replace(/^\\/+/, '');\n const parts = normalized.split('/');\n const fileName = parts[parts.length - 1] || normalized;\n return join(targetDir, fileName);\n}\n\n/**\n * Platform Mapper Module\n * Unified functions for mapping between universal subdirs and platform-specific paths\n * \n * Note: This module currently uses subdirs-based mapping. Flow-based path resolution\n * will be added in a future update (Section 6.4 of platform-flows implementation).\n */\n\n/**\n * Map a universal file path to platform-specific directory and file paths\n * \n * TODO (Section 6.4): Update to support flow-based path resolution when flows are defined\n */\nexport function mapUniversalToPlatform(\n platform: Platform,\n subdir: string,\n relPath: string,\n cwd?: string\n): PlatformPathMapping {\n const definition = getPlatformDefinition(platform, cwd);\n \n // Use export flow-based resolution (package \u2192 workspace)\n if (definition.export && definition.export.length > 0) {\n return mapUniversalToPlatformWithFlows(definition, subdir, relPath);\n }\n \n // No export flows defined - should not happen with flows-only system\n throw new Error(`Platform ${platform} does not have export flows defined for subdir ${subdir}`);\n}\n\n/**\n * Extract all possible 'to' patterns from a flow, including from $switch expressions\n */\nfunction extractToPatternsFromFlow(flow: Flow): string[] {\n const toField = flow.to;\n const patterns: string[] = [];\n \n // Handle $switch expressions - collect all possible patterns\n if (typeof toField === 'object' && toField !== null && '$switch' in toField) {\n const switchExpr = toField as any;\n \n // Collect all case values\n if (switchExpr.$switch?.cases) {\n for (const caseItem of switchExpr.$switch.cases) {\n if (typeof caseItem.value === 'string') {\n patterns.push(caseItem.value);\n } else if (typeof caseItem.value === 'object' && 'pattern' in caseItem.value) {\n patterns.push(caseItem.value.pattern);\n }\n }\n }\n \n // Add default value\n if (switchExpr.$switch?.default) {\n if (typeof switchExpr.$switch.default === 'string') {\n patterns.push(switchExpr.$switch.default);\n } else if (typeof switchExpr.$switch.default === 'object' && 'pattern' in switchExpr.$switch.default) {\n patterns.push(switchExpr.$switch.default.pattern);\n }\n }\n \n return patterns;\n }\n \n // Handle simple string\n if (typeof toField === 'string') {\n return [toField];\n }\n \n // Handle pattern object with 'pattern' field\n if (typeof toField === 'object' && 'pattern' in toField && typeof toField.pattern === 'string') {\n return [toField.pattern];\n }\n \n // Handle multi-target (object)\n if (typeof toField === 'object') {\n return Object.keys(toField);\n }\n \n return [];\n}\n\n/**\n * Map a platform-specific file path back to universal subdir and relative path\n * Uses EXPORT flows (package \u2192 workspace direction)\n * This is used during install/apply operations.\n * \n * Supports local platform configs via cwd.\n * Handles $switch expressions by checking all possible target patterns.\n */\nexport function mapPlatformFileToUniversal(\n absPath: string,\n cwd = process.cwd()\n): { platform: Platform; subdir: string; relPath: string } | null {\n const normalizedPath = normalizePathForProcessing(absPath);\n\n // Check each platform using export flows (package \u2192 workspace)\n for (const platform of getAllPlatforms({ includeDisabled: true }, cwd)) {\n const definition = getPlatformDefinition(platform, cwd);\n\n if (definition.export && definition.export.length > 0) {\n for (const flow of definition.export) {\n // Extract all possible 'to' patterns (handles $switch expressions)\n const toPatterns = extractToPatternsFromFlow(flow);\n \n for (const toPattern of toPatterns) {\n if (!toPattern) continue;\n \n // Extract directory from 'to' pattern (e.g., \".cursor/rules/{name}.mdc\" -> \".cursor/rules\")\n const parts = toPattern.split('/');\n const platformSubdirPath = parts.slice(0, -1).join('/');\n \n // Check if the path contains this platform subdir\n const subdirIndex = findSubpathIndex(normalizedPath, platformSubdirPath);\n if (subdirIndex !== -1) {\n // Skip switch expressions in 'from' field\n if (typeof flow.from === 'object' && '$switch' in flow.from) {\n continue;\n }\n // Extract universal subdir from 'from' pattern\n // For array patterns, use the first pattern\n const fromPatternRaw = Array.isArray(flow.from) ? flow.from[0] : flow.from;\n const fromPattern = extractPatternString(fromPatternRaw);\n const fromParts = fromPattern.split('/');\n const subdir = fromParts[0];\n \n // Extract the relative path within the subdir\n const absPattern = `/${platformSubdirPath}/`;\n const relPattern = `${platformSubdirPath}/`;\n const isAbsPattern = normalizedPath.indexOf(absPattern) !== -1;\n\n const patternLength = isAbsPattern ? absPattern.length : relPattern.length;\n const relPathStart = subdirIndex + patternLength;\n\n let relPath = normalizedPath.substring(relPathStart);\n\n // Handle extension transformations from flow\n const workspaceExtMatch = relPath.match(/\\.[^.]+$/);\n const toExtMatch = toPattern.match(/\\.[^./]+$/);\n const fromExtMatch = fromPattern.match(/\\.[^./]+$/);\n \n if (workspaceExtMatch && toExtMatch && fromExtMatch) {\n const workspaceExt = workspaceExtMatch[0];\n const toExt = toExtMatch[0];\n const fromExt = fromExtMatch[0];\n \n if (workspaceExt === toExt && toExt !== fromExt) {\n // Transform back to package extension\n relPath = relPath.slice(0, -workspaceExt.length) + fromExt;\n }\n }\n\n return { platform, subdir, relPath };\n }\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Map a workspace file path to universal package path using IMPORT flows\n * Uses IMPORT flows (workspace \u2192 package direction)\n * This is used during add/save operations.\n * \n * @param workspaceFilePath - Absolute or workspace-relative path to a workspace file\n * @param cwd - Workspace root directory\n * @returns Mapping result with platform, universal subdir, and relative path, or null if no match\n */\nexport function mapWorkspaceFileToUniversal(\n workspaceFilePath: string,\n cwd = process.cwd()\n): { platform: Platform; subdir: string; relPath: string; flow: Flow } | null {\n // Resolve symlinks to get real paths for consistent comparison\n const absolutePath = realpathSync(workspaceFilePath);\n const absoluteCwd = realpathSync(cwd);\n \n // Convert to workspace-relative path for matching against flow patterns\n const relativePath = relative(absoluteCwd, absolutePath).replace(/\\\\/g, '/');\n\n // Check each platform using import flows (workspace \u2192 package)\n for (const platform of getAllPlatforms({ includeDisabled: true }, cwd)) {\n const definition = getPlatformDefinition(platform, cwd);\n\n if (definition.import && definition.import.length > 0) {\n for (const flow of definition.import) {\n // Extract from patterns (handles $switch, array, string, pattern object)\n const fromPatterns = extractFromPatternsFromFlow(flow);\n if (fromPatterns.length === 0) continue;\n\n // Find first matching from pattern\n let matchedFromPattern: string | null = null;\n for (const p of fromPatterns) {\n if (matchesFlowPattern(relativePath, p)) {\n matchedFromPattern = p;\n break;\n }\n }\n if (!matchedFromPattern) continue;\n\n // Extract universal subdir from 'to' pattern (handle $switch in to)\n let toPattern: string | undefined;\n if (typeof flow.to === 'string') {\n toPattern = flow.to;\n } else if (typeof flow.to === 'object' && flow.to !== null && '$switch' in flow.to) {\n const sw = (flow.to as { $switch: { cases?: Array<{ pattern: string; value: unknown }>; default?: unknown } }).$switch;\n // For workspace add, use default (workspace paths like .opencode/... not ~/.config/...)\n const d = sw.default;\n toPattern = typeof d === 'string' ? d : (typeof d === 'object' && d !== null && 'pattern' in d) ? (d as { pattern: string }).pattern : undefined;\n } else if (typeof flow.to === 'object' && flow.to !== null) {\n toPattern = Object.keys(flow.to)[0];\n }\n if (!toPattern) continue;\n\n const toParts = toPattern.split('/');\n const subdir = toParts[0];\n\n // Extract the relative path by mapping from fromPattern to toPattern\n const relPath = mapPathUsingFlowPattern(relativePath, matchedFromPattern, toPattern);\n\n if (relPath) {\n return { platform, subdir, relPath, flow };\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Check if a path matches a flow pattern (supports globs)\n */\nfunction matchesFlowPattern(normalizedPath: string, pattern: string): boolean {\n // Convert glob pattern to regex\n let regexPattern = pattern\n .replace(/\\./g, '\\\\.')\n .replace(/\\*\\*\\//g, '___DOUBLESTAR_SLASH___')\n .replace(/\\/\\*\\*/g, '___SLASH_DOUBLESTAR___')\n .replace(/\\*\\*/g, '___DOUBLESTAR___')\n .replace(/\\*/g, '[^/]+')\n .replace(/___DOUBLESTAR_SLASH___/g, '(?:.*?/)?')\n .replace(/___SLASH_DOUBLESTAR___/g, '(?:/.*)?')\n .replace(/___DOUBLESTAR___/g, '.*');\n \n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(normalizedPath);\n}\n\n/**\n * Map a path from one pattern to another (workspace \u2192 package)\n * Handles glob patterns and extension transformations\n */\nfunction mapPathUsingFlowPattern(\n sourcePath: string,\n fromPattern: string,\n toPattern: string\n): string | null {\n // Handle ** recursive patterns\n if (fromPattern.includes('**') && toPattern.includes('**')) {\n const fromParts = fromPattern.split('**');\n const toParts = toPattern.split('**');\n const fromBase = fromParts[0].replace(/\\/$/, '');\n const toBase = toParts[0].replace(/\\/$/, '');\n \n // Get the file pattern after **\n const fromSuffix = fromParts[1] || '';\n const toSuffix = toParts[1] || '';\n \n // Extract the relative path after the base directory\n let relativeSubpath = sourcePath;\n if (fromBase) {\n if (!sourcePath.startsWith(fromBase + '/') && !sourcePath.startsWith('/' + fromBase + '/')) {\n return null;\n }\n const startPos = sourcePath.indexOf(fromBase);\n relativeSubpath = sourcePath.slice(startPos + fromBase.length + 1);\n }\n \n // Handle extension mapping if suffixes specify extensions\n if (fromSuffix && toSuffix) {\n const fromExt = fromSuffix.replace(/^\\/?\\*+/, '');\n const toExt = toSuffix.replace(/^\\/?\\*+/, '');\n if (fromExt && toExt && fromExt !== toExt) {\n relativeSubpath = relativeSubpath.replace(new RegExp(fromExt.replace('.', '\\\\.') + '$'), toExt);\n }\n }\n \n // Build target path (package-relative, no base)\n return relativeSubpath;\n }\n \n // Handle single-level * patterns\n if (fromPattern.includes('*') && toPattern.includes('*')) {\n const sourceFileName = basename(sourcePath);\n const sourceExt = extname(sourcePath);\n const sourceBase = basename(sourcePath, sourceExt);\n \n const toParts = toPattern.split('*');\n const toPrefix = toParts[0];\n const toSuffix = toParts[1] || '';\n \n const targetExt = toSuffix.startsWith('.') ? toSuffix : (sourceExt + toSuffix);\n const targetFileName = sourceBase + targetExt;\n \n // Get directory structure from toPrefix (remove leading platform dir)\n const toPrefixParts = toPrefix.split('/').filter(p => p);\n // First part is the subdir, rest is the directory structure\n const targetRelPath = toPrefixParts.slice(1).concat([targetFileName]).join('/');\n \n return targetRelPath;\n }\n \n // No globs - exact mapping\n // Extract just the filename and map it\n const fileName = basename(sourcePath);\n const toFileName = basename(toPattern);\n \n // Check if extensions differ\n const sourceExt = extname(fileName);\n const targetExt = extname(toFileName);\n \n let mappedFileName = fileName;\n if (sourceExt !== targetExt && targetExt) {\n mappedFileName = basename(fileName, sourceExt) + targetExt;\n }\n \n // Get directory from toPattern\n const toDir = dirname(toPattern);\n const toDirParts = toDir.split('/').filter(p => p && p !== '.');\n // First part is the subdir, rest is directory structure\n const relDir = toDirParts.slice(1).join('/');\n \n return relDir ? `${relDir}/${mappedFileName}` : mappedFileName;\n}\n\n/**\n * Map universal path to platform-specific path using flows configuration.\n * Handles glob patterns correctly by resolving them to concrete file paths.\n */\nfunction mapUniversalToPlatformWithFlows(\n definition: PlatformDefinition,\n subdir: string,\n relPath: string\n): PlatformPathMapping {\n const flows = definition.export || [];\n \n // Construct the full source path for matching\n const sourcePath = `${subdir}/${relPath}`;\n \n const candidateFlows = flows.filter((flow: Flow) => {\n // Skip switch expressions\n if (typeof flow.from === 'object' && '$switch' in flow.from) {\n return false;\n }\n const fromPatternRaw = Array.isArray(flow.from) ? flow.from[0] : flow.from;\n const fromPattern = extractPatternString(fromPatternRaw);\n return fromPattern.startsWith(`${subdir}/`);\n });\n if (candidateFlows.length === 0) {\n throw new Error(`Platform ${definition.id} does not support subdir ${subdir}`);\n }\n\n // Find a flow that matches this source path\n const matchingFlow = candidateFlows.find((flow: Flow) => {\n // Skip switch expressions\n if (typeof flow.from === 'object' && '$switch' in flow.from) {\n return false;\n }\n const fromPatternRaw = Array.isArray(flow.from) ? flow.from[0] : flow.from;\n const fromPattern = extractPatternString(fromPatternRaw);\n \n // Check if the source path matches the pattern\n // Handle glob patterns with ** and *\n if (fromPattern.includes('*')) {\n // Convert glob pattern to regex for matching\n // Use placeholders to prevent replacement interference\n const regexPattern = fromPattern\n .replace(/\\./g, '\\\\.')\n .replace(/\\*\\*\\//g, '___DOUBLESTAR_SLASH___') // **/ matches zero or more segments\n .replace(/\\/\\*\\*/g, '___SLASH_DOUBLESTAR___') // /** matches zero or more segments\n .replace(/\\*\\*/g, '___DOUBLESTAR___') // ** alone matches anything\n .replace(/\\*/g, '[^/]+') // * matches filename characters\n .replace(/___DOUBLESTAR_SLASH___/g, '(?:.*/)?' ) // Replace placeholders\n .replace(/___SLASH_DOUBLESTAR___/g, '(?:/.*)?')\n .replace(/___DOUBLESTAR___/g, '.*');\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(sourcePath);\n }\n \n // Exact match\n return fromPattern === sourcePath;\n });\n \n if (!matchingFlow) {\n const sourceExt = extname(sourcePath);\n const expectedExts = Array.from(\n new Set(\n candidateFlows\n .map((flow: Flow) => {\n // Skip switch expressions\n if (typeof flow.from === 'object' && '$switch' in flow.from) {\n return '';\n }\n const fromPatternRaw = Array.isArray(flow.from) ? flow.from[0] : flow.from;\n const fromPattern = extractPatternString(fromPatternRaw);\n return extname(fromPattern);\n })\n .filter((ext: string) => typeof ext === 'string' && ext.length > 0)\n )\n );\n\n if (sourceExt && expectedExts.length > 0 && !expectedExts.includes(sourceExt)) {\n logger.warn(\n `Skipped ${relPath} for platform ${definition.id}: extension ${sourceExt} does not match flow pattern`,\n { subdir, expectedExts }\n );\n throw new Error(\n `File extension ${sourceExt} is not allowed for subdir ${subdir} on platform ${definition.id}`\n );\n }\n\n throw new Error(`Platform ${definition.id} does not support path ${sourcePath}`);\n }\n \n const fromPattern = matchingFlow.from;\n const toPattern = matchingFlow.to;\n \n // Get the target path string (handle multi-target by taking first)\n let targetPathPattern: string;\n if (typeof toPattern === 'string') {\n targetPathPattern = toPattern;\n } else {\n // Multi-target flow - use first target\n const targets = toPattern as Record<string, Partial<import('../../types/flows.js').Flow>>;\n const firstTargetConfig = Object.values(targets)[0];\n targetPathPattern = typeof firstTargetConfig === 'string' ? firstTargetConfig : (firstTargetConfig as any).to;\n \n if (typeof targetPathPattern !== 'string') {\n throw new Error(`Invalid multi-target flow configuration for platform ${definition.id}`);\n }\n }\n \n // Resolve the target path from the glob pattern\n // For array patterns, use the first pattern\n // Skip switch expressions\n if (typeof fromPattern === 'object' && '$switch' in fromPattern) {\n throw new Error('Cannot resolve target path from SwitchExpression - expression must be resolved first');\n }\n const fromPatternStr = Array.isArray(fromPattern) ? fromPattern[0] : fromPattern;\n const targetPath = resolveTargetPathFromGlob(sourcePath, fromPatternStr, targetPathPattern);\n\n // Normalize: callers expect workspace-relative paths and will join them with `cwd`.\n const workspaceRoot = normalizePathForProcessing(process.cwd());\n let relTarget = normalizePathForProcessing(targetPath);\n const workspaceRootNoLeading = workspaceRoot.replace(/^\\/+/, '');\n\n // If targetPath accidentally includes the workspace root, strip it back to a workspace-relative path.\n if (relTarget === workspaceRoot) {\n relTarget = '';\n } else if (relTarget.startsWith(`${workspaceRoot}/`)) {\n relTarget = relTarget.slice(workspaceRoot.length + 1);\n } else if (workspaceRootNoLeading && relTarget.startsWith(`${workspaceRootNoLeading}/`)) {\n relTarget = relTarget.slice(workspaceRootNoLeading.length + 1);\n }\n\n // Ensure it's relative (no leading slash), but keep leading dot dirs like \".claude\".\n relTarget = relTarget.replace(/^\\/+/, '');\n\n const relFile = relTarget;\n const relDir = dirname(relFile);\n\n return { relDir, relFile };\n}\n\n/**\n * Resolve target path from glob patterns\n * This implements the same logic as flow-executor's resolveTargetFromGlob\n */\nfunction resolveTargetPathFromGlob(sourcePath: string, fromPattern: string, toPattern: string): string {\n // If 'to' pattern has glob, map the structure\n if (toPattern.includes('*')) {\n // Handle ** recursive patterns\n if (fromPattern.includes('**') && toPattern.includes('**')) {\n // Extract the base directories before **\n const fromParts = fromPattern.split('**');\n const toParts = toPattern.split('**');\n const fromBase = fromParts[0].replace(/\\/$/, '');\n const toBase = toParts[0].replace(/\\/$/, '');\n \n // Get the file pattern after **\n const fromSuffix = fromParts[1] || '';\n const toSuffix = toParts[1] || '';\n \n // Extract the relative path after the base directory\n let relativeSubpath = sourcePath;\n if (fromBase) {\n relativeSubpath = sourcePath.startsWith(fromBase + '/') \n ? sourcePath.slice(fromBase.length + 1)\n : sourcePath;\n }\n \n // Handle extension mapping if suffixes specify extensions\n // e.g., /**/*.md -> /**/*.mdc\n if (fromSuffix && toSuffix) {\n const fromExt = fromSuffix.replace(/^\\/?\\*+/, '');\n const toExt = toSuffix.replace(/^\\/?\\*+/, '');\n if (fromExt && toExt && fromExt !== toExt) {\n relativeSubpath = relativeSubpath.replace(new RegExp(fromExt.replace('.', '\\\\.') + '$'), toExt);\n }\n }\n \n // Build target path\n const targetPath = toBase ? join(toBase, relativeSubpath) : relativeSubpath;\n return targetPath;\n }\n \n // Handle single-level * patterns\n const sourceFileName = basename(sourcePath);\n const sourceExt = extname(sourcePath);\n const sourceBase = basename(sourcePath, sourceExt);\n \n const toParts = toPattern.split('*');\n const toPrefix = toParts[0];\n const toSuffix = toParts[1] || '';\n \n const targetExt = toSuffix.startsWith('.') ? toSuffix : (sourceExt + toSuffix);\n const targetFileName = sourceBase + targetExt;\n \n const resolvedTo = toPrefix + targetFileName;\n return resolvedTo;\n }\n \n // Handle {name} placeholder pattern\n if (toPattern.includes('{name}')) {\n const fileName = basename(sourcePath);\n const fileExt = extname(sourcePath);\n const baseName = fileName.slice(0, -fileExt.length);\n \n let targetPath = toPattern.replace('{name}', baseName);\n \n // Check if the target pattern changes the extension\n const targetExt = extname(targetPath);\n \n // If no extension in pattern, preserve original extension\n if (!targetExt && fileExt) {\n targetPath += fileExt;\n }\n \n return targetPath;\n }\n \n // No glob or placeholder in target - use as-is\n return toPattern;\n}\n\n\n", "/**\n * Platform File Utilities\n * Shared utilities for handling platform-specific file paths and extensions\n */\n\nimport { basename, join } from 'path';\nimport type { Platform } from '../../types/platform.js';\nimport {\n getPlatformDefinition,\n getAllPlatforms,\n getPlatformsState,\n isPlatformId\n} from '../platforms.js';\nimport { DIR_PATTERNS, FILE_PATTERNS, type UniversalSubdir } from '../../constants/index.js';\nimport { getFirstPathComponent, parsePathWithPrefix, normalizePathForProcessing } from '../../utils/path-normalization.js';\nimport { mapUniversalToPlatform } from './platform-mapper.js';\n\n/**\n * Parse a registry or universal path to extract subdir and relative path info\n * Platform suffix detection is always enabled and supports both file-level and directory-level suffixes.\n * @param path - The registry path from package files or universal path\n * @param options - Parsing options (allowPlatformSuffix is always true, kept for backward compatibility)\n * @returns Parsed information or null if not a universal subdir path\n */\nexport function parseUniversalPath(\n path: string,\n options: { allowPlatformSuffix?: boolean; cwd?: string } = {}\n): { universalSubdir: string; relPath: string; platformSuffix?: string } | null {\n // Check if path starts with universal subdirs (dynamically discovered)\n const state = getPlatformsState(options.cwd ?? null);\n const universalSubdirs = state.universalSubdirs;\n const knownPlatforms = getAllPlatforms({ includeDisabled: true }) as readonly Platform[];\n const normalized = normalizePathForProcessing(path);\n const withoutPrefix = normalized; // Strict v2: do not strip legacy .openpackage/ prefix\n\n for (const subdir of universalSubdirs) {\n const parsed = parsePathWithPrefix(withoutPrefix, subdir);\n if (parsed) {\n const remainingPath = parsed.remaining;\n let platformSuffix: string | undefined;\n let normalizedRelPath = remainingPath;\n\n // Platform suffix detection is always enabled (options.allowPlatformSuffix defaults to true)\n if (options.allowPlatformSuffix !== false) {\n // Check for directory-level platform suffix (e.g., commands/foo.cursor/bar.md)\n const segments = remainingPath.split('/');\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i];\n for (const platform of knownPlatforms) {\n if (segment.endsWith(`.${platform}`) && isPlatformId(platform)) {\n platformSuffix = platform;\n // Remove platform suffix from directory name for normalized path\n segments[i] = segment.slice(0, -platform.length - 1);\n normalizedRelPath = segments.join('/');\n break;\n }\n }\n if (platformSuffix) break;\n }\n\n // Check for file-level platform suffix (e.g., auth.cursor.md) if not already found\n if (!platformSuffix) {\n const parts = remainingPath.split('.');\n if (parts.length >= 3 && parts[parts.length - 1] === 'md') {\n // Check if the second-to-last part is a known platform\n const possiblePlatformSuffix = parts[parts.length - 2];\n if (isPlatformId(possiblePlatformSuffix)) {\n platformSuffix = possiblePlatformSuffix;\n // Remove platform suffix from filename\n const baseName = parts.slice(0, -2).join('.');\n normalizedRelPath = baseName + FILE_PATTERNS.MD_FILES;\n }\n }\n }\n }\n\n return {\n universalSubdir: subdir,\n relPath: normalizedRelPath,\n platformSuffix\n };\n }\n }\n\n return null;\n}\n\n/**\n * Get platform-specific filename for a universal path\n * Converts universal paths like \"rules/auth.md\" to platform-specific names like \"auth.mdc\"\n * @param universalPath - Universal path like \"rules/auth.md\"\n * @param platform - Target platform\n * @returns Platform-specific filename like \"auth.mdc\"\n */\nexport function getPlatformSpecificFilename(universalPath: string, platform: Platform, cwd?: string): string {\n const universalSubdir = getFirstPathComponent(universalPath);\n const registryFileName = basename(universalPath);\n\n const platformDef = getPlatformDefinition(platform, cwd);\n \n // TODO: Use export flows to determine extension transformation\n // For now, check export flows for extension mappings (package \u2192 workspace)\n if (platformDef.export && platformDef.export.length > 0) {\n for (const flow of platformDef.export) {\n // Skip switch expressions\n if (typeof flow.from === 'object' && '$switch' in flow.from) {\n continue;\n }\n // Check if this flow matches the universal path\n // For array patterns, use the first pattern\n const fromPattern = Array.isArray(flow.from) ? flow.from[0] : flow.from;\n if (fromPattern.includes(universalSubdir)) {\n const toPattern = typeof flow.to === 'string' ? flow.to : Object.keys(flow.to)[0];\n if (toPattern) {\n // Extract extension from 'to' pattern\n const toExtMatch = toPattern.match(/\\.[^./]+$/);\n const fromExtMatch = fromPattern.match(/\\.[^./]+$/);\n \n if (toExtMatch && fromExtMatch) {\n // Extension transformation found\n const fromExt = fromExtMatch[0];\n const toExt = toExtMatch[0];\n \n if (registryFileName.endsWith(fromExt)) {\n return registryFileName.slice(0, -fromExt.length) + toExt;\n }\n }\n }\n }\n }\n }\n\n // No transformation found, return original filename\n return registryFileName;\n}\n\n/**\n * Get platform-specific file path information (full paths with directories)\n * Wrapper around existing platform-mapper utilities for convenience\n * @param cwd - Current working directory\n * @param universalSubdir - Universal subdirectory\n * @param relPath - Relative path within the subdir\n * @param platform - Target platform\n * @returns Object with absolute directory and file paths\n */\nexport async function getPlatformSpecificPath(\n cwd: string,\n universalSubdir: string,\n relPath: string,\n platform: Platform\n): Promise<{ absDir: string; absFile: string }> {\n // Get the mapping\n const { relDir, relFile } = mapUniversalToPlatform(platform, universalSubdir, relPath, cwd);\n\n // Convert relative paths to absolute paths\n return {\n absDir: join(cwd, relDir),\n absFile: join(cwd, relFile)\n };\n}\n", "/**\n * JSONC (JSON with Comments) file utilities\n * Handles reading and parsing JSONC files with comment support\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { parse } from 'jsonc-parser';\nimport { logger } from './logger.js';\n\n/**\n * Get the project root directory by walking up from the current file's\n * location until we find platforms.jsonc (a known root marker).\n *\n * This approach is resilient to monorepo restructuring and esbuild bundling,\n * where the runtime __dirname may be at varying depths relative to the\n * repository root (e.g. packages/core/src/utils, packages/cli/dist, etc.).\n */\nfunction getProjectRoot(): string {\n const __filename = fileURLToPath(import.meta.url);\n let dir = dirname(__filename);\n\n // Walk up at most 10 levels to find the directory containing platforms.jsonc\n for (let i = 0; i < 10; i++) {\n if (existsSync(join(dir, 'platforms.jsonc'))) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break; // reached filesystem root\n dir = parent;\n }\n\n // Fallback: return two levels up (original behaviour) so we get a clear\n // error message pointing at the resolved path rather than a silent failure.\n const fallback = dirname(__filename);\n return join(fallback, '..', '..');\n}\n\n/**\n * Read and parse a JSONC file from the project root\n * @param relativePath - Path relative to project root (e.g., 'platforms.jsonc')\n * @returns Parsed JSON object\n */\nexport function readJsoncFileSync<T = unknown>(relativePath: string): T {\n const projectRoot = getProjectRoot();\n const fullPath = join(projectRoot, relativePath);\n \n try {\n const content = readFileSync(fullPath, 'utf-8');\n const parsed = parse(content);\n \n if (parsed === undefined) {\n throw new Error(`Failed to parse JSONC file: ${relativePath}`);\n }\n \n return parsed as T;\n } catch (error) {\n logger.error(`Failed to read JSONC file: ${relativePath}`, { error, fullPath });\n throw new Error(`Failed to read JSONC file ${relativePath}: ${error}`);\n }\n}\n\n/**\n * Read and parse a JSONC or JSON file from an absolute path.\n * Returns undefined if the file doesn't exist, parsing fails, or result is not a plain object.\n * @param fullPath - Absolute path to the file\n * @returns Parsed object or undefined\n */\nexport function readJsoncOrJson(fullPath: string): Record<string, any> | undefined {\n if (!existsSync(fullPath)) {\n return undefined;\n }\n\n try {\n const content = readFileSync(fullPath, 'utf-8');\n const parsed = parse(content);\n\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed) && parsed !== null) {\n return parsed as Record<string, any>;\n }\n } catch (error) {\n logger.warn(`Failed to parse JSONC/JSON file ${fullPath}: ${(error as Error).message}`);\n }\n\n return undefined;\n}\n\n", "/**\n * Switch Expression Resolver\n * \n * Resolves $switch expressions in flow configurations to concrete target paths.\n * Inspired by MongoDB's $switch aggregation operator.\n */\n\nimport { minimatch } from 'minimatch';\nimport type { SwitchExpression, SwitchCase, SwitchCaseValue, FlowContext } from '../../types/flows.js';\nimport { smartEquals } from '../../utils/path-comparison.js';\n\n/**\n * Result of resolving a switch expression\n * Contains both the resolved pattern string and optional schema\n */\nexport interface SwitchResolutionResult {\n /** Resolved pattern string */\n pattern: string;\n /** Optional schema path (if value was a FlowPattern with schema) */\n schema?: string;\n}\n\n/**\n * Extract pattern string from a SwitchCaseValue\n */\nfunction extractPattern(value: SwitchCaseValue): string {\n if (typeof value === 'string') {\n return value;\n }\n return value.pattern;\n}\n\n/**\n * Extract schema from a SwitchCaseValue (if present)\n */\nfunction extractSchema(value: SwitchCaseValue): string | undefined {\n if (typeof value === 'string') {\n return undefined;\n }\n return value.schema;\n}\n\n/**\n * Resolve a switch expression to a concrete target path\n * \n * Evaluates cases in order and returns the value of the first matching case.\n * If no cases match and a default is provided, returns the default.\n * If no cases match and no default exists, throws an error.\n * \n * @param switchExpr - The switch expression to resolve\n * @param context - Flow execution context with variables\n * @returns Resolved target path string (for backward compatibility)\n * @throws Error if no cases match and no default is provided\n */\nexport function resolveSwitchExpression(\n switchExpr: SwitchExpression,\n context: FlowContext\n): string {\n return resolveSwitchExpressionFull(switchExpr, context).pattern;\n}\n\n/**\n * Resolve a switch expression to a full result with pattern and optional schema\n * \n * @param switchExpr - The switch expression to resolve\n * @param context - Flow execution context with variables\n * @returns Full resolution result with pattern and optional schema\n * @throws Error if no cases match and no default is provided\n */\nexport function resolveSwitchExpressionFull(\n switchExpr: SwitchExpression,\n context: FlowContext\n): SwitchResolutionResult {\n const { field, cases, default: defaultValue } = switchExpr.$switch;\n\n // Resolve the field value from context variables\n const fieldValue = resolveFieldValue(field, context);\n\n // Evaluate cases in order (first match wins)\n for (const switchCase of cases) {\n if (matchesPattern(fieldValue, switchCase.pattern)) {\n return {\n pattern: extractPattern(switchCase.value),\n schema: extractSchema(switchCase.value),\n };\n }\n }\n\n // No match - return default or throw error\n if (defaultValue !== undefined) {\n return {\n pattern: extractPattern(defaultValue),\n schema: extractSchema(defaultValue),\n };\n }\n\n throw new Error(\n `No matching case in $switch expression for ${field}=${JSON.stringify(fieldValue)}, and no default provided`\n );\n}\n\n/**\n * Resolve a field value from context variables\n * Handles $$variable references\n */\nfunction resolveFieldValue(field: string, context: FlowContext): any {\n if (field.startsWith('$$')) {\n const varName = field.slice(2);\n if (!(varName in context.variables)) {\n throw new Error(`Variable '${varName}' not found in flow context`);\n }\n return context.variables[varName];\n }\n \n // Direct value (not a variable reference)\n return field;\n}\n\n/**\n * Check if a value matches a pattern\n * \n * Supports:\n * - String equality (using smartEquals for path normalization)\n * - Glob patterns (*, **, etc.)\n * - Object deep equality\n */\nfunction matchesPattern(value: any, pattern: string | object): boolean {\n // Object pattern - deep equality check\n if (typeof pattern === 'object' && pattern !== null) {\n return deepEquals(value, pattern);\n }\n\n // String pattern\n if (typeof pattern === 'string') {\n // If pattern contains glob characters, use minimatch\n if (pattern.includes('*') || pattern.includes('?') || pattern.includes('[')) {\n return minimatch(String(value), pattern);\n }\n\n // Exact match using smart comparison (handles ~/ normalization)\n return smartEquals(value, pattern);\n }\n\n // Fallback to strict equality\n return value === pattern;\n}\n\n/**\n * Deep equality check for objects\n */\nfunction deepEquals(a: any, b: any): boolean {\n if (a === b) return true;\n \n if (typeof a !== typeof b) return false;\n \n if (a === null || b === null) return a === b;\n \n if (typeof a !== 'object') return a === b;\n \n if (Array.isArray(a) !== Array.isArray(b)) return false;\n \n if (Array.isArray(a)) {\n if (a.length !== b.length) return false;\n return a.every((item, index) => deepEquals(item, b[index]));\n }\n \n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n \n if (keysA.length !== keysB.length) return false;\n \n return keysA.every(key => keysB.includes(key) && deepEquals(a[key], b[key]));\n}\n\n/**\n * Validate a switch expression\n * Returns validation result with error messages\n */\nexport function validateSwitchExpression(\n switchExpr: SwitchExpression\n): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (!switchExpr.$switch) {\n errors.push('Switch expression must have $switch property');\n return { valid: false, errors };\n }\n\n const { field, cases, default: defaultValue } = switchExpr.$switch;\n\n // Validate field\n if (!field) {\n errors.push('Switch expression missing required field: field');\n } else if (typeof field !== 'string') {\n errors.push('Switch expression field must be a string');\n }\n\n // Validate cases\n if (!cases) {\n errors.push('Switch expression missing required field: cases');\n } else if (!Array.isArray(cases)) {\n errors.push('Switch expression cases must be an array');\n } else if (cases.length === 0) {\n errors.push('Switch expression must have at least one case');\n } else {\n // Validate each case\n cases.forEach((switchCase, index) => {\n if (!switchCase || typeof switchCase !== 'object') {\n errors.push(`Case at index ${index} must be an object`);\n return;\n }\n\n if (!('pattern' in switchCase)) {\n errors.push(`Case at index ${index} missing required field: pattern`);\n }\n\n if (!('value' in switchCase)) {\n errors.push(`Case at index ${index} missing required field: value`);\n } else if (!isValidSwitchCaseValue(switchCase.value)) {\n errors.push(`Case at index ${index} value must be a string or object with 'pattern' field`);\n }\n });\n }\n\n // Validate default (optional, but must be valid SwitchCaseValue if provided)\n if (defaultValue !== undefined && !isValidSwitchCaseValue(defaultValue)) {\n errors.push('Switch expression default must be a string or object with \\'pattern\\' field');\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Check if a value is a valid SwitchCaseValue (string or FlowPattern with pattern field)\n */\nfunction isValidSwitchCaseValue(value: unknown): boolean {\n if (typeof value === 'string') {\n return true;\n }\n if (typeof value === 'object' && value !== null && 'pattern' in value) {\n const pattern = (value as { pattern: unknown }).pattern;\n return typeof pattern === 'string';\n }\n return false;\n}\n", "/**\n * Path Comparison Utilities\n * \n * Provides path-aware comparison with support for:\n * - Tilde expansion (~/)\n * - Path normalization\n * - Glob pattern matching\n * - Cross-platform compatibility\n */\n\nimport * as path from 'path';\nimport * as os from 'os';\nimport { minimatch } from 'minimatch';\n\n/**\n * Check if a string looks like a filesystem path\n */\nexport function isPathLike(value: any): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n\n // Check for common path patterns\n return (\n value.includes('/') || // Unix-style path\n value.includes('\\\\') || // Windows-style path\n value.startsWith('~') || // Home directory reference\n value.match(/^[A-Za-z]:/) !== null // Windows drive letter\n );\n}\n\n/**\n * Expand tilde (~) to home directory\n */\nexport function expandTilde(filepath: string): string {\n if (!filepath) {\n return filepath;\n }\n\n if (filepath === '~') {\n return os.homedir();\n }\n\n if (filepath.startsWith('~/')) {\n return path.join(os.homedir(), filepath.slice(2));\n }\n\n return filepath;\n}\n\n/**\n * Check if a pattern contains glob characters\n */\nexport function hasGlobChars(pattern: string): boolean {\n return /[*?[\\]{}]/.test(pattern);\n}\n\n/**\n * Compare two paths with support for:\n * - Tilde expansion\n * - Path normalization\n * - Glob pattern matching\n * \n * @param value - The actual path value to test\n * @param pattern - The pattern to match against (can include globs)\n * @returns true if the paths match\n */\nexport function comparePathsWithGlobSupport(value: string, pattern: string): boolean {\n // Expand tildes in both paths\n const expandedValue = expandTilde(value);\n const expandedPattern = expandTilde(pattern);\n\n // Normalize paths to handle . and .. correctly\n const normalizedValue = path.normalize(expandedValue);\n const normalizedPattern = path.normalize(expandedPattern);\n\n // If pattern contains glob characters, use minimatch\n if (hasGlobChars(normalizedPattern)) {\n return minimatch(normalizedValue, normalizedPattern, {\n dot: true, // Match dotfiles\n nocase: process.platform === 'win32' // Case-insensitive on Windows\n });\n }\n\n // Otherwise do exact string comparison\n // On Windows, normalize case for comparison\n if (process.platform === 'win32') {\n return normalizedValue.toLowerCase() === normalizedPattern.toLowerCase();\n }\n\n return normalizedValue === normalizedPattern;\n}\n\n/**\n * Smart equality comparison with automatic path handling\n * \n * If either value looks like a path, uses path-aware comparison.\n * Otherwise, uses standard equality.\n * \n * @param left - Left operand\n * @param right - Right operand\n * @returns true if values are equal\n */\nexport function smartEquals(left: any, right: any): boolean {\n // If either looks like a path, use path comparison\n if (isPathLike(left) || isPathLike(right)) {\n // Convert both to strings for path comparison\n const leftStr = String(left);\n const rightStr = String(right);\n return comparePathsWithGlobSupport(leftStr, rightStr);\n }\n\n // Standard equality\n return left === right;\n}\n\n/**\n * Smart inequality comparison with automatic path handling\n * \n * @param left - Left operand\n * @param right - Right operand\n * @returns true if values are not equal\n */\nexport function smartNotEquals(left: any, right: any): boolean {\n return !smartEquals(left, right);\n}\n", "/**\n * Universal Pattern Matching Module\n * \n * Uses minimatch for reliable glob pattern matching\n */\n\nimport { minimatch } from 'minimatch';\nimport { normalizePathForProcessing } from '../utils/path-normalization.js';\n\n/**\n * Check if a file path matches a glob pattern.\n */\nexport function isPatternMatch(filePath: string, pattern: string): boolean {\n const normalizedPath = normalizePathForProcessing(filePath);\n const normalizedPattern = normalizePathForProcessing(pattern);\n \n return minimatch(normalizedPath, normalizedPattern, {\n dot: false, // Don't match dotfiles by default\n nocase: false, // Case-sensitive matching\n matchBase: false, // Don't match basename only\n });\n}\n\n/**\n * Check if a file path matches any pattern in a set of glob patterns.\n */\nexport function matchesAnyPattern(filePath: string, patterns: Set<string>): boolean {\n const normalized = normalizePathForProcessing(filePath);\n \n for (const pattern of patterns) {\n if (isPatternMatch(normalized, pattern)) {\n return true;\n }\n }\n \n return false;\n}\n\n/**\n * Extract the first path component (directory or file) from a pattern or path.\n */\nexport function extractFirstComponent(pathOrPattern: string): string | null {\n const normalized = normalizePathForProcessing(pathOrPattern);\n if (!normalized) return null;\n \n const parts = normalized.split('/');\n return parts[0] || null;\n}\n\n/**\n * Check if a pattern represents a subdirectory (not a root-level file).\n */\nexport function isSubdirectoryPattern(pattern: string): boolean {\n const firstComponent = extractFirstComponent(pattern);\n return firstComponent !== null && !firstComponent.includes('.');\n}\n\n/**\n * Extract all subdirectory names from a set of patterns.\n */\nexport function extractSubdirectoriesFromPatterns(patterns: Set<string>): Set<string> {\n const subdirs = new Set<string>();\n \n for (const pattern of patterns) {\n if (isSubdirectoryPattern(pattern)) {\n const firstComponent = extractFirstComponent(pattern);\n if (firstComponent) {\n subdirs.add(firstComponent);\n }\n }\n }\n \n return subdirs;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["join", "sourceExt", "targetExt", "path", "dirname", "join", "dirname", "join", "os", "minimatch", "minimatch", "minimatch", "minimatch", "extractPatternString", "join", "join", "globalConfig", "extractPatternString", "join", "getDetectedPlatforms"]
7
+ }
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolvePackageByName
4
+ } from "./chunk-3PZRVA6O.js";
5
+ import {
6
+ detectPluginType
7
+ } from "./chunk-HYKYECAE.js";
8
+ import {
9
+ isValidPackageDirectory
10
+ } from "./chunk-GSWHZBT2.js";
11
+ import {
12
+ parsePackageInstallSpec
13
+ } from "./chunk-VN22A7NW.js";
14
+ import {
15
+ CLAUDE_PLUGIN_PATHS,
16
+ DIR_PATTERNS,
17
+ FILE_PATTERNS
18
+ } from "./chunk-IHVZ5AUJ.js";
19
+ import {
20
+ exists
21
+ } from "./chunk-S47F4OG4.js";
22
+ import {
23
+ ValidationError
24
+ } from "./chunk-ID4SVDQZ.js";
25
+ import {
26
+ logger
27
+ } from "./chunk-5EFWGD33.js";
28
+
29
+ // ../core/src/core/install/package-input.ts
30
+ import { resolve, isAbsolute } from "path";
31
+
32
+ // ../core/src/utils/git-url-detection.ts
33
+ function detectGitSource(input) {
34
+ if (!input || typeof input != "string")
35
+ return null;
36
+ let legacy = parseLegacyPrefix(input);
37
+ if (legacy)
38
+ return legacy;
39
+ let ghShorthand = parseGitHubShorthand(input);
40
+ if (ghShorthand)
41
+ return ghShorthand;
42
+ let ghUrl = parseGitHubUrl(input);
43
+ if (ghUrl)
44
+ return ghUrl;
45
+ let genericGit = parseGenericGitUrl(input);
46
+ return genericGit || null;
47
+ }
48
+ function parseGitHubShorthand(input) {
49
+ if (!input.startsWith("gh@"))
50
+ return null;
51
+ let remainder = input.slice(3);
52
+ if (!remainder)
53
+ throw new ValidationError(
54
+ `Invalid GitHub shorthand 'gh@'. Expected format: gh@owner/repo[/path]
55
+
56
+ Examples:
57
+ gh@anthropics/claude-code
58
+ gh@user/repo/plugins/my-plugin`
59
+ );
60
+ let segments = remainder.split("/").filter((s) => s.length > 0);
61
+ if (segments.length < 2)
62
+ throw new ValidationError(
63
+ `Invalid GitHub shorthand '${input}'. Expected format: gh@owner/repo[/path]
64
+
65
+ Examples:
66
+ gh@anthropics/claude-code
67
+ gh@user/repo/plugins/my-plugin`
68
+ );
69
+ let owner = segments[0], repo = segments[1], url = normalizeGitHubUrl(owner, repo), path = segments.length > 2 ? segments.slice(2).join("/") : void 0;
70
+ return logger.debug("Parsed GitHub shorthand", { input, owner, repo, path, url }), {
71
+ url,
72
+ ref: void 0,
73
+ // GitHub shorthand always uses default branch
74
+ path
75
+ };
76
+ }
77
+ function parseGitHubUrl(input) {
78
+ let url;
79
+ try {
80
+ url = new URL(input);
81
+ } catch {
82
+ return null;
83
+ }
84
+ if (url.hostname !== "github.com")
85
+ return null;
86
+ let segments = url.pathname.split("/").filter((s) => s.length > 0);
87
+ if (segments.length < 2)
88
+ throw new ValidationError(
89
+ `Invalid GitHub URL. Expected: https://github.com/owner/repo
90
+
91
+ Got: ${input}`
92
+ );
93
+ let owner = segments[0], repo = segments[1];
94
+ repo.endsWith(".git") && (repo = repo.slice(0, -4));
95
+ let normalizedUrl = normalizeGitHubUrl(owner, repo), ref, path;
96
+ if (segments.length > 2) {
97
+ let pathType = segments[2];
98
+ if (pathType === "blob")
99
+ throw new ValidationError(
100
+ `Cannot install from single file URL
101
+
102
+ You provided:
103
+ ${input}
104
+
105
+ To install a package, use:
106
+ \u2022 Repository: https://github.com/${owner}/${repo}
107
+ \u2022 With branch: https://github.com/${owner}/${repo}/tree/main
108
+ \u2022 Subdirectory: https://github.com/${owner}/${repo}/tree/main/plugins/x
109
+ \u2022 Shorthand: gh@${owner}/${repo}/plugins/x`
110
+ );
111
+ if (pathType === "tree") {
112
+ if (segments.length < 4)
113
+ throw new ValidationError(
114
+ `Invalid GitHub URL. Ref is required after /tree/
115
+
116
+ Got: ${input}
117
+
118
+ Expected: https://github.com/${owner}/${repo}/tree/<ref>[/path]`
119
+ );
120
+ ref = decodeURIComponent(segments[3]), segments.length > 4 && (path = segments.slice(4).map((s) => decodeURIComponent(s)).join("/"));
121
+ }
122
+ }
123
+ return logger.debug("Parsed GitHub URL", { input, owner, repo, ref, path, url: normalizedUrl }), {
124
+ url: normalizedUrl,
125
+ ref,
126
+ path
127
+ };
128
+ }
129
+ function parseGenericGitUrl(input) {
130
+ if (!isGitUrl(input))
131
+ return null;
132
+ let [baseUrl, hashPart] = input.split("#", 2), result = {
133
+ url: baseUrl
134
+ };
135
+ if (hashPart) {
136
+ let { ref, path } = parseHashFragment(hashPart, input);
137
+ ref && (result.ref = ref), path && (result.path = path);
138
+ }
139
+ return logger.debug("Parsed generic git URL", { input, ...result }), result;
140
+ }
141
+ function parseLegacyPrefix(input) {
142
+ if (input.startsWith("github:")) {
143
+ logger.warn("\u26A0\uFE0F The 'github:' prefix is deprecated. Use 'gh@user/repo' instead.");
144
+ let remainder = input.slice(7), [repoPart, hashPart] = remainder.split("#", 2), [owner, repo] = repoPart.split("/");
145
+ if (!owner || !repo)
146
+ throw new ValidationError(
147
+ `Invalid github spec '${input}'. Expected github:owner/repo[#ref][&subdirectory=path]`
148
+ );
149
+ let result = { url: normalizeGitHubUrl(owner, repo) };
150
+ if (hashPart) {
151
+ let { ref, path } = parseHashFragment(hashPart, input);
152
+ ref && (result.ref = ref), path && (result.path = path);
153
+ }
154
+ return result;
155
+ }
156
+ if (input.startsWith("git:")) {
157
+ logger.warn("\u26A0\uFE0F The 'git:' prefix is deprecated. Use the URL directly.");
158
+ let remainder = input.slice(4), [url, hashPart] = remainder.split("#", 2);
159
+ if (!url)
160
+ throw new ValidationError(
161
+ `Invalid git spec '${input}'. Expected git:<url>[#ref][&subdirectory=path]`
162
+ );
163
+ let result = { url };
164
+ if (hashPart) {
165
+ let { ref, path } = parseHashFragment(hashPart, input);
166
+ ref && (result.ref = ref), path && (result.path = path);
167
+ }
168
+ return result;
169
+ }
170
+ return null;
171
+ }
172
+ function parseHashFragment(hashPart, fullInput) {
173
+ let result = {}, parts = hashPart.split("&");
174
+ for (let part of parts)
175
+ if (part)
176
+ if (part.includes("=")) {
177
+ let eqIndex = part.indexOf("="), key = part.slice(0, eqIndex), value = part.slice(eqIndex + 1);
178
+ if (key === "path" || key === "subdirectory")
179
+ result.path = value;
180
+ else
181
+ throw new ValidationError(
182
+ `Invalid hash fragment '#${hashPart}'
183
+
184
+ Unknown parameter: ${key}
185
+
186
+ Supported parameters:
187
+ \u2022 ref (unnamed): #main
188
+ \u2022 path: #path=plugins/x
189
+ \u2022 combined: #main&path=plugins/x`
190
+ );
191
+ } else {
192
+ if (result.ref)
193
+ throw new ValidationError(
194
+ `Multiple refs specified in hash fragment
195
+
196
+ Got: #${hashPart}
197
+
198
+ Use only one ref: #main or #v1.0.0`
199
+ );
200
+ result.ref = part;
201
+ }
202
+ return result;
203
+ }
204
+ function isGitUrl(input) {
205
+ return input.startsWith("https://") || input.startsWith("http://") || input.startsWith("git://") || input.startsWith("git@") || input.endsWith(".git");
206
+ }
207
+ function normalizeGitHubUrl(owner, repo) {
208
+ let cleanRepo = repo.endsWith(".git") ? repo.slice(0, -4) : repo;
209
+ return `https://github.com/${owner}/${cleanRepo}.git`;
210
+ }
211
+
212
+ // ../core/src/core/install/package-input.ts
213
+ async function classifyPackageInput(raw, cwd = process.cwd()) {
214
+ let gitSpec = detectGitSource(raw);
215
+ if (gitSpec)
216
+ return {
217
+ type: "git",
218
+ gitUrl: gitSpec.url,
219
+ gitRef: gitSpec.ref,
220
+ gitPath: gitSpec.path
221
+ };
222
+ let isTarballPath = raw.endsWith(FILE_PATTERNS.TGZ_FILES) || raw.endsWith(FILE_PATTERNS.TAR_GZ_FILES), looksLikePath = raw.startsWith("/") || raw.startsWith("./") || raw.startsWith("../") || raw === "." || raw.startsWith("~/") || raw.startsWith(DIR_PATTERNS.OPENPACKAGE + "/") || // Include .openpackage paths
223
+ isAbsolute(raw) && !raw.includes("@");
224
+ if (isTarballPath || looksLikePath) {
225
+ let resolvedPath = isAbsolute(raw) ? raw : resolve(cwd, raw);
226
+ if (isTarballPath && await exists(resolvedPath))
227
+ return { type: "tarball", resolvedPath };
228
+ let isValid = await isValidPackageDirectory(resolvedPath), pluginDetection = await detectPluginType(resolvedPath);
229
+ if (isValid || pluginDetection.isPlugin)
230
+ return { type: "directory", resolvedPath };
231
+ if (await exists(resolvedPath))
232
+ throw new ValidationError(
233
+ `Path '${raw}' exists but is not a valid OpenPackage directory or Claude Code plugin. Valid packages must contain ${FILE_PATTERNS.OPENPACKAGE_YML} or ${CLAUDE_PLUGIN_PATHS.PLUGIN_MANIFEST}`
234
+ );
235
+ }
236
+ if (!looksLikePath && !isTarballPath) {
237
+ let resolution = await resolvePackageByName({
238
+ cwd,
239
+ packageName: raw,
240
+ checkCwd: !1,
241
+ // Install doesn't prioritize CWD
242
+ searchWorkspace: !0,
243
+ // Search workspace packages
244
+ searchGlobal: !0,
245
+ // Search global packages
246
+ searchRegistry: !0
247
+ // Search registry (install needs this)
248
+ });
249
+ if (resolution.found && resolution.path)
250
+ return logger.info("Resolved package name to path for install", {
251
+ packageName: raw,
252
+ path: resolution.path,
253
+ sourceType: resolution.sourceType
254
+ }), {
255
+ type: "directory",
256
+ resolvedPath: resolution.path,
257
+ sourceComparisonInfo: resolution.resolutionInfo
258
+ };
259
+ }
260
+ try {
261
+ let { name, version, registryPath } = parsePackageInstallSpec(raw);
262
+ return { type: "registry", name, version, registryPath };
263
+ } catch {
264
+ return { type: "registry", name: raw };
265
+ }
266
+ }
267
+
268
+ export {
269
+ detectGitSource,
270
+ parseGitHubShorthand,
271
+ parseGitHubUrl,
272
+ classifyPackageInput
273
+ };
274
+ //# sourceMappingURL=chunk-OUZRMGPV.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../core/src/core/install/package-input.ts", "../../core/src/utils/git-url-detection.ts"],
4
+ "sourcesContent": ["import { resolve, isAbsolute } from 'path';\nimport { exists } from '../../utils/fs.js';\nimport { isValidPackageDirectory } from '../package-context.js';\nimport { parsePackageInstallSpec } from '../../utils/package-name.js';\nimport { ValidationError } from '../../utils/errors.js';\nimport { detectGitSource } from '../../utils/git-url-detection.js';\nimport { logger } from '../../utils/logger.js';\nimport {\n resolvePackageByName,\n type PackageSourceCandidate,\n type SourceResolutionInfo\n} from '../package-name-resolution.js';\nimport { detectPluginType } from './plugin-detector.js';\nimport { DIR_PATTERNS, FILE_PATTERNS, CLAUDE_PLUGIN_PATHS } from '../../constants/index.js';\n\nexport type PackageInputType = 'registry' | 'directory' | 'tarball' | 'git';\n\nexport interface PackageInputClassification {\n type: PackageInputType;\n \n // For 'registry' type\n name?: string;\n version?: string;\n registryPath?: string;\n\n // For 'git' type\n gitUrl?: string;\n gitRef?: string;\n gitPath?: string;\n \n // For 'directory' or 'tarball' types\n resolvedPath?: string; // Absolute path\n \n // For version-aware resolution metadata\n sourceComparisonInfo?: SourceResolutionInfo;\n}\n\n// Re-export types from package-name-resolution for backward compatibility\nexport type { PackageSourceCandidate, SourceResolutionInfo as SourceComparisonInfo };\n\n/**\n * Classify whether input is a registry package name, local directory, or tarball.\n * \n * Detection order:\n * 1. Ends with .tgz or .tar.gz AND file exists -> 'tarball'\n * 2. Starts with /, ./, ../, or is . AND isValidPackageDirectory -> 'directory'\n * 3. Otherwise -> parse as registry name via parsePackageInstallSpec\n * \n * @param raw - The raw input string from the user\n * @param cwd - Current working directory for resolving relative paths\n * @returns Classification of the input type and relevant information\n */\nexport async function classifyPackageInput(\n raw: string,\n cwd: string = process.cwd()\n): Promise<PackageInputClassification> {\n // Check for git sources first (new detection system)\n const gitSpec = detectGitSource(raw);\n if (gitSpec) {\n return {\n type: 'git',\n gitUrl: gitSpec.url,\n gitRef: gitSpec.ref,\n gitPath: gitSpec.path\n };\n }\n\n // Check for tarball file extension\n const isTarballPath = raw.endsWith(FILE_PATTERNS.TGZ_FILES) || raw.endsWith(FILE_PATTERNS.TAR_GZ_FILES);\n \n // Check if input looks like a path\n const looksLikePath = raw.startsWith('/') ||\n raw.startsWith('./') ||\n raw.startsWith('../') ||\n raw === '.' ||\n raw.startsWith('~/') ||\n raw.startsWith(DIR_PATTERNS.OPENPACKAGE + '/') || // Include .openpackage paths\n (isAbsolute(raw) && !raw.includes('@'));\n \n if (isTarballPath || looksLikePath) {\n const resolvedPath = isAbsolute(raw) ? raw : resolve(cwd, raw);\n \n if (isTarballPath) {\n if (await exists(resolvedPath)) {\n return { type: 'tarball', resolvedPath };\n }\n // File doesn't exist - fall through to treat as registry name\n // (will error later with \"file not found\" or \"package not found\")\n }\n \n // Check if it's a valid package directory OR a plugin\n const isValid = await isValidPackageDirectory(resolvedPath);\n const pluginDetection = await detectPluginType(resolvedPath);\n \n if (isValid || pluginDetection.isPlugin) {\n return { type: 'directory', resolvedPath };\n }\n \n // Path exists but isn't a valid package? Error\n if (await exists(resolvedPath)) {\n throw new ValidationError(\n `Path '${raw}' exists but is not a valid OpenPackage directory or Claude Code plugin. ` +\n `Valid packages must contain ${FILE_PATTERNS.OPENPACKAGE_YML} or ${CLAUDE_PLUGIN_PATHS.PLUGIN_MANIFEST}`\n );\n }\n }\n \n // Check if this looks like a simple package name (not an explicit path)\n // Search in workspace/global/registry packages using shared resolution\n if (!looksLikePath && !isTarballPath) {\n const resolution = await resolvePackageByName({\n cwd,\n packageName: raw,\n checkCwd: false, // Install doesn't prioritize CWD\n searchWorkspace: true, // Search workspace packages\n searchGlobal: true, // Search global packages \n searchRegistry: true // Search registry (install needs this)\n });\n\n if (resolution.found && resolution.path) {\n logger.info('Resolved package name to path for install', { \n packageName: raw, \n path: resolution.path,\n sourceType: resolution.sourceType\n });\n \n return { \n type: 'directory', \n resolvedPath: resolution.path,\n sourceComparisonInfo: resolution.resolutionInfo\n };\n }\n }\n \n // Treat as registry package name\n try {\n const { name, version, registryPath } = parsePackageInstallSpec(raw);\n return { type: 'registry', name, version, registryPath };\n } catch (error) {\n // If parsing fails, still return registry type - let downstream handle the error\n return { type: 'registry', name: raw };\n }\n}\n\n\n", "/**\n * Modern git source detection and parsing.\n * Supports:\n * - GitHub shorthand (gh@owner/repo[/path])\n * - GitHub web URLs (https://github.com/owner/repo/tree/ref/path)\n * - Generic git URLs with hash fragments (#ref&path=x)\n * - Legacy prefixes (github:, git:) with deprecation warnings\n */\n\nimport { ValidationError } from './errors.js';\nimport { logger } from './logger.js';\n\n/**\n * Parsed git source specification.\n */\nexport interface GitSpec {\n url: string; // Normalized git URL\n ref?: string; // Branch/tag/commit\n path?: string; // Subdirectory within repo\n}\n\n/**\n * Detect and parse git sources from user input.\n * Returns null if input is not a git source.\n * \n * Detection priority (by user intent):\n * 1. GitHub shorthand (gh@) - new explicit syntax\n * 2. URL protocols (https://, http://, git://, git@) - direct URLs\n * 3. Git file extension (.git) - any URL ending with .git\n * 4. Legacy prefixes (github:, git:) - deprecated, with warnings\n * \n * Implementation order (to avoid conflicts):\n * - Legacy prefixes checked first (they mask underlying URL patterns)\n * - GitHub shorthand (explicit new syntax)\n * - GitHub URLs (specific pattern matching)\n * - Generic git URLs (catch-all)\n * \n * @param input - Raw user input\n * @returns Parsed GitSpec or null if not a git source\n */\nexport function detectGitSource(input: string): GitSpec | null {\n if (!input || typeof input !== 'string') {\n return null;\n }\n\n // Check legacy prefixes first (they hide the URL underneath)\n const legacy = parseLegacyPrefix(input);\n if (legacy) {\n return legacy;\n }\n\n // GitHub shorthand (gh@owner/repo)\n const ghShorthand = parseGitHubShorthand(input);\n if (ghShorthand) {\n return ghShorthand;\n }\n\n // GitHub URLs (extract ref/path from URL structure)\n const ghUrl = parseGitHubUrl(input);\n if (ghUrl) {\n return ghUrl;\n }\n\n // Generic git URLs (with hash fragments)\n const genericGit = parseGenericGitUrl(input);\n if (genericGit) {\n return genericGit;\n }\n\n return null;\n}\n\n/**\n * Parse GitHub shorthand format: gh@owner/repo[/path]\n * \n * Examples:\n * - gh@anthropics/claude-code\n * - gh@user/repo/plugins/x\n * \n * @param input - Raw input string\n * @returns GitSpec or null if not GitHub shorthand\n */\nexport function parseGitHubShorthand(input: string): GitSpec | null {\n if (!input.startsWith('gh@')) {\n return null;\n }\n\n const remainder = input.slice(3); // Remove 'gh@'\n \n if (!remainder) {\n throw new ValidationError(\n `Invalid GitHub shorthand 'gh@'. Expected format: gh@owner/repo[/path]\\n\\n` +\n `Examples:\\n` +\n ` gh@anthropics/claude-code\\n` +\n ` gh@user/repo/plugins/my-plugin`\n );\n }\n\n const segments = remainder.split('/').filter(s => s.length > 0);\n \n if (segments.length < 2) {\n throw new ValidationError(\n `Invalid GitHub shorthand '${input}'. Expected format: gh@owner/repo[/path]\\n\\n` +\n `Examples:\\n` +\n ` gh@anthropics/claude-code\\n` +\n ` gh@user/repo/plugins/my-plugin`\n );\n }\n\n const owner = segments[0];\n const repo = segments[1];\n\n const url = normalizeGitHubUrl(owner, repo);\n const path = segments.length > 2 ? segments.slice(2).join('/') : undefined;\n\n logger.debug('Parsed GitHub shorthand', { input, owner, repo, path, url });\n\n return {\n url,\n ref: undefined, // GitHub shorthand always uses default branch\n path\n };\n}\n\n/**\n * Parse GitHub web URLs.\n * \n * Supported formats:\n * - https://github.com/owner/repo\n * - https://github.com/owner/repo.git\n * - https://github.com/owner/repo/tree/ref\n * - https://github.com/owner/repo/tree/ref/path\n * \n * @param input - Raw input string\n * @returns GitSpec or null if not a GitHub URL\n */\nexport function parseGitHubUrl(input: string): GitSpec | null {\n let url: URL;\n \n try {\n url = new URL(input);\n } catch {\n return null;\n }\n\n // Must be github.com\n if (url.hostname !== 'github.com') {\n return null;\n }\n\n const segments = url.pathname.split('/').filter(s => s.length > 0);\n \n if (segments.length < 2) {\n throw new ValidationError(\n `Invalid GitHub URL. Expected: https://github.com/owner/repo\\n\\n` +\n `Got: ${input}`\n );\n }\n\n const owner = segments[0];\n let repo = segments[1];\n \n // Strip .git suffix from repo if present\n if (repo.endsWith('.git')) {\n repo = repo.slice(0, -4);\n }\n\n const normalizedUrl = normalizeGitHubUrl(owner, repo);\n let ref: string | undefined;\n let path: string | undefined;\n\n // Check for /tree/ or /blob/ paths\n if (segments.length > 2) {\n const pathType = segments[2];\n \n if (pathType === 'blob') {\n throw new ValidationError(\n `Cannot install from single file URL\\n\\n` +\n `You provided:\\n` +\n ` ${input}\\n\\n` +\n `To install a package, use:\\n` +\n ` \u2022 Repository: https://github.com/${owner}/${repo}\\n` +\n ` \u2022 With branch: https://github.com/${owner}/${repo}/tree/main\\n` +\n ` \u2022 Subdirectory: https://github.com/${owner}/${repo}/tree/main/plugins/x\\n` +\n ` \u2022 Shorthand: gh@${owner}/${repo}/plugins/x`\n );\n }\n \n if (pathType === 'tree') {\n if (segments.length < 4) {\n throw new ValidationError(\n `Invalid GitHub URL. Ref is required after /tree/\\n\\n` +\n `Got: ${input}\\n\\n` +\n `Expected: https://github.com/${owner}/${repo}/tree/<ref>[/path]`\n );\n }\n \n ref = decodeURIComponent(segments[3]);\n \n // Path is everything after the ref\n if (segments.length > 4) {\n path = segments.slice(4).map(s => decodeURIComponent(s)).join('/');\n }\n }\n }\n\n logger.debug('Parsed GitHub URL', { input, owner, repo, ref, path, url: normalizedUrl });\n\n return {\n url: normalizedUrl,\n ref,\n path\n };\n}\n\n/**\n * Parse generic git URLs with hash fragments.\n * \n * Supported formats:\n * - https://host/path.git\n * - git://host/path\n * - git@host:path.git\n * - <any-git-url>#<ref>\n * - <any-git-url>#<ref>&path=<path>\n * - <any-git-url>#path=<path>\n * \n * @param input - Raw input string\n * @returns GitSpec or null if not a git URL\n */\nexport function parseGenericGitUrl(input: string): GitSpec | null {\n if (!isGitUrl(input)) {\n return null;\n }\n\n // Split by # to separate base URL and hash fragment\n const [baseUrl, hashPart] = input.split('#', 2);\n \n const result: GitSpec = {\n url: baseUrl\n };\n\n // Parse hash fragment if present\n if (hashPart) {\n const { ref, path } = parseHashFragment(hashPart, input);\n if (ref) result.ref = ref;\n if (path) result.path = path;\n }\n\n logger.debug('Parsed generic git URL', { input, ...result });\n\n return result;\n}\n\n/**\n * Parse legacy prefix formats with deprecation warnings.\n * \n * Supported formats:\n * - github:owner/repo[#ref][&subdirectory=path]\n * - git:<url>[#ref][&subdirectory=path]\n * \n * @param input - Raw input string\n * @returns GitSpec or null if not using legacy prefix\n */\nfunction parseLegacyPrefix(input: string): GitSpec | null {\n // Check for github: prefix\n if (input.startsWith('github:')) {\n logger.warn(`\u26A0\uFE0F The 'github:' prefix is deprecated. Use 'gh@user/repo' instead.`);\n \n const remainder = input.slice(7); // Remove 'github:'\n const [repoPart, hashPart] = remainder.split('#', 2);\n const [owner, repo] = repoPart.split('/');\n \n if (!owner || !repo) {\n throw new ValidationError(\n `Invalid github spec '${input}'. Expected github:owner/repo[#ref][&subdirectory=path]`\n );\n }\n \n const url = normalizeGitHubUrl(owner, repo);\n const result: GitSpec = { url };\n \n if (hashPart) {\n const { ref, path } = parseHashFragment(hashPart, input);\n if (ref) result.ref = ref;\n if (path) result.path = path;\n }\n \n return result;\n }\n \n // Check for git: prefix\n if (input.startsWith('git:')) {\n logger.warn(`\u26A0\uFE0F The 'git:' prefix is deprecated. Use the URL directly.`);\n \n const remainder = input.slice(4); // Remove 'git:'\n const [url, hashPart] = remainder.split('#', 2);\n \n if (!url) {\n throw new ValidationError(\n `Invalid git spec '${input}'. Expected git:<url>[#ref][&subdirectory=path]`\n );\n }\n \n const result: GitSpec = { url };\n \n if (hashPart) {\n const { ref, path } = parseHashFragment(hashPart, input);\n if (ref) result.ref = ref;\n if (path) result.path = path;\n }\n \n return result;\n }\n \n return null;\n}\n\n/**\n * Parse hash fragment for ref and path parameters.\n * \n * Supported formats:\n * - #<ref>\n * - #path=<path>\n * - #subdirectory=<path> (backward compat, no warning)\n * - #<ref>&path=<path>\n * - #<ref>&subdirectory=<path>\n * \n * @param hashPart - Hash fragment (without #)\n * @param fullInput - Full input for error messages\n * @returns Object with ref and path\n */\nfunction parseHashFragment(\n hashPart: string,\n fullInput: string\n): { ref?: string; path?: string } {\n const result: { ref?: string; path?: string } = {};\n \n // Split by & to get parts\n const parts = hashPart.split('&');\n \n for (const part of parts) {\n if (!part) continue;\n \n if (part.includes('=')) {\n // It's a key=value parameter\n const eqIndex = part.indexOf('=');\n const key = part.slice(0, eqIndex);\n const value = part.slice(eqIndex + 1);\n \n if (key === 'path' || key === 'subdirectory') {\n result.path = value;\n } else {\n throw new ValidationError(\n `Invalid hash fragment '#${hashPart}'\\n\\n` +\n `Unknown parameter: ${key}\\n\\n` +\n `Supported parameters:\\n` +\n ` \u2022 ref (unnamed): #main\\n` +\n ` \u2022 path: #path=plugins/x\\n` +\n ` \u2022 combined: #main&path=plugins/x`\n );\n }\n } else {\n // It's the ref (branch/tag/sha)\n if (result.ref) {\n throw new ValidationError(\n `Multiple refs specified in hash fragment\\n\\n` +\n `Got: #${hashPart}\\n\\n` +\n `Use only one ref: #main or #v1.0.0`\n );\n }\n result.ref = part;\n }\n }\n \n return result;\n}\n\n/**\n * Check if input looks like a git URL.\n * \n * Detection criteria:\n * - Starts with git protocol: https://, http://, git://, git@\n * - Ends with .git extension\n */\nexport function isGitUrl(input: string): boolean {\n return (\n input.startsWith('https://') ||\n input.startsWith('http://') ||\n input.startsWith('git://') ||\n input.startsWith('git@') ||\n input.endsWith('.git')\n );\n}\n\n/**\n * Normalize GitHub owner/repo to full git URL.\n * \n * @param owner - GitHub username or org\n * @param repo - Repository name\n * @returns Normalized GitHub git URL\n */\nexport function normalizeGitHubUrl(owner: string, repo: string): string {\n // Ensure repo doesn't have .git suffix for consistent handling\n const cleanRepo = repo.endsWith('.git') ? repo.slice(0, -4) : repo;\n return `https://github.com/${owner}/${cleanRepo}.git`;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }