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,1728 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ assertMutableSourceOrThrow,
4
+ isRegistryPath
5
+ } from "./chunk-BVVSU7QD.js";
6
+ import {
7
+ calculateFileHash,
8
+ createFlowExecutor
9
+ } from "./chunk-WT4VVCXM.js";
10
+ import "./chunk-IXOEIRDT.js";
11
+ import "./chunk-QURLGVA4.js";
12
+ import {
13
+ getTargetPath
14
+ } from "./chunk-SHKYQQJJ.js";
15
+ import {
16
+ readWorkspaceIndex
17
+ } from "./chunk-DEC24S7E.js";
18
+ import "./chunk-VXNS3X5O.js";
19
+ import {
20
+ resolveDeclaredPath
21
+ } from "./chunk-FRYA3JAQ.js";
22
+ import {
23
+ createCliExecutionContext,
24
+ resolveOutput,
25
+ resolvePrompt
26
+ } from "./chunk-RAKMX654.js";
27
+ import "./chunk-GDVFS3YP.js";
28
+ import "./chunk-427DCURL.js";
29
+ import {
30
+ arePackageNamesEquivalent,
31
+ normalizePackageName
32
+ } from "./chunk-VN22A7NW.js";
33
+ import "./chunk-4X2EJHJN.js";
34
+ import {
35
+ splitFrontmatter
36
+ } from "./chunk-VQ2KY6CK.js";
37
+ import {
38
+ getGlobalExportFlows,
39
+ getGlobalImportFlows,
40
+ getPlatformDefinition,
41
+ inferPlatformFromWorkspaceFile
42
+ } from "./chunk-N43IXOND.js";
43
+ import {
44
+ normalizePathForProcessing
45
+ } from "./chunk-YMKK4XPN.js";
46
+ import {
47
+ FILE_PATTERNS,
48
+ MUTABILITY,
49
+ SOURCE_TYPES
50
+ } from "./chunk-IHVZ5AUJ.js";
51
+ import {
52
+ ensureDir,
53
+ exists,
54
+ getStats,
55
+ readTextFile,
56
+ walkFiles,
57
+ writeTextFile
58
+ } from "./chunk-S47F4OG4.js";
59
+ import "./chunk-ID4SVDQZ.js";
60
+ import {
61
+ logger
62
+ } from "./chunk-5EFWGD33.js";
63
+
64
+ // ../core/src/core/source-resolution/resolve-package-source.ts
65
+ import path from "path";
66
+ async function resolvePackageSource(workspaceRoot, packageName) {
67
+ let normalizedTarget = normalizePackageName(packageName), ws = await readWorkspaceIndex(workspaceRoot), entryKey = Object.keys(ws.index.packages ?? {}).find(
68
+ (k) => arePackageNamesEquivalent(k, normalizedTarget)
69
+ ), entry = entryKey ? ws.index.packages?.[entryKey] : void 0;
70
+ if (!entry?.path)
71
+ throw new Error(
72
+ `Package '${packageName}' is not installed in this workspace.
73
+ Run 'opkg install ${packageName}' to install it first.`
74
+ );
75
+ let resolved = resolveDeclaredPath(entry.path, workspaceRoot), absolutePath = path.join(resolved.absolute, path.sep), mutability = isRegistryPath(absolutePath) ? MUTABILITY.IMMUTABLE : MUTABILITY.MUTABLE, sourceType = isRegistryPath(absolutePath) ? SOURCE_TYPES.REGISTRY : SOURCE_TYPES.PATH;
76
+ return {
77
+ packageName: normalizePackageName(entryKey ?? normalizedTarget),
78
+ absolutePath,
79
+ declaredPath: resolved.declared,
80
+ mutability,
81
+ version: entry.version,
82
+ sourceType
83
+ };
84
+ }
85
+
86
+ // ../core/src/core/save/save-candidate-builder.ts
87
+ import { join, relative } from "path";
88
+ async function buildCandidates(options) {
89
+ let errors = [];
90
+ logger.debug("Building workspace candidates from workspace paths");
91
+ let { candidates: workspaceCandidates, errors: workspaceErrors } = await buildWorkspaceCandidates(
92
+ options.workspaceRoot,
93
+ options.packageRoot,
94
+ options.filesMapping
95
+ );
96
+ errors.push(...workspaceErrors), logger.debug("Building local source refs from package source (lazy mode)");
97
+ let localSourceRefs = await buildLocalSourceRefs(
98
+ options.packageRoot
99
+ );
100
+ return logger.debug(
101
+ `Built ${localSourceRefs.length} local source refs, ${workspaceCandidates.length} workspace candidates`
102
+ ), {
103
+ localCandidates: [],
104
+ localSourceRefs,
105
+ workspaceCandidates,
106
+ errors
107
+ };
108
+ }
109
+ async function buildLocalSourceRefs(packageRoot) {
110
+ let refs = [];
111
+ for await (let absPath of walkFiles(packageRoot)) {
112
+ let relPath = relative(packageRoot, absPath), normalizedPath = normalizePathForProcessing(relPath);
113
+ normalizedPath && (normalizedPath.startsWith(".openpackage/") || normalizedPath === "openpackage.yml" || normalizedPath.startsWith(".") && !normalizedPath.match(/^\.(cursor|claude|opencode|windsurf|roo|factory|kilo|qwen|warp|codex|pi|kilocode|agent|augment)/) || (refs.push({ registryPath: normalizedPath, fullPath: absPath }), logger.debug(`Built local source ref: ${normalizedPath}`)));
114
+ }
115
+ return refs;
116
+ }
117
+ async function materializeLocalCandidate(ref, packageRoot) {
118
+ return buildCandidate("local", ref.fullPath, ref.registryPath, {
119
+ packageRoot,
120
+ workspaceRoot: packageRoot,
121
+ inferPlatform: !1,
122
+ parseMarkdown: !0
123
+ });
124
+ }
125
+ async function buildWorkspaceCandidates(workspaceRoot, packageRoot, filesMapping) {
126
+ let candidates = [], errors = [];
127
+ for (let [rawKey, targets] of Object.entries(filesMapping)) {
128
+ let registryKey = normalizePathForProcessing(rawKey);
129
+ if (!registryKey || !Array.isArray(targets)) continue;
130
+ let isDirectoryMapping = registryKey.endsWith("/");
131
+ for (let mapping of targets) {
132
+ let workspaceRel = getTargetPath(mapping), normalizedTargetPath = normalizePathForProcessing(workspaceRel);
133
+ if (!normalizedTargetPath) continue;
134
+ let absTargetPath = join(workspaceRoot, normalizedTargetPath), mergeMetadata = typeof mapping == "object" && mapping !== null ? { merge: mapping.merge, keys: mapping.keys } : void 0;
135
+ if (isDirectoryMapping) {
136
+ logger.debug(`Enumerating directory mapping: ${registryKey} -> ${normalizedTargetPath}`);
137
+ try {
138
+ let files = await collectFilesUnderDirectory(absTargetPath);
139
+ logger.debug(`Found ${files.length} files under directory ${normalizedTargetPath}`);
140
+ for (let relFile of files) {
141
+ let registryPath = normalizePathForProcessing(join(registryKey, relFile));
142
+ if (!registryPath) continue;
143
+ let absWorkspaceFile = join(absTargetPath, relFile), candidate = await buildCandidate("workspace", absWorkspaceFile, registryPath, {
144
+ packageRoot,
145
+ workspaceRoot,
146
+ inferPlatform: !0,
147
+ parseMarkdown: !0,
148
+ mergeStrategy: mergeMetadata?.merge,
149
+ mergeKeys: mergeMetadata?.keys
150
+ });
151
+ candidate && (candidates.push(candidate), logger.debug(`Built workspace candidate: ${registryPath} (from directory)`));
152
+ }
153
+ } catch (error) {
154
+ let errorMsg = error instanceof Error ? error.message : String(error);
155
+ errors.push({
156
+ path: absTargetPath,
157
+ registryPath: registryKey,
158
+ reason: `Failed to enumerate directory: ${errorMsg}`
159
+ }), logger.warn(`Failed to enumerate directory ${absTargetPath}: ${errorMsg}`);
160
+ }
161
+ } else {
162
+ if (!await exists(absTargetPath)) {
163
+ logger.debug(`Workspace file not found (skipping): ${normalizedTargetPath}`);
164
+ continue;
165
+ }
166
+ let candidate = await buildCandidate("workspace", absTargetPath, registryKey, {
167
+ packageRoot,
168
+ workspaceRoot,
169
+ inferPlatform: !0,
170
+ parseMarkdown: !0,
171
+ mergeStrategy: mergeMetadata?.merge,
172
+ mergeKeys: mergeMetadata?.keys
173
+ });
174
+ candidate && (candidates.push(candidate), logger.debug(`Built workspace candidate: ${registryKey}`));
175
+ }
176
+ }
177
+ }
178
+ return { candidates, errors };
179
+ }
180
+ async function buildCandidate(source, absPath, registryPath, options) {
181
+ try {
182
+ let content = await readTextFile(absPath), contentHash = await calculateFileHash(content), stats = await getStats(absPath), rootPath = source === "workspace" ? options.workspaceRoot : options.packageRoot, relPath = absPath.slice(rootPath.length + 1), displayPath = normalizePathForProcessing(relPath) || registryPath, platform;
183
+ if (options.inferPlatform && source === "workspace") {
184
+ let sourceDir = deriveSourceDir(displayPath);
185
+ platform = inferPlatformFromWorkspaceFile(
186
+ absPath,
187
+ sourceDir,
188
+ registryPath,
189
+ options.workspaceRoot
190
+ );
191
+ }
192
+ let frontmatter, rawFrontmatter, markdownBody, isMarkdown = !1;
193
+ if (options.parseMarkdown && (absPath.endsWith(".md") || absPath.endsWith(".markdown"))) {
194
+ isMarkdown = !0;
195
+ try {
196
+ let parsed = splitFrontmatter(content);
197
+ parsed.frontmatter && Object.keys(parsed.frontmatter).length > 0 && (frontmatter = parsed.frontmatter, rawFrontmatter = parsed.rawFrontmatter, markdownBody = parsed.body);
198
+ } catch (error) {
199
+ logger.debug(`Failed to parse frontmatter for ${absPath}: ${error}`);
200
+ }
201
+ }
202
+ return {
203
+ source,
204
+ registryPath,
205
+ fullPath: absPath,
206
+ content,
207
+ contentHash,
208
+ mtime: stats.mtime.getTime(),
209
+ displayPath,
210
+ platform,
211
+ frontmatter,
212
+ rawFrontmatter,
213
+ markdownBody,
214
+ isMarkdown,
215
+ mergeStrategy: options.mergeStrategy,
216
+ mergeKeys: options.mergeKeys
217
+ };
218
+ } catch (error) {
219
+ let errorMsg = error instanceof Error ? error.message : String(error);
220
+ return logger.warn(`Failed to build candidate for ${absPath}: ${errorMsg}`), null;
221
+ }
222
+ }
223
+ async function collectFilesUnderDirectory(absDir) {
224
+ let collected = [];
225
+ if (!await exists(absDir))
226
+ return collected;
227
+ for await (let absFile of walkFiles(absDir)) {
228
+ let relPath = absFile.slice(absDir.length + 1).replace(/\\/g, "/");
229
+ collected.push(relPath);
230
+ }
231
+ return collected;
232
+ }
233
+ function deriveSourceDir(relPath) {
234
+ return relPath && relPath.split("/")[0] || "";
235
+ }
236
+
237
+ // ../core/src/core/save/save-group-builder.ts
238
+ import { minimatch } from "minimatch";
239
+ function buildCandidateGroups(localRefs, workspaceCandidates, workspaceRoot = process.cwd()) {
240
+ let map = /* @__PURE__ */ new Map();
241
+ logger.debug(`Building groups from ${localRefs.length} local refs and ${workspaceCandidates.length} workspace candidates`);
242
+ for (let ref of localRefs) {
243
+ let group = ensureGroup(map, ref.registryPath);
244
+ group.localRef = ref, logger.debug(`Added local ref: ${ref.registryPath}`);
245
+ }
246
+ for (let candidate of workspaceCandidates) {
247
+ logger.debug(
248
+ `Processing workspace candidate: ${candidate.displayPath} (registryPath: ${candidate.registryPath}, platform: ${candidate.platform || "none"})`
249
+ );
250
+ let group = map.get(candidate.registryPath);
251
+ if (group && logger.debug(` Found exact match by registryPath: ${candidate.registryPath}`), !group) {
252
+ let sourceRegistryPath = findSourceFileForWorkspace(
253
+ candidate,
254
+ localRefs,
255
+ workspaceRoot
256
+ );
257
+ sourceRegistryPath || (sourceRegistryPath = findSourceFileByFallback(
258
+ candidate.registryPath,
259
+ localRefs
260
+ )), sourceRegistryPath ? (logger.debug(
261
+ ` Matched to source: workspace ${candidate.displayPath} \u2192 source ${sourceRegistryPath}`
262
+ ), group = ensureGroup(map, sourceRegistryPath)) : logger.debug(" No source match found");
263
+ }
264
+ group || (logger.debug(` Creating new group with workspace registryPath: ${candidate.registryPath}`), group = ensureGroup(map, candidate.registryPath)), group.workspace.push(candidate);
265
+ }
266
+ let allGroups = Array.from(map.values()), activeCount = allGroups.filter((g) => g.workspace.length > 0).length;
267
+ return logger.debug(`Built ${map.size} candidate groups (${activeCount} with workspace candidates)`), allGroups;
268
+ }
269
+ function findSourceFileByFallback(registryPath, localRefs) {
270
+ let baseName = registryPath.replace(/\.[^.]+$/, ""), candidates = localRefs.filter((c) => c.registryPath.replace(/\.[^.]+$/, "") === baseName);
271
+ if (candidates.length === 1)
272
+ return logger.debug(` Fallback match: ${registryPath} \u2192 ${candidates[0].registryPath} (same basename)`), candidates[0].registryPath;
273
+ let fileNameBase = (registryPath.split("/").pop() || "").replace(/\.[^.]+$/, "");
274
+ if (fileNameBase) {
275
+ let fileNameCandidates = localRefs.filter((c) => (c.registryPath.split("/").pop() || "").replace(/\.[^.]+$/, "") === fileNameBase);
276
+ if (fileNameCandidates.length === 1)
277
+ return logger.debug(
278
+ ` Fallback match: ${registryPath} \u2192 ${fileNameCandidates[0].registryPath} (same filename)`
279
+ ), fileNameCandidates[0].registryPath;
280
+ }
281
+ return null;
282
+ }
283
+ function findSourceFileForWorkspace(workspaceCandidate, localRefs, workspaceRoot) {
284
+ let platform = workspaceCandidate.platform;
285
+ if (!platform || platform === "ai")
286
+ return null;
287
+ try {
288
+ let platformExportFlows = getPlatformDefinition(platform, workspaceRoot).export || [], allExportFlows = [...getGlobalExportFlows(workspaceRoot) || [], ...platformExportFlows];
289
+ logger.debug(` Checking ${allExportFlows.length} export flows for platform ${platform}`);
290
+ let workspacePath = workspaceCandidate.displayPath;
291
+ for (let flow of allExportFlows) {
292
+ let toPattern = Array.isArray(flow.to) ? flow.to[0] : flow.to;
293
+ if (typeof toPattern == "object" && "$switch" in toPattern || typeof toPattern != "string" || !minimatch(workspacePath, toPattern, { dot: !0 }))
294
+ continue;
295
+ logger.debug(` Workspace path ${workspacePath} matches 'to' pattern: ${toPattern}`);
296
+ let fromPatterns = Array.isArray(flow.from) ? flow.from : [flow.from];
297
+ for (let fromPattern of fromPatterns)
298
+ if (!(typeof fromPattern == "object" && "$switch" in fromPattern) && typeof fromPattern == "string") {
299
+ logger.debug(` Checking 'from' pattern: ${fromPattern}`);
300
+ for (let ref of localRefs)
301
+ if (minimatch(ref.registryPath, fromPattern, { dot: !0 }))
302
+ return logger.debug(` Found matching source: ${ref.registryPath}`), ref.registryPath;
303
+ }
304
+ }
305
+ logger.debug(" No matching source file found");
306
+ } catch (error) {
307
+ logger.warn(`Failed to find source file for workspace candidate: ${error}`);
308
+ }
309
+ return null;
310
+ }
311
+ function filterGroupsWithWorkspace(groups) {
312
+ return groups.filter((group) => group.workspace.length > 0);
313
+ }
314
+ function ensureGroup(map, registryPath) {
315
+ let group = map.get(registryPath);
316
+ return group || (group = {
317
+ registryPath,
318
+ workspace: []
319
+ }, map.set(registryPath, group)), group;
320
+ }
321
+
322
+ // ../core/src/core/save/save-conversion-helper.ts
323
+ import { join as join2 } from "path";
324
+ import { tmpdir } from "os";
325
+ import { mkdtemp, rm } from "fs/promises";
326
+ import { minimatch as minimatch2 } from "minimatch";
327
+
328
+ // ../core/src/core/save/save-merge-extractor.ts
329
+ async function extractPackageContribution(candidate) {
330
+ if (candidate.source !== "workspace")
331
+ return {
332
+ success: !1,
333
+ error: "Extract only applies to workspace candidates"
334
+ };
335
+ if (!candidate.mergeStrategy || !candidate.mergeKeys || candidate.mergeKeys.length === 0)
336
+ return {
337
+ success: !1,
338
+ error: "No merge metadata present"
339
+ };
340
+ let { mergeStrategy, mergeKeys, content } = candidate;
341
+ try {
342
+ switch (mergeStrategy) {
343
+ case "deep":
344
+ case "shallow":
345
+ let normalizedKeys = normalizeKeysToParent(mergeKeys);
346
+ return await extractFromJsonMerge(content, normalizedKeys);
347
+ case "composite":
348
+ return {
349
+ success: !1,
350
+ error: "Composite merge extraction not yet implemented"
351
+ };
352
+ case "replace":
353
+ return {
354
+ success: !1,
355
+ error: "Replace strategy does not require extraction"
356
+ };
357
+ default:
358
+ return {
359
+ success: !1,
360
+ error: `Unknown merge strategy: ${mergeStrategy}`
361
+ };
362
+ }
363
+ } catch (error) {
364
+ return logger.debug(`Failed to extract package contribution: ${error}`), {
365
+ success: !1,
366
+ error: error instanceof Error ? error.message : String(error)
367
+ };
368
+ }
369
+ }
370
+ async function extractContentByKeys(content, mergeKeys) {
371
+ try {
372
+ let normalizedKeys = normalizeKeysToParent(mergeKeys);
373
+ return await extractFromJsonMerge(content, normalizedKeys);
374
+ } catch (error) {
375
+ return {
376
+ success: !1,
377
+ error: error instanceof Error ? error.message : String(error)
378
+ };
379
+ }
380
+ }
381
+ function normalizeKeysToParent(keys) {
382
+ if (keys.length === 0) return [];
383
+ if (keys.every((key) => key.split(".").length <= 2))
384
+ return logger.debug(
385
+ "Keys already at parent level - using as-is",
386
+ { keys }
387
+ ), keys;
388
+ if (keys.length === 1) {
389
+ let parts = keys[0].split(".");
390
+ return parts.length >= 2 ? [parts.slice(0, 2).join(".")] : keys;
391
+ }
392
+ let firstParts = keys[0].split("."), commonDepth = 0;
393
+ for (let depth = 0; depth < firstParts.length; depth++) {
394
+ let segment = firstParts[depth];
395
+ if (keys.every((key) => {
396
+ let parts = key.split(".");
397
+ return parts.length > depth && parts[depth] === segment;
398
+ }))
399
+ commonDepth = depth + 1;
400
+ else
401
+ break;
402
+ }
403
+ let normalized = /* @__PURE__ */ new Set();
404
+ for (let key of keys) {
405
+ let parts = key.split("."), targetDepth = Math.max(2, commonDepth + 1), extractDepth = Math.min(targetDepth, parts.length);
406
+ extractDepth >= 2 ? normalized.add(parts.slice(0, extractDepth).join(".")) : parts.length > 0 && normalized.add(key);
407
+ }
408
+ let result = Array.from(normalized);
409
+ return logger.debug(
410
+ `Normalized ${keys.length} tracked keys to ${result.length} extraction key(s)`,
411
+ { original: keys, normalized: result }
412
+ ), result;
413
+ }
414
+ async function extractFromJsonMerge(content, mergeKeys) {
415
+ try {
416
+ let merged = JSON.parse(content), extracted = {};
417
+ for (let keyPath of mergeKeys) {
418
+ let value = getNestedValue(merged, keyPath);
419
+ value !== void 0 && setNestedValue(extracted, keyPath, value);
420
+ }
421
+ let extractedContent = JSON.stringify(extracted, null, 2) + `
422
+ `, extractedHash = await calculateFileHash(extractedContent);
423
+ return logger.debug(
424
+ `Extracted ${mergeKeys.length} key(s) from merged file`,
425
+ { keys: mergeKeys }
426
+ ), {
427
+ success: !0,
428
+ extractedContent,
429
+ extractedHash
430
+ };
431
+ } catch (error) {
432
+ return {
433
+ success: !1,
434
+ error: error instanceof Error ? error.message : String(error)
435
+ };
436
+ }
437
+ }
438
+ function getNestedValue(obj, keyPath) {
439
+ let keys = keyPath.split("."), current = obj;
440
+ for (let key of keys) {
441
+ if (current == null || typeof current != "object")
442
+ return;
443
+ current = current[key];
444
+ }
445
+ return current;
446
+ }
447
+ function setNestedValue(obj, keyPath, value) {
448
+ let keys = keyPath.split("."), current = obj;
449
+ for (let i = 0; i < keys.length - 1; i++) {
450
+ let key = keys[i];
451
+ (!(key in current) || typeof current[key] != "object") && (current[key] = {}), current = current[key];
452
+ }
453
+ let lastKey = keys[keys.length - 1];
454
+ current[lastKey] = value;
455
+ }
456
+
457
+ // ../core/src/core/save/save-conversion-helper.ts
458
+ var sharedTempDir = null, tempDirCounter = 0;
459
+ async function initSharedTempDir() {
460
+ sharedTempDir || (sharedTempDir = await mkdtemp(join2(tmpdir(), "opkg-save-")));
461
+ }
462
+ async function cleanupSharedTempDir() {
463
+ if (sharedTempDir) {
464
+ try {
465
+ await rm(sharedTempDir, { recursive: !0, force: !0 });
466
+ } catch (error) {
467
+ logger.debug("Failed to cleanup shared temp directory", { tempDir: sharedTempDir, error });
468
+ }
469
+ sharedTempDir = null, tempDirCounter = 0;
470
+ }
471
+ }
472
+ async function allocateTempSubdir() {
473
+ if (!sharedTempDir)
474
+ return await mkdtemp(join2(tmpdir(), "opkg-save-standalone-"));
475
+ let subDir = join2(sharedTempDir, `op-${tempDirCounter++}`);
476
+ return await ensureDir(subDir), subDir;
477
+ }
478
+ var conversionCache = /* @__PURE__ */ new Map();
479
+ function getCacheKey(candidate) {
480
+ return `${candidate.fullPath}:${candidate.contentHash}:${candidate.platform || "none"}`;
481
+ }
482
+ async function calculateConvertedHash(candidate, workspaceRoot) {
483
+ if (!candidate.platform || candidate.platform === "ai")
484
+ return candidate.contentHash;
485
+ let cacheKey = getCacheKey(candidate), cached = conversionCache.get(cacheKey);
486
+ if (cached)
487
+ return logger.debug(`Cache hit for converted hash: ${candidate.displayPath}`), cached;
488
+ let result = await convertWorkspaceToUniversal(
489
+ candidate.content,
490
+ candidate.platform,
491
+ candidate.registryPath,
492
+ workspaceRoot
493
+ );
494
+ return !result.success || !result.convertedHash ? (logger.debug(
495
+ `Conversion not applicable or failed for ${candidate.displayPath}, using raw hash`,
496
+ { reason: result.error }
497
+ ), candidate.contentHash) : (conversionCache.set(cacheKey, result.convertedHash), result.convertedHash);
498
+ }
499
+ async function convertWorkspaceToUniversal(workspaceContent, platform, registryPath, workspaceRoot) {
500
+ try {
501
+ let platformImportFlows = getPlatformDefinition(platform, workspaceRoot).import || [], allImportFlows = [...getGlobalImportFlows(workspaceRoot) || [], ...platformImportFlows];
502
+ if (allImportFlows.length === 0)
503
+ return logger.debug(`No import flows defined for platform ${platform}`), {
504
+ success: !1,
505
+ error: "No import flows defined for platform"
506
+ };
507
+ let matchingFlow = findMatchingImportFlow(
508
+ allImportFlows,
509
+ registryPath,
510
+ platform,
511
+ workspaceRoot
512
+ );
513
+ if (!matchingFlow)
514
+ return logger.debug(`No matching import flow for ${registryPath} on platform ${platform}`), {
515
+ success: !1,
516
+ error: "No matching import flow found"
517
+ };
518
+ let tempDir = await allocateTempSubdir(), inputDir = join2(tempDir, "in"), outputDir = join2(tempDir, "out");
519
+ await ensureDir(inputDir), await ensureDir(outputDir);
520
+ let workspaceSourcePath = inferWorkspaceSourcePath(
521
+ matchingFlow,
522
+ registryPath,
523
+ platform
524
+ ), inputFilePath = join2(inputDir, workspaceSourcePath);
525
+ await ensureDir(join2(inputFilePath, "..")), await writeTextFile(inputFilePath, workspaceContent);
526
+ let flowContext = {
527
+ workspaceRoot: outputDir,
528
+ // Output goes to outputDir
529
+ packageRoot: inputDir,
530
+ // Input comes from inputDir
531
+ platform,
532
+ // Source platform
533
+ packageName: "temp",
534
+ direction: "install",
535
+ // Import flows are used during "install" direction
536
+ variables: {
537
+ name: "temp",
538
+ version: "0.0.0",
539
+ platform,
540
+ // For conditionals: $$platform
541
+ source: platform,
542
+ // For conditionals: $$source
543
+ sourcePlatform: platform,
544
+ targetPlatform: "openpackage"
545
+ },
546
+ dryRun: !1
547
+ }, executor = createFlowExecutor(), concreteFlow = {
548
+ ...matchingFlow,
549
+ from: workspaceSourcePath
550
+ // Use concrete file path
551
+ }, flowResult = await executor.executeFlow(concreteFlow, flowContext);
552
+ if (!flowResult.success)
553
+ return {
554
+ success: !1,
555
+ error: `Flow execution failed: ${flowResult.error?.message}`
556
+ };
557
+ if (typeof flowResult.target != "string")
558
+ return {
559
+ success: !1,
560
+ error: "Flow did not produce target path"
561
+ };
562
+ let outputFilePath = flowResult.target;
563
+ if (!await exists(outputFilePath))
564
+ return {
565
+ success: !1,
566
+ error: "Flow did not produce output file"
567
+ };
568
+ let convertedContent = await readTextFile(outputFilePath), convertedHash = await calculateFileHash(convertedContent);
569
+ return logger.debug(
570
+ `Successfully converted ${registryPath} from ${platform} format to universal`,
571
+ {
572
+ originalHash: await calculateFileHash(workspaceContent),
573
+ convertedHash
574
+ }
575
+ ), {
576
+ success: !0,
577
+ convertedContent,
578
+ convertedHash
579
+ };
580
+ } catch (error) {
581
+ return logger.warn(
582
+ `Conversion failed for ${registryPath} (platform: ${platform})`,
583
+ { error }
584
+ ), {
585
+ success: !1,
586
+ error: error instanceof Error ? error.message : String(error)
587
+ };
588
+ }
589
+ }
590
+ function findMatchingImportFlow(flows, registryPath, platform, workspaceRoot) {
591
+ for (let flow of flows) {
592
+ let toPattern = Array.isArray(flow.to) ? flow.to[0] : flow.to;
593
+ if (typeof toPattern == "object" && "$switch" in toPattern) {
594
+ logger.debug("Skipping flow with switch expression in to field");
595
+ continue;
596
+ }
597
+ if (typeof toPattern == "string" && minimatch2(registryPath, toPattern, { dot: !0 })) {
598
+ if (flow.when && !evaluateWhenCondition(flow.when, platform, workspaceRoot)) {
599
+ logger.debug(`Flow condition not met for ${registryPath}`, { when: flow.when });
600
+ continue;
601
+ }
602
+ return flow;
603
+ }
604
+ }
605
+ }
606
+ function evaluateWhenCondition(when, platform, workspaceRoot) {
607
+ if (when.$eq && Array.isArray(when.$eq) && when.$eq.length === 2) {
608
+ let left = resolveVariable(when.$eq[0], platform), right = resolveVariable(when.$eq[1], platform);
609
+ return left === right;
610
+ }
611
+ if (when.$ne && Array.isArray(when.$ne) && when.$ne.length === 2) {
612
+ let left = resolveVariable(when.$ne[0], platform), right = resolveVariable(when.$ne[1], platform);
613
+ return left !== right;
614
+ }
615
+ return when.exists ? !0 : (logger.debug("Unknown condition type in when clause", { when }), !1);
616
+ }
617
+ function resolveVariable(value, platform) {
618
+ return typeof value == "string" && (value === "$$platform" || value === "$$source") ? platform : value;
619
+ }
620
+ function inferWorkspaceSourcePath(flow, registryPath, platform) {
621
+ let fromPattern = Array.isArray(flow.from) ? flow.from[0] : flow.from;
622
+ if (typeof fromPattern == "object" && "$switch" in fromPattern)
623
+ return logger.debug("Cannot infer source path from switch expression, using registry path"), registryPath;
624
+ if (typeof fromPattern != "string")
625
+ return registryPath;
626
+ if (fromPattern.includes("**") || fromPattern.includes("*")) {
627
+ let baseDir = fromPattern.split("**")[0].replace(/\*+/g, ""), toPattern = Array.isArray(flow.to) ? flow.to[0] : flow.to;
628
+ if (typeof toPattern == "string" && toPattern.includes("**")) {
629
+ let toBase = toPattern.split("**")[0], subPath = registryPath.startsWith(toBase) ? registryPath.slice(toBase.length) : registryPath;
630
+ return `${baseDir}${subPath}`;
631
+ }
632
+ return registryPath;
633
+ }
634
+ return fromPattern;
635
+ }
636
+ async function convertSourceToWorkspace(sourceContent, platform, sourceRegistryPath, workspacePath, workspaceRoot) {
637
+ try {
638
+ let platformExportFlows = getPlatformDefinition(platform, workspaceRoot).export || [], allExportFlows = [...getGlobalExportFlows(workspaceRoot) || [], ...platformExportFlows];
639
+ if (allExportFlows.length === 0)
640
+ return {
641
+ success: !1,
642
+ error: "No export flows defined for platform"
643
+ };
644
+ let matchingFlow = findMatchingExportFlow(
645
+ allExportFlows,
646
+ sourceRegistryPath,
647
+ workspacePath,
648
+ platform,
649
+ workspaceRoot
650
+ );
651
+ if (!matchingFlow)
652
+ return {
653
+ success: !1,
654
+ error: "No matching export flow found"
655
+ };
656
+ let tempDir = await allocateTempSubdir(), inputDir = join2(tempDir, "in"), outputDir = join2(tempDir, "out");
657
+ await ensureDir(inputDir), await ensureDir(outputDir);
658
+ let inputFilePath = join2(inputDir, sourceRegistryPath);
659
+ await ensureDir(join2(inputFilePath, "..")), await writeTextFile(inputFilePath, sourceContent);
660
+ let flowContext = {
661
+ workspaceRoot: outputDir,
662
+ // Output goes to outputDir
663
+ packageRoot: inputDir,
664
+ // Input comes from inputDir
665
+ platform,
666
+ packageName: "temp",
667
+ direction: "install",
668
+ // Export flows are used during "install" direction
669
+ variables: {
670
+ name: "temp",
671
+ version: "0.0.0",
672
+ platform,
673
+ source: "openpackage",
674
+ sourcePlatform: "openpackage",
675
+ targetPlatform: platform,
676
+ targetRoot: "./"
677
+ },
678
+ dryRun: !1
679
+ }, flowResult = await createFlowExecutor().executeFlow(matchingFlow, flowContext);
680
+ if (!flowResult.success)
681
+ return {
682
+ success: !1,
683
+ error: `Flow execution failed: ${flowResult.error?.message}`
684
+ };
685
+ if (typeof flowResult.target != "string")
686
+ return {
687
+ success: !1,
688
+ error: "Flow did not produce target path"
689
+ };
690
+ let outputFilePath = flowResult.target;
691
+ if (!await exists(outputFilePath))
692
+ return {
693
+ success: !1,
694
+ error: "Flow did not produce output file"
695
+ };
696
+ let convertedContent = await readTextFile(outputFilePath), convertedHash = await calculateFileHash(convertedContent);
697
+ return logger.debug(
698
+ `Successfully forward converted ${sourceRegistryPath} to ${platform} format`,
699
+ {
700
+ originalHash: await calculateFileHash(sourceContent),
701
+ convertedHash
702
+ }
703
+ ), {
704
+ success: !0,
705
+ convertedContent,
706
+ convertedHash
707
+ };
708
+ } catch (error) {
709
+ return logger.warn(
710
+ `Forward conversion failed for ${sourceRegistryPath} (platform: ${platform})`,
711
+ { error }
712
+ ), {
713
+ success: !1,
714
+ error: error instanceof Error ? error.message : String(error)
715
+ };
716
+ }
717
+ }
718
+ function findMatchingExportFlow(flows, sourceRegistryPath, workspacePath, platform, workspaceRoot) {
719
+ for (let flow of flows) {
720
+ let fromPatterns = Array.isArray(flow.from) ? flow.from : [flow.from];
721
+ if (!(fromPatterns.some((p) => typeof p == "object" && "$switch" in p) || fromPatterns.some((p) => typeof p != "string") || !fromPatterns.some(
722
+ (p) => typeof p == "string" && minimatch2(sourceRegistryPath, p, { dot: !0 })
723
+ )) && !(flow.when && !evaluateWhenCondition(flow.when, platform, workspaceRoot)))
724
+ return flow;
725
+ }
726
+ }
727
+ async function ensureComparableHash(candidate, workspaceRoot) {
728
+ if (candidate.comparableHash !== void 0)
729
+ return candidate.comparableHash;
730
+ let hash = candidate.contentHash;
731
+ if (candidate.mergeStrategy && candidate.mergeKeys && candidate.mergeKeys.length > 0) {
732
+ let extractResult = await extractPackageContribution(candidate);
733
+ extractResult.success && extractResult.extractedHash ? (hash = extractResult.extractedHash, extractResult.extractedContent && (candidate.extractedContent = extractResult.extractedContent)) : hash = await calculateConvertedHash(candidate, workspaceRoot);
734
+ } else
735
+ hash = await calculateConvertedHash(candidate, workspaceRoot);
736
+ return candidate.comparableHash = hash, hash;
737
+ }
738
+ function clearConversionCache() {
739
+ conversionCache.clear();
740
+ }
741
+
742
+ // ../core/src/core/save/save-conflict-analyzer.ts
743
+ async function analyzeGroup(group, force, workspaceRoot) {
744
+ let registryPath = group.registryPath, hasLocal = !!group.local, workspaceCandidates = group.workspace, workspaceCandidateCount = workspaceCandidates.length, isRootFile = registryPath === FILE_PATTERNS.AGENTS_MD || registryPath === FILE_PATTERNS.CLAUDE_MD || registryPath === FILE_PATTERNS.GEMINI_MD || registryPath === FILE_PATTERNS.QWEN_MD || registryPath === FILE_PATTERNS.WARP_MD || workspaceCandidates.some((c) => c.isRootFile), hasPlatformCandidates = workspaceCandidates.some(
745
+ (c) => c.platform && c.platform !== "ai"
746
+ );
747
+ if (workspaceCandidateCount === 0)
748
+ return {
749
+ registryPath,
750
+ type: "no-action-needed",
751
+ workspaceCandidateCount: 0,
752
+ uniqueWorkspaceCandidates: [],
753
+ hasLocalCandidate: hasLocal,
754
+ localMatchesWorkspace: !1,
755
+ isRootFile,
756
+ hasPlatformCandidates: !1,
757
+ recommendedStrategy: "skip"
758
+ };
759
+ let uniqueWorkspace = await deduplicateCandidatesWithMerge(workspaceCandidates, workspaceRoot), localMatchesWorkspace = hasLocal && uniqueWorkspace.length === 1 ? await checkConvertedParity(uniqueWorkspace[0], group.local, workspaceRoot) : !1;
760
+ return hasLocal && uniqueWorkspace.length > 1 && (await Promise.all(
761
+ uniqueWorkspace.map(async (candidate) => ({
762
+ workspacePath: candidate.displayPath,
763
+ platform: candidate.platform || "none",
764
+ matchesLocal: await checkConvertedParity(candidate, group.local, workspaceRoot)
765
+ }))
766
+ )).every((result) => result.matchesLocal) ? {
767
+ registryPath,
768
+ type: "no-change-needed",
769
+ workspaceCandidateCount,
770
+ uniqueWorkspaceCandidates: uniqueWorkspace,
771
+ hasLocalCandidate: hasLocal,
772
+ localMatchesWorkspace: !0,
773
+ isRootFile,
774
+ hasPlatformCandidates,
775
+ recommendedStrategy: "skip"
776
+ } : localMatchesWorkspace ? {
777
+ registryPath,
778
+ type: "no-change-needed",
779
+ workspaceCandidateCount,
780
+ uniqueWorkspaceCandidates: uniqueWorkspace,
781
+ hasLocalCandidate: hasLocal,
782
+ localMatchesWorkspace: !0,
783
+ isRootFile,
784
+ hasPlatformCandidates,
785
+ recommendedStrategy: "skip"
786
+ } : uniqueWorkspace.length === 1 ? {
787
+ registryPath,
788
+ type: "auto-write",
789
+ workspaceCandidateCount,
790
+ uniqueWorkspaceCandidates: uniqueWorkspace,
791
+ hasLocalCandidate: hasLocal,
792
+ localMatchesWorkspace: !1,
793
+ isRootFile,
794
+ hasPlatformCandidates,
795
+ recommendedStrategy: "write-single"
796
+ } : {
797
+ registryPath,
798
+ type: "needs-resolution",
799
+ workspaceCandidateCount,
800
+ uniqueWorkspaceCandidates: uniqueWorkspace,
801
+ hasLocalCandidate: hasLocal,
802
+ localMatchesWorkspace: !1,
803
+ isRootFile,
804
+ hasPlatformCandidates,
805
+ recommendedStrategy: force ? "force-newest" : "interactive"
806
+ };
807
+ }
808
+ async function checkConvertedParity(workspace, local, workspaceRoot) {
809
+ let workspaceHash = await ensureComparableHash(workspace, workspaceRoot);
810
+ if (workspace.mergeStrategy && workspace.mergeKeys && workspace.mergeKeys.length > 0) {
811
+ if (workspace.platform && workspace.platform !== "ai") {
812
+ let forward = await convertSourceToWorkspace(
813
+ local.content,
814
+ workspace.platform,
815
+ local.registryPath,
816
+ workspace.displayPath,
817
+ workspaceRoot
818
+ );
819
+ if (forward.success && forward.convertedContent) {
820
+ let localConvertedExtract = await extractContentByKeys(
821
+ forward.convertedContent,
822
+ workspace.mergeKeys
823
+ );
824
+ if (localConvertedExtract.success && localConvertedExtract.extractedHash)
825
+ return workspaceHash === localConvertedExtract.extractedHash;
826
+ }
827
+ }
828
+ let localExtract = await extractContentByKeys(local.content, workspace.mergeKeys);
829
+ return localExtract.success && localExtract.extractedHash ? workspaceHash === localExtract.extractedHash : workspaceHash === local.contentHash;
830
+ }
831
+ return workspaceHash === local.contentHash;
832
+ }
833
+ async function deduplicateCandidatesWithMerge(candidates, workspaceRoot) {
834
+ let seen = /* @__PURE__ */ new Set(), unique = [];
835
+ for (let candidate of candidates) {
836
+ let hash = await ensureComparableHash(candidate, workspaceRoot);
837
+ if (logger.debug(
838
+ `Dedup check for ${candidate.displayPath}: hash=${hash}, rawHash=${candidate.contentHash}, seen=${seen.has(hash)}`
839
+ ), seen.has(hash)) {
840
+ logger.debug(` Skipping duplicate: ${candidate.displayPath}`);
841
+ continue;
842
+ }
843
+ seen.add(hash), unique.push(candidate);
844
+ }
845
+ return logger.debug(`Deduplication: ${candidates.length} \u2192 ${unique.length} unique candidates`), unique;
846
+ }
847
+ function getNewestCandidate(candidates) {
848
+ if (candidates.length === 0)
849
+ throw new Error("Cannot get newest candidate from empty array");
850
+ if (candidates.length === 1)
851
+ return candidates[0];
852
+ let newest = candidates[0];
853
+ for (let i = 1; i < candidates.length; i++) {
854
+ let current = candidates[i];
855
+ (current.mtime > newest.mtime || current.mtime === newest.mtime && current.displayPath < newest.displayPath) && (newest = current);
856
+ }
857
+ return newest;
858
+ }
859
+ function sortCandidatesByMtime(candidates) {
860
+ return [...candidates].sort((a, b) => b.mtime !== a.mtime ? b.mtime - a.mtime : a.displayPath.localeCompare(b.displayPath));
861
+ }
862
+
863
+ // ../core/src/core/save/save-interactive-resolver.ts
864
+ import { join as join3 } from "path";
865
+
866
+ // ../core/src/core/platform/platform-specific-paths.ts
867
+ function joinSegments(segments) {
868
+ return segments.filter(Boolean).join("/");
869
+ }
870
+ function suffixFileBasename(registryPath, platform) {
871
+ let segments = registryPath.split("/"), fileName = segments.pop();
872
+ if (!fileName)
873
+ return registryPath;
874
+ let lastDotIndex = fileName.lastIndexOf(".");
875
+ if (lastDotIndex <= 0)
876
+ return fileName.endsWith(`.${platform}`) ? segments.push(fileName) : segments.push(`${fileName}.${platform}`), joinSegments(segments);
877
+ let name = fileName.slice(0, lastDotIndex), ext = fileName.slice(lastDotIndex);
878
+ return name.endsWith(`.${platform}`) ? (segments.push(fileName), joinSegments(segments)) : (segments.push(`${name}.${platform}${ext}`), joinSegments(segments));
879
+ }
880
+ function createPlatformSpecificRegistryPath(registryPath, platform) {
881
+ let segments = registryPath.split("/"), fileName = segments[segments.length - 1], isRoot = segments.length === 1;
882
+ if (!fileName)
883
+ return registryPath;
884
+ if (isRoot) {
885
+ let definition = getPlatformDefinition(platform);
886
+ return definition?.rootFile ? definition.rootFile : null;
887
+ }
888
+ return registryPath.endsWith(FILE_PATTERNS.MD_FILES), suffixFileBasename(registryPath, platform);
889
+ }
890
+
891
+ // ../core/src/core/save/save-interactive-resolver.ts
892
+ async function resolveInteractively(input, output, prompt) {
893
+ let { registryPath, workspaceCandidates, group, packageRoot, workspaceRoot } = input, out = output ?? resolveOutput(), prm = prompt ?? resolvePrompt(), sortedCandidates = sortCandidatesByMtime(workspaceCandidates);
894
+ displayConflictHeader(registryPath, sortedCandidates, out);
895
+ let universalSelected = null, platformSpecificCandidates = [], skippedCandidates = [];
896
+ for (let candidate of sortedCandidates) {
897
+ let parityCheck = await isAtParity(candidate, group, packageRoot, workspaceRoot);
898
+ if (parityCheck.atParity) {
899
+ out.info(`
900
+ \u2713 ${candidate.displayPath}`), out.info(` ${parityCheck.reason} - auto-skipping
901
+ `), skippedCandidates.push(candidate);
902
+ continue;
903
+ }
904
+ if (universalSelected) {
905
+ let universalHash = await ensureComparableHash(universalSelected, workspaceRoot);
906
+ if (await ensureComparableHash(candidate, workspaceRoot) === universalHash) {
907
+ out.info(`
908
+ \u2713 ${candidate.displayPath}`), out.info(` Identical to universal - auto-skipping
909
+ `), skippedCandidates.push(candidate);
910
+ continue;
911
+ }
912
+ }
913
+ switch (await promptCandidateAction(
914
+ candidate,
915
+ registryPath,
916
+ universalSelected !== null,
917
+ prm
918
+ )) {
919
+ case "universal":
920
+ universalSelected = candidate, out.success(`
921
+ \u2713 Selected as universal: ${candidate.displayPath}
922
+ `);
923
+ break;
924
+ case "platform-specific":
925
+ platformSpecificCandidates.push(candidate), out.success(`
926
+ \u2713 Marked as platform-specific: ${candidate.displayPath}
927
+ `);
928
+ break;
929
+ case "skip":
930
+ skippedCandidates.push(candidate), out.info(`
931
+ \u2713 Skipped: ${candidate.displayPath}
932
+ `);
933
+ break;
934
+ }
935
+ }
936
+ return displayResolutionSummary(universalSelected, platformSpecificCandidates, skippedCandidates, out), {
937
+ selectedCandidate: universalSelected,
938
+ platformSpecificCandidates
939
+ };
940
+ }
941
+ async function checkForwardParity(workspaceCandidate, localCandidate, packageRoot, workspaceRoot) {
942
+ try {
943
+ let result = await convertSourceToWorkspace(
944
+ localCandidate.content,
945
+ workspaceCandidate.platform,
946
+ localCandidate.registryPath,
947
+ workspaceCandidate.displayPath,
948
+ workspaceRoot
949
+ );
950
+ if (result.success && result.convertedHash && (logger.debug(
951
+ `Forward conversion check: converted source hash=${result.convertedHash}, workspace hash=${workspaceCandidate.contentHash}`
952
+ ), result.convertedHash === workspaceCandidate.contentHash))
953
+ return {
954
+ atParity: !0,
955
+ reason: "Matches source after forward conversion (export flow)"
956
+ };
957
+ } catch (error) {
958
+ logger.debug(`Forward parity check failed: ${error}`);
959
+ }
960
+ return { atParity: !1 };
961
+ }
962
+ async function isAtParity(candidate, group, packageRoot, workspaceRoot) {
963
+ if (group.local) {
964
+ let comparisonHash = await ensureComparableHash(candidate, workspaceRoot);
965
+ if (logger.debug(
966
+ `Parity check for ${candidate.displayPath}: comparisonHash=${comparisonHash}, localHash=${group.local.contentHash}`
967
+ ), comparisonHash === group.local.contentHash)
968
+ return {
969
+ atParity: !0,
970
+ reason: "Already matches universal (cached comparable hash)"
971
+ };
972
+ if (candidate.platform && candidate.platform !== "ai" && !(candidate.mergeStrategy && candidate.mergeKeys && candidate.mergeKeys.length > 0)) {
973
+ let forwardCheck = await checkForwardParity(
974
+ candidate,
975
+ group.local,
976
+ packageRoot,
977
+ workspaceRoot
978
+ );
979
+ if (forwardCheck.atParity)
980
+ return forwardCheck;
981
+ }
982
+ }
983
+ if (candidate.platform && candidate.platform !== "ai") {
984
+ let platformPath = createPlatformSpecificRegistryPath(
985
+ group.registryPath,
986
+ candidate.platform
987
+ );
988
+ if (platformPath) {
989
+ let platformFullPath = join3(packageRoot, platformPath);
990
+ if (await exists(platformFullPath))
991
+ try {
992
+ let platformContent = await readTextFile(platformFullPath), platformHash = await calculateFileHash(platformContent);
993
+ if (candidate.contentHash === platformHash)
994
+ return {
995
+ atParity: !0,
996
+ reason: "Already matches platform-specific file"
997
+ };
998
+ } catch (error) {
999
+ logger.debug(`Could not read platform file ${platformFullPath}: ${error}`);
1000
+ }
1001
+ }
1002
+ }
1003
+ return { atParity: !1 };
1004
+ }
1005
+ async function promptCandidateAction(candidate, registryPath, universalAlreadySelected, prm) {
1006
+ let candidateLabel = formatCandidateLabel(candidate, !0), choices = universalAlreadySelected ? [
1007
+ { title: "Mark as platform-specific", value: "platform-specific" },
1008
+ { title: "Skip", value: "skip" }
1009
+ ] : [
1010
+ { title: "Set as universal", value: "universal" },
1011
+ { title: "Mark as platform-specific", value: "platform-specific" },
1012
+ { title: "Skip", value: "skip" }
1013
+ ];
1014
+ return await prm.select(
1015
+ ` ${candidateLabel}
1016
+ What should we do with this file?`,
1017
+ choices,
1018
+ "Arrow keys to navigate, Enter to select"
1019
+ );
1020
+ }
1021
+ function displayConflictHeader(registryPath, candidates, out) {
1022
+ out.warn(`Multiple workspace versions found for ${registryPath}`), out.info(` Resolving conflicts for ${candidates.length} file(s)...
1023
+ `);
1024
+ }
1025
+ function displayResolutionSummary(universal, platformSpecific, skipped, out) {
1026
+ out.info("\u2500".repeat(60)), out.info("Resolution summary:"), universal ? out.success(` \u2713 Universal: ${universal.displayPath}`) : out.info(" \u2139 No universal content selected"), platformSpecific.length > 0 && (out.success(` \u2713 Platform-specific: ${platformSpecific.length} file(s)`), platformSpecific.forEach((c) => {
1027
+ let platform = c.platform ? `(${c.platform})` : "";
1028
+ out.info(` \u2022 ${c.displayPath} ${platform}`);
1029
+ })), skipped.length > 0 && out.info(` \u2022 Skipped: ${skipped.length} file(s)`), out.info("\u2500".repeat(60) + `
1030
+ `);
1031
+ }
1032
+ function formatCandidateLabel(candidate, includeTimestamp = !1) {
1033
+ let parts = [];
1034
+ if (parts.push(candidate.displayPath), candidate.platform && candidate.platform !== "ai" && parts.push(`(${candidate.platform})`), includeTimestamp) {
1035
+ let timestamp = new Date(candidate.mtime).toLocaleString();
1036
+ parts.push(`[${timestamp}]`);
1037
+ }
1038
+ return parts.join(" ");
1039
+ }
1040
+
1041
+ // ../core/src/core/save/save-resolution-executor.ts
1042
+ async function executeResolution(group, analysis, packageRoot, workspaceRoot, output, prompt) {
1043
+ let strategy = analysis.recommendedStrategy;
1044
+ if (strategy === "skip")
1045
+ return null;
1046
+ let sortedCandidates = sortCandidatesByMtime(analysis.uniqueWorkspaceCandidates);
1047
+ switch (strategy) {
1048
+ case "write-single":
1049
+ return resolveSingle(sortedCandidates[0]);
1050
+ case "write-newest":
1051
+ return resolveIdentical(sortedCandidates);
1052
+ case "force-newest":
1053
+ return resolveForce(sortedCandidates, group.registryPath);
1054
+ case "interactive":
1055
+ return resolveInteractive(
1056
+ group.registryPath,
1057
+ sortedCandidates,
1058
+ analysis.isRootFile,
1059
+ group,
1060
+ packageRoot,
1061
+ workspaceRoot,
1062
+ output,
1063
+ prompt
1064
+ );
1065
+ default:
1066
+ return logger.warn(`Unknown resolution strategy: ${strategy}`), null;
1067
+ }
1068
+ }
1069
+ function resolveSingle(candidate) {
1070
+ return {
1071
+ selection: candidate,
1072
+ platformSpecific: [],
1073
+ strategy: "write-single",
1074
+ wasInteractive: !1
1075
+ };
1076
+ }
1077
+ function resolveIdentical(candidates) {
1078
+ return {
1079
+ selection: getNewestCandidate(candidates),
1080
+ platformSpecific: [],
1081
+ strategy: "write-newest",
1082
+ wasInteractive: !1
1083
+ };
1084
+ }
1085
+ function resolveForce(candidates, registryPath) {
1086
+ let newest = getNewestCandidate(candidates), maxMtime = newest.mtime, tiedCandidates = candidates.filter((c) => c.mtime === maxMtime);
1087
+ if (tiedCandidates.length > 1)
1088
+ logger.info(
1089
+ `Force mode: Multiple files have same modification time (${formatTimestamp(maxMtime)})`
1090
+ ), logger.info(` Auto-selecting first alphabetically: ${newest.displayPath}`), logger.info(" Tied files:"), tiedCandidates.forEach((c) => {
1091
+ let marker = c === newest ? "\u2192" : " ";
1092
+ logger.info(` ${marker} ${c.displayPath}`);
1093
+ }), tiedCandidates.filter((c) => c !== newest).forEach((c) => {
1094
+ logger.info(` Skipping: ${c.displayPath} (tied, not alphabetically first)`);
1095
+ }), candidates.filter((c) => c.mtime < maxMtime).forEach((c) => {
1096
+ logger.info(` Skipping: ${c.displayPath} (older)`);
1097
+ });
1098
+ else {
1099
+ logger.info(`Force mode: Auto-selecting newest (${newest.displayPath})`);
1100
+ let skipped = candidates.filter((c) => c !== newest);
1101
+ skipped.length > 0 && skipped.forEach((c) => {
1102
+ logger.info(` Skipping: ${c.displayPath} (older)`);
1103
+ });
1104
+ }
1105
+ return {
1106
+ selection: newest,
1107
+ platformSpecific: [],
1108
+ // Force mode doesn't auto-create platform-specific variants
1109
+ strategy: "force-newest",
1110
+ wasInteractive: !1
1111
+ };
1112
+ }
1113
+ async function resolveInteractive(registryPath, candidates, isRootFile, group, packageRoot, workspaceRoot, output, prompt) {
1114
+ let result = await resolveInteractively({
1115
+ registryPath,
1116
+ workspaceCandidates: candidates,
1117
+ isRootFile,
1118
+ group,
1119
+ packageRoot,
1120
+ workspaceRoot
1121
+ }, output, prompt);
1122
+ return {
1123
+ selection: result.selectedCandidate,
1124
+ platformSpecific: result.platformSpecificCandidates,
1125
+ strategy: "interactive",
1126
+ wasInteractive: !0
1127
+ };
1128
+ }
1129
+ function formatTimestamp(mtime) {
1130
+ return new Date(mtime).toLocaleString();
1131
+ }
1132
+
1133
+ // ../core/src/core/save/save-platform-handler.ts
1134
+ import { join as join4 } from "path";
1135
+ async function pruneExistingPlatformCandidates(packageRoot, groups) {
1136
+ for (let group of groups) {
1137
+ if (!group.local && !group.localRef)
1138
+ continue;
1139
+ let filtered = [];
1140
+ for (let candidate of group.workspace) {
1141
+ let platform = candidate.platform;
1142
+ if (!platform || platform === "ai") {
1143
+ filtered.push(candidate);
1144
+ continue;
1145
+ }
1146
+ let platformPath = createPlatformSpecificRegistryPath(
1147
+ group.registryPath,
1148
+ platform
1149
+ );
1150
+ if (!platformPath) {
1151
+ filtered.push(candidate);
1152
+ continue;
1153
+ }
1154
+ let platformFullPath = join4(packageRoot, platformPath);
1155
+ if (await exists(platformFullPath)) {
1156
+ logger.debug(
1157
+ `Pruning workspace candidate ${candidate.displayPath} for ${group.registryPath} (platform file ${platformPath} exists in source)`
1158
+ );
1159
+ continue;
1160
+ }
1161
+ filtered.push(candidate);
1162
+ }
1163
+ group.workspace = filtered;
1164
+ }
1165
+ }
1166
+
1167
+ // ../core/src/core/save/save-write-coordinator.ts
1168
+ import { dirname, join as join5 } from "path";
1169
+ import { minimatch as minimatch3 } from "minimatch";
1170
+ async function writeResolution(packageRoot, registryPath, resolution, localCandidate, workspaceRoot) {
1171
+ let results = [];
1172
+ if (resolution.selection) {
1173
+ let universalResult = await writeUniversal(
1174
+ packageRoot,
1175
+ registryPath,
1176
+ resolution.selection,
1177
+ localCandidate,
1178
+ workspaceRoot
1179
+ );
1180
+ results.push(universalResult);
1181
+ } else
1182
+ logger.debug(`No universal content selected for ${registryPath} - keeping original untouched`);
1183
+ for (let platformCandidate of resolution.platformSpecific) {
1184
+ let platformResult = await writePlatformSpecific(
1185
+ packageRoot,
1186
+ registryPath,
1187
+ platformCandidate,
1188
+ workspaceRoot
1189
+ );
1190
+ results.push(platformResult);
1191
+ }
1192
+ return results;
1193
+ }
1194
+ async function writeUniversal(packageRoot, registryPath, candidate, localCandidate, workspaceRoot) {
1195
+ let targetPath = join5(packageRoot, registryPath), preparedContent = await prepareContentForWrite(candidate, registryPath, workspaceRoot), writeDecision = shouldWrite(candidate, localCandidate, preparedContent.content), operation = {
1196
+ registryPath,
1197
+ targetPath,
1198
+ content: preparedContent.content,
1199
+ operation: writeDecision.operation,
1200
+ isPlatformSpecific: !1
1201
+ };
1202
+ if (!writeDecision.needed)
1203
+ return logger.debug(`Skipping write for ${registryPath}: content identical to source`), {
1204
+ operation,
1205
+ success: !0
1206
+ };
1207
+ let writeResult = await safeWrite(targetPath, preparedContent.content);
1208
+ if (writeResult.success) {
1209
+ let action = operation.operation === "create" ? "Created" : "Updated";
1210
+ logger.debug(`${action} ${registryPath}${preparedContent.wasExtracted ? " (extracted package contribution)" : ""}`);
1211
+ }
1212
+ return {
1213
+ operation,
1214
+ success: writeResult.success,
1215
+ error: writeResult.error
1216
+ };
1217
+ }
1218
+ async function writePlatformSpecific(packageRoot, registryPath, candidate, workspaceRoot) {
1219
+ let platform = candidate.platform;
1220
+ if (!platform || platform === "ai")
1221
+ return {
1222
+ operation: {
1223
+ registryPath,
1224
+ targetPath: "",
1225
+ content: "",
1226
+ operation: "skip",
1227
+ isPlatformSpecific: !0
1228
+ },
1229
+ success: !1,
1230
+ error: new Error("Candidate has no platform association")
1231
+ };
1232
+ let platformRegistryPath = createPlatformSpecificRegistryPath(registryPath, platform);
1233
+ if (!platformRegistryPath)
1234
+ return {
1235
+ operation: {
1236
+ registryPath,
1237
+ targetPath: "",
1238
+ content: "",
1239
+ operation: "skip",
1240
+ isPlatformSpecific: !0,
1241
+ platform
1242
+ },
1243
+ success: !1,
1244
+ error: new Error(`Could not create platform-specific path for ${platform}`)
1245
+ };
1246
+ let targetPath = join5(packageRoot, platformRegistryPath), preparedContent = await prepareContentForWrite(candidate, platformRegistryPath, workspaceRoot), fileExists = await exists(targetPath), operationType = fileExists ? "update" : "create", operation = {
1247
+ registryPath: platformRegistryPath,
1248
+ targetPath,
1249
+ content: preparedContent.content,
1250
+ operation: operationType,
1251
+ isPlatformSpecific: !0,
1252
+ platform
1253
+ };
1254
+ if (fileExists)
1255
+ try {
1256
+ if (await readTextFile(targetPath) === preparedContent.content)
1257
+ return logger.debug(`Skipping write for ${platformRegistryPath}: content identical`), operation.operation = "skip", {
1258
+ operation,
1259
+ success: !0
1260
+ };
1261
+ } catch (error) {
1262
+ logger.debug(`Could not read existing file ${platformRegistryPath}: ${error}`);
1263
+ }
1264
+ let writeResult = await safeWrite(targetPath, preparedContent.content);
1265
+ if (writeResult.success) {
1266
+ let action = operationType === "create" ? "Created" : "Updated";
1267
+ logger.debug(
1268
+ `${action} platform-specific file: ${platformRegistryPath}${preparedContent.wasExtracted ? " (extracted package contribution)" : ""}`
1269
+ );
1270
+ }
1271
+ return {
1272
+ operation,
1273
+ success: writeResult.success,
1274
+ error: writeResult.error
1275
+ };
1276
+ }
1277
+ async function applyImportTransformation(content, platform, registryPath, workspacePath, workspaceRoot) {
1278
+ try {
1279
+ let platformImportFlows = getPlatformDefinition(platform, workspaceRoot).import || [], allImportFlows = [...getGlobalImportFlows(workspaceRoot) || [], ...platformImportFlows];
1280
+ if (allImportFlows.length === 0)
1281
+ return {
1282
+ success: !1,
1283
+ reason: "No import flows defined for platform"
1284
+ };
1285
+ let matchingFlow = findMatchingFlow(
1286
+ allImportFlows,
1287
+ workspacePath,
1288
+ registryPath,
1289
+ platform,
1290
+ workspaceRoot
1291
+ );
1292
+ if (!matchingFlow)
1293
+ return {
1294
+ success: !1,
1295
+ reason: "No matching import flow found"
1296
+ };
1297
+ if (!matchingFlow.map || matchingFlow.map.length === 0)
1298
+ return {
1299
+ success: !1,
1300
+ reason: "Flow has no map operations"
1301
+ };
1302
+ let tempDir = await allocateTempSubdir(), inputDir = join5(tempDir, "in"), outputDir = join5(tempDir, "out");
1303
+ await ensureDir(inputDir), await ensureDir(outputDir);
1304
+ let inputFileName = registryPath.split("/").pop() || "file.json", inputFilePath = join5(inputDir, inputFileName);
1305
+ await writeTextFile(inputFilePath, content);
1306
+ let flowContext = {
1307
+ workspaceRoot: outputDir,
1308
+ packageRoot: inputDir,
1309
+ platform,
1310
+ packageName: "temp",
1311
+ direction: "install",
1312
+ // Import flows run during install
1313
+ variables: {
1314
+ name: "temp",
1315
+ version: "0.0.0",
1316
+ platform,
1317
+ source: platform,
1318
+ sourcePlatform: platform,
1319
+ targetPlatform: "openpackage"
1320
+ },
1321
+ dryRun: !1
1322
+ }, executor = createFlowExecutor(), concreteFlow = {
1323
+ ...matchingFlow,
1324
+ from: inputFileName
1325
+ }, flowResult = await executor.executeFlow(concreteFlow, flowContext);
1326
+ if (!flowResult.success)
1327
+ return {
1328
+ success: !1,
1329
+ reason: `Flow execution failed: ${flowResult.error?.message}`
1330
+ };
1331
+ if (typeof flowResult.target != "string")
1332
+ return {
1333
+ success: !1,
1334
+ reason: "Flow did not produce target path"
1335
+ };
1336
+ let outputFilePath = flowResult.target;
1337
+ if (!await exists(outputFilePath))
1338
+ return {
1339
+ success: !1,
1340
+ reason: "Flow did not produce output file"
1341
+ };
1342
+ let transformedContent = await readTextFile(outputFilePath);
1343
+ return logger.debug(
1344
+ `Successfully transformed extracted content from ${platform} format to universal`,
1345
+ { registryPath }
1346
+ ), {
1347
+ success: !0,
1348
+ transformedContent
1349
+ };
1350
+ } catch (error) {
1351
+ return logger.debug(
1352
+ `Import transformation failed for ${registryPath} (platform: ${platform})`,
1353
+ { error }
1354
+ ), {
1355
+ success: !1,
1356
+ reason: error instanceof Error ? error.message : String(error)
1357
+ };
1358
+ }
1359
+ }
1360
+ function findMatchingFlow(flows, workspacePath, registryPath, platform, workspaceRoot) {
1361
+ let registryPathCandidates = getRegistryPathCandidates(registryPath);
1362
+ for (let flow of flows) {
1363
+ let fromPatterns = Array.isArray(flow.from) ? flow.from : [flow.from], matchesFrom = !1;
1364
+ for (let fromPattern of fromPatterns) {
1365
+ if (typeof fromPattern == "object" && "$switch" in fromPattern) {
1366
+ let defaultValue = fromPattern.$switch?.default;
1367
+ if (typeof defaultValue == "string" && minimatch3(workspacePath, defaultValue, { dot: !0 })) {
1368
+ matchesFrom = !0;
1369
+ break;
1370
+ }
1371
+ continue;
1372
+ }
1373
+ if (typeof fromPattern == "string" && minimatch3(workspacePath, fromPattern, { dot: !0 })) {
1374
+ matchesFrom = !0;
1375
+ break;
1376
+ }
1377
+ }
1378
+ if (!matchesFrom)
1379
+ continue;
1380
+ let toPattern = Array.isArray(flow.to) ? flow.to[0] : flow.to;
1381
+ if (typeof toPattern == "object" && "$switch" in toPattern) {
1382
+ logger.debug("Skipping flow with switch expression in to field");
1383
+ continue;
1384
+ }
1385
+ if (!(typeof toPattern != "string" || !registryPathCandidates.some(
1386
+ (candidatePath) => minimatch3(candidatePath, toPattern, { dot: !0 })
1387
+ ))) {
1388
+ if (flow.when && !evaluateWhenCondition2(flow.when, platform)) {
1389
+ logger.debug(`Flow condition not met for ${registryPath}`, { when: flow.when });
1390
+ continue;
1391
+ }
1392
+ return logger.debug(
1393
+ `Matched import flow: from=${workspacePath} to=${registryPath}`,
1394
+ { platform }
1395
+ ), flow;
1396
+ }
1397
+ }
1398
+ logger.debug(
1399
+ "No matching import flow found",
1400
+ { workspacePath, registryPath, platform, flowCount: flows.length }
1401
+ );
1402
+ }
1403
+ function getRegistryPathCandidates(registryPath) {
1404
+ let candidates = [registryPath];
1405
+ return registryPath.endsWith(".jsonc") ? candidates.push(registryPath.replace(/\.jsonc$/, ".json")) : registryPath.endsWith(".json") && candidates.push(registryPath.replace(/\.json$/, ".jsonc")), candidates;
1406
+ }
1407
+ function evaluateWhenCondition2(when, platform) {
1408
+ if (when.$eq && Array.isArray(when.$eq) && when.$eq.length === 2) {
1409
+ let left = resolveVariable2(when.$eq[0], platform), right = resolveVariable2(when.$eq[1], platform);
1410
+ return left === right;
1411
+ }
1412
+ if (when.$ne && Array.isArray(when.$ne) && when.$ne.length === 2) {
1413
+ let left = resolveVariable2(when.$ne[0], platform), right = resolveVariable2(when.$ne[1], platform);
1414
+ return left !== right;
1415
+ }
1416
+ return when.exists ? !0 : (logger.debug("Unknown condition type in when clause", { when }), !1);
1417
+ }
1418
+ function resolveVariable2(value, platform) {
1419
+ return typeof value == "string" && (value === "$$platform" || value === "$$source") ? platform : value;
1420
+ }
1421
+ async function prepareContentForWrite(candidate, registryPath, workspaceRoot) {
1422
+ if (!!!(candidate.source === "workspace" && candidate.mergeStrategy && candidate.mergeKeys && candidate.mergeKeys.length > 0))
1423
+ return { content: candidate.content, wasExtracted: !1 };
1424
+ logger.debug(
1425
+ `Extracting package contribution from merged file: ${registryPath}`,
1426
+ {
1427
+ strategy: candidate.mergeStrategy,
1428
+ keyCount: candidate.mergeKeys.length,
1429
+ platform: candidate.platform
1430
+ }
1431
+ );
1432
+ let extractResult = await extractPackageContribution(candidate);
1433
+ if (extractResult.success && extractResult.extractedContent) {
1434
+ logger.info(
1435
+ `Successfully extracted package contribution for ${registryPath} (${candidate.mergeKeys.length} key(s))`
1436
+ );
1437
+ let finalContent = extractResult.extractedContent;
1438
+ if (candidate.platform && candidate.platform !== "ai" && workspaceRoot) {
1439
+ logger.info(
1440
+ "Attempting import transformation for merged file",
1441
+ {
1442
+ platform: candidate.platform,
1443
+ registryPath,
1444
+ displayPath: candidate.displayPath,
1445
+ hasWorkspaceRoot: !!workspaceRoot
1446
+ }
1447
+ );
1448
+ let transformResult = await applyImportTransformation(
1449
+ extractResult.extractedContent,
1450
+ candidate.platform,
1451
+ registryPath,
1452
+ candidate.displayPath,
1453
+ workspaceRoot
1454
+ );
1455
+ transformResult.success && transformResult.transformedContent ? (logger.info(
1456
+ `Successfully applied import transformation for platform ${candidate.platform}`,
1457
+ { registryPath }
1458
+ ), finalContent = transformResult.transformedContent) : logger.warn(
1459
+ `Import transformation failed or not applicable: ${transformResult.reason}`,
1460
+ { registryPath, platform: candidate.platform }
1461
+ );
1462
+ } else
1463
+ logger.debug(
1464
+ "Skipping import transformation",
1465
+ {
1466
+ hasPlatform: !!candidate.platform,
1467
+ platform: candidate.platform,
1468
+ hasWorkspaceRoot: !!workspaceRoot
1469
+ }
1470
+ );
1471
+ return {
1472
+ content: finalContent,
1473
+ wasExtracted: !0
1474
+ };
1475
+ }
1476
+ return logger.warn(
1477
+ `Failed to extract package contribution from merged file: ${registryPath}`,
1478
+ {
1479
+ reason: extractResult.error,
1480
+ fallback: "Using full content"
1481
+ }
1482
+ ), logger.warn(
1483
+ `\u26A0\uFE0F Writing full merged content to ${registryPath} - this may include keys from other packages or base workspace content`
1484
+ ), { content: candidate.content, wasExtracted: !1 };
1485
+ }
1486
+ function shouldWrite(candidate, localCandidate, preparedContent) {
1487
+ return localCandidate ? preparedContent && preparedContent !== candidate.content ? preparedContent === localCandidate.content ? { needed: !1, operation: "skip" } : { needed: !0, operation: "update" } : candidate.contentHash === localCandidate.contentHash ? { needed: !1, operation: "skip" } : { needed: !0, operation: "update" } : { needed: !0, operation: "create" };
1488
+ }
1489
+ async function safeWrite(targetPath, content) {
1490
+ try {
1491
+ return await ensureDir(dirname(targetPath)), await writeTextFile(targetPath, content), { success: !0 };
1492
+ } catch (error) {
1493
+ return logger.error(`Failed to write file ${targetPath}: ${error}`), {
1494
+ success: !1,
1495
+ error: error instanceof Error ? error : new Error(String(error))
1496
+ };
1497
+ }
1498
+ }
1499
+
1500
+ // ../core/src/core/save/save-result-reporter.ts
1501
+ function buildSaveReport(packageName, analyses, allWriteResults) {
1502
+ let totalGroups = analyses.length, groupsWithAction = analyses.filter(
1503
+ (a) => a.type !== "no-action-needed" && a.type !== "no-change-needed"
1504
+ ).length, flatResults = allWriteResults.flat(), successfulWrites = flatResults.filter((r) => r.success), filesSaved = successfulWrites.length, filesCreated = successfulWrites.filter(
1505
+ (r) => r.operation.operation === "create"
1506
+ ).length, filesUpdated = successfulWrites.filter(
1507
+ (r) => r.operation.operation === "update"
1508
+ ).length, platformSpecificFiles = successfulWrites.filter(
1509
+ (r) => r.operation.isPlatformSpecific
1510
+ ).length, interactiveResolutions = analyses.filter(
1511
+ (a) => a.recommendedStrategy === "interactive" && a.type === "needs-resolution"
1512
+ ).length, errors = flatResults.filter((r) => !r.success).map((r) => ({
1513
+ path: r.operation.registryPath,
1514
+ error: r.error || new Error("Unknown write error")
1515
+ }));
1516
+ return {
1517
+ packageName,
1518
+ totalGroups,
1519
+ groupsWithAction,
1520
+ filesSaved,
1521
+ filesCreated,
1522
+ filesUpdated,
1523
+ platformSpecificFiles,
1524
+ interactiveResolutions,
1525
+ errors,
1526
+ writeResults: flatResults
1527
+ };
1528
+ }
1529
+ function createCommandResult(report) {
1530
+ return {
1531
+ success: !0,
1532
+ data: {
1533
+ message: formatSaveMessage(report),
1534
+ report
1535
+ }
1536
+ };
1537
+ }
1538
+ function createSuccessResult(packageName, message) {
1539
+ return {
1540
+ success: !0,
1541
+ data: {
1542
+ message,
1543
+ packageName
1544
+ }
1545
+ };
1546
+ }
1547
+ function createErrorResult(error) {
1548
+ return {
1549
+ success: !1,
1550
+ error
1551
+ };
1552
+ }
1553
+ function formatSaveMessage(report) {
1554
+ let lines = [];
1555
+ if (report.filesSaved === 0 && report.errors.length === 0)
1556
+ return `\u2713 Saved ${report.packageName}
1557
+ No changes detected`;
1558
+ lines.push(`\u2713 Saved ${report.packageName}`), report.filesCreated > 0 && lines.push(` ${report.filesCreated} file(s) created`), report.filesUpdated > 0 && lines.push(` ${report.filesUpdated} file(s) updated`), report.platformSpecificFiles > 0 && lines.push(` ${report.platformSpecificFiles} platform-specific file(s)`), report.interactiveResolutions > 0 && lines.push(` ${report.interactiveResolutions} interactive resolution(s)`), report.errors.length > 0 && (lines.push(""), lines.push(`\u26A0\uFE0F ${report.errors.length} error(s) occurred:`), report.errors.forEach((err) => {
1559
+ lines.push(` \u2022 ${err.path}: ${err.error.message}`);
1560
+ }));
1561
+ let successfulWrites = report.writeResults.filter((r) => r.success);
1562
+ if (successfulWrites.length > 0) {
1563
+ lines.push(""), lines.push(" Files saved:");
1564
+ let sorted = [...successfulWrites].sort(
1565
+ (a, b) => a.operation.registryPath.localeCompare(b.operation.registryPath)
1566
+ );
1567
+ for (let result of sorted) {
1568
+ let { registryPath, isPlatformSpecific, platform } = result.operation, label = isPlatformSpecific && platform ? `${registryPath} (${platform})` : `${registryPath} (universal)`;
1569
+ lines.push(` \u251C\u2500\u2500 ${label}`);
1570
+ }
1571
+ }
1572
+ return report.filesSaved > 0 && (lines.push(""), lines.push("\u{1F4A1} Changes saved to package source."), lines.push(" To sync changes to workspace, run:"), lines.push(` opkg install ${report.packageName}`)), lines.join(`
1573
+ `);
1574
+ }
1575
+
1576
+ // ../core/src/core/save/save-to-source-pipeline.ts
1577
+ async function runSaveToSourcePipeline(packageName, options = {}, ctx) {
1578
+ try {
1579
+ await initSharedTempDir(), logger.debug(`Validating save preconditions for ${packageName}`);
1580
+ let validation = await validateSavePreconditions(packageName);
1581
+ if (!validation.valid)
1582
+ return createErrorResult(validation.error);
1583
+ let { cwd, packageRoot, filesMapping } = validation;
1584
+ logger.debug(`Building candidates for ${packageName}`);
1585
+ let candidateResult = await buildCandidates({
1586
+ packageRoot,
1587
+ workspaceRoot: cwd,
1588
+ filesMapping
1589
+ });
1590
+ candidateResult.errors.length > 0 && (logger.warn(`Encountered ${candidateResult.errors.length} error(s) building candidates`), candidateResult.errors.forEach(
1591
+ (err) => logger.warn(` ${err.path}: ${err.reason}`)
1592
+ )), logger.debug("Building candidate groups");
1593
+ let allGroups = buildCandidateGroups(
1594
+ candidateResult.localSourceRefs,
1595
+ candidateResult.workspaceCandidates,
1596
+ cwd
1597
+ ), activeGroups = filterGroupsWithWorkspace(allGroups);
1598
+ if (activeGroups.length === 0)
1599
+ return logger.info(`No workspace changes detected for ${packageName}`), createSuccessResult(
1600
+ packageName,
1601
+ `\u2713 Saved ${packageName}
1602
+ No workspace changes detected`
1603
+ );
1604
+ logger.debug("Pruning existing platform-specific files"), await pruneExistingPlatformCandidates(packageRoot, activeGroups);
1605
+ let finalGroups = activeGroups.filter((g) => g.workspace.length > 0);
1606
+ if (finalGroups.length === 0)
1607
+ return logger.info(`No workspace changes detected for ${packageName}`), createSuccessResult(
1608
+ packageName,
1609
+ `\u2713 Saved ${packageName}
1610
+ No workspace changes detected`
1611
+ );
1612
+ for (let group of finalGroups)
1613
+ group.localRef && !group.local && (group.local = await materializeLocalCandidate(group.localRef, packageRoot) ?? void 0);
1614
+ logger.debug(`Processing ${finalGroups.length} group(s) with workspace candidates`);
1615
+ let groupAnalyses = await Promise.all(
1616
+ finalGroups.map(async (group) => ({
1617
+ group,
1618
+ analysis: await analyzeGroup(group, options.force ?? !1, cwd)
1619
+ }))
1620
+ ), analyses = groupAnalyses.map((ga) => ga.analysis), allWriteResults = [], autoResolvable = [], interactive = [];
1621
+ for (let ga of groupAnalyses) {
1622
+ if (ga.analysis.type === "no-action-needed" || ga.analysis.type === "no-change-needed") {
1623
+ logger.debug(`Skipping ${ga.group.registryPath}: ${ga.analysis.type}`);
1624
+ continue;
1625
+ }
1626
+ ga.analysis.recommendedStrategy === "interactive" ? interactive.push(ga) : autoResolvable.push(ga);
1627
+ }
1628
+ if (autoResolvable.length > 0) {
1629
+ logger.debug(`Processing ${autoResolvable.length} auto-resolvable group(s) in parallel`);
1630
+ let autoResults = await Promise.all(
1631
+ autoResolvable.map(async ({ group, analysis }) => {
1632
+ let resolution = await executeResolution(group, analysis, packageRoot, cwd, resolveOutput(ctx), resolvePrompt(ctx));
1633
+ return resolution ? writeResolution(packageRoot, group.registryPath, resolution, group.local, cwd) : null;
1634
+ })
1635
+ );
1636
+ for (let result of autoResults)
1637
+ result && allWriteResults.push(result);
1638
+ }
1639
+ for (let { group, analysis } of interactive) {
1640
+ let resolution = await executeResolution(group, analysis, packageRoot, cwd, resolveOutput(ctx), resolvePrompt(ctx));
1641
+ if (!resolution) {
1642
+ logger.debug(`No resolution returned for ${group.registryPath}`);
1643
+ continue;
1644
+ }
1645
+ let writeResults = await writeResolution(
1646
+ packageRoot,
1647
+ group.registryPath,
1648
+ resolution,
1649
+ group.local,
1650
+ cwd
1651
+ );
1652
+ allWriteResults.push(writeResults);
1653
+ }
1654
+ logger.debug("Building save report");
1655
+ let report = buildSaveReport(packageName, analyses, allWriteResults);
1656
+ return createCommandResult(report);
1657
+ } finally {
1658
+ clearConversionCache(), await cleanupSharedTempDir();
1659
+ }
1660
+ }
1661
+ async function validateSavePreconditions(packageName) {
1662
+ let cwd = process.cwd();
1663
+ if (!packageName)
1664
+ return {
1665
+ valid: !1,
1666
+ error: "Package name is required for save."
1667
+ };
1668
+ let index;
1669
+ try {
1670
+ index = (await readWorkspaceIndex(cwd)).index;
1671
+ } catch (error) {
1672
+ return {
1673
+ valid: !1,
1674
+ error: `Failed to read workspace index: ${error}`
1675
+ };
1676
+ }
1677
+ let pkgIndex = index.packages?.[packageName];
1678
+ if (!pkgIndex)
1679
+ return {
1680
+ valid: !1,
1681
+ error: `Package '${packageName}' is not installed in this workspace.
1682
+ Run 'opkg install ${packageName}' to install it first.`
1683
+ };
1684
+ if (!pkgIndex.files || Object.keys(pkgIndex.files).length === 0)
1685
+ return {
1686
+ valid: !1,
1687
+ error: `Package '${packageName}' has no files installed.
1688
+ Nothing to save.`
1689
+ };
1690
+ let source;
1691
+ try {
1692
+ source = await resolvePackageSource(cwd, packageName);
1693
+ } catch (error) {
1694
+ return {
1695
+ valid: !1,
1696
+ error: `Failed to resolve package source: ${error}`
1697
+ };
1698
+ }
1699
+ try {
1700
+ assertMutableSourceOrThrow(source.absolutePath, {
1701
+ packageName: source.packageName,
1702
+ command: "save"
1703
+ });
1704
+ } catch (error) {
1705
+ return {
1706
+ valid: !1,
1707
+ error: error instanceof Error ? error.message : String(error)
1708
+ };
1709
+ }
1710
+ return {
1711
+ valid: !0,
1712
+ cwd,
1713
+ packageRoot: source.absolutePath,
1714
+ filesMapping: pkgIndex.files
1715
+ };
1716
+ }
1717
+
1718
+ // src/commands/save.ts
1719
+ async function setupSaveCommand(args) {
1720
+ let [packageName, options] = args, ctx = await createCliExecutionContext(), out = resolveOutput(ctx), result = await runSaveToSourcePipeline(packageName, options, ctx);
1721
+ if (!result.success)
1722
+ throw new Error(result.error || "Save operation failed");
1723
+ result.data?.message && out.success(result.data.message);
1724
+ }
1725
+ export {
1726
+ setupSaveCommand
1727
+ };
1728
+ //# sourceMappingURL=save-24TESYKI.js.map