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/workspace-package-context.ts", "../../core/src/utils/expand-directory-selections.ts", "../src/utils/interactive-file-selector.ts", "../src/utils/file-selector-with-header.ts", "../../core/src/utils/file-scanner.ts", "../../core/src/utils/source-operation-arguments.ts"],
4
+ "sourcesContent": ["import { join, basename } from 'path';\n\nimport { FILE_PATTERNS } from '../constants/index.js';\nimport { ensureLocalOpenPackageStructure, createWorkspacePackageYml } from './package-management.js';\nimport { getLocalOpenPackageDir } from '../utils/paths.js';\nimport { parsePackageYml } from '../utils/package-yml.js';\nimport type { PackageYml } from '../types/index.js';\n\n/**\n * Workspace package context for add/remove operations.\n * Contains essential package metadata for operating on workspace root (.openpackage/).\n */\nexport interface WorkspacePackageContext {\n /** Package name (from manifest or workspace directory name) */\n name: string;\n /** Package version (if specified in manifest) */\n version?: string;\n /** Full package configuration from openpackage.yml */\n config: PackageYml;\n /** Absolute path to package manifest (openpackage.yml) */\n packageYmlPath: string;\n /** Root directory of the package (.openpackage/) */\n packageRootDir: string;\n /** Directory containing package files (same as root for workspace packages) */\n packageFilesDir: string;\n}\n\n/**\n * Build workspace package context for operations on workspace root (.openpackage/).\n * \n * This utility creates or ensures the workspace package structure exists and loads\n * the manifest configuration. Used by add/remove commands when operating on the\n * workspace root (no specific package specified via --to/--from).\n * \n * @param cwd - Current working directory\n * @returns Workspace package context with loaded configuration\n * @throws Error if manifest cannot be read\n * \n * @example\n * // Add command: opkg add ./file.md (no --to option)\n * const context = await buildWorkspacePackageContext(cwd);\n * // Files will be added to context.packageRootDir (.openpackage/)\n * \n * @example\n * // Remove command: opkg remove agents/my-agent (no --from option)\n * const context = await buildWorkspacePackageContext(cwd);\n * // Files will be removed from context.packageRootDir (.openpackage/)\n */\nexport async function buildWorkspacePackageContext(\n cwd: string\n): Promise<WorkspacePackageContext> {\n // Ensure .openpackage/ structure exists\n await ensureLocalOpenPackageStructure(cwd);\n\n // Create workspace manifest if it doesn't exist\n await createWorkspacePackageYml(cwd);\n\n const openpackageDir = getLocalOpenPackageDir(cwd);\n const packageYmlPath = join(openpackageDir, FILE_PATTERNS.OPENPACKAGE_YML);\n\n // Load workspace manifest\n let config: PackageYml;\n try {\n config = await parsePackageYml(packageYmlPath);\n } catch (error) {\n throw new Error(\n `Failed to read workspace manifest at ${packageYmlPath}: ${error}`\n );\n }\n\n // Use workspace directory name as package name if not specified in manifest\n const packageName = config.name || basename(cwd);\n\n return {\n name: packageName,\n version: config.version,\n config,\n packageYmlPath,\n packageRootDir: openpackageDir,\n packageFilesDir: openpackageDir\n };\n}\n\n/**\n * Ensure workspace package structure exists and is initialized.\n * This is a convenience wrapper around ensureLocalOpenPackageStructure and createWorkspacePackageYml.\n * \n * @param cwd - Current working directory\n * \n * @example\n * // Ensure workspace is ready before performing operations\n * await ensureWorkspacePackageExists(cwd);\n * // Now .openpackage/ directory and openpackage.yml exist\n */\nexport async function ensureWorkspacePackageExists(cwd: string): Promise<void> {\n await ensureLocalOpenPackageStructure(cwd);\n await createWorkspacePackageYml(cwd);\n}\n", "/**\n * Directory Selection Expansion Utility\n * \n * Expands directory selections (paths ending with '/') into all files within them.\n * Used by add and remove commands to handle directory selections from interactive file selector.\n */\n\nimport { join, relative } from 'path';\nimport { promises as fs } from 'fs';\nimport { walkFiles } from './file-walker.js';\nimport { isJunk } from 'junk';\n\n/**\n * Expand directory selections into individual file paths\n * \n * @param selectedPaths - Array of selected paths (files and directories with '/' suffix)\n * @param basePath - Base directory path for resolving relative paths\n * @returns Array of individual file paths (no directories)\n * \n * @example\n * const selections = ['src/', 'package.json', 'docs/readme.md'];\n * const expanded = await expandDirectorySelections(selections, '/workspace');\n * // Returns: ['src/index.ts', 'src/utils/helper.ts', 'package.json', 'docs/readme.md']\n */\nexport async function expandDirectorySelections(\n selectedPaths: string[],\n basePath: string\n): Promise<string[]> {\n const expandedFiles: string[] = [];\n const seenFiles = new Set<string>();\n \n for (const path of selectedPaths) {\n if (path.endsWith('/')) {\n // This is a directory - expand it to all files within\n const dirPath = path.slice(0, -1); // Remove trailing '/'\n const absDirPath = join(basePath, dirPath);\n \n // Check if directory exists\n try {\n const stat = await fs.stat(absDirPath);\n if (!stat.isDirectory()) {\n // Not a directory, skip\n continue;\n }\n } catch {\n // Directory doesn't exist or is inaccessible, skip\n continue;\n }\n \n // Walk all files in the directory\n const filter = (filePath: string, isDirectory: boolean) => {\n if (isDirectory) {\n return true; // Always traverse directories\n }\n \n // Filter out junk files\n const segments = filePath.split('/');\n const basename = segments[segments.length - 1];\n return !isJunk(basename);\n };\n \n for await (const filePath of walkFiles(absDirPath, { filter })) {\n // Convert to relative path from basePath (path.relative handles trailing slashes correctly)\n const relativePath = relative(basePath, filePath);\n \n // Only add if not already seen (avoid duplicates)\n if (!seenFiles.has(relativePath)) {\n seenFiles.add(relativePath);\n expandedFiles.push(relativePath);\n }\n }\n } else {\n // This is a regular file - add it directly if not already seen\n if (!seenFiles.has(path)) {\n seenFiles.add(path);\n expandedFiles.push(path);\n }\n }\n }\n \n return expandedFiles;\n}\n\n/**\n * Check if any selected paths are directories\n * \n * @param selectedPaths - Array of selected paths\n * @returns True if at least one path is a directory (ends with '/')\n */\nexport function hasDirectorySelections(selectedPaths: string[]): boolean {\n return selectedPaths.some(path => path.endsWith('/'));\n}\n\n/**\n * Count how many directories and files are in the selection\n * \n * @param selectedPaths - Array of selected paths\n * @returns Object with counts of directories and files\n */\nexport function countSelectionTypes(selectedPaths: string[]): { dirs: number; files: number } {\n let dirs = 0;\n let files = 0;\n \n for (const path of selectedPaths) {\n if (path.endsWith('/')) {\n dirs++;\n } else {\n files++;\n }\n }\n \n return { dirs, files };\n}\n", "/**\n * Interactive File Selector\n * \n * Provides fuzzy file selection with dynamic header showing selected files.\n * Uses custom AutocompletePrompt that updates the header in real-time.\n */\n\nimport { note, log } from '@clack/prompts';\nimport { promptFileSelector } from './file-selector-with-header.js';\nimport { scanWorkspaceFiles } from '@opkg/core/utils/file-scanner.js';\nimport { countSelectionTypes } from '@opkg/core/utils/expand-directory-selections.js';\nimport { logger } from '@opkg/core/utils/logger.js';\n\n/**\n * Options for interactive file selection\n */\nexport interface FileSelectionOptions {\n /** Base directory to scan from (default: process.cwd()) */\n cwd?: string;\n \n /** Specific directory path to scan (overrides cwd if provided) */\n basePath?: string;\n \n /** Prompt message to display (default: 'Select files') */\n message?: string;\n \n /** Placeholder text when no input (default: 'Type to search files...') */\n placeholder?: string;\n \n /** Maximum items to display at once (default: 10) */\n maxItems?: number;\n \n /** Additional directories to exclude from scanning */\n excludeDirs?: string[];\n \n /** Fuzzy search threshold (0-1, default: 0.5) */\n fuzzyThreshold?: number;\n \n /** Whether to include directories in results (default: false) */\n includeDirs?: boolean;\n}\n\n/**\n * Display an interactive fuzzy file selector with dynamic header\n * \n * Features:\n * - Dynamic header showing selected files (updates in real-time)\n * - Fuzzy search with real-time filtering\n * - Space to toggle selection\n * - Enter to confirm\n * \n * @param options - Selection options\n * @returns Array of selected relative file paths, or null if cancelled\n * \n * @example\n * const files = await interactiveFileSelect({ cwd: process.cwd() });\n * if (files) {\n * console.log('Selected:', files);\n * } else {\n * console.log('Cancelled');\n * }\n */\nexport async function interactiveFileSelect(\n options: FileSelectionOptions = {}\n): Promise<string[] | null> {\n const {\n cwd = process.cwd(),\n basePath,\n message,\n placeholder,\n maxItems = 10,\n excludeDirs = [],\n fuzzyThreshold = 0.5,\n includeDirs = false\n } = options;\n \n // Set smart defaults based on whether directories are included\n const finalMessage = message || (includeDirs ? 'Select files or directories to add' : 'Select files to add');\n const finalPlaceholder = placeholder || (includeDirs ? 'Type to search...' : 'Type to search files...');\n \n const scanDir = basePath || cwd;\n \n try {\n // Scan workspace for all files\n logger.debug('Scanning workspace for files', { scanDir });\n const allFiles = await scanWorkspaceFiles({ cwd, basePath, excludeDirs, includeDirs });\n \n // Check if any files found\n if (allFiles.length === 0) {\n logger.warn('No files found in workspace');\n note('No files found in the workspace directory', 'No Files');\n return null;\n }\n \n logger.debug(`Found ${allFiles.length} files to display`);\n \n // Display the file selector with dynamic header\n const selectedFiles = await promptFileSelector({\n message: finalMessage,\n files: allFiles,\n placeholder: finalPlaceholder,\n maxItems,\n fuzzyThreshold\n });\n \n // Check if user cancelled or selected nothing\n if (!selectedFiles || selectedFiles.length === 0) {\n logger.debug('No files selected or user cancelled');\n return null; // Prompt handles its own cancellation display\n }\n \n logger.debug(`User selected ${selectedFiles.length} file(s)`, { selectedFiles });\n\n // Show summary after selection (use dir/file counts when includeDirs)\n const fileList = selectedFiles.length <= 5\n ? selectedFiles.join('\\n')\n : selectedFiles.slice(0, 5).join('\\n') + `\\n... and ${selectedFiles.length - 5} more`;\n const countLabel = includeDirs\n ? (() => {\n const { dirs, files } = countSelectionTypes(selectedFiles);\n const parts: string[] = [];\n if (dirs > 0) parts.push(`${dirs} dir${dirs === 1 ? '' : 's'}`);\n if (files > 0) parts.push(`${files} file${files === 1 ? '' : 's'}`);\n return parts.join(' and ');\n })()\n : `${selectedFiles.length} file${selectedFiles.length === 1 ? '' : 's'}`;\n log.success(`Selected ${countLabel}:\\n${fileList}`);\n \n return selectedFiles;\n \n } catch (error) {\n logger.error('Error during file selection', { error });\n throw new Error(`File selection failed: ${error}`);\n }\n}\n\n/**\n * Display an interactive fuzzy file selector for single file selection\n * \n * @param options - Selection options\n * @returns Selected relative file path, or null if cancelled\n */\nexport async function interactiveFileSelectSingle(\n options: FileSelectionOptions = {}\n): Promise<string | null> {\n const result = await interactiveFileSelect({\n ...options,\n message: options.message || 'Select a file'\n });\n \n if (!result || result.length === 0) {\n return null;\n }\n \n // Return the first selected file\n return result[0];\n}\n", "/**\n * File Selector with Dynamic Header\n * \n * Custom AutocompletePrompt that shows selected files in a dynamic header\n * that updates in real-time as selections change.\n */\n\nimport { AutocompletePrompt, isCancel } from '@clack/core';\nimport { search } from 'fast-fuzzy';\nimport pico from 'picocolors';\nimport type { Key } from 'node:readline';\n\n/**\n * Options for file selector with dynamic header\n */\nexport interface FileSelectorOptions {\n /** Prompt message */\n message: string;\n \n /** All available files */\n files: string[];\n \n /** Placeholder text */\n placeholder?: string;\n \n /** Maximum items to show */\n maxItems?: number;\n \n /** Fuzzy search threshold */\n fuzzyThreshold?: number;\n}\n\n/**\n * File option for autocomplete\n */\ninterface FileOption {\n value: string;\n label: string;\n}\n\n/**\n * Custom AutocompletePrompt that shows selected files above the search UI\n */\nexport class FileSelectorWithHeader extends AutocompletePrompt<FileOption> {\n private allFiles: string[];\n private fuzzyThreshold: number;\n private message: string;\n private placeholder: string;\n private maxVisibleItems: number;\n\n constructor(options: FileSelectorOptions) {\n const fileOptions: FileOption[] = options.files.map(file => ({\n value: file,\n label: file\n }));\n\n super({\n options: fileOptions,\n multiple: true,\n render() {\n return this.renderWithHeader();\n }\n } as any);\n\n this.allFiles = options.files;\n this.message = options.message;\n this.placeholder = options.placeholder || 'Type to search...';\n this.maxVisibleItems = options.maxItems || 10;\n this.fuzzyThreshold = options.fuzzyThreshold || 0.5;\n\n // Override the options to provide dynamic filtering\n this.setupFuzzyFiltering();\n\n // Disable wrap-around: stay at top when pressing up at first item\n this.setupNoOverscroll();\n }\n\n /**\n * Prevent wrap-around: stay at top when pressing up at first item (don't jump to last)\n */\n private setupNoOverscroll(): void {\n this.on('key', (_char: string | undefined, key: Key) => {\n const len = this.filteredOptions.length;\n if (len <= 1) return;\n\n if (key.name === 'up' && this.cursor === len - 1) {\n // Cursor wrapped from 0 to end; emit synthetic down to undo\n this.emit('key', undefined, { name: 'down', ctrl: false, meta: false, shift: false } as Key);\n }\n });\n }\n\n /**\n * Setup fuzzy filtering based on user input\n */\n private setupFuzzyFiltering(): void {\n // Listen to userInput changes to update filtered options\n this.on('userInput', () => {\n this.updateFilteredOptions();\n });\n }\n\n /**\n * Update filtered options based on current user input\n */\n private updateFilteredOptions(): void {\n const input = this.userInput;\n \n let filteredFiles: string[];\n \n if (!input || input.trim() === '') {\n filteredFiles = this.allFiles;\n } else {\n filteredFiles = search(input, this.allFiles, {\n threshold: this.fuzzyThreshold,\n ignoreCase: true,\n returnMatchData: false\n }) as string[];\n }\n\n // Update filteredOptions (this is a public property we can modify)\n this.filteredOptions = filteredFiles.map(file => ({\n value: file,\n label: file\n }));\n }\n\n /**\n * Main render method with dynamic header\n */\n private renderWithHeader(): string {\n // Handle final states with collapsed rendering\n if (this.state === 'cancel') {\n return this.renderCancelled();\n }\n \n if (this.state === 'submit') {\n // Treat empty selection as cancellation\n if (this.selectedValues.length === 0) {\n return this.renderCancelled();\n }\n return this.renderSubmitted();\n }\n \n // Render full interactive UI for active/initial/error states\n const sections: string[] = [];\n\n // === DYNAMIC HEADER SECTION ===\n sections.push(this.renderSelectedFilesHeader());\n\n // === PROMPT SECTION ===\n sections.push(this.renderSearchSection());\n\n // === OPTIONS LIST ===\n sections.push(this.renderOptionsList());\n\n // === FOOTER ===\n sections.push(this.renderFooter());\n\n return sections.join('\\n');\n }\n\n /**\n * Get a smart label for the current selection (e.g., \"2 dirs, 1 file\" or \"3 files\")\n */\n private getSelectionLabel(): string {\n const count = this.selectedValues.length;\n const dirs = this.selectedValues.filter(v => v.endsWith('/')).length;\n const files = count - dirs;\n \n if (dirs === 0) {\n return `${files} file${files === 1 ? '' : 's'}`;\n } else if (files === 0) {\n return `${dirs} dir${dirs === 1 ? '' : 's'}`;\n } else {\n return `${dirs} dir${dirs === 1 ? '' : 's'}, ${files} file${files === 1 ? '' : 's'}`;\n }\n }\n\n /**\n * Render the selected files header using Clack's simple log-style format\n */\n private renderSelectedFilesHeader(): string {\n const count = this.selectedValues.length;\n const lines: string[] = [];\n \n // Title line with pointer symbol (\u25C6) for consistency with prompt message\n const title = count === 0 \n ? `Selected: ${pico.dim('none (use Space to select)')}`\n : `Selected: ${pico.cyan(this.getSelectionLabel())}`;\n \n lines.push(`${pico.cyan('\u25C6')} ${title}`);\n \n // Show selected files (up to 5)\n if (count > 0) {\n const displayCount = Math.min(5, count);\n for (let i = 0; i < displayCount; i++) {\n const file = this.selectedValues[i];\n lines.push(`${pico.cyan('\u2502')} ${pico.dim('\u2713 ' + file)}`);\n }\n \n // Show \"... and X more\" if there are more\n if (count > displayCount) {\n lines.push(`${pico.cyan('\u2502')} ${pico.dim(`... and ${count - displayCount} more`)}`);\n }\n }\n \n // Separator line\n lines.push(pico.cyan('\u2502'));\n \n return lines.join('\\n');\n }\n\n /**\n * Render the search section\n */\n private renderSearchSection(): string {\n const matchCount = this.filteredOptions.length;\n const totalCount = this.allFiles.length;\n\n const stateSymbol = pico.cyan('\u25C6');\n const searchLabel = pico.dim('Search:');\n const input = this.userInput || pico.gray(this.placeholder);\n const cursor = this.state === 'active' ? pico.cyan('\u2588') : '';\n const matches = matchCount !== totalCount\n ? pico.dim(` (${matchCount} ${matchCount === 1 ? 'match' : 'matches'})`)\n : '';\n\n return `${stateSymbol} ${this.message}\\n${pico.cyan('\u2502')} ${searchLabel} ${input}${cursor}${matches}`;\n }\n\n /**\n * Render the options list with sliding window to keep cursor in view\n */\n private renderOptionsList(): string {\n const lines: string[] = [];\n const totalOptions = this.filteredOptions.length;\n const maxItems = this.maxVisibleItems;\n\n if (totalOptions === 0) {\n lines.push(`${pico.cyan('\u2502')} ${pico.gray('No matches found')}`);\n return lines.join('\\n');\n }\n\n // Sliding window: scroll so cursor stays in view\n let visibleStart = 0;\n if (this.cursor >= maxItems - 3) {\n visibleStart = Math.max(0, Math.min(this.cursor - maxItems + 3, totalOptions - maxItems));\n }\n const visibleEnd = Math.min(visibleStart + maxItems, totalOptions);\n const visibleOptions = this.filteredOptions.slice(visibleStart, visibleEnd);\n\n // Show \"more above\" indicator when scrolled down\n if (visibleStart > 0) {\n lines.push(`${pico.cyan('\u2502')} ${pico.gray(`... ${visibleStart} above`)}`);\n }\n\n for (let i = 0; i < visibleOptions.length; i++) {\n const option = visibleOptions[i];\n const isSelected = this.selectedValues.includes(option.value);\n const isCursor = visibleStart + i === this.cursor;\n\n // Checkbox\n const checkbox = isSelected ? pico.cyan('\u25FC') : pico.dim('\u25FB');\n\n // Cursor indicator\n const cursorMark = isCursor ? pico.cyan('\u25B8') : ' ';\n\n // File name\n let fileName = option.label;\n if (isCursor) {\n fileName = pico.cyan(fileName);\n } else if (isSelected) {\n fileName = pico.white(fileName);\n } else {\n fileName = pico.dim(fileName);\n }\n\n lines.push(`${pico.cyan('\u2502')} ${cursorMark} ${checkbox} ${fileName}`);\n }\n\n // Show \"more below\" indicator when there are more items\n if (visibleEnd < totalOptions) {\n const remaining = totalOptions - visibleEnd;\n lines.push(`${pico.cyan('\u2502')} ${pico.gray(`... ${remaining} more`)}`);\n }\n\n return lines.join('\\n');\n }\n\n /**\n * Render the footer with hints\n */\n private renderFooter(): string {\n const hints = pico.dim('Space: select \u2022 Enter: confirm \u2022 Esc: cancel');\n return `${pico.cyan('\u2514')} ${hints}`;\n }\n\n /**\n * Render the collapsed cancelled state\n */\n private renderCancelled(): string {\n const symbol = pico.red('\u25A0'); // Red square for cancelled\n const end = pico.gray('\u2514');\n \n return `${symbol} ${this.message}\\n${end} ${pico.dim('Operation cancelled')}`;\n }\n\n /**\n * Render the collapsed submitted state (for successful selection)\n */\n private renderSubmitted(): string {\n const symbol = pico.green('\u25C7'); // Green hollow diamond for success\n const bar = pico.gray('\u2502');\n \n const status = pico.dim(this.getSelectionLabel() + ' selected');\n \n return `${symbol} ${this.message}\\n${bar} ${status}`;\n }\n}\n\n/**\n * Helper function to create and run the file selector\n */\nexport async function promptFileSelector(\n options: FileSelectorOptions\n): Promise<string[] | null> {\n const selector = new FileSelectorWithHeader(options);\n const result = await selector.prompt();\n\n if (isCancel(result)) {\n return null;\n }\n\n return result as string[];\n}\n", "/**\n * File Scanner Utility\n * \n * Scans all files in a workspace directory for interactive file selection.\n * Filters out junk files and common build/dependency directories.\n */\n\nimport { relative } from 'path';\nimport { isJunk } from 'junk';\nimport { walkFiles } from './file-walker.js';\nimport { logger } from './logger.js';\n\n/**\n * Common directories to exclude from file scanning\n */\nconst DEFAULT_EXCLUDE_DIRS = new Set([\n 'node_modules',\n '.git',\n '.next',\n '.turbo',\n 'dist',\n 'build',\n 'out',\n '.cache',\n 'coverage',\n '.nyc_output',\n '.parcel-cache',\n '.webpack',\n '.vscode',\n '.idea',\n '__pycache__',\n 'target',\n 'vendor',\n]);\n\n/**\n * Options for scanning workspace files\n */\nexport interface FileScanOptions {\n /** Base directory to scan from (default: process.cwd()) */\n cwd?: string;\n \n /** Specific directory path to scan (overrides cwd if provided) */\n basePath?: string;\n \n /** Additional directory names to exclude (merged with defaults) */\n excludeDirs?: string[];\n \n /** Maximum number of files to return (default: 10000) */\n maxFiles?: number;\n \n /** Whether to follow symbolic links (default: false) */\n followSymlinks?: boolean;\n \n /** Whether to include directories in results (default: false) */\n includeDirs?: boolean;\n}\n\n/**\n * Check if a path segment is an excluded directory\n */\nfunction isExcludedDir(fullPath: string, excludeDirs: Set<string>): boolean {\n const segments = fullPath.split('/');\n \n // Check if any segment matches an excluded directory\n for (const segment of segments) {\n if (excludeDirs.has(segment)) {\n return true;\n }\n }\n \n return false;\n}\n\n/**\n * Scan workspace for all non-junk files\n * \n * @param options - Scanning options\n * @returns Array of relative file paths (and optionally directory paths with '/' suffix) from cwd (or basePath if specified)\n * \n * @example\n * const files = await scanWorkspaceFiles({ cwd: '/path/to/workspace' });\n * // Returns: ['src/index.ts', 'package.json', '.openpkgs/rules/cursor.md', ...]\n * \n * @example\n * // Scan a specific directory\n * const packageFiles = await scanWorkspaceFiles({ \n * cwd: '/workspace',\n * basePath: '/workspace/.openpackage/packages/my-pkg'\n * });\n * // Returns files relative to basePath: ['file1.txt', 'subdir/file2.txt', ...]\n * \n * @example\n * // Include directories in results\n * const filesAndDirs = await scanWorkspaceFiles({ \n * cwd: '/path/to/workspace',\n * includeDirs: true\n * });\n * // Returns: ['src/', 'src/index.ts', 'src/utils/', 'src/utils/helper.ts', ...]\n */\nexport async function scanWorkspaceFiles(\n options: FileScanOptions = {}\n): Promise<string[]> {\n const {\n cwd = process.cwd(),\n basePath,\n excludeDirs = [],\n maxFiles = 10000,\n followSymlinks = false,\n includeDirs = false\n } = options;\n \n // Use basePath if provided, otherwise use cwd\n const scanDir = basePath || cwd;\n \n // Merge default and custom exclude directories\n const allExcludeDirs = new Set([\n ...DEFAULT_EXCLUDE_DIRS,\n ...excludeDirs\n ]);\n \n const files: string[] = [];\n const dirs: string[] = [];\n let fileCount = 0;\n \n try {\n // Create filter for file walker\n const filter = (path: string, isDirectory: boolean) => {\n // Get the basename for junk checking\n const segments = path.split('/');\n const basename = segments[segments.length - 1];\n \n // Filter out junk files\n if (isJunk(basename)) {\n return false;\n }\n \n // Filter out excluded directories and their contents\n if (isExcludedDir(path, allExcludeDirs)) {\n return false;\n }\n \n return true;\n };\n \n // Walk files and collect relative paths\n for await (const filePath of walkFiles(scanDir, { filter, followSymlinks, includeDirs })) {\n // Stop if we've hit the max files limit\n if (fileCount >= maxFiles) {\n logger.debug(`File scan limit reached: ${maxFiles} files`);\n break;\n }\n \n // Convert to relative path for display\n const relativePath = relative(scanDir, filePath);\n \n // Skip if relative path is empty (shouldn't happen, but safety check)\n if (!relativePath || relativePath === '.') {\n continue;\n }\n \n // Check if this is a directory (when includeDirs is enabled)\n if (includeDirs) {\n const fs = await import('fs');\n const stat = await fs.promises.stat(filePath);\n if (stat.isDirectory()) {\n // Add '/' suffix to directories for visual distinction\n dirs.push(relativePath + '/');\n } else {\n files.push(relativePath);\n }\n } else {\n files.push(relativePath);\n }\n \n fileCount++;\n }\n \n // Sort files and directories for better UX\n // Directories first, then files, both alphabetically within their group\n const allItems = [...dirs.sort(), ...files.sort()];\n \n // Apply depth-based sorting to prioritize shallow items\n allItems.sort((a, b) => {\n // Remove trailing '/' for directory depth calculation\n const aPath = a.endsWith('/') ? a.slice(0, -1) : a;\n const bPath = b.endsWith('/') ? b.slice(0, -1) : b;\n \n // Prioritize items in root directory\n const aDepth = aPath.split('/').length;\n const bDepth = bPath.split('/').length;\n \n if (aDepth !== bDepth) {\n return aDepth - bDepth;\n }\n \n // Then alphabetically\n return a.localeCompare(b);\n });\n \n logger.debug(`Scanned ${allItems.length} items in workspace`, { scanDir, includeDirs });\n \n return allItems;\n \n } catch (error) {\n logger.error('Error scanning workspace files', { error, scanDir });\n throw new Error(`Failed to scan workspace files: ${error}`);\n }\n}\n\n/**\n * Check if the current environment supports interactive prompts.\n *\n * Prefer using `ExecutionContext.interactive` when available -- this\n * function exists as a last-resort fallback for code paths that\n * don't have access to a context object.\n * \n * @returns True if stdin and stdout are TTY (terminal)\n * @deprecated Use ExecutionContext.interactive instead when possible.\n */\nexport function canPrompt(): boolean {\n return Boolean(process.stdin.isTTY && process.stdout.isTTY);\n}\n", "import { resolve as resolvePath, join } from 'path';\n\nimport { exists } from './fs.js';\nimport { getLocalOpenPackageDir } from './paths.js';\n\n/**\n * Options for resolving source operation arguments.\n */\nexport interface SourceOperationOptions {\n /** Command name for error messages ('add' | 'remove') */\n command: 'add' | 'remove';\n /** Whether to check workspace root path in addition to filesystem path (for remove) */\n checkWorkspaceRoot?: boolean;\n}\n\n/**\n * Resolved source operation result.\n */\nexport interface ResolvedSourceOperation {\n /** Package name (null = workspace root, string = specific package) */\n resolvedPackageName: string | null;\n /** Path to operate on */\n resolvedPath: string;\n}\n\n/**\n * Resolve source operation arguments to determine package name and operation path.\n * \n * This shared utility handles argument resolution for both add and remove commands:\n * - For add: packageName from --to option, pathArg is source path to add\n * - For remove: packageName from --from option, pathArg is target path to remove\n * \n * @param cwd - Current working directory\n * @param packageName - Package name from --to/--from option (undefined = workspace root)\n * @param pathArg - Path argument from command line\n * @param options - Command-specific options\n * @returns Resolved package name and path\n * \n * @example\n * // Add command: opkg add ./file.md --to my-package\n * const result = await resolveSourceOperationArguments(\n * cwd, 'my-package', './file.md', { command: 'add' }\n * );\n * // => { resolvedPackageName: 'my-package', resolvedPath: './file.md' }\n * \n * @example\n * // Remove command: opkg remove agents/my-agent\n * const result = await resolveSourceOperationArguments(\n * cwd, undefined, 'agents/my-agent', { command: 'remove', checkWorkspaceRoot: true }\n * );\n * // Checks both ./agents/my-agent AND .openpackage/agents/my-agent\n * // => { resolvedPackageName: null, resolvedPath: 'agents/my-agent' }\n */\nexport async function resolveSourceOperationArguments(\n cwd: string,\n packageName: string | undefined,\n pathArg: string | undefined,\n options: SourceOperationOptions\n): Promise<ResolvedSourceOperation> {\n const { command, checkWorkspaceRoot = false } = options;\n const flagName = command === 'add' ? '--to' : '--from';\n \n // Two arguments provided: explicit package name + path\n if (packageName && pathArg) {\n return { resolvedPackageName: packageName, resolvedPath: pathArg };\n }\n\n // One argument provided\n const singleArg = packageName || pathArg;\n if (!singleArg) {\n throw new Error(`Path argument is required for ${command}.`);\n }\n\n // Check if single arg is a valid path\n const absPath = resolvePath(cwd, singleArg);\n let pathExists = await exists(absPath);\n \n // For remove command, also check workspace root path\n if (!pathExists && checkWorkspaceRoot) {\n const openpackageDir = getLocalOpenPackageDir(cwd);\n const workspaceRootPath = join(openpackageDir, singleArg);\n pathExists = await exists(workspaceRootPath);\n }\n \n if (pathExists) {\n // It's a valid path \u2192 operate on workspace root\n return { resolvedPackageName: null, resolvedPath: singleArg };\n }\n\n // Path doesn't exist. For remove, pass through so the pipeline can try dependency resolution.\n // For add, this would have failed earlier. Only remove uses checkWorkspaceRoot.\n if (checkWorkspaceRoot && command === 'remove') {\n return { resolvedPackageName: null, resolvedPath: singleArg };\n }\n\n // Not a valid path \u2192 treat as package name (error will be thrown later)\n throw new Error(\n `Path '${singleArg}' not found.\\n\\n` +\n `If you meant to specify a package name, use: opkg ${command} <path> ${flagName} ${singleArg}`\n );\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["join", "join", "basename", "relative", "isJunk", "basename", "isJunk", "relative", "join", "join"]
7
+ }
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ normalizePackageName
4
+ } from "./chunk-VN22A7NW.js";
5
+ import {
6
+ DIR_PATTERNS,
7
+ OPENPACKAGE_DIRS,
8
+ UNVERSIONED
9
+ } from "./chunk-IHVZ5AUJ.js";
10
+ import {
11
+ ensureDir,
12
+ exists,
13
+ listDirectories,
14
+ remove
15
+ } from "./chunk-S47F4OG4.js";
16
+ import {
17
+ logger
18
+ } from "./chunk-5EFWGD33.js";
19
+
20
+ // ../core/src/core/directory.ts
21
+ import * as os from "os";
22
+ import * as path from "path";
23
+ import * as semver from "semver";
24
+ function getOpenPackageDirectories() {
25
+ let homeDir = os.homedir(), openPackageDir = path.join(homeDir, DIR_PATTERNS.OPENPACKAGE);
26
+ return {
27
+ config: openPackageDir,
28
+ data: openPackageDir,
29
+ // Same directory - follows dotfile convention
30
+ cache: path.join(openPackageDir, OPENPACKAGE_DIRS.CACHE),
31
+ runtime: path.join(os.tmpdir(), "openpackage")
32
+ };
33
+ }
34
+ async function ensureOpenPackageDirectories() {
35
+ let openPackageDirs = getOpenPackageDirectories();
36
+ try {
37
+ return await Promise.all([
38
+ ensureDir(openPackageDirs.config),
39
+ ensureDir(openPackageDirs.data),
40
+ ensureDir(openPackageDirs.cache),
41
+ ensureDir(openPackageDirs.runtime)
42
+ ]), logger.debug("OpenPackage directories ensured", { directories: openPackageDirs }), openPackageDirs;
43
+ } catch (error) {
44
+ throw logger.error("Failed to create OpenPackage directories", { error, directories: openPackageDirs }), error;
45
+ }
46
+ }
47
+ function getRegistryDirectories() {
48
+ let openPackageDirs = getOpenPackageDirectories();
49
+ return {
50
+ packages: path.join(openPackageDirs.data, OPENPACKAGE_DIRS.REGISTRY)
51
+ };
52
+ }
53
+ async function ensureRegistryDirectories() {
54
+ let dirs = getRegistryDirectories();
55
+ try {
56
+ return await ensureDir(dirs.packages), logger.debug("Registry directories ensured", { directories: dirs }), dirs;
57
+ } catch (error) {
58
+ throw logger.error("Failed to create registry directories", { error, directories: dirs }), error;
59
+ }
60
+ }
61
+ function getPackagePath(packageName) {
62
+ let dirs = getRegistryDirectories(), normalizedName = normalizePackageName(packageName);
63
+ return path.join(dirs.packages, normalizedName);
64
+ }
65
+ function getPackageVersionPath(packageName, version) {
66
+ let versionSegment = version ?? UNVERSIONED;
67
+ return path.join(getPackagePath(packageName), versionSegment);
68
+ }
69
+ async function listPackageVersions(packageName) {
70
+ let packagePath = getPackagePath(packageName);
71
+ return await exists(packagePath) ? (await listDirectories(packagePath)).filter((version) => semver.valid(version)).sort((a, b) => semver.compare(b, a)) : [];
72
+ }
73
+ async function getLatestPackageVersion(packageName) {
74
+ let versions = await listPackageVersions(packageName);
75
+ return versions.length === 0 ? null : versions[0];
76
+ }
77
+ async function hasPackageVersion(packageName, version) {
78
+ let versionPath = getPackageVersionPath(packageName, version);
79
+ return await exists(versionPath);
80
+ }
81
+ async function findPackageByName(packageName) {
82
+ let normalizedTarget = normalizePackageName(packageName), dirs = getRegistryDirectories();
83
+ if (!await exists(dirs.packages))
84
+ return null;
85
+ let packageDirs = await listDirectories(dirs.packages);
86
+ if (packageDirs.includes(normalizedTarget))
87
+ return normalizedTarget;
88
+ for (let dirName of packageDirs)
89
+ if (normalizePackageName(dirName) === normalizedTarget)
90
+ return dirName;
91
+ return null;
92
+ }
93
+ async function listAllPackages() {
94
+ let { packages } = getRegistryDirectories();
95
+ if (!await exists(packages))
96
+ return [];
97
+ let result = [];
98
+ async function scanForPackages(currentPath, relativePath) {
99
+ let children = await listDirectories(currentPath);
100
+ if (children.some((child) => child === UNVERSIONED || semver.valid(child))) {
101
+ result.push(relativePath);
102
+ return;
103
+ }
104
+ for (let child of children) {
105
+ let childPath = path.join(currentPath, child), childRelativePath = relativePath ? `${relativePath}/${child}` : child;
106
+ await scanForPackages(childPath, childRelativePath);
107
+ }
108
+ }
109
+ return await scanForPackages(packages, ""), result.sort((a, b) => a.localeCompare(b)), result;
110
+ }
111
+ async function cleanupEmptyPackageDirectory(packageName) {
112
+ let packagePath = getPackagePath(packageName);
113
+ return (await listPackageVersions(packageName)).length === 0 && await exists(packagePath) ? (await remove(packagePath), logger.info("Removed empty package directory", { packagePath }), !0) : !1;
114
+ }
115
+
116
+ export {
117
+ getOpenPackageDirectories,
118
+ ensureOpenPackageDirectories,
119
+ getRegistryDirectories,
120
+ ensureRegistryDirectories,
121
+ getPackagePath,
122
+ getPackageVersionPath,
123
+ listPackageVersions,
124
+ getLatestPackageVersion,
125
+ hasPackageVersion,
126
+ findPackageByName,
127
+ listAllPackages,
128
+ cleanupEmptyPackageDirectory
129
+ };
130
+ //# sourceMappingURL=chunk-GDVFS3YP.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../core/src/core/directory.ts"],
4
+ "sourcesContent": ["import * as os from 'os';\nimport * as path from 'path';\nimport * as semver from 'semver';\nimport { OpenPackageDirectories } from '../types/index.js';\nimport { DIR_PATTERNS, OPENPACKAGE_DIRS, UNVERSIONED } from '../constants/index.js';\nimport { ensureDir, exists, listDirectories, remove } from '../utils/fs.js';\nimport { logger } from '../utils/logger.js';\nimport { normalizePackageName } from '../utils/package-name.js';\n\n/**\n * Cross-platform directory resolution following platform conventions\n */\n\n/**\n * Get OpenPackage directories using unified dotfile convention\n * Uses ~/.openpackage on all platforms for consistency (like AWS CLI with ~/.aws)\n * This approach prioritizes simplicity and cross-platform consistency\n */\nexport function getOpenPackageDirectories(): OpenPackageDirectories {\n const homeDir = os.homedir();\n const openPackageDir = path.join(homeDir, DIR_PATTERNS.OPENPACKAGE);\n \n return {\n config: openPackageDir,\n data: openPackageDir, // Same directory - follows dotfile convention\n cache: path.join(openPackageDir, OPENPACKAGE_DIRS.CACHE),\n runtime: path.join(os.tmpdir(), 'openpackage')\n };\n}\n\n/**\n * Ensure all OpenPackage directories exist\n */\nexport async function ensureOpenPackageDirectories(): Promise<OpenPackageDirectories> {\n const openPackageDirs = getOpenPackageDirectories();\n \n try {\n await Promise.all([\n ensureDir(openPackageDirs.config),\n ensureDir(openPackageDirs.data),\n ensureDir(openPackageDirs.cache),\n ensureDir(openPackageDirs.runtime)\n ]);\n \n logger.debug('OpenPackage directories ensured', { directories: openPackageDirs });\n return openPackageDirs;\n } catch (error) {\n logger.error('Failed to create OpenPackage directories', { error, directories: openPackageDirs });\n throw error;\n }\n}\n\n/**\n * Get the registry directories\n */\nexport function getRegistryDirectories(): { packages: string } {\n const openPackageDirs = getOpenPackageDirectories();\n const registryDir = path.join(openPackageDirs.data, OPENPACKAGE_DIRS.REGISTRY);\n\n return {\n packages: registryDir\n };\n}\n\n/**\n * Ensure registry directories exist\n */\nexport async function ensureRegistryDirectories(): Promise<{ packages: string }> {\n const dirs = getRegistryDirectories();\n \n try {\n await ensureDir(dirs.packages);\n \n logger.debug('Registry directories ensured', { directories: dirs });\n return dirs;\n } catch (error) {\n logger.error('Failed to create registry directories', { error, directories: dirs });\n throw error;\n }\n}\n\n/**\n * Get the cache directory for a specific type of cache\n */\nexport function getCacheDirectory(cacheType: string): string {\n const openPackageDirs = getOpenPackageDirectories();\n return path.join(openPackageDirs.cache, cacheType);\n}\n\n/**\n * Get the temporary directory for a specific operation\n */\nexport function getTempDirectory(operation: string): string {\n const openPackageDirs = getOpenPackageDirectories();\n return path.join(openPackageDirs.runtime, operation);\n}\n\n/**\n * Get the base path for a package (contains all versions)\n * Package names are normalized to lowercase for consistent registry paths.\n */\nexport function getPackagePath(packageName: string): string {\n const dirs = getRegistryDirectories();\n const normalizedName = normalizePackageName(packageName);\n return path.join(dirs.packages, normalizedName);\n}\n\n/**\n * Get the path for a specific version of a package\n * If version is undefined, return the unversioned path.\n */\nexport function getPackageVersionPath(packageName: string, version?: string): string {\n const versionSegment = version ?? UNVERSIONED;\n return path.join(getPackagePath(packageName), versionSegment);\n}\n\n/**\n * List all versions of a package\n */\nexport async function listPackageVersions(packageName: string): Promise<string[]> {\n const packagePath = getPackagePath(packageName);\n \n if (!(await exists(packagePath))) {\n return [];\n }\n \n const versions = await listDirectories(packagePath);\n const semverVersions = versions.filter(version => semver.valid(version));\n return semverVersions.sort((a, b) => semver.compare(b, a)); // Latest first\n}\n\n/**\n * Get the latest version of a package\n */\nexport async function getLatestPackageVersion(packageName: string): Promise<string | null> {\n const versions = await listPackageVersions(packageName);\n if (versions.length === 0) {\n return null;\n }\n return versions[0];\n}\n\n/**\n * Check if a specific version exists\n */\nexport async function hasPackageVersion(packageName: string, version?: string): Promise<boolean> {\n const versionPath = getPackageVersionPath(packageName, version);\n return await exists(versionPath);\n}\n\n/**\n * Find a package by name, searching case-insensitively across registry directories.\n * Returns the normalized package name if found, null otherwise.\n * If multiple packages match the same normalized name, returns the first one found.\n */\nexport async function findPackageByName(packageName: string): Promise<string | null> {\n const normalizedTarget = normalizePackageName(packageName);\n const dirs = getRegistryDirectories();\n\n if (!(await exists(dirs.packages))) {\n return null;\n }\n\n const packageDirs = await listDirectories(dirs.packages);\n\n // First try exact normalized match\n if (packageDirs.includes(normalizedTarget)) {\n return normalizedTarget;\n }\n\n // Then try case-insensitive match\n for (const dirName of packageDirs) {\n if (normalizePackageName(dirName) === normalizedTarget) {\n return dirName; // Return the actual directory name as it exists on disk\n }\n }\n\n return null;\n}\n\n/**\n * List all package base names in the local registry, including scoped packages.\n * Returns names relative to the packages root, e.g. 'name', '@scope/name', or '@scope/name/subname'.\n * Supports arbitrary nesting for hierarchical package names.\n */\nexport async function listAllPackages(): Promise<string[]> {\n const { packages } = getRegistryDirectories();\n\n if (!(await exists(packages))) {\n return [];\n }\n\n const result: string[] = [];\n\n /**\n * Recursively scan for packages by checking for version directories\n */\n async function scanForPackages(currentPath: string, relativePath: string): Promise<void> {\n const children = await listDirectories(currentPath);\n\n // Check if this directory contains version directories (is a package)\n const hasVersions = children.some(child => child === UNVERSIONED || semver.valid(child));\n if (hasVersions) {\n result.push(relativePath);\n return; // Don't recurse into version directories\n }\n\n // Otherwise, recurse into subdirectories\n for (const child of children) {\n const childPath = path.join(currentPath, child);\n const childRelativePath = relativePath ? `${relativePath}/${child}` : child;\n await scanForPackages(childPath, childRelativePath);\n }\n }\n\n await scanForPackages(packages, '');\n\n // Stable order\n result.sort((a, b) => a.localeCompare(b));\n return result;\n}\n\n/**\n * Clean up empty package directory after all versions are removed\n * Returns true if directory was removed, false if it still has versions\n */\nexport async function cleanupEmptyPackageDirectory(packageName: string): Promise<boolean> {\n const packagePath = getPackagePath(packageName);\n const versions = await listPackageVersions(packageName);\n \n if (versions.length === 0 && await exists(packagePath)) {\n await remove(packagePath);\n logger.info('Removed empty package directory', { packagePath });\n return true;\n }\n \n return false;\n}\n\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ createHttpClient
4
+ } from "./chunk-6DITYAFA.js";
5
+ import {
6
+ authManager
7
+ } from "./chunk-C6FY55UP.js";
8
+
9
+ // ../core/src/core/api-keys.ts
10
+ async function getCurrentApiKeyInfo(authOptions = {}) {
11
+ let apiKey = await authManager.getApiKey(authOptions);
12
+ if (!apiKey)
13
+ throw new Error("No API key found. Configure a profile API key or use --api-key.");
14
+ return await (await createHttpClient(authOptions)).get("/api-keys/me", {
15
+ headers: {
16
+ "X-API-Key": apiKey
17
+ },
18
+ skipAuth: !0
19
+ });
20
+ }
21
+ async function getCurrentUsername(authOptions = {}) {
22
+ let apiKeyInfo = await getCurrentApiKeyInfo(authOptions);
23
+ if (!apiKeyInfo.user?.username)
24
+ throw new Error("Unable to determine username from API key. Please verify your credentials.");
25
+ return apiKeyInfo.user.username;
26
+ }
27
+
28
+ export {
29
+ getCurrentUsername
30
+ };
31
+ //# sourceMappingURL=chunk-GEP2G5HF.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../core/src/core/api-keys.ts"],
4
+ "sourcesContent": ["import { AuthOptions } from '../types/index.js';\nimport { authManager } from './auth.js';\nimport { createHttpClient } from './http-client.js';\n\nexport interface ApiKeyInfo {\n id: string;\n name: string;\n keyPrefix: string;\n isActive: boolean;\n lastUsedAt?: string;\n user: {\n _id: string;\n username: string;\n };\n}\n\n/**\n * Fetch metadata about the currently authenticated API key.\n */\nexport async function getCurrentApiKeyInfo(\n authOptions: AuthOptions = {}\n): Promise<ApiKeyInfo> {\n const apiKey = await authManager.getApiKey(authOptions);\n if (!apiKey) {\n throw new Error('No API key found. Configure a profile API key or use --api-key.');\n }\n const httpClient = await createHttpClient(authOptions);\n\n return await httpClient.get<ApiKeyInfo>('/api-keys/me', {\n headers: {\n 'X-API-Key': apiKey\n },\n skipAuth: true\n });\n}\n\n/**\n * Resolve the username associated with the current API key.\n */\nexport async function getCurrentUsername(authOptions: AuthOptions = {}): Promise<string> {\n const apiKeyInfo = await getCurrentApiKeyInfo(authOptions);\n\n if (!apiKeyInfo.user?.username) {\n throw new Error('Unable to determine username from API key. Please verify your credentials.');\n }\n\n return apiKeyInfo.user.username;\n}\n\n"],
5
+ "mappings": ";;;;;;;;;AAmBA,eAAsB,qBACpB,cAA2B,CAAC,GACP;AACrB,MAAM,SAAS,MAAM,YAAY,UAAU,WAAW;AACtD,MAAI,CAAC;AACH,UAAM,IAAI,MAAM,iEAAiE;AAInF,SAAO,OAFY,MAAM,iBAAiB,WAAW,GAE7B,IAAgB,gBAAgB;AAAA,IACtD,SAAS;AAAA,MACP,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,EACZ,CAAC;AACH;AAKA,eAAsB,mBAAmB,cAA2B,CAAC,GAAoB;AACvF,MAAM,aAAa,MAAM,qBAAqB,WAAW;AAEzD,MAAI,CAAC,WAAW,MAAM;AACpB,UAAM,IAAI,MAAM,4EAA4E;AAG9F,SAAO,WAAW,KAAK;AACzB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ parsePackageYml
4
+ } from "./chunk-427DCURL.js";
5
+ import {
6
+ getRelativePathFromBase
7
+ } from "./chunk-YMKK4XPN.js";
8
+ import {
9
+ FILE_PATTERNS
10
+ } from "./chunk-IHVZ5AUJ.js";
11
+ import {
12
+ exists,
13
+ isDirectory,
14
+ listDirectories,
15
+ listFiles
16
+ } from "./chunk-S47F4OG4.js";
17
+ import {
18
+ logger
19
+ } from "./chunk-5EFWGD33.js";
20
+
21
+ // ../core/src/core/package-context.ts
22
+ import { join as join2 } from "path";
23
+
24
+ // ../core/src/utils/file-processing.ts
25
+ import { join } from "path";
26
+ async function findFilesByExtension(dir, extensions = [], baseDir = dir, options = {}) {
27
+ if (!await exists(dir) || !await isDirectory(dir))
28
+ return [];
29
+ let files = [], normalizedExtensions = extensions.map((extension) => extension.startsWith(".") ? extension : `.${extension}`), dirFiles = await listFiles(dir);
30
+ for (let file of dirFiles)
31
+ if (normalizedExtensions.length === 0 || normalizedExtensions.some((extension) => file.endsWith(extension))) {
32
+ let fullPath = join(dir, file), relativePath = getRelativePathFromBase(fullPath, baseDir);
33
+ files.push({ fullPath, relativePath });
34
+ }
35
+ let subFilesPromises = (await listDirectories(dir)).filter((subdir) => !(options.excludeDirs && options.excludeDirs.has(subdir))).map(
36
+ (subdir) => findFilesByExtension(join(dir, subdir), extensions, baseDir, options)
37
+ ), subFiles = await Promise.all(subFilesPromises);
38
+ return files.push(...subFiles.flat()), files;
39
+ }
40
+
41
+ // ../core/src/core/package-context.ts
42
+ async function isValidPackageDirectory(dir) {
43
+ let packageYmlPath = join2(dir, FILE_PATTERNS.OPENPACKAGE_YML);
44
+ return exists(packageYmlPath);
45
+ }
46
+ async function loadPackageConfig(dir) {
47
+ let packageYmlPath = join2(dir, FILE_PATTERNS.OPENPACKAGE_YML);
48
+ if (!await exists(packageYmlPath))
49
+ return null;
50
+ try {
51
+ return await parsePackageYml(packageYmlPath);
52
+ } catch (error) {
53
+ return logger.debug(`Failed to parse openpackage.yml at ${packageYmlPath}: ${error}`), null;
54
+ }
55
+ }
56
+
57
+ export {
58
+ findFilesByExtension,
59
+ isValidPackageDirectory,
60
+ loadPackageConfig
61
+ };
62
+ //# sourceMappingURL=chunk-GSWHZBT2.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../core/src/core/package-context.ts", "../../core/src/utils/file-processing.ts"],
4
+ "sourcesContent": ["/**\n * Unified Package Context\n * \n * Provides consistent package location resolution for all pipelines.\n * Package payloads store content at the package root alongside openpackage.yml.\n * Cached packages (workspace) live under .openpackage/packages/<name>/ with the same layout.\n */\n\nimport { join } from 'path';\n\nimport { DIR_PATTERNS, FILE_PATTERNS, OPENPACKAGE_DIRS } from '../constants/index.js';\nimport type { PackageYml } from '../types/index.js';\nimport { exists, isDirectory } from '../utils/fs.js';\nimport { parsePackageYml } from '../utils/package-yml.js';\nimport { arePackageNamesEquivalent, normalizePackageName } from '../utils/package-name.js';\nimport { findDirectoriesContainingFile } from '../utils/file-processing.js';\nimport { logger } from '../utils/logger.js';\n\n/**\n * Package location type\n */\nexport type PackageLocation = 'root' | 'nested';\n\n/**\n * Unified package context used by all pipelines.\n * \n * Key distinction:\n * - packageRootDir: the package root directory (content lives directly here)\n * - packageYmlPath: <packageRootDir>/openpackage.yml\n * \n * For root packages:\n * packageRootDir = cwd/\n * packageYmlPath = cwd/openpackage.yml\n * \n * For cached packages:\n * packageRootDir = cwd/.openpackage/packages/<name>/\n * packageYmlPath = cwd/.openpackage/packages/<name>/openpackage.yml\n */\nexport interface PackageContext {\n /** Normalized package name */\n name: string;\n \n /** Package version from openpackage.yml */\n version?: string;\n \n /** Full config from openpackage.yml */\n config: PackageYml;\n \n /** Absolute path to openpackage.yml */\n packageYmlPath: string;\n \n /** \n * Absolute path to the package root directory.\n * - Root: <cwd>/\n * - Nested: <cwd>/.openpackage/packages/<name>/\n */\n packageRootDir: string;\n \n /** \n * Absolute path to the content directory (same as package root for v2 layout)\n */\n packageFilesDir: string;\n \n /** Package location type */\n location: PackageLocation;\n \n /** Whether this is the cwd's own package (root package without explicit name) */\n isCwdPackage: boolean;\n \n /** Whether this package was newly created (for init/add flows) */\n isNew?: boolean;\n}\n\n/**\n * Get the package root directory based on location.\n * - Root: cwd/\n * - Nested: cwd/.openpackage/packages/<name>/\n */\nexport function getPackageRootDir(cwd: string, location: PackageLocation, packageName?: string): string {\n if (location === 'root') {\n return cwd;\n }\n \n if (!packageName) {\n throw new Error('Package name required for nested packages');\n }\n \n return join(cwd, DIR_PATTERNS.OPENPACKAGE, OPENPACKAGE_DIRS.PACKAGES, normalizePackageName(packageName));\n}\n\n/**\n * Get the package content directory (v2 layout: same as the package root).\n */\nexport function getPackageFilesDir(cwd: string, location: PackageLocation, packageName?: string): string {\n // In v2, content lives at the package root.\n return getPackageRootDir(cwd, location, packageName);\n}\n\n/**\n * Get the openpackage.yml path based on location.\n */\nexport function getPackageYmlPath(cwd: string, location: PackageLocation, packageName?: string): string {\n const contentDir = getPackageRootDir(cwd, location, packageName);\n return join(contentDir, FILE_PATTERNS.OPENPACKAGE_YML);\n}\n\n/**\n * Core rule: any directory that contains `openpackage.yml` is a valid package.\n */\nexport async function isValidPackageDirectory(dir: string): Promise<boolean> {\n const packageYmlPath = join(dir, FILE_PATTERNS.OPENPACKAGE_YML);\n return exists(packageYmlPath);\n}\n\n/**\n * Load package config from a directory that satisfies the core rule.\n */\nexport async function loadPackageConfig(dir: string): Promise<PackageYml | null> {\n const packageYmlPath = join(dir, FILE_PATTERNS.OPENPACKAGE_YML);\n if (!(await exists(packageYmlPath))) {\n return null;\n }\n\n try {\n return await parsePackageYml(packageYmlPath);\n } catch (error) {\n logger.debug(`Failed to parse openpackage.yml at ${packageYmlPath}: ${error}`);\n return null;\n }\n}\n\n/**\n * Detect package context for any pipeline operation.\n * \n * Resolution order:\n * 1. No packageName provided \u2192 target cwd as root package\n * 2. packageName matches root package name \u2192 root package\n * 3. packageName found in nested packages \u2192 nested package\n * 4. packageName not found \u2192 null (caller decides: error or create)\n */\nexport async function detectPackageContext(\n cwd: string,\n packageName?: string\n): Promise<PackageContext | null> {\n const rootPackageYmlPath = getPackageYmlPath(cwd, 'root');\n const hasRootPackage = await exists(rootPackageYmlPath);\n\n // No package name provided: target cwd as the package itself\n if (!packageName) {\n if (!hasRootPackage) {\n return null;\n }\n\n try {\n const config = await parsePackageYml(rootPackageYmlPath);\n return {\n name: normalizePackageName(config.name),\n version: config.version,\n config,\n packageYmlPath: rootPackageYmlPath,\n packageRootDir: getPackageRootDir(cwd, 'root'),\n packageFilesDir: getPackageFilesDir(cwd, 'root'),\n location: 'root',\n isCwdPackage: true\n };\n } catch (error) {\n logger.warn(`Failed to parse root openpackage.yml: ${error}`);\n return null;\n }\n }\n\n const normalizedName = normalizePackageName(packageName);\n\n // Package name provided: check if it matches root package\n if (hasRootPackage) {\n try {\n const rootConfig = await parsePackageYml(rootPackageYmlPath);\n if (arePackageNamesEquivalent(rootConfig.name, packageName)) {\n return {\n name: normalizedName,\n version: rootConfig.version,\n config: rootConfig,\n packageYmlPath: rootPackageYmlPath,\n packageRootDir: getPackageRootDir(cwd, 'root'),\n packageFilesDir: getPackageFilesDir(cwd, 'root'),\n location: 'root',\n isCwdPackage: true\n };\n }\n } catch (error) {\n logger.debug(`Failed to parse root openpackage.yml: ${error}`);\n }\n }\n\n // Check nested packages directory\n // Check cached packages directory for a matching package name\n const packagesDir = join(cwd, DIR_PATTERNS.OPENPACKAGE, OPENPACKAGE_DIRS.PACKAGES);\n if (await exists(packagesDir) && (await isDirectory(packagesDir))) {\n try {\n // Direct match on expected path\n const nestedPackageRootDir = getPackageRootDir(cwd, 'nested', packageName);\n const nestedPackageYmlPath = getPackageYmlPath(cwd, 'nested', packageName);\n\n if (await exists(nestedPackageYmlPath)) {\n const nestedConfig = await parsePackageYml(nestedPackageYmlPath);\n if (arePackageNamesEquivalent(nestedConfig.name, packageName)) {\n return {\n name: normalizedName,\n version: nestedConfig.version,\n config: nestedConfig,\n packageYmlPath: nestedPackageYmlPath,\n packageRootDir: nestedPackageRootDir,\n packageFilesDir: nestedPackageRootDir,\n location: 'nested',\n isCwdPackage: false\n };\n }\n }\n\n // Fallback: scan for mismatched directory name\n const packageDirs = await findDirectoriesContainingFile(\n packagesDir,\n FILE_PATTERNS.OPENPACKAGE_YML,\n async filePath => {\n try {\n return await parsePackageYml(filePath);\n } catch {\n return null;\n }\n }\n );\n\n for (const { dirPath, parsedContent } of packageDirs) {\n if (!parsedContent) continue;\n\n if (arePackageNamesEquivalent(parsedContent.name, packageName)) {\n // dirPath is the package root containing openpackage.yml\n const packageRootDir = dirPath;\n return {\n name: normalizedName,\n version: parsedContent.version,\n config: parsedContent,\n packageYmlPath: join(dirPath, FILE_PATTERNS.OPENPACKAGE_YML),\n packageRootDir,\n packageFilesDir: packageRootDir,\n location: 'nested',\n isCwdPackage: false\n };\n }\n }\n } catch (error) {\n logger.debug(`Failed to scan packages directory: ${error}`);\n }\n }\n\n return null;\n}\n\n/**\n * Create a new package context for initialization.\n * Does not write any files - just builds the context.\n */\nexport function createPackageContext(\n cwd: string,\n config: PackageYml,\n location: PackageLocation\n): PackageContext {\n const normalizedName = normalizePackageName(config.name);\n \n return {\n name: normalizedName,\n version: config.version,\n config,\n packageYmlPath: getPackageYmlPath(cwd, location, location === 'nested' ? normalizedName : undefined),\n packageRootDir: getPackageRootDir(cwd, location, location === 'nested' ? normalizedName : undefined),\n packageFilesDir: getPackageFilesDir(cwd, location, location === 'nested' ? normalizedName : undefined),\n location,\n isCwdPackage: location === 'root',\n isNew: true\n };\n}\n\n/**\n * Check if a package context represents a root package.\n */\nexport function isRootPackage(ctx: PackageContext): boolean {\n return ctx.location === 'root';\n}\n\n/**\n * Error message for when no package is detected.\n */\nexport function getNoPackageDetectedMessage(packageName?: string): string {\n if (packageName) {\n return (\n `Package '${packageName}' not found.\\n\\n` +\n `Checked locations:\\n` +\n ` \u2022 Root package: openpackage.yml\\n` +\n ` \u2022 Cached packages: .openpackage/packages/${packageName}/\\n\\n` +\n `\uD83D\uDCA1 To install a package, run: opkg install ${packageName}`\n );\n }\n\n return (\n `No package detected at current directory.\\n\\n` +\n `A valid package requires openpackage.yml to exist.\\n\\n` +\n `\uD83D\uDCA1 To create a package:\\n` +\n ` \u2022 Run 'opkg new' to create a new package`\n );\n}\n\n", "import { join } from 'path';\nimport { logger } from './logger.js';\nimport {\n exists,\n listFiles,\n listDirectories,\n isDirectory,\n getStats\n} from './fs.js';\nimport { getRelativePathFromBase } from './path-normalization.js';\n\n/**\n * Get file modification time\n * @throws Error if unable to get file stats\n */\nexport async function getFileMtime(filePath: string): Promise<number> {\n const stats = await getStats(filePath);\n return stats.mtime.getTime();\n}\n\n/**\n * Recursively find files by extension in a directory\n */\nexport async function findFilesByExtension(\n dir: string,\n extensions: string[] = [],\n baseDir: string = dir,\n options: { excludeDirs?: Set<string> } = {}\n): Promise<Array<{ fullPath: string; relativePath: string }>> {\n if (!(await exists(dir)) || !(await isDirectory(dir))) {\n return [];\n }\n\n const files: Array<{ fullPath: string; relativePath: string }> = [];\n const normalizedExtensions = extensions.map(extension => extension.startsWith('.') ? extension : `.${extension}`);\n\n // Check current directory files\n const dirFiles = await listFiles(dir);\n for (const file of dirFiles) {\n // If no extension is provided, include all files\n // Otherwise, include only files with the specified extension\n if (normalizedExtensions.length === 0 || normalizedExtensions.some(extension => file.endsWith(extension))) {\n const fullPath = join(dir, file);\n const relativePath = getRelativePathFromBase(fullPath, baseDir);\n files.push({ fullPath, relativePath });\n }\n }\n\n // Recursively search subdirectories\n const subdirs = await listDirectories(dir);\n const subFilesPromises = subdirs\n .filter(subdir => !(options.excludeDirs && options.excludeDirs.has(subdir)))\n .map(subdir =>\n findFilesByExtension(join(dir, subdir), extensions, baseDir, options)\n );\n const subFiles = await Promise.all(subFilesPromises);\n files.push(...subFiles.flat());\n\n return files;\n}\n\n/**\n * Recursively find directories containing a specific file\n * @param rootDir - Root directory to start searching from\n * @param targetFileName - Name of the file to search for (e.g., 'openpackage.yml')\n * @param parseCallback - Optional callback to parse and validate the file content\n * @returns Array of directory paths where the file was found\n */\nexport async function findDirectoriesContainingFile<T = void>(\n rootDir: string,\n targetFileName: string,\n parseCallback?: (filePath: string) => Promise<T | null>\n): Promise<Array<{ dirPath: string; parsedContent?: T }>> {\n const results: Array<{ dirPath: string; parsedContent?: T }> = [];\n\n if (!(await exists(rootDir)) || !(await isDirectory(rootDir))) {\n return results;\n }\n\n async function recurse(dir: string): Promise<void> {\n try {\n const files = await listFiles(dir);\n\n // Check if target file exists in current directory\n if (files.includes(targetFileName)) {\n const filePath = join(dir, targetFileName);\n\n // If parse callback provided, use it to validate/parse\n if (parseCallback) {\n try {\n const parsedContent = await parseCallback(filePath);\n if (parsedContent !== null) {\n results.push({ dirPath: dir, parsedContent });\n }\n } catch (error) {\n logger.warn(`Failed to parse ${targetFileName} at ${filePath}: ${error}`);\n }\n } else {\n // No callback, just record the directory\n results.push({ dirPath: dir });\n }\n }\n\n // Recursively search subdirectories\n const subdirs = await listDirectories(dir);\n for (const subdir of subdirs) {\n const subdirPath = join(dir, subdir);\n await recurse(subdirPath);\n }\n } catch (error) {\n logger.warn(`Failed to scan directory: ${dir}`, { error });\n }\n }\n\n await recurse(rootDir);\n return results;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;AAQA,SAAS,QAAAA,aAAY;;;ACRrB,SAAS,YAAY;AAuBrB,eAAsB,qBACpB,KACA,aAAuB,CAAC,GACxB,UAAkB,KAClB,UAAyC,CAAC,GACkB;AAC5D,MAAI,CAAE,MAAM,OAAO,GAAG,KAAM,CAAE,MAAM,YAAY,GAAG;AACjD,WAAO,CAAC;AAGV,MAAM,QAA2D,CAAC,GAC5D,uBAAuB,WAAW,IAAI,eAAa,UAAU,WAAW,GAAG,IAAI,YAAY,IAAI,SAAS,EAAE,GAG1G,WAAW,MAAM,UAAU,GAAG;AACpC,WAAW,QAAQ;AAGjB,QAAI,qBAAqB,WAAW,KAAK,qBAAqB,KAAK,eAAa,KAAK,SAAS,SAAS,CAAC,GAAG;AACzG,UAAM,WAAW,KAAK,KAAK,IAAI,GACzB,eAAe,wBAAwB,UAAU,OAAO;AAC9D,YAAM,KAAK,EAAE,UAAU,aAAa,CAAC;AAAA,IACvC;AAKF,MAAM,oBADU,MAAM,gBAAgB,GAAG,GAEtC,OAAO,YAAU,EAAE,QAAQ,eAAe,QAAQ,YAAY,IAAI,MAAM,EAAE,EAC1E;AAAA,IAAI,YACH,qBAAqB,KAAK,KAAK,MAAM,GAAG,YAAY,SAAS,OAAO;AAAA,EACtE,GACI,WAAW,MAAM,QAAQ,IAAI,gBAAgB;AACnD,eAAM,KAAK,GAAG,SAAS,KAAK,CAAC,GAEtB;AACT;;;ADkDA,eAAsB,wBAAwB,KAA+B;AAC3E,MAAM,iBAAiBC,MAAK,KAAK,cAAc,eAAe;AAC9D,SAAO,OAAO,cAAc;AAC9B;AAKA,eAAsB,kBAAkB,KAAyC;AAC/E,MAAM,iBAAiBA,MAAK,KAAK,cAAc,eAAe;AAC9D,MAAI,CAAE,MAAM,OAAO,cAAc;AAC/B,WAAO;AAGT,MAAI;AACF,WAAO,MAAM,gBAAgB,cAAc;AAAA,EAC7C,SAAS,OAAO;AACd,kBAAO,MAAM,sCAAsC,cAAc,KAAK,KAAK,EAAE,GACtE;AAAA,EACT;AACF;",
6
+ "names": ["join", "join"]
7
+ }
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveOutput
4
+ } from "./chunk-BROJ6OUT.js";
5
+
6
+ // ../core/src/core/list/list-tree-renderer.ts
7
+ var DIM = "\x1B[2m", RESET = "\x1B[0m", RED = "\x1B[31m";
8
+ function dim(text) {
9
+ return `${DIM}${text}${RESET}`;
10
+ }
11
+ function red(text) {
12
+ return `${RED}${text}${RESET}`;
13
+ }
14
+ function getTreeConnector(isLast, hasBranches) {
15
+ return isLast ? hasBranches ? "\u2514\u2500\u252C " : "\u2514\u2500\u2500 " : hasBranches ? "\u251C\u2500\u252C " : "\u251C\u2500\u2500 ";
16
+ }
17
+ function getChildPrefix(parentPrefix, isLast) {
18
+ return parentPrefix + (isLast ? " " : "\u2502 ");
19
+ }
20
+ function formatFileLabel(file, config) {
21
+ let filePath = config.formatPath(file);
22
+ return config.isMissing(file) ? `${dim(filePath)} ${red("[MISSING]")}` : dim(filePath);
23
+ }
24
+ function renderFlatFileList(files, prefix, config, output) {
25
+ let out = output ?? resolveOutput();
26
+ for (let fi = 0; fi < files.length; fi++) {
27
+ let file = files[fi], isLastFile = fi === files.length - 1, fileConnector = getTreeConnector(isLastFile, !1), label = formatFileLabel(file, config);
28
+ out.message(`${prefix}${fileConnector}${label}`);
29
+ }
30
+ }
31
+ function renderResource(resource, prefix, isLast, showFiles, config, output) {
32
+ let out = output ?? resolveOutput(), enhanced = resource, packageLabels = config.getResourcePackageLabels?.(enhanced.packages) ?? [], hasFileBranches = showFiles && resource.files.length > 0, connector = getTreeConnector(isLast, hasFileBranches), childPrefix = getChildPrefix(prefix, isLast), packagePrefix = hasFileBranches ? childPrefix + "\u2502 " : childPrefix, badge = config.getResourceBadge?.(enhanced.scopes) ?? "";
33
+ out.message(`${prefix}${connector}${resource.name}${badge ? " " + badge : ""}`);
34
+ let packageSpacing = hasFileBranches ? "" : " ";
35
+ for (let label of packageLabels)
36
+ out.message(`${packagePrefix}${packageSpacing}${label}`);
37
+ if (hasFileBranches) {
38
+ let sortedFiles = [...resource.files].sort(config.sortFiles);
39
+ renderFlatFileList(sortedFiles, childPrefix, config, output);
40
+ }
41
+ }
42
+ function flattenResourceGroups(groups) {
43
+ let flat = [];
44
+ for (let group of groups)
45
+ flat.push(...group.resources);
46
+ return flat.sort((a, b) => a.name.localeCompare(b.name));
47
+ }
48
+ function renderFlatResourceList(resources, prefix, showFiles, config, hasMoreSiblings, output) {
49
+ for (let ri = 0; ri < resources.length; ri++) {
50
+ let resource = resources[ri], isNaturalLast = ri === resources.length - 1;
51
+ renderResource(resource, prefix, hasMoreSiblings ? !1 : isNaturalLast, showFiles, config, output);
52
+ }
53
+ }
54
+
55
+ export {
56
+ getTreeConnector,
57
+ getChildPrefix,
58
+ flattenResourceGroups,
59
+ renderFlatResourceList
60
+ };
61
+ //# sourceMappingURL=chunk-HTYHJA3B.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../core/src/core/list/list-tree-renderer.ts"],
4
+ "sourcesContent": ["import type { ListResourceGroup, ListResourceInfo, ListFileMapping } from './list-pipeline.js';\nimport type { ResourceScope } from '../resources/scope-traversal.js';\nimport type { OutputPort } from '../ports/output.js';\nimport { resolveOutput } from '../ports/resolve.js';\n\nexport type { ResourceScope } from '../resources/scope-traversal.js';\n\n/**\n * Enhanced file mapping with status and scope\n */\nexport interface EnhancedFileMapping extends ListFileMapping {\n status: 'tracked' | 'untracked' | 'missing';\n scope: ResourceScope;\n}\n\n/**\n * Enhanced resource info with status and scopes\n */\nexport interface EnhancedResourceInfo {\n name: string;\n resourceType: string;\n files: EnhancedFileMapping[];\n status: 'tracked' | 'partial' | 'untracked' | 'mixed';\n scopes: Set<ResourceScope>;\n /** Package(s) this resource belongs to (tracked resources only) */\n packages?: Set<string>;\n}\n\n/**\n * Enhanced resource group\n */\nexport interface EnhancedResourceGroup {\n resourceType: string;\n resources: EnhancedResourceInfo[];\n}\n\n/**\n * Configuration for tree rendering behavior\n */\nexport interface TreeRenderConfig<TFile> {\n /** Function to format file path for display */\n formatPath: (file: TFile) => string;\n /** Function to check if file is missing */\n isMissing: (file: TFile) => boolean;\n /** Function to sort files */\n sortFiles: (a: TFile, b: TFile) => number;\n /** Optional badge/suffix for resource names */\n getResourceBadge?: (scopes?: Set<ResourceScope>) => string;\n /** Optional dimmed package labels shown under resource name, one line per package (vertical bar, no connector) */\n getResourcePackageLabels?: (packages?: Set<string>) => string[];\n}\n\n// ANSI color codes\nconst DIM = '\\x1b[2m';\nconst RESET = '\\x1b[0m';\nconst RED = '\\x1b[31m';\n\nfunction dim(text: string): string {\n return `${DIM}${text}${RESET}`;\n}\n\nfunction red(text: string): string {\n return `${RED}${text}${RESET}`;\n}\n\n/**\n * Get tree connector character based on position\n */\nexport function getTreeConnector(isLast: boolean, hasBranches: boolean): string {\n if (isLast) {\n return hasBranches ? '\u2514\u2500\u252C ' : '\u2514\u2500\u2500 ';\n }\n return hasBranches ? '\u251C\u2500\u252C ' : '\u251C\u2500\u2500 ';\n}\n\n/**\n * Calculate child prefix based on parent prefix and position\n */\nexport function getChildPrefix(parentPrefix: string, isLast: boolean): string {\n return parentPrefix + (isLast ? ' ' : '\u2502 ');\n}\n\n/**\n * Format file label with missing indicator if needed\n */\nexport function formatFileLabel<TFile>(\n file: TFile,\n config: TreeRenderConfig<TFile>\n): string {\n const filePath = config.formatPath(file);\n const isMissing = config.isMissing(file);\n \n return isMissing\n ? `${dim(filePath)} ${red('[MISSING]')}`\n : dim(filePath);\n}\n\n/**\n * Collect and sort all files from a resource group\n */\nexport function collectGroupFiles<TFile>(\n group: ListResourceGroup | EnhancedResourceGroup,\n config: TreeRenderConfig<TFile>\n): TFile[] {\n const allFiles: TFile[] = [];\n for (const resource of group.resources) {\n allFiles.push(...(resource.files as TFile[]));\n }\n return allFiles.sort(config.sortFiles);\n}\n\n/**\n * Render files directly under a group (for 'other' type)\n */\nexport function renderFlatFileList<TFile>(\n files: TFile[],\n prefix: string,\n config: TreeRenderConfig<TFile>,\n output?: OutputPort\n): void {\n const out = output ?? resolveOutput();\n for (let fi = 0; fi < files.length; fi++) {\n const file = files[fi];\n const isLastFile = fi === files.length - 1;\n const fileConnector = getTreeConnector(isLastFile, false);\n const label = formatFileLabel(file, config);\n out.message(`${prefix}${fileConnector}${label}`);\n }\n}\n\n/**\n * Render a single resource with its files\n */\nexport function renderResource<TFile>(\n resource: ListResourceInfo | EnhancedResourceInfo,\n prefix: string,\n isLast: boolean,\n showFiles: boolean,\n config: TreeRenderConfig<TFile>,\n output?: OutputPort\n): void {\n const out = output ?? resolveOutput();\n const enhanced = resource as EnhancedResourceInfo;\n const packageLabels = config.getResourcePackageLabels?.(enhanced.packages) ?? [];\n\n // Single source of truth: file branches (\u251C\u2500\u252C/\u2514\u2500\u252C) only when -f and resource has files.\n // Package-only uses \u251C\u2500\u2500/\u2514\u2500\u2500; double \u2502 for package labels only when file branches exist.\n const hasFileBranches = showFiles && resource.files.length > 0;\n\n const connector = getTreeConnector(isLast, hasFileBranches);\n const childPrefix = getChildPrefix(prefix, isLast);\n const packagePrefix = hasFileBranches ? childPrefix + '\u2502 ' : childPrefix;\n\n // Resource name with optional badge\n const badge = config.getResourceBadge?.(enhanced.scopes) ?? '';\n out.message(`${prefix}${connector}${resource.name}${badge ? ' ' + badge : ''}`);\n\n // Package labels: dimmed (package) under resource name, one per package.\n // With -f: align (package) with resource name (no extra spacing); without -f: 2 spaces.\n const packageSpacing = hasFileBranches ? '' : ' ';\n for (const label of packageLabels) {\n out.message(`${packagePrefix}${packageSpacing}${label}`);\n }\n\n // Render files if requested\n if (hasFileBranches) {\n const sortedFiles = [...(resource.files as TFile[])].sort(config.sortFiles);\n renderFlatFileList(sortedFiles, childPrefix, config, output);\n }\n}\n\n/**\n * Flatten resource groups into a single sorted list of resources.\n * Shared by resources view, deps view, and remote package detail.\n */\nexport function flattenResourceGroups<T extends { name: string; files: unknown[] }>(\n groups: Array<{ resourceType: string; resources: T[] }>\n): T[] {\n const flat: T[] = [];\n for (const group of groups) {\n flat.push(...group.resources);\n }\n return flat.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/**\n * Render a flat list of resources (no category grouping).\n * Each resource is displayed as category/namespace with optional file children.\n * @param hasMoreSiblings - when true, the last resource uses \u251C instead of \u2514 (more siblings follow)\n */\nexport function renderFlatResourceList<TFile>(\n resources: (ListResourceInfo | EnhancedResourceInfo)[],\n prefix: string,\n showFiles: boolean,\n config: TreeRenderConfig<TFile>,\n hasMoreSiblings?: boolean,\n output?: OutputPort\n): void {\n for (let ri = 0; ri < resources.length; ri++) {\n const resource = resources[ri];\n const isNaturalLast = ri === resources.length - 1;\n const isLast = hasMoreSiblings ? false : isNaturalLast;\n renderResource(resource, prefix, isLast, showFiles, config, output);\n }\n}\n\n/**\n * Render a single resource group with all its resources.\n * Reserved for potential future hierarchical (grouped) display.\n * Currently unused; list/view use renderFlatResourceList.\n *\n * @deprecated Unused - kept for potential hierarchical view support\n */\nexport function renderResourceGroup<TFile>(\n group: ListResourceGroup | EnhancedResourceGroup,\n prefix: string,\n isLast: boolean,\n showFiles: boolean,\n config: TreeRenderConfig<TFile>,\n output?: OutputPort\n): void {\n const out = output ?? resolveOutput();\n const isOtherGroup = group.resourceType === 'other';\n \n if (isOtherGroup) {\n // Flatten: show files directly without resource subcategories\n const allFiles = collectGroupFiles<TFile>(group, config);\n const totalFileCount = allFiles.length;\n const hasFiles = showFiles && allFiles.length > 0;\n \n const connector = getTreeConnector(isLast, hasFiles);\n out.message(`${prefix}${connector}${group.resourceType}${dim(` (${totalFileCount})`)}`);\n \n if (hasFiles) {\n const childPrefix = getChildPrefix(prefix, isLast);\n renderFlatFileList(allFiles, childPrefix, config, output);\n }\n } else {\n // Normal: show resources as subcategories, then files\n const hasResources = group.resources.length > 0;\n const connector = getTreeConnector(isLast, hasResources);\n const childPrefix = getChildPrefix(prefix, isLast);\n \n out.message(`${prefix}${connector}${group.resourceType}${dim(` (${group.resources.length})`)}`);\n \n for (let ri = 0; ri < group.resources.length; ri++) {\n const resource = group.resources[ri];\n const isLastResource = ri === group.resources.length - 1;\n renderResource(resource, childPrefix, isLastResource, showFiles, config, output);\n }\n }\n}\n"],
5
+ "mappings": ";;;;;;AAqDA,IAAM,MAAM,WACN,QAAQ,WACR,MAAM;AAEZ,SAAS,IAAI,MAAsB;AACjC,SAAO,GAAG,GAAG,GAAG,IAAI,GAAG,KAAK;AAC9B;AAEA,SAAS,IAAI,MAAsB;AACjC,SAAO,GAAG,GAAG,GAAG,IAAI,GAAG,KAAK;AAC9B;AAKO,SAAS,iBAAiB,QAAiB,aAA8B;AAC9E,SAAI,SACK,cAAc,wBAAS,wBAEzB,cAAc,wBAAS;AAChC;AAKO,SAAS,eAAe,cAAsB,QAAyB;AAC5E,SAAO,gBAAgB,SAAS,OAAO;AACzC;AAKO,SAAS,gBACd,MACA,QACQ;AACR,MAAM,WAAW,OAAO,WAAW,IAAI;AAGvC,SAFkB,OAAO,UAAU,IAAI,IAGnC,GAAG,IAAI,QAAQ,CAAC,IAAI,IAAI,WAAW,CAAC,KACpC,IAAI,QAAQ;AAClB;AAmBO,SAAS,mBACd,OACA,QACA,QACA,QACM;AACN,MAAM,MAAM,UAAU,cAAc;AACpC,WAAS,KAAK,GAAG,KAAK,MAAM,QAAQ,MAAM;AACxC,QAAM,OAAO,MAAM,EAAE,GACf,aAAa,OAAO,MAAM,SAAS,GACnC,gBAAgB,iBAAiB,YAAY,EAAK,GAClD,QAAQ,gBAAgB,MAAM,MAAM;AAC1C,QAAI,QAAQ,GAAG,MAAM,GAAG,aAAa,GAAG,KAAK,EAAE;AAAA,EACjD;AACF;AAKO,SAAS,eACd,UACA,QACA,QACA,WACA,QACA,QACM;AACN,MAAM,MAAM,UAAU,cAAc,GAC9B,WAAW,UACX,gBAAgB,OAAO,2BAA2B,SAAS,QAAQ,KAAK,CAAC,GAIzE,kBAAkB,aAAa,SAAS,MAAM,SAAS,GAEvD,YAAY,iBAAiB,QAAQ,eAAe,GACpD,cAAc,eAAe,QAAQ,MAAM,GAC3C,gBAAgB,kBAAkB,cAAc,YAAO,aAGvD,QAAQ,OAAO,mBAAmB,SAAS,MAAM,KAAK;AAC5D,MAAI,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,IAAI,GAAG,QAAQ,MAAM,QAAQ,EAAE,EAAE;AAI9E,MAAM,iBAAiB,kBAAkB,KAAK;AAC9C,WAAW,SAAS;AAClB,QAAI,QAAQ,GAAG,aAAa,GAAG,cAAc,GAAG,KAAK,EAAE;AAIzD,MAAI,iBAAiB;AACnB,QAAM,cAAc,CAAC,GAAI,SAAS,KAAiB,EAAE,KAAK,OAAO,SAAS;AAC1E,uBAAmB,aAAa,aAAa,QAAQ,MAAM;AAAA,EAC7D;AACF;AAMO,SAAS,sBACd,QACK;AACL,MAAM,OAAY,CAAC;AACnB,WAAW,SAAS;AAClB,SAAK,KAAK,GAAG,MAAM,SAAS;AAE9B,SAAO,KAAK,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AACzD;AAOO,SAAS,uBACd,WACA,QACA,WACA,QACA,iBACA,QACM;AACN,WAAS,KAAK,GAAG,KAAK,UAAU,QAAQ,MAAM;AAC5C,QAAM,WAAW,UAAU,EAAE,GACvB,gBAAgB,OAAO,UAAU,SAAS;AAEhD,mBAAe,UAAU,QADV,kBAAkB,KAAQ,eACA,WAAW,QAAQ,MAAM;AAAA,EACpE;AACF;",
6
+ "names": []
7
+ }