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.
- package/.claude/agents/code-reviewer.md +171 -0
- package/.claude/commands/commit-push-pr.md +20 -0
- package/.claude/commands/{specs/read.md → read-specs.md} +1 -1
- package/.claude/commands/{specs/update.md → update-specs.md} +4 -0
- package/.claude/skills/code-review-excellence/SKILL.md +538 -0
- package/README.md +2 -2
- package/package.json +3 -1
- package/packages/cli/dist/add-IJAPFHIX.js +624 -0
- package/packages/cli/dist/add-IJAPFHIX.js.map +7 -0
- package/packages/cli/dist/add-LLUNFLJI.js +624 -0
- package/packages/cli/dist/add-LLUNFLJI.js.map +7 -0
- package/packages/cli/dist/add-U44SL3OR.js +624 -0
- package/packages/cli/dist/add-U44SL3OR.js.map +7 -0
- package/packages/cli/dist/chunk-23VBP5L6.js +371 -0
- package/packages/cli/dist/chunk-23VBP5L6.js.map +7 -0
- package/packages/cli/dist/chunk-2SVHLF5C.js +1419 -0
- package/packages/cli/dist/chunk-2SVHLF5C.js.map +7 -0
- package/packages/cli/dist/chunk-37256POU.js +99 -0
- package/packages/cli/dist/chunk-37256POU.js.map +7 -0
- package/packages/cli/dist/chunk-3PZRVA6O.js +196 -0
- package/packages/cli/dist/chunk-3PZRVA6O.js.map +7 -0
- package/packages/cli/dist/chunk-427DCURL.js +155 -0
- package/packages/cli/dist/chunk-427DCURL.js.map +7 -0
- package/packages/cli/dist/chunk-4B5HJLP2.js +48 -0
- package/packages/cli/dist/chunk-4B5HJLP2.js.map +7 -0
- package/packages/cli/dist/chunk-4OWT3YEG.js +413 -0
- package/packages/cli/dist/chunk-4OWT3YEG.js.map +7 -0
- package/packages/cli/dist/chunk-4RIBTBXI.js +568 -0
- package/packages/cli/dist/chunk-4RIBTBXI.js.map +7 -0
- package/packages/cli/dist/chunk-4X2EJHJN.js +63 -0
- package/packages/cli/dist/chunk-4X2EJHJN.js.map +7 -0
- package/packages/cli/dist/chunk-6CYW66HD.js +1136 -0
- package/packages/cli/dist/chunk-6CYW66HD.js.map +7 -0
- package/packages/cli/dist/chunk-6DITYAFA.js +172 -0
- package/packages/cli/dist/chunk-6DITYAFA.js.map +7 -0
- package/packages/cli/dist/chunk-7KEAKEVZ.js +568 -0
- package/packages/cli/dist/chunk-7KEAKEVZ.js.map +7 -0
- package/packages/cli/dist/chunk-ABFUD25D.js +61 -0
- package/packages/cli/dist/chunk-ABFUD25D.js.map +7 -0
- package/packages/cli/dist/chunk-AR7GJCG6.js +274 -0
- package/packages/cli/dist/chunk-AR7GJCG6.js.map +7 -0
- package/packages/cli/dist/chunk-AYTGQCXH.js +86 -0
- package/packages/cli/dist/chunk-AYTGQCXH.js.map +7 -0
- package/packages/cli/dist/chunk-BROJ6OUT.js +631 -0
- package/packages/cli/dist/chunk-BROJ6OUT.js.map +7 -0
- package/packages/cli/dist/chunk-BVVSU7QD.js +23 -0
- package/packages/cli/dist/chunk-BVVSU7QD.js.map +7 -0
- package/packages/cli/dist/chunk-C6FY55UP.js +108 -0
- package/packages/cli/dist/chunk-C6FY55UP.js.map +7 -0
- package/packages/cli/dist/chunk-CVA64SXK.js +1136 -0
- package/packages/cli/dist/chunk-CVA64SXK.js.map +7 -0
- package/packages/cli/dist/chunk-D3O7LY2Q.js +1151 -0
- package/packages/cli/dist/chunk-D3O7LY2Q.js.map +7 -0
- package/packages/cli/dist/chunk-D6LEPODL.js +413 -0
- package/packages/cli/dist/chunk-D6LEPODL.js.map +7 -0
- package/packages/cli/dist/chunk-DEC24S7E.js +186 -0
- package/packages/cli/dist/chunk-DEC24S7E.js.map +7 -0
- package/packages/cli/dist/chunk-FMVVJH5M.js +371 -0
- package/packages/cli/dist/chunk-FMVVJH5M.js.map +7 -0
- package/packages/cli/dist/chunk-GDVFS3YP.js +130 -0
- package/packages/cli/dist/chunk-GDVFS3YP.js.map +7 -0
- package/packages/cli/dist/chunk-GEP2G5HF.js +31 -0
- package/packages/cli/dist/chunk-GEP2G5HF.js.map +7 -0
- package/packages/cli/dist/chunk-GSWHZBT2.js +62 -0
- package/packages/cli/dist/chunk-GSWHZBT2.js.map +7 -0
- package/packages/cli/dist/chunk-HTYHJA3B.js +61 -0
- package/packages/cli/dist/chunk-HTYHJA3B.js.map +7 -0
- package/packages/cli/dist/chunk-HYKYECAE.js +222 -0
- package/packages/cli/dist/chunk-HYKYECAE.js.map +7 -0
- package/packages/cli/dist/chunk-I7FEAHB4.js +100 -0
- package/packages/cli/dist/chunk-I7FEAHB4.js.map +7 -0
- package/packages/cli/dist/chunk-IHVZ5AUJ.js +107 -0
- package/packages/cli/dist/chunk-IHVZ5AUJ.js.map +7 -0
- package/packages/cli/dist/chunk-KI7FDU3H.js +99 -0
- package/packages/cli/dist/chunk-KI7FDU3H.js.map +7 -0
- package/packages/cli/dist/chunk-L5GRJQBS.js +32 -0
- package/packages/cli/dist/chunk-L5GRJQBS.js.map +7 -0
- package/packages/cli/dist/chunk-LHEAUDJL.js +302 -0
- package/packages/cli/dist/chunk-LHEAUDJL.js.map +7 -0
- package/packages/cli/dist/chunk-MIURCESJ.js +48 -0
- package/packages/cli/dist/chunk-MIURCESJ.js.map +7 -0
- package/packages/cli/dist/chunk-N43IXOND.js +732 -0
- package/packages/cli/dist/chunk-N43IXOND.js.map +7 -0
- package/packages/cli/dist/chunk-OUZRMGPV.js +274 -0
- package/packages/cli/dist/chunk-OUZRMGPV.js.map +7 -0
- package/packages/cli/dist/chunk-PSQXKAL4.js +371 -0
- package/packages/cli/dist/chunk-PSQXKAL4.js.map +7 -0
- package/packages/cli/dist/chunk-PUDRKDVZ.js +1419 -0
- package/packages/cli/dist/chunk-PUDRKDVZ.js.map +7 -0
- package/packages/cli/dist/chunk-RAKMX654.js +631 -0
- package/packages/cli/dist/chunk-RAKMX654.js.map +7 -0
- package/packages/cli/dist/chunk-RSFLK2TP.js +195 -0
- package/packages/cli/dist/chunk-RSFLK2TP.js.map +7 -0
- package/packages/cli/dist/chunk-S26PR2BS.js +99 -0
- package/packages/cli/dist/chunk-S26PR2BS.js.map +7 -0
- package/packages/cli/dist/chunk-U7FW7SXX.js +568 -0
- package/packages/cli/dist/chunk-U7FW7SXX.js.map +7 -0
- package/packages/cli/dist/chunk-VKM6K5TN.js +413 -0
- package/packages/cli/dist/chunk-VKM6K5TN.js.map +7 -0
- package/packages/cli/dist/chunk-VKNJG4JN.js +253 -0
- package/packages/cli/dist/chunk-VKNJG4JN.js.map +7 -0
- package/packages/cli/dist/chunk-VQ2KY6CK.js +113 -0
- package/packages/cli/dist/chunk-VQ2KY6CK.js.map +7 -0
- package/packages/cli/dist/chunk-VQDTXLOX.js +1312 -0
- package/packages/cli/dist/chunk-VQDTXLOX.js.map +7 -0
- package/packages/cli/dist/chunk-VXNS3X5O.js +60 -0
- package/packages/cli/dist/chunk-VXNS3X5O.js.map +7 -0
- package/packages/cli/dist/chunk-WF7H2YDU.js +376 -0
- package/packages/cli/dist/chunk-WF7H2YDU.js.map +7 -0
- package/packages/cli/dist/chunk-WNRXZLWW.js +266 -0
- package/packages/cli/dist/chunk-WNRXZLWW.js.map +7 -0
- package/packages/cli/dist/chunk-WT4VVCXM.js +1121 -0
- package/packages/cli/dist/chunk-WT4VVCXM.js.map +7 -0
- package/packages/cli/dist/configure-3AZUMDJZ.js +107 -0
- package/packages/cli/dist/configure-3AZUMDJZ.js.map +7 -0
- package/packages/cli/dist/configure-D722JQOD.js +107 -0
- package/packages/cli/dist/configure-D722JQOD.js.map +7 -0
- package/packages/cli/dist/configure-IU5H7XD6.js +107 -0
- package/packages/cli/dist/configure-IU5H7XD6.js.map +7 -0
- package/packages/cli/dist/file-format-detector-PXCIAKTK.js +22 -0
- package/packages/cli/dist/file-format-detector-PXCIAKTK.js.map +7 -0
- package/packages/cli/dist/index.js +17 -17
- package/packages/cli/dist/install-EZNWMLJR.js +7581 -0
- package/packages/cli/dist/install-EZNWMLJR.js.map +7 -0
- package/packages/cli/dist/install-F5ANFUBX.js +7577 -0
- package/packages/cli/dist/install-F5ANFUBX.js.map +7 -0
- package/packages/cli/dist/install-JSXEPPC2.js +7104 -0
- package/packages/cli/dist/install-JSXEPPC2.js.map +7 -0
- package/packages/cli/dist/install-QHEBX7JH.js +7101 -0
- package/packages/cli/dist/install-QHEBX7JH.js.map +7 -0
- package/packages/cli/dist/list-DMOUATYI.js +327 -0
- package/packages/cli/dist/list-DMOUATYI.js.map +7 -0
- package/packages/cli/dist/list-UESSCB7Y.js +327 -0
- package/packages/cli/dist/list-UESSCB7Y.js.map +7 -0
- package/packages/cli/dist/list-XR7RSJFS.js +327 -0
- package/packages/cli/dist/list-XR7RSJFS.js.map +7 -0
- package/packages/cli/dist/login-EYZ2SOYZ.js +150 -0
- package/packages/cli/dist/login-EYZ2SOYZ.js.map +7 -0
- package/packages/cli/dist/login-JWCSTAEU.js +150 -0
- package/packages/cli/dist/login-JWCSTAEU.js.map +7 -0
- package/packages/cli/dist/login-NRKHXZKM.js +150 -0
- package/packages/cli/dist/login-NRKHXZKM.js.map +7 -0
- package/packages/cli/dist/logout-HDMYRXIE.js +40 -0
- package/packages/cli/dist/logout-HDMYRXIE.js.map +7 -0
- package/packages/cli/dist/logout-SYHXCVCQ.js +40 -0
- package/packages/cli/dist/logout-SYHXCVCQ.js.map +7 -0
- package/packages/cli/dist/logout-X3XUUOH5.js +40 -0
- package/packages/cli/dist/logout-X3XUUOH5.js.map +7 -0
- package/packages/cli/dist/new-3LTFKDTQ.js +277 -0
- package/packages/cli/dist/new-3LTFKDTQ.js.map +7 -0
- package/packages/cli/dist/new-F46OSD72.js +277 -0
- package/packages/cli/dist/new-F46OSD72.js.map +7 -0
- package/packages/cli/dist/new-OPCCLNL2.js +277 -0
- package/packages/cli/dist/new-OPCCLNL2.js.map +7 -0
- package/packages/cli/dist/package-marker-detector-T5O5YD2E.js +80 -0
- package/packages/cli/dist/package-marker-detector-T5O5YD2E.js.map +7 -0
- package/packages/cli/dist/package-yml-QWZIJDYU.js +16 -0
- package/packages/cli/dist/package-yml-QWZIJDYU.js.map +7 -0
- package/packages/cli/dist/plugin-naming-YP2I4NPA.js +29 -0
- package/packages/cli/dist/plugin-naming-YP2I4NPA.js.map +7 -0
- package/packages/cli/dist/publish-4H43PCSG.js +619 -0
- package/packages/cli/dist/publish-4H43PCSG.js.map +7 -0
- package/packages/cli/dist/publish-RULKLNUX.js +619 -0
- package/packages/cli/dist/publish-RULKLNUX.js.map +7 -0
- package/packages/cli/dist/publish-URWY2P3E.js +619 -0
- package/packages/cli/dist/publish-URWY2P3E.js.map +7 -0
- package/packages/cli/dist/remove-BD52BHR2.js +542 -0
- package/packages/cli/dist/remove-BD52BHR2.js.map +7 -0
- package/packages/cli/dist/remove-G5NRC7LD.js +542 -0
- package/packages/cli/dist/remove-G5NRC7LD.js.map +7 -0
- package/packages/cli/dist/remove-TC3FQUYQ.js +542 -0
- package/packages/cli/dist/remove-TC3FQUYQ.js.map +7 -0
- package/packages/cli/dist/resource-discoverer-4X4RY43E.js +17 -0
- package/packages/cli/dist/resource-discoverer-4X4RY43E.js.map +7 -0
- package/packages/cli/dist/save-24TESYKI.js +1728 -0
- package/packages/cli/dist/save-24TESYKI.js.map +7 -0
- package/packages/cli/dist/save-N3QWF2WN.js +1728 -0
- package/packages/cli/dist/save-N3QWF2WN.js.map +7 -0
- package/packages/cli/dist/save-P2U67DTV.js +1728 -0
- package/packages/cli/dist/save-P2U67DTV.js.map +7 -0
- package/packages/cli/dist/search-ABROK3UO.js +157 -0
- package/packages/cli/dist/search-ABROK3UO.js.map +7 -0
- package/packages/cli/dist/search-WVFXFNAV.js +157 -0
- package/packages/cli/dist/search-WVFXFNAV.js.map +7 -0
- package/packages/cli/dist/search-YQN2Q2SO.js +157 -0
- package/packages/cli/dist/search-YQN2Q2SO.js.map +7 -0
- package/packages/cli/dist/set-DCWF73F6.js +251 -0
- package/packages/cli/dist/set-DCWF73F6.js.map +7 -0
- package/packages/cli/dist/set-GJEG2F6Y.js +251 -0
- package/packages/cli/dist/set-GJEG2F6Y.js.map +7 -0
- package/packages/cli/dist/set-NGM2FIKF.js +251 -0
- package/packages/cli/dist/set-NGM2FIKF.js.map +7 -0
- package/packages/cli/dist/uninstall-3CJQMTYH.js +539 -0
- package/packages/cli/dist/uninstall-3CJQMTYH.js.map +7 -0
- package/packages/cli/dist/uninstall-Q3CP4UN5.js +539 -0
- package/packages/cli/dist/uninstall-Q3CP4UN5.js.map +7 -0
- package/packages/cli/dist/uninstall-QU5OMEEC.js +539 -0
- package/packages/cli/dist/uninstall-QU5OMEEC.js.map +7 -0
- package/packages/cli/dist/unpublish-GHJQYC4S.js +245 -0
- package/packages/cli/dist/unpublish-GHJQYC4S.js.map +7 -0
- package/packages/cli/dist/unpublish-L2CYMK4B.js +245 -0
- package/packages/cli/dist/unpublish-L2CYMK4B.js.map +7 -0
- package/packages/cli/dist/unpublish-VBTNTMS5.js +245 -0
- package/packages/cli/dist/unpublish-VBTNTMS5.js.map +7 -0
- package/packages/cli/dist/view-MXRBMXOG.js +488 -0
- package/packages/cli/dist/view-MXRBMXOG.js.map +7 -0
- package/packages/cli/dist/view-NMND7SAW.js +488 -0
- package/packages/cli/dist/view-NMND7SAW.js.map +7 -0
- package/packages/cli/dist/view-RPQRDSYB.js +488 -0
- package/packages/cli/dist/view-RPQRDSYB.js.map +7 -0
- package/packages/cli/package.json +2 -0
- package/packages/core/dist/constants/index.d.ts +9 -0
- package/packages/core/dist/constants/index.d.ts.map +1 -1
- package/packages/core/dist/constants/index.js +12 -0
- package/packages/core/dist/constants/index.js.map +1 -1
- package/packages/core/dist/core/dependency-resolver/index.d.ts +2 -10
- package/packages/core/dist/core/dependency-resolver/index.d.ts.map +1 -1
- package/packages/core/dist/core/dependency-resolver/index.js +3 -14
- package/packages/core/dist/core/dependency-resolver/index.js.map +1 -1
- package/packages/core/dist/core/install/base-detector.d.ts +2 -1
- package/packages/core/dist/core/install/base-detector.d.ts.map +1 -1
- package/packages/core/dist/core/install/base-detector.js +54 -1
- package/packages/core/dist/core/install/base-detector.js.map +1 -1
- package/packages/core/dist/core/install/conflicts/file-conflict-resolver.d.ts +7 -5
- package/packages/core/dist/core/install/conflicts/file-conflict-resolver.d.ts.map +1 -1
- package/packages/core/dist/core/install/conflicts/file-conflict-resolver.js +25 -9
- package/packages/core/dist/core/install/conflicts/file-conflict-resolver.js.map +1 -1
- package/packages/core/dist/core/install/flow-index-installer.d.ts +2 -1
- package/packages/core/dist/core/install/flow-index-installer.d.ts.map +1 -1
- package/packages/core/dist/core/install/flow-index-installer.js +19 -4
- package/packages/core/dist/core/install/flow-index-installer.js.map +1 -1
- package/packages/core/dist/core/install/input-classifier-base.js +3 -3
- package/packages/core/dist/core/install/input-classifier-base.js.map +1 -1
- package/packages/core/dist/core/install/install-reporting.d.ts.map +1 -1
- package/packages/core/dist/core/install/install-reporting.js +7 -9
- package/packages/core/dist/core/install/install-reporting.js.map +1 -1
- package/packages/core/dist/core/install/list-handler.d.ts.map +1 -1
- package/packages/core/dist/core/install/list-handler.js +3 -0
- package/packages/core/dist/core/install/list-handler.js.map +1 -1
- package/packages/core/dist/core/install/marketplace-handler.d.ts.map +1 -1
- package/packages/core/dist/core/install/marketplace-handler.js.map +1 -1
- package/packages/core/dist/core/install/operations/conflict-handler.d.ts +2 -1
- package/packages/core/dist/core/install/operations/conflict-handler.d.ts.map +1 -1
- package/packages/core/dist/core/install/operations/conflict-handler.js +2 -2
- package/packages/core/dist/core/install/operations/conflict-handler.js.map +1 -1
- package/packages/core/dist/core/install/operations/installation-executor.d.ts +3 -0
- package/packages/core/dist/core/install/operations/installation-executor.d.ts.map +1 -1
- package/packages/core/dist/core/install/operations/installation-executor.js +39 -22
- package/packages/core/dist/core/install/operations/installation-executor.js.map +1 -1
- package/packages/core/dist/core/install/orchestrator/orchestrator.d.ts +7 -3
- package/packages/core/dist/core/install/orchestrator/orchestrator.d.ts.map +1 -1
- package/packages/core/dist/core/install/orchestrator/orchestrator.js +193 -93
- package/packages/core/dist/core/install/orchestrator/orchestrator.js.map +1 -1
- package/packages/core/dist/core/install/orchestrator/strategies/git-strategy.d.ts +1 -0
- package/packages/core/dist/core/install/orchestrator/strategies/git-strategy.d.ts.map +1 -1
- package/packages/core/dist/core/install/orchestrator/strategies/git-strategy.js +11 -24
- package/packages/core/dist/core/install/orchestrator/strategies/git-strategy.js.map +1 -1
- package/packages/core/dist/core/install/orchestrator/strategies/path-strategy.d.ts +2 -0
- package/packages/core/dist/core/install/orchestrator/strategies/path-strategy.d.ts.map +1 -1
- package/packages/core/dist/core/install/orchestrator/strategies/path-strategy.js +14 -14
- package/packages/core/dist/core/install/orchestrator/strategies/path-strategy.js.map +1 -1
- package/packages/core/dist/core/install/orchestrator/strategies/registry-strategy.d.ts +7 -0
- package/packages/core/dist/core/install/orchestrator/strategies/registry-strategy.d.ts.map +1 -1
- package/packages/core/dist/core/install/orchestrator/strategies/registry-strategy.js +28 -0
- package/packages/core/dist/core/install/orchestrator/strategies/registry-strategy.js.map +1 -1
- package/packages/core/dist/core/install/orchestrator/types.d.ts +2 -0
- package/packages/core/dist/core/install/orchestrator/types.d.ts.map +1 -1
- package/packages/core/dist/core/install/path-package-loader.d.ts.map +1 -1
- package/packages/core/dist/core/install/path-package-loader.js +20 -1
- package/packages/core/dist/core/install/path-package-loader.js.map +1 -1
- package/packages/core/dist/core/install/platform-resolution.d.ts +3 -0
- package/packages/core/dist/core/install/platform-resolution.d.ts.map +1 -1
- package/packages/core/dist/core/install/platform-resolution.js +5 -2
- package/packages/core/dist/core/install/platform-resolution.js.map +1 -1
- package/packages/core/dist/core/install/preprocessing/context-population.d.ts +18 -0
- package/packages/core/dist/core/install/preprocessing/context-population.d.ts.map +1 -0
- package/packages/core/dist/core/install/preprocessing/context-population.js +36 -0
- package/packages/core/dist/core/install/preprocessing/context-population.js.map +1 -0
- package/packages/core/dist/core/install/preprocessing/convenience-preprocessor.d.ts +23 -0
- package/packages/core/dist/core/install/preprocessing/convenience-preprocessor.d.ts.map +1 -1
- package/packages/core/dist/core/install/preprocessing/convenience-preprocessor.js +44 -0
- package/packages/core/dist/core/install/preprocessing/convenience-preprocessor.js.map +1 -1
- package/packages/core/dist/core/install/sources/git-source.d.ts.map +1 -1
- package/packages/core/dist/core/install/sources/git-source.js +67 -4
- package/packages/core/dist/core/install/sources/git-source.js.map +1 -1
- package/packages/core/dist/core/install/sources/path-source.d.ts.map +1 -1
- package/packages/core/dist/core/install/sources/path-source.js +8 -0
- package/packages/core/dist/core/install/sources/path-source.js.map +1 -1
- package/packages/core/dist/core/install/strategies/flow-based-strategy.d.ts.map +1 -1
- package/packages/core/dist/core/install/strategies/flow-based-strategy.js +12 -5
- package/packages/core/dist/core/install/strategies/flow-based-strategy.js.map +1 -1
- package/packages/core/dist/core/install/strategies/types.d.ts +11 -1
- package/packages/core/dist/core/install/strategies/types.d.ts.map +1 -1
- package/packages/core/dist/core/install/unified/context-builders.d.ts +5 -0
- package/packages/core/dist/core/install/unified/context-builders.d.ts.map +1 -1
- package/packages/core/dist/core/install/unified/context-builders.js +12 -0
- package/packages/core/dist/core/install/unified/context-builders.js.map +1 -1
- package/packages/core/dist/core/install/unified/context-helpers.d.ts +0 -4
- package/packages/core/dist/core/install/unified/context-helpers.d.ts.map +1 -1
- package/packages/core/dist/core/install/unified/context-helpers.js +0 -24
- package/packages/core/dist/core/install/unified/context-helpers.js.map +1 -1
- package/packages/core/dist/core/install/unified/index.d.ts +1 -1
- package/packages/core/dist/core/install/unified/index.d.ts.map +1 -1
- package/packages/core/dist/core/install/unified/index.js +1 -1
- package/packages/core/dist/core/install/unified/index.js.map +1 -1
- package/packages/core/dist/core/install/unified/multi-context-pipeline.d.ts +6 -0
- package/packages/core/dist/core/install/unified/multi-context-pipeline.d.ts.map +1 -1
- package/packages/core/dist/core/install/unified/multi-context-pipeline.js +11 -4
- package/packages/core/dist/core/install/unified/multi-context-pipeline.js.map +1 -1
- package/packages/core/dist/core/install/unified/phases/conflicts.d.ts.map +1 -1
- package/packages/core/dist/core/install/unified/phases/conflicts.js +1 -1
- package/packages/core/dist/core/install/unified/phases/conflicts.js.map +1 -1
- package/packages/core/dist/core/install/unified/phases/execute.d.ts.map +1 -1
- package/packages/core/dist/core/install/unified/phases/execute.js +5 -5
- package/packages/core/dist/core/install/unified/phases/execute.js.map +1 -1
- package/packages/core/dist/core/install/unified/phases/load-package.js +3 -3
- package/packages/core/dist/core/install/unified/phases/load-package.js.map +1 -1
- package/packages/core/dist/core/install/unified/phases/report.js +1 -1
- package/packages/core/dist/core/install/unified/phases/report.js.map +1 -1
- package/packages/core/dist/core/install/unified/pipeline.d.ts.map +1 -1
- package/packages/core/dist/core/install/unified/pipeline.js +7 -10
- package/packages/core/dist/core/install/unified/pipeline.js.map +1 -1
- package/packages/core/dist/core/install/wave-resolver/content-root-cache.d.ts +24 -0
- package/packages/core/dist/core/install/wave-resolver/content-root-cache.d.ts.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/content-root-cache.js +71 -0
- package/packages/core/dist/core/install/wave-resolver/content-root-cache.js.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/context-builder.d.ts +39 -0
- package/packages/core/dist/core/install/wave-resolver/context-builder.d.ts.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/context-builder.js +148 -0
- package/packages/core/dist/core/install/wave-resolver/context-builder.js.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/fetcher.d.ts +49 -0
- package/packages/core/dist/core/install/wave-resolver/fetcher.d.ts.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/fetcher.js +221 -0
- package/packages/core/dist/core/install/wave-resolver/fetcher.js.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/index-updater.d.ts +23 -0
- package/packages/core/dist/core/install/wave-resolver/index-updater.d.ts.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/index-updater.js +87 -0
- package/packages/core/dist/core/install/wave-resolver/index-updater.js.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/index-write-collector.d.ts +101 -0
- package/packages/core/dist/core/install/wave-resolver/index-write-collector.d.ts.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/index-write-collector.js +194 -0
- package/packages/core/dist/core/install/wave-resolver/index-write-collector.js.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/index.d.ts +17 -0
- package/packages/core/dist/core/install/wave-resolver/index.d.ts.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/index.js +16 -0
- package/packages/core/dist/core/install/wave-resolver/index.js.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/manifest-reader.d.ts +34 -0
- package/packages/core/dist/core/install/wave-resolver/manifest-reader.d.ts.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/manifest-reader.js +112 -0
- package/packages/core/dist/core/install/wave-resolver/manifest-reader.js.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/types.d.ts +210 -0
- package/packages/core/dist/core/install/wave-resolver/types.d.ts.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/types.js +6 -0
- package/packages/core/dist/core/install/wave-resolver/types.js.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/version-solver.d.ts +65 -0
- package/packages/core/dist/core/install/wave-resolver/version-solver.d.ts.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/version-solver.js +166 -0
- package/packages/core/dist/core/install/wave-resolver/version-solver.js.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/wave-engine.d.ts +16 -0
- package/packages/core/dist/core/install/wave-resolver/wave-engine.d.ts.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/wave-engine.js +337 -0
- package/packages/core/dist/core/install/wave-resolver/wave-engine.js.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/wave-installer.d.ts +50 -0
- package/packages/core/dist/core/install/wave-resolver/wave-installer.d.ts.map +1 -0
- package/packages/core/dist/core/install/wave-resolver/wave-installer.js +246 -0
- package/packages/core/dist/core/install/wave-resolver/wave-installer.js.map +1 -0
- package/packages/core/dist/core/ports/buffered-output.d.ts +36 -0
- package/packages/core/dist/core/ports/buffered-output.d.ts.map +1 -0
- package/packages/core/dist/core/ports/buffered-output.js +89 -0
- package/packages/core/dist/core/ports/buffered-output.js.map +1 -0
- package/packages/core/dist/core/ports/resolve.d.ts +0 -13
- package/packages/core/dist/core/ports/resolve.d.ts.map +1 -1
- package/packages/core/dist/core/ports/resolve.js +0 -28
- package/packages/core/dist/core/ports/resolve.js.map +1 -1
- package/packages/core/dist/core/remove/removal-confirmation.d.ts +4 -1
- package/packages/core/dist/core/remove/removal-confirmation.d.ts.map +1 -1
- package/packages/core/dist/core/remove/removal-confirmation.js +5 -4
- package/packages/core/dist/core/remove/removal-confirmation.js.map +1 -1
- package/packages/core/dist/core/remove/remove-from-source-pipeline.d.ts.map +1 -1
- package/packages/core/dist/core/remove/remove-from-source-pipeline.js +1 -10
- package/packages/core/dist/core/remove/remove-from-source-pipeline.js.map +1 -1
- package/packages/core/dist/core/uninstall/uninstall-executor.js +1 -1
- package/packages/core/dist/core/uninstall/uninstall-executor.js.map +1 -1
- package/packages/core/dist/core/uninstall/uninstall-reporter.d.ts +2 -2
- package/packages/core/dist/core/uninstall/uninstall-reporter.d.ts.map +1 -1
- package/packages/core/dist/core/uninstall/uninstall-reporter.js +4 -4
- package/packages/core/dist/core/uninstall/uninstall-reporter.js.map +1 -1
- package/packages/core/dist/index.d.ts +1 -1
- package/packages/core/dist/index.d.ts.map +1 -1
- package/packages/core/dist/types/execution-context.d.ts +40 -10
- package/packages/core/dist/types/execution-context.d.ts.map +1 -1
- package/packages/core/dist/utils/concurrency-pool.d.ts +34 -0
- package/packages/core/dist/utils/concurrency-pool.d.ts.map +1 -0
- package/packages/core/dist/utils/concurrency-pool.js +58 -0
- package/packages/core/dist/utils/concurrency-pool.js.map +1 -0
- package/packages/core/dist/utils/plugin-naming.d.ts +11 -3
- package/packages/core/dist/utils/plugin-naming.d.ts.map +1 -1
- package/packages/core/dist/utils/plugin-naming.js +27 -7
- package/packages/core/dist/utils/plugin-naming.js.map +1 -1
- package/plans/wave-resolver.md +254 -0
- package/.claude/agents/essentials/code-simplifier.md +0 -52
- package/.claude/commands/essentials/cleanup.md +0 -1
- package/.claude/commands/essentials/review.md +0 -8
- package/.claude/commands/git/commit.md +0 -5
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../core/src/core/platform/directory-preservation.ts", "../../core/src/core/uninstall/uninstall-pipeline.ts", "../../core/src/utils/workspace-index-ownership.ts", "../../core/src/core/platform/root-file-uninstaller.ts", "../../core/src/utils/package-index-yml.ts", "../../core/src/core/uninstall/flow-aware-uninstaller.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Directory Preservation Utilities\n * \n * Determines which directories should be preserved during uninstall cleanup.\n * Uses platform detection patterns to identify platform root directories that\n * should never be removed, even if empty.\n */\n\nimport path from 'path';\nimport { getAllPlatforms, getPlatformDefinition } from '../platforms.js';\n\n/**\n * Extract the directory path from a detection pattern.\n * \n * Detection patterns can be:\n * - Directory names: \".cursor\", \".claude\"\n * - File paths: \".claude-plugin/plugin.json\", \"CLAUDE.md\"\n * - Future: glob patterns\n * \n * @param pattern - Detection pattern from platform definition\n * @param targetDir - Target directory (workspace root or global home)\n * @returns Absolute directory path to preserve, or null if pattern points to workspace root\n * \n * @example\n * extractDirectoryFromPattern(\".cursor\", \"/workspace\") \n * \u2192 \"/workspace/.cursor\"\n * \n * extractDirectoryFromPattern(\".claude-plugin/plugin.json\", \"/workspace\")\n * \u2192 \"/workspace/.claude-plugin\"\n * \n * extractDirectoryFromPattern(\"CLAUDE.md\", \"/workspace\")\n * \u2192 null (root file, don't preserve workspace root)\n */\nexport function extractDirectoryFromPattern(pattern: string, targetDir: string): string | null {\n // Normalize path separators\n const normalized = pattern.replace(/\\\\/g, '/');\n \n // Check if it's a directory or a file\n // A dotfile directory (e.g., \".cursor\", \".claude\") is a single segment starting with \".\"\n // and no path separators \u2014 distinct from a file extension like \"file.md\"\n const isDotfileDir = /^\\.[^./]+$/.test(normalized);\n const hasExtension = !isDotfileDir && /\\.[a-z0-9]+$/i.test(normalized);\n const isDirectory = normalized.endsWith('/') || !hasExtension;\n \n let dirPath: string;\n \n if (isDirectory) {\n // Remove trailing slash if present\n dirPath = normalized.replace(/\\/$/, '');\n } else {\n // Extract directory from file path\n const lastSlash = normalized.lastIndexOf('/');\n dirPath = lastSlash >= 0 ? normalized.substring(0, lastSlash) : '';\n }\n \n // Convert to absolute path\n const absPath = dirPath ? path.join(targetDir, dirPath) : targetDir;\n \n // Don't preserve the workspace root itself\n // Root files (like CLAUDE.md, AGENTS.md) have their own preservation logic\n return absPath === targetDir ? null : absPath;\n}\n\n/**\n * Build a Set of absolute directory paths that should be preserved during cleanup.\n * \n * These directories are identified from platform detection patterns and represent\n * platform root directories (e.g., .cursor, .claude, .opencode) that should never\n * be removed, even if they become empty after uninstalling packages.\n * \n * @param targetDir - Target directory (workspace root or global home)\n * @returns Set of absolute directory paths to preserve\n * \n * @example\n * buildPreservedDirectoriesSet(\"/workspace\")\n * \u2192 Set([\n * \"/workspace/.cursor\",\n * \"/workspace/.claude\", \n * \"/workspace/.opencode\",\n * \"/workspace/.claude-plugin\",\n * ...\n * ])\n */\nexport function buildPreservedDirectoriesSet(targetDir: string): Set<string> {\n const preserved = new Set<string>();\n const platforms = getAllPlatforms(undefined, targetDir);\n \n for (const platform of platforms) {\n const definition = getPlatformDefinition(platform, targetDir);\n \n // Primary: use detection patterns\n if (definition.detection && definition.detection.length > 0) {\n for (const pattern of definition.detection) {\n const dirToPreserve = extractDirectoryFromPattern(pattern, targetDir);\n if (dirToPreserve) {\n preserved.add(dirToPreserve);\n }\n }\n } else if (definition.rootDir) {\n // Fallback: use rootDir for platforms without detection patterns\n const rootPath = path.join(targetDir, definition.rootDir);\n if (rootPath !== targetDir) {\n preserved.add(rootPath);\n }\n }\n }\n \n return preserved;\n}\n", "import path from 'path';\n\nimport type { CommandResult, UninstallOptions, ExecutionContext } from '../../types/index.js';\nimport { ValidationError } from '../../utils/errors.js';\nimport { getLocalOpenPackageDir, getLocalPackageYmlPath } from '../../utils/paths.js';\nimport { readWorkspaceIndex, writeWorkspaceIndex } from '../../utils/workspace-index-yml.js';\nimport { removeWorkspaceIndexEntry, removeWorkspaceIndexFileKeys } from '../../utils/workspace-index-ownership.js';\nimport { processRootFileRemovals } from '../platform/root-file-uninstaller.js';\nimport { exists, remove, walkFiles } from '../../utils/fs.js';\nimport { isDirKey } from '../../utils/package-index-yml.js';\nimport { removePackageFromOpenpackageYml } from '../package-management.js';\nimport { getPlatformRootFileNames } from '../platform/platform-root-files.js';\nimport { getAllPlatforms } from '../platforms.js';\nimport { logger } from '../../utils/logger.js';\nimport { removeFileMapping } from './flow-aware-uninstaller.js';\nimport { getTargetPath } from '../../utils/workspace-index-helpers.js';\nimport { buildPreservedDirectoriesSet } from '../platform/directory-preservation.js';\nimport { cleanupEmptyParents } from '../../utils/cleanup-empty-parents.js';\nimport type { WorkspaceIndexFileMapping } from '../../types/workspace-index.js';\nimport type { OutputPort } from '../ports/output.js';\nimport { resolveOutput } from '../ports/resolve.js';\n\ninterface ProcessFileMappingsOptions {\n dryRun?: boolean;\n}\n\ninterface ProcessFileMappingsResult {\n removed: string[];\n updated: string[];\n}\n\nfunction isRootFileKey(key: string, rootNames: Set<string>): boolean {\n const normalized = key.replace(/\\\\/g, '/');\n return rootNames.has(normalized);\n}\n\nasync function processFileMappings(\n filesMapping: Record<string, (string | WorkspaceIndexFileMapping)[]>,\n targetDir: string,\n packageName: string,\n rootNames: Set<string>,\n options: ProcessFileMappingsOptions = {}\n): Promise<ProcessFileMappingsResult> {\n const removed: string[] = [];\n const updated: string[] = [];\n const seenPaths = new Set<string>();\n\n for (const [rawKey, mappings] of Object.entries(filesMapping || {})) {\n if (!Array.isArray(mappings) || mappings.length === 0) continue;\n\n const isDir = isDirKey(rawKey);\n\n if (isDir) {\n for (const mapping of mappings) {\n const targetPath = getTargetPath(mapping);\n const absDir = path.join(targetDir, targetPath);\n if (!(await exists(absDir))) continue;\n\n if (options.dryRun) {\n for await (const filePath of walkFiles(absDir)) {\n if (!seenPaths.has(filePath)) {\n seenPaths.add(filePath);\n removed.push(filePath);\n }\n }\n } else {\n const result = await removeFileMapping(targetDir, mapping, packageName);\n removed.push(...result.removed);\n updated.push(...result.updated);\n }\n }\n continue;\n }\n\n if (isRootFileKey(rawKey, rootNames)) {\n continue;\n }\n\n for (const mapping of mappings) {\n const targetPath = getTargetPath(mapping);\n const absPath = path.join(targetDir, targetPath);\n\n if (options.dryRun) {\n if (!seenPaths.has(absPath)) {\n seenPaths.add(absPath);\n removed.push(absPath);\n }\n } else {\n const result = await removeFileMapping(targetDir, mapping, packageName);\n removed.push(...result.removed);\n updated.push(...result.updated);\n }\n }\n }\n\n return { removed, updated };\n}\n\nexport interface UninstallPipelineResult {\n removedFiles: string[];\n rootFilesUpdated: string[];\n}\n\nexport async function runUninstallPipeline(\n packageName: string,\n options: UninstallOptions = {},\n execContext: ExecutionContext\n): Promise<CommandResult<UninstallPipelineResult>> {\n // Use targetDir for uninstall operations\n const targetDir = execContext.targetDir;\n const openpkgDir = getLocalOpenPackageDir(targetDir);\n const manifestPath = getLocalPackageYmlPath(targetDir);\n\n if (!(await exists(openpkgDir)) || !(await exists(manifestPath))) {\n throw new ValidationError(\n `No .openpackage/openpackage.yml found in ${targetDir}.`\n );\n }\n\n // Look up package by exact name provided by user (no normalization)\n const { index, path: indexPath } = await readWorkspaceIndex(targetDir);\n const pkgEntry = index.packages?.[packageName];\n\n if (!pkgEntry) {\n return { success: false, error: `Package '${packageName}' not found in workspace index.` };\n }\n\n const rootNames = getPlatformRootFileNames(getAllPlatforms(undefined, targetDir), targetDir);\n\n if (options.dryRun) {\n const out = resolveOutput(execContext);\n const plannedRemovals = await processFileMappings(\n pkgEntry.files || {},\n targetDir,\n packageName,\n rootNames,\n { dryRun: true }\n );\n const rootPlan = await processRootFileRemovals(targetDir, [packageName], { dryRun: true });\n out.info(`(dry-run) Would remove ${plannedRemovals.removed.length} files for ${packageName}`);\n for (const filePath of plannedRemovals.removed) {\n out.info(` - ${filePath}`);\n }\n if (rootPlan.updated.length > 0) {\n out.info(`Root files to update:`);\n rootPlan.updated.forEach(f => out.info(` - ${f}`));\n }\n return {\n success: true,\n data: {\n removedFiles: plannedRemovals.removed,\n rootFilesUpdated: rootPlan.updated\n }\n };\n }\n\n const { removed: deleted, updated } = await processFileMappings(\n pkgEntry.files || {},\n targetDir,\n packageName,\n rootNames,\n { dryRun: false }\n );\n\n const rootResult = await processRootFileRemovals(targetDir, [packageName]);\n\n // Update workspace index (migration will happen on write)\n removeWorkspaceIndexEntry(index, packageName);\n await writeWorkspaceIndex({ path: indexPath, index });\n\n // Update openpackage.yml (migration will happen on write)\n await removePackageFromOpenpackageYml(targetDir, packageName);\n\n // Cleanup empty directories (preserve platform roots from detection patterns)\n const preservedDirs = buildPreservedDirectoriesSet(targetDir);\n // Convert relative paths to absolute paths for cleanup\n const deletedAbsolutePaths = deleted.map(relativePath => path.join(targetDir, relativePath));\n await cleanupEmptyParents(targetDir, deletedAbsolutePaths, preservedDirs);\n\n logger.info(`Uninstalled ${packageName}: removed ${deleted.length} files, updated ${updated.length} merged files`);\n\n return {\n success: true,\n data: {\n removedFiles: deleted,\n rootFilesUpdated: [...rootResult.updated, ...updated]\n }\n };\n}\n\nexport async function runSelectiveUninstallPipeline(\n packageName: string,\n sourceKeysToRemove: Set<string>,\n options: UninstallOptions = {},\n execContext: ExecutionContext\n): Promise<CommandResult<UninstallPipelineResult>> {\n const targetDir = execContext.targetDir;\n const openpkgDir = getLocalOpenPackageDir(targetDir);\n const manifestPath = getLocalPackageYmlPath(targetDir);\n\n if (!(await exists(openpkgDir)) || !(await exists(manifestPath))) {\n throw new ValidationError(\n `No .openpackage/openpackage.yml found in ${targetDir}.`\n );\n }\n\n const { index, path: indexPath } = await readWorkspaceIndex(targetDir);\n const pkgEntry = index.packages?.[packageName];\n\n if (!pkgEntry) {\n return { success: false, error: `Package '${packageName}' not found in workspace index.` };\n }\n\n const filteredFiles: Record<string, (string | WorkspaceIndexFileMapping)[]> = {};\n for (const key of sourceKeysToRemove) {\n if (pkgEntry.files[key]) {\n filteredFiles[key] = pkgEntry.files[key];\n }\n }\n\n const rootNames = getPlatformRootFileNames(getAllPlatforms(undefined, targetDir), targetDir);\n\n if (options.dryRun) {\n const out = resolveOutput(execContext);\n const plannedRemovals = await processFileMappings(\n filteredFiles,\n targetDir,\n packageName,\n rootNames,\n { dryRun: true }\n );\n out.info(`(dry-run) Would remove ${plannedRemovals.removed.length} files for ${packageName}`);\n for (const filePath of plannedRemovals.removed) {\n out.info(` - ${filePath}`);\n }\n return {\n success: true,\n data: {\n removedFiles: plannedRemovals.removed,\n rootFilesUpdated: []\n }\n };\n }\n\n const { removed: deleted, updated } = await processFileMappings(\n filteredFiles,\n targetDir,\n packageName,\n rootNames,\n { dryRun: false }\n );\n\n removeWorkspaceIndexFileKeys(index, packageName, sourceKeysToRemove);\n await writeWorkspaceIndex({ path: indexPath, index });\n\n const preservedDirs = buildPreservedDirectoriesSet(targetDir);\n const deletedAbsolutePaths = deleted.map(relativePath => path.join(targetDir, relativePath));\n await cleanupEmptyParents(targetDir, deletedAbsolutePaths, preservedDirs);\n\n logger.info(`Selectively uninstalled from ${packageName}: removed ${deleted.length} files, updated ${updated.length} merged files`);\n\n return {\n success: true,\n data: {\n removedFiles: deleted,\n rootFilesUpdated: updated\n }\n };\n}\n", "import { join } from 'path';\nimport { getTargetPath } from './workspace-index-helpers.js';\n\nimport type { WorkspaceIndex, WorkspaceIndexPackage } from '../types/workspace-index.js';\nimport { normalizePathForProcessing } from './path-normalization.js';\nimport { exists, walkFiles } from './fs.js';\n\nexport interface WorkspaceConflictOwner {\n packageName: string;\n key: string;\n type: 'file' | 'dir';\n}\n\nexport interface WorkspaceOwnershipContext {\n /**\n * Directory-key owners (key ends with \"/\").\n * Each key may have multiple owners, though consumers typically expect none or one.\n */\n dirKeyOwners: Map<string, WorkspaceConflictOwner[]>;\n /**\n * Concrete workspace path \u2192 owning package.\n */\n installedPathOwners: Map<string, WorkspaceConflictOwner>;\n}\n\nexport function getWorkspaceIndexEntry(\n index: WorkspaceIndex,\n packageName: string\n): WorkspaceIndexPackage | undefined {\n return index.packages?.[packageName];\n}\n\nexport function upsertWorkspaceIndexEntry(\n index: WorkspaceIndex,\n packageName: string,\n entry: WorkspaceIndexPackage\n): void {\n if (!index.packages) {\n index.packages = {};\n }\n index.packages[packageName] = entry;\n}\n\nexport function removeWorkspaceIndexEntry(index: WorkspaceIndex, packageName: string): void {\n if (index.packages && index.packages[packageName]) {\n delete index.packages[packageName];\n }\n}\n\nexport function removeWorkspaceIndexFileKeys(\n index: WorkspaceIndex,\n packageName: string,\n sourceKeysToRemove: Set<string>\n): void {\n const pkg = index.packages?.[packageName];\n if (!pkg) return;\n\n for (const key of sourceKeysToRemove) {\n delete pkg.files[key];\n }\n\n if (Object.keys(pkg.files).length === 0) {\n delete index.packages[packageName];\n }\n}\n\n/**\n * Build ownership maps from the unified workspace index.\n *\n * - Directory keys (trailing \"/\") are expanded to the concrete file paths that\n * currently exist on disk under the mapped directories.\n * - File keys map directly to the listed workspace-relative paths.\n */\nexport async function buildWorkspaceOwnershipContext(\n cwd: string,\n index: WorkspaceIndex,\n opts: { excludePackage?: string } = {}\n): Promise<WorkspaceOwnershipContext> {\n const dirKeyOwners = new Map<string, WorkspaceConflictOwner[]>();\n const installedPathOwners = new Map<string, WorkspaceConflictOwner>();\n\n const packages = index.packages ?? {};\n const exclude = opts.excludePackage;\n\n for (const [rawName, pkg] of Object.entries(packages)) {\n if (exclude && rawName === exclude) continue;\n if (!pkg || typeof pkg !== 'object') continue;\n\n const pkgName = rawName;\n const files = pkg.files ?? {};\n\n for (const [rawKey, rawValues] of Object.entries(files)) {\n if (!Array.isArray(rawValues)) continue;\n const normalizedKey = normalizePathForProcessing(rawKey);\n if (!normalizedKey) continue;\n\n const owner: WorkspaceConflictOwner = {\n packageName: pkgName,\n key: normalizedKey,\n type: normalizedKey.endsWith('/') ? 'dir' : 'file'\n };\n\n if (owner.type === 'dir') {\n if (!dirKeyOwners.has(normalizedKey)) {\n dirKeyOwners.set(normalizedKey, []);\n }\n dirKeyOwners.get(normalizedKey)!.push(owner);\n\n for (const rawMapping of rawValues) {\n // Handle both simple string and WorkspaceIndexFileMapping\n const targetPath = typeof rawMapping === 'string' ? rawMapping : rawMapping.target;\n const dirRel = normalizePathForProcessing(targetPath);\n if (!dirRel) continue;\n const expanded = await collectFilesUnderDirectory(cwd, dirRel);\n for (const relFile of expanded) {\n if (!installedPathOwners.has(relFile)) {\n installedPathOwners.set(relFile, owner);\n }\n }\n }\n continue;\n }\n\n // file key\n for (const rawMapping of rawValues) {\n // Handle both simple string and WorkspaceIndexFileMapping\n const targetPath = typeof rawMapping === 'string' ? rawMapping : rawMapping.target;\n const relPath = normalizePathForProcessing(targetPath);\n if (!relPath) continue;\n if (!installedPathOwners.has(relPath)) {\n installedPathOwners.set(relPath, owner);\n }\n }\n }\n }\n\n return { dirKeyOwners, installedPathOwners };\n}\n\nasync function collectFilesUnderDirectory(cwd: string, dirRel: string): Promise<string[]> {\n const normalizedDir = normalizePathForProcessing(dirRel);\n if (!normalizedDir) return [];\n\n const absDir = join(cwd, normalizedDir);\n if (!(await exists(absDir))) {\n return [];\n }\n\n const collected: string[] = [];\n for await (const absFile of walkFiles(absDir)) {\n const rel = normalizePathForProcessing(absFile.slice(absDir.length + 1));\n if (rel) {\n collected.push(normalizePathForProcessing(join(normalizedDir, rel)));\n }\n }\n return collected;\n}\n", "/**\n * Root File Uninstaller\n * Utilities to remove package-marked sections from root files and delete empty files\n */\n\nimport { join } from 'path';\nimport { exists, readTextFile, writeTextFile } from '../../utils/fs.js';\nimport { logger } from '../../utils/logger.js';\nimport { getAllPlatforms, getPlatformDefinition } from '../platforms.js';\nimport { buildOpenMarkerRegex, CLOSE_MARKER_REGEX } from '../../utils/root-file-extractor.js';\nimport { FILE_PATTERNS } from '../../constants/index.js';\n\n/** Remove a single package section from root-file content using markers */\nfunction stripPackageSection(content: string, packageName: string): { changed: boolean; content: string } {\n if (!content) return { changed: false, content };\n const openRe = buildOpenMarkerRegex(packageName);\n const closeRe = CLOSE_MARKER_REGEX;\n const openMatch = openRe.exec(content);\n if (!openMatch) return { changed: false, content };\n const before = content.slice(0, openMatch.index);\n const rest = content.slice(openMatch.index + openMatch[0].length);\n const closeMatch = closeRe.exec(rest);\n if (!closeMatch) return { changed: false, content };\n const after = rest.slice(closeMatch.index + closeMatch[0].length);\n return { changed: true, content: before + after };\n}\n\n/** Remove multiple package sections from content */\nfunction stripMultiplePackageSections(content: string, packageNames: string[]): { changed: boolean; content: string } {\n let changed = false;\n let current = content;\n for (const name of packageNames) {\n const result = stripPackageSection(current, name);\n if (result.changed) changed = true;\n current = result.content;\n }\n return { changed, content: current };\n}\n\n/** Discover platform root filenames from platform definitions */\nfunction getUniqueRootFilenames(): string[] {\n const set = new Set<string>([FILE_PATTERNS.AGENTS_MD]);\n for (const platform of getAllPlatforms()) {\n const def = getPlatformDefinition(platform);\n if (def.rootFile) set.add(def.rootFile);\n }\n return Array.from(set);\n}\n\n/**\n * Process root file removals: strip package sections from root files.\n * When dryRun is true, returns the list of files that would be updated without writing.\n * When dryRun is false (default), writes the changes and returns the updated files.\n */\nexport async function processRootFileRemovals(\n targetDir: string,\n packageNames: string[],\n options: { dryRun?: boolean } = {}\n): Promise<{ updated: string[] }> {\n const updated: string[] = [];\n const rootFiles = getUniqueRootFilenames();\n\n for (const filename of rootFiles) {\n const absPath = join(targetDir, filename);\n if (!(await exists(absPath))) continue;\n\n const original = await readTextFile(absPath);\n const { changed, content } = stripMultiplePackageSections(original, packageNames);\n if (!changed) continue;\n\n if (!options.dryRun) {\n await writeTextFile(absPath, content);\n logger.debug(`Updated root file: ${absPath}`);\n }\n\n updated.push(filename);\n }\n\n return { updated };\n}\n", "import { join, dirname } from 'path';\nimport * as yaml from 'js-yaml';\nimport { FILE_PATTERNS } from '../constants/index.js';\nimport { exists, readTextFile, writeTextFile, ensureDir } from './fs.js';\nimport { getLocalOpenPackageDir, getLocalPackageContentDir } from './paths.js';\nimport { normalizePathForProcessing } from './path-normalization.js';\nimport { logger } from './logger.js';\n\nconst HEADER_COMMENT = '# This file is managed by OpenPackage. Do not edit manually.';\n\nexport type PackageIndexLocation = 'root' | 'nested';\n\nexport interface PackageIndexWorkspace {\n hash?: string;\n version: string;\n}\n\nexport interface PackageIndexData {\n workspace: PackageIndexWorkspace;\n files: Record<string, string[]>;\n}\n\nexport interface PackageIndexRecord extends PackageIndexData {\n path: string;\n packageName: string;\n}\n\nexport function getPackageIndexPath(\n cwd: string,\n packageName: string,\n location: PackageIndexLocation = 'nested'\n): string {\n if (location === 'root') {\n return join(getLocalOpenPackageDir(cwd), FILE_PATTERNS.OPENPACKAGE_INDEX_YML);\n }\n\n // Nested: cached package root (cwd/.openpackage/packages/<name>/)\n const contentDir = getLocalPackageContentDir(cwd, packageName);\n return join(contentDir, FILE_PATTERNS.OPENPACKAGE_INDEX_YML);\n}\n\nexport function ensureTrailingSlash(value: string): string {\n return value.endsWith('/') ? value : `${value}/`;\n}\n\nexport function sortMapping(record: Record<string, any[]>): Record<string, any[]> {\n const sortedKeys = Object.keys(record).sort();\n const normalized: Record<string, any[]> = {};\n for (const key of sortedKeys) {\n const values = record[key] || [];\n const hasComplex = values.some(v => typeof v === 'object' && v !== null);\n if (hasComplex) {\n // Complex mappings - sort by target path\n const sorted = [...values].sort((a, b) => {\n const targetA = typeof a === 'string' ? a : a.target;\n const targetB = typeof b === 'string' ? b : b.target;\n return targetA.localeCompare(targetB);\n });\n // Dedupe by target\n const seen = new Set<string>();\n normalized[key] = sorted.filter(item => {\n const target = typeof item === 'string' ? item : item.target;\n if (seen.has(target)) return false;\n seen.add(target);\n return true;\n });\n } else {\n // Simple string array\n const sortedValues = [...new Set(values)].sort();\n normalized[key] = sortedValues;\n }\n }\n return normalized;\n}\n\nexport function sanitizeIndexData(data: any): PackageIndexData | null {\n if (!data || typeof data !== 'object') return null;\n\n let workspaceVer: string | undefined;\n let workspaceHash: string | undefined;\n\n const workspaceSection = (data as { workspace?: unknown }).workspace;\n if (workspaceSection && typeof workspaceSection === 'object') {\n const maybeVersion = (workspaceSection as { version?: unknown }).version;\n if (typeof maybeVersion === 'string') {\n workspaceVer = maybeVersion;\n }\n const maybeHash = (workspaceSection as { hash?: unknown }).hash;\n if (typeof maybeHash === 'string') {\n workspaceHash = maybeHash;\n }\n }\n\n if (typeof workspaceVer !== 'string') return null;\n\n const files = (data as { files?: unknown }).files;\n if (!files || typeof files !== 'object') return null;\n\n const entries: Record<string, string[]> = {};\n for (const [rawKey, rawValue] of Object.entries(files as Record<string, unknown>)) {\n if (typeof rawKey !== 'string') continue;\n if (!Array.isArray(rawValue)) continue;\n\n const cleanedValues = rawValue\n .filter((entry): entry is string => typeof entry === 'string' && entry.trim().length > 0)\n .map(value => normalizePathForProcessing(value));\n\n entries[normalizePathForProcessing(rawKey)] = cleanedValues;\n }\n\n return {\n workspace: {\n version: workspaceVer,\n hash: workspaceHash\n },\n files: sortMapping(entries)\n };\n}\n\nexport async function readPackageIndex(\n cwd: string,\n packageName: string,\n location: PackageIndexLocation = 'nested'\n): Promise<PackageIndexRecord | null> {\n const canonicalPath = getPackageIndexPath(cwd, packageName, location);\n const indexPath = canonicalPath;\n\n if (!(await exists(indexPath))) {\n return null;\n }\n\n try {\n const content = await readTextFile(indexPath);\n const parsed = yaml.load(content) as any;\n const sanitized = sanitizeIndexData(parsed);\n if (!sanitized) {\n logger.warn(`Invalid package index detected at ${indexPath}, will repair on write.`);\n return {\n path: indexPath,\n packageName,\n workspace: { version: '', hash: undefined },\n files: {}\n };\n }\n return {\n path: canonicalPath,\n packageName,\n workspace: sanitized.workspace,\n files: sanitized.files\n };\n } catch (error) {\n logger.warn(`Failed to read package index at ${indexPath}: ${error}`);\n return {\n path: canonicalPath,\n packageName,\n workspace: { version: '', hash: undefined },\n files: {}\n };\n }\n}\n\nexport async function writePackageIndex(record: PackageIndexRecord): Promise<void> {\n const { path: indexPath, files } = record;\n const workspaceVer = record.workspace?.version;\n if (!workspaceVer) {\n throw new Error(`workspace.version is required when writing ${FILE_PATTERNS.OPENPACKAGE_INDEX_YML}`);\n }\n const workspace: PackageIndexWorkspace = {\n hash: record.workspace?.hash,\n version: workspaceVer\n };\n await ensureDir(dirname(indexPath));\n\n const normalizedFiles = sortMapping(files);\n const body = yaml.dump(\n {\n workspace,\n files: normalizedFiles\n },\n {\n lineWidth: 120,\n sortKeys: true\n }\n );\n\n const serialized = `${HEADER_COMMENT}\\n\\n${body}`;\n await writeTextFile(indexPath, serialized);\n}\n\nexport function isDirKey(key: string): boolean {\n return key.endsWith('/');\n}\n\n/**\n * Prune nested child directories if their parent directory is already present.\n * Example: keep \"skills/nestjs/\" and drop \"skills/nestjs/examples/\".\n */\nexport function pruneNestedDirectories(dirs: string[]): string[] {\n const sorted = [...dirs].sort((a, b) => {\n if (a.length === b.length) {\n return a.localeCompare(b);\n }\n return a.length - b.length;\n });\n\n const pruned: string[] = [];\n for (const dir of sorted) {\n const hasParent = pruned.some(parent => dir !== parent && dir.startsWith(parent));\n if (!hasParent) {\n pruned.push(dir);\n }\n }\n return pruned;\n}\n\n", "/**\n * Flow-Aware Uninstaller\n * \n * Handles uninstallation of packages installed with flows,\n * including precise removal of keys from merged files.\n */\n\nimport { join } from 'path';\nimport { readTextFile, writeTextFile, exists, remove } from '../../utils/fs.js';\nimport { logger } from '../../utils/logger.js';\nimport type { WorkspaceIndexFileMapping } from '../../types/workspace-index.js';\nimport { deleteNestedKey, isEffectivelyEmpty } from '../flows/flow-key-extractor.js';\nimport yaml from 'js-yaml';\nimport * as TOML from 'smol-toml';\n\n/**\n * File format detection\n */\ntype FileFormat = 'json' | 'jsonc' | 'yaml' | 'yml' | 'toml' | 'text';\n\nfunction detectFileFormat(filePath: string): FileFormat {\n const ext = filePath.toLowerCase().split('.').pop();\n switch (ext) {\n case 'json':\n return 'json';\n case 'jsonc':\n return 'jsonc';\n case 'yaml':\n case 'yml':\n return 'yaml';\n case 'toml':\n return 'toml';\n default:\n return 'text';\n }\n}\n\n/**\n * Parse file content based on format\n */\nfunction parseContent(content: string, format: FileFormat): any {\n try {\n switch (format) {\n case 'json':\n case 'jsonc':\n // Strip comments for JSONC\n const cleaned = format === 'jsonc' \n ? content.replace(/\\/\\/.*$/gm, '').replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n : content;\n return JSON.parse(cleaned);\n \n case 'yaml':\n case 'yml':\n return yaml.load(content);\n \n case 'toml':\n return TOML.parse(content);\n \n default:\n return content;\n }\n } catch (error) {\n throw new Error(`Failed to parse ${format} file: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/**\n * Serialize content based on format\n */\nfunction serializeContent(data: any, format: FileFormat): string {\n try {\n switch (format) {\n case 'json':\n case 'jsonc':\n return JSON.stringify(data, null, 2);\n \n case 'yaml':\n case 'yml':\n return yaml.dump(data, { indent: 2, flowLevel: 1, lineWidth: -1 });\n \n case 'toml':\n return TOML.stringify(data);\n \n default:\n return typeof data === 'string' ? data : JSON.stringify(data, null, 2);\n }\n } catch (error) {\n throw new Error(`Failed to serialize ${format} file: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/**\n * Remove specific keys from a merged file\n * Deletes the file if it becomes empty after removal\n * \n * @param targetDir - Target directory (workspace root or global home)\n * @param targetPath - Relative path to target file\n * @param keysToRemove - Dot-notated keys to remove\n * @returns true if file was deleted, false if updated\n */\nexport async function removeKeysFromMergedFile(\n targetDir: string,\n targetPath: string,\n keysToRemove: string[]\n): Promise<{ deleted: boolean; updated: boolean }> {\n const absPath = join(targetDir, targetPath);\n\n if (!(await exists(absPath))) {\n return { deleted: false, updated: false };\n }\n\n // Load and parse file\n const content = await readTextFile(absPath);\n const format = detectFileFormat(targetPath);\n let data: any;\n\n try {\n data = parseContent(content, format);\n } catch (error) {\n logger.warn(`Failed to parse ${targetPath} for key removal: ${error instanceof Error ? error.message : String(error)}`);\n return { deleted: false, updated: false };\n }\n\n const hasNestedKeyPath = (obj: any, keyPath: string): boolean => {\n if (!obj || typeof obj !== 'object') return false;\n const parts = keyPath.split('.').filter(Boolean);\n let current: any = obj;\n for (const part of parts) {\n if (!current || typeof current !== 'object' || !(part in current)) return false;\n current = current[part];\n }\n return true;\n };\n\n const existingBefore = keysToRemove.filter(k => typeof k === 'string' && hasNestedKeyPath(data, k)).length;\n // Remove each key\n for (const key of keysToRemove) {\n deleteNestedKey(data, key);\n }\n\n // Check if file is now empty\n if (isEffectivelyEmpty(data)) {\n await remove(absPath);\n logger.info(`Removed empty file: ${targetPath}`);\n return { deleted: true, updated: false };\n }\n\n // Write back updated content\n const serialized = serializeContent(data, format);\n await writeTextFile(absPath, serialized);\n logger.info(`Updated ${targetPath}: removed ${keysToRemove.length} keys`);\n return { deleted: false, updated: true };\n}\n\n/**\n * Remove a file mapping during uninstall\n * Handles both simple file removal and key-based removal from merged files\n * \n * @param targetDir - Target directory (workspace root or global home)\n * @param mapping - File mapping from workspace index\n * @param packageName - Package being uninstalled (for logging)\n * @returns Paths that were removed or updated\n */\nexport async function removeFileMapping(\n targetDir: string,\n mapping: string | WorkspaceIndexFileMapping,\n packageName: string\n): Promise<{ removed: string[]; updated: string[] }> {\n const removed: string[] = [];\n const updated: string[] = [];\n\n if (typeof mapping === 'string') {\n // Simple file mapping - delete entire file\n const absPath = join(targetDir, mapping);\n if (await exists(absPath)) {\n await remove(absPath);\n removed.push(mapping);\n logger.debug(`Removed file: ${mapping}`);\n }\n } else {\n // Complex mapping with potential key tracking\n const targetPath = mapping.target;\n\n if (mapping.merge === 'composite') {\n // Composite merge uses delimiters - handled by existing root file logic\n // This is already handled by applyRootFileRemovals\n logger.debug(`Skipping composite merge file (handled by root file logic): ${targetPath}`);\n } else if (mapping.keys && mapping.keys.length > 0) {\n // Remove specific keys from merged file\n const result = await removeKeysFromMergedFile(targetDir, targetPath, mapping.keys);\n \n if (result.deleted) {\n removed.push(targetPath);\n } else if (result.updated) {\n updated.push(targetPath);\n }\n\n logger.debug(\n `Removed ${mapping.keys.length} keys from ${targetPath}: ${mapping.keys.join(', ')}`\n );\n } else if (mapping.merge === 'deep' || mapping.merge === 'shallow') {\n // Merged file but no key tracking - this shouldn't happen with new installs\n logger.warn(\n `Cannot precisely remove ${targetPath} for ${packageName} - no key tracking available. ` +\n `File may contain content from other packages.`\n );\n // Don't delete - safer to leave it\n } else {\n // merge: 'replace' or no merge - delete entire file\n const absPath = join(targetDir, targetPath);\n if (await exists(absPath)) {\n await remove(absPath);\n removed.push(targetPath);\n logger.debug(`Removed file: ${targetPath}`);\n }\n }\n }\n\n return { removed, updated };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["path", "join", "yaml", "join", "path"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
readWorkspaceIndex
|
|
4
|
+
} from "./chunk-DEC24S7E.js";
|
|
5
|
+
import {
|
|
6
|
+
resolveDeclaredPath
|
|
7
|
+
} from "./chunk-FRYA3JAQ.js";
|
|
8
|
+
import {
|
|
9
|
+
getDetectedPlatforms,
|
|
10
|
+
getPlatformDefinition,
|
|
11
|
+
normalizePlatforms
|
|
12
|
+
} from "./chunk-N43IXOND.js";
|
|
13
|
+
import {
|
|
14
|
+
normalizePathForProcessing
|
|
15
|
+
} from "./chunk-YMKK4XPN.js";
|
|
16
|
+
import {
|
|
17
|
+
DIR_TO_TYPE
|
|
18
|
+
} from "./chunk-IHVZ5AUJ.js";
|
|
19
|
+
import {
|
|
20
|
+
logger
|
|
21
|
+
} from "./chunk-5EFWGD33.js";
|
|
22
|
+
|
|
23
|
+
// ../core/src/core/resources/source-key-classifier.ts
|
|
24
|
+
function classifySourceKey(sourceKey) {
|
|
25
|
+
let parts = sourceKey.replace(/\\/g, "/").replace(/\/$/, "").split("/");
|
|
26
|
+
if (parts.length === 1 && (sourceKey === "mcp.json" || sourceKey === "mcp.jsonc"))
|
|
27
|
+
return { resourceType: "mcp", resourceName: "configs" };
|
|
28
|
+
let firstDir = parts[0], singularType = DIR_TO_TYPE[firstDir];
|
|
29
|
+
if (!singularType)
|
|
30
|
+
return { resourceType: "other", resourceName: parts[parts.length - 1].replace(/\.[^.]+$/, "") || sourceKey };
|
|
31
|
+
if (singularType === "skill")
|
|
32
|
+
return { resourceType: "skill", resourceName: parts.length > 1 ? parts[1] : "unnamed" };
|
|
33
|
+
let fileName = parts[parts.length - 1], nameWithoutExt = fileName.replace(/\.[^.]+$/, "") || fileName;
|
|
34
|
+
return { resourceType: singularType, resourceName: nameWithoutExt };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ../core/src/core/list/untracked-files-scanner.ts
|
|
38
|
+
import { join } from "path";
|
|
39
|
+
import { homedir } from "os";
|
|
40
|
+
import fg from "fast-glob";
|
|
41
|
+
import { minimatch } from "minimatch";
|
|
42
|
+
async function scanUntrackedFiles(workspaceRoot, platformFilter) {
|
|
43
|
+
logger.debug("Starting untracked files scan", { workspaceRoot, platformFilter });
|
|
44
|
+
let platforms = await getDetectedPlatforms(workspaceRoot), normalizedFilter = normalizePlatforms(platformFilter);
|
|
45
|
+
if (normalizedFilter && normalizedFilter.length > 0 ? (platforms = platforms.filter((p) => normalizedFilter.includes(p.toLowerCase())), logger.debug(`Filtered to platforms: ${platforms.join(", ") || "none"}`)) : logger.debug(`Detected platforms: ${platforms.join(", ") || "none"}`), platforms.length === 0)
|
|
46
|
+
return logger.debug("No platforms detected in workspace"), createEmptyResult();
|
|
47
|
+
let patterns = extractPatternsFromPlatforms(platforms, workspaceRoot);
|
|
48
|
+
logger.debug(`Extracted ${patterns.length} patterns from ${platforms.length} platforms`);
|
|
49
|
+
let discoveredFiles = await discoverFilesFromPatterns(patterns, workspaceRoot);
|
|
50
|
+
logger.debug(`Discovered ${discoveredFiles.size} unique files from patterns`);
|
|
51
|
+
let trackedPaths = await loadTrackedFilePaths(workspaceRoot);
|
|
52
|
+
logger.debug(`Loaded ${trackedPaths.size} tracked files from index`);
|
|
53
|
+
let untrackedFiles = filterUntrackedFiles(discoveredFiles, trackedPaths);
|
|
54
|
+
return logger.debug(`Filtered to ${untrackedFiles.length} untracked files`), groupUntrackedFiles(untrackedFiles);
|
|
55
|
+
}
|
|
56
|
+
function extractPatternsFromPlatforms(platforms, workspaceRoot) {
|
|
57
|
+
let patterns = [];
|
|
58
|
+
for (let platform of platforms) {
|
|
59
|
+
let definition = getPlatformDefinition(platform, workspaceRoot);
|
|
60
|
+
for (let flow of definition.export) {
|
|
61
|
+
let patternStrings = extractToPatterns(flow, workspaceRoot);
|
|
62
|
+
for (let pattern of patternStrings) {
|
|
63
|
+
let category = extractCategoryFromFlow(flow);
|
|
64
|
+
patterns.push({
|
|
65
|
+
pattern,
|
|
66
|
+
platform,
|
|
67
|
+
flow,
|
|
68
|
+
category
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return patterns;
|
|
74
|
+
}
|
|
75
|
+
function extractCategoryFromFlow(flow) {
|
|
76
|
+
let fromField = flow.from, fromPattern;
|
|
77
|
+
if (typeof fromField == "string")
|
|
78
|
+
fromPattern = fromField;
|
|
79
|
+
else if (Array.isArray(fromField))
|
|
80
|
+
fromPattern = fromField[0] || "";
|
|
81
|
+
else if (typeof fromField == "object" && "$switch" in fromField) {
|
|
82
|
+
let switchExpr = fromField;
|
|
83
|
+
if (switchExpr.$switch.default)
|
|
84
|
+
if (typeof switchExpr.$switch.default == "string")
|
|
85
|
+
fromPattern = switchExpr.$switch.default;
|
|
86
|
+
else if (typeof switchExpr.$switch.default == "object" && "pattern" in switchExpr.$switch.default)
|
|
87
|
+
fromPattern = switchExpr.$switch.default.pattern;
|
|
88
|
+
else
|
|
89
|
+
return "other";
|
|
90
|
+
else if (switchExpr.$switch.cases && switchExpr.$switch.cases.length > 0) {
|
|
91
|
+
let firstCase = switchExpr.$switch.cases[0].value;
|
|
92
|
+
if (typeof firstCase == "string")
|
|
93
|
+
fromPattern = firstCase;
|
|
94
|
+
else if (typeof firstCase == "object" && "pattern" in firstCase)
|
|
95
|
+
fromPattern = firstCase.pattern;
|
|
96
|
+
else
|
|
97
|
+
return "other";
|
|
98
|
+
} else
|
|
99
|
+
return "other";
|
|
100
|
+
} else if (typeof fromField == "object" && "pattern" in fromField)
|
|
101
|
+
fromPattern = fromField.pattern;
|
|
102
|
+
else
|
|
103
|
+
return "other";
|
|
104
|
+
let firstPart = fromPattern.split("/")[0];
|
|
105
|
+
return firstPart.includes(".") ? firstPart === "mcp.jsonc" || firstPart === "mcp.json" ? "mcps" : firstPart === "AGENTS.md" || firstPart === "CLAUDE.md" || firstPart === "QWEN.md" || firstPart === "WARP.md" ? "agents" : firstPart.replace(/\.[^.]+$/, "").toLowerCase() || "other" : firstPart || "other";
|
|
106
|
+
}
|
|
107
|
+
function extractToPatterns(flow, workspaceRoot) {
|
|
108
|
+
let toField = flow.to;
|
|
109
|
+
if (typeof toField == "object" && "$switch" in toField) {
|
|
110
|
+
let switchExpr = toField, patterns = [], isGlobal = workspaceRoot.replace(/\/+$/, "") === homedir();
|
|
111
|
+
if (switchExpr.$switch.cases) {
|
|
112
|
+
for (let caseItem of switchExpr.$switch.cases)
|
|
113
|
+
if (caseItem.pattern === "~/" && isGlobal) {
|
|
114
|
+
if (typeof caseItem.value == "string")
|
|
115
|
+
return [caseItem.value];
|
|
116
|
+
if (typeof caseItem.value == "object" && "pattern" in caseItem.value)
|
|
117
|
+
return [caseItem.value.pattern];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (switchExpr.$switch.default) {
|
|
121
|
+
if (typeof switchExpr.$switch.default == "string")
|
|
122
|
+
return [switchExpr.$switch.default];
|
|
123
|
+
if (typeof switchExpr.$switch.default == "object" && "pattern" in switchExpr.$switch.default)
|
|
124
|
+
return [switchExpr.$switch.default.pattern];
|
|
125
|
+
}
|
|
126
|
+
if (switchExpr.$switch.cases)
|
|
127
|
+
for (let caseItem of switchExpr.$switch.cases)
|
|
128
|
+
typeof caseItem.value == "string" ? patterns.push(caseItem.value) : typeof caseItem.value == "object" && "pattern" in caseItem.value && patterns.push(caseItem.value.pattern);
|
|
129
|
+
return patterns;
|
|
130
|
+
}
|
|
131
|
+
return typeof toField == "object" && "pattern" in toField && typeof toField.pattern == "string" ? [toField.pattern] : typeof toField == "string" ? [toField] : Array.isArray(toField) ? toField.filter((p) => typeof p == "string") : [];
|
|
132
|
+
}
|
|
133
|
+
function extractStaticWalkRoot(pattern) {
|
|
134
|
+
let normalized = pattern.replace(/\\/g, "/");
|
|
135
|
+
if (!normalized.includes("/"))
|
|
136
|
+
return { root: null, rootOnly: !0 };
|
|
137
|
+
let segments = normalized.split("/"), hasGlobMeta = (seg) => /[*?\[\]{}()!+@]/.test(seg), staticSegments = [];
|
|
138
|
+
for (let seg of segments)
|
|
139
|
+
if (seg) {
|
|
140
|
+
if (hasGlobMeta(seg)) break;
|
|
141
|
+
staticSegments.push(seg);
|
|
142
|
+
}
|
|
143
|
+
return staticSegments.length === 0 ? { root: null, rootOnly: !1 } : { root: staticSegments.join("/"), rootOnly: !1 };
|
|
144
|
+
}
|
|
145
|
+
var IGNORED_DIRS = ["**/.openpackage/**", "**/node_modules/**", "**/.git/**"];
|
|
146
|
+
function isDangerousRoot(workspaceRoot) {
|
|
147
|
+
let normalized = workspaceRoot.replace(/\/+$/, "");
|
|
148
|
+
return normalized === homedir() || normalized === "/" || normalized === "";
|
|
149
|
+
}
|
|
150
|
+
async function discoverFilesFromPatterns(patterns, workspaceRoot) {
|
|
151
|
+
let filesMap = /* @__PURE__ */ new Map(), dangerous = isDangerousRoot(workspaceRoot), rootOnlyPatterns = [], unsafePatterns = [], rootedGroups = /* @__PURE__ */ new Map();
|
|
152
|
+
for (let patternInfo of patterns) {
|
|
153
|
+
let { root, rootOnly } = extractStaticWalkRoot(patternInfo.pattern);
|
|
154
|
+
rootOnly ? rootOnlyPatterns.push(patternInfo) : root === null ? unsafePatterns.push(patternInfo) : (rootedGroups.has(root) || rootedGroups.set(root, []), rootedGroups.get(root).push(patternInfo));
|
|
155
|
+
}
|
|
156
|
+
if (unsafePatterns.length > 0 && (dangerous ? logger.debug(
|
|
157
|
+
`Skipping ${unsafePatterns.length} unsafe patterns for dangerous root ${workspaceRoot}: ` + unsafePatterns.map((p) => p.pattern).join(", ")
|
|
158
|
+
) : rootedGroups.set("", unsafePatterns)), rootOnlyPatterns.length > 0)
|
|
159
|
+
try {
|
|
160
|
+
let rootLevelGlobs = rootOnlyPatterns.map((p) => p.pattern), matched = await fg(rootLevelGlobs, {
|
|
161
|
+
cwd: workspaceRoot,
|
|
162
|
+
dot: !0,
|
|
163
|
+
onlyFiles: !0,
|
|
164
|
+
deep: 1,
|
|
165
|
+
ignore: IGNORED_DIRS
|
|
166
|
+
});
|
|
167
|
+
for (let relativePath of matched)
|
|
168
|
+
addMatchToMap(filesMap, relativePath, rootOnlyPatterns, workspaceRoot);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
logger.debug("Error scanning root-only patterns", { error });
|
|
171
|
+
}
|
|
172
|
+
for (let [root, groupPatterns] of rootedGroups)
|
|
173
|
+
try {
|
|
174
|
+
let scopedGlobs = groupPatterns.map((p) => root && p.pattern.startsWith(root + "/") ? p.pattern.slice(root.length + 1) : p.pattern), matched = await fg(scopedGlobs, {
|
|
175
|
+
cwd: root ? join(workspaceRoot, root) : workspaceRoot,
|
|
176
|
+
dot: !0,
|
|
177
|
+
onlyFiles: !0,
|
|
178
|
+
ignore: IGNORED_DIRS
|
|
179
|
+
});
|
|
180
|
+
for (let matchedRelative of matched) {
|
|
181
|
+
let relativePath = root ? `${root}/${matchedRelative}` : matchedRelative;
|
|
182
|
+
addMatchToMap(filesMap, relativePath, groupPatterns, workspaceRoot);
|
|
183
|
+
}
|
|
184
|
+
} catch (error) {
|
|
185
|
+
logger.debug(`Error scanning rooted group "${root}"`, { error });
|
|
186
|
+
}
|
|
187
|
+
return filesMap;
|
|
188
|
+
}
|
|
189
|
+
function addMatchToMap(filesMap, relativePath, patterns, workspaceRoot) {
|
|
190
|
+
let absolutePath = join(workspaceRoot, relativePath), normalizedPath = normalizePathForProcessing(absolutePath);
|
|
191
|
+
if (filesMap.has(normalizedPath)) return;
|
|
192
|
+
let matchingPattern = patterns.find(
|
|
193
|
+
(p) => minimatch(relativePath, p.pattern, { dot: !0 })
|
|
194
|
+
) || patterns[0];
|
|
195
|
+
filesMap.set(normalizedPath, {
|
|
196
|
+
absolutePath: normalizedPath,
|
|
197
|
+
workspacePath: normalizePathForProcessing(relativePath),
|
|
198
|
+
platform: matchingPattern.platform,
|
|
199
|
+
flowPattern: matchingPattern.pattern,
|
|
200
|
+
category: matchingPattern.category
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
async function loadTrackedFilePaths(workspaceRoot) {
|
|
204
|
+
let trackedPaths = /* @__PURE__ */ new Set();
|
|
205
|
+
try {
|
|
206
|
+
let { index } = await readWorkspaceIndex(workspaceRoot);
|
|
207
|
+
for (let [packageName, packageData] of Object.entries(index.packages)) {
|
|
208
|
+
let filesMapping = packageData.files || {};
|
|
209
|
+
for (let [sourceKey, targets] of Object.entries(filesMapping))
|
|
210
|
+
if (Array.isArray(targets))
|
|
211
|
+
for (let target of targets) {
|
|
212
|
+
let targetPath = typeof target == "string" ? target : target.target, resolved = resolveDeclaredPath(targetPath, workspaceRoot), normalized = normalizePathForProcessing(resolved.absolute);
|
|
213
|
+
trackedPaths.add(normalized);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
} catch (error) {
|
|
217
|
+
logger.debug("Failed to load workspace index", { error });
|
|
218
|
+
}
|
|
219
|
+
return trackedPaths;
|
|
220
|
+
}
|
|
221
|
+
function filterUntrackedFiles(discoveredFiles, trackedPaths) {
|
|
222
|
+
let untracked = [];
|
|
223
|
+
for (let [absolutePath, fileInfo] of discoveredFiles) {
|
|
224
|
+
let normalized = normalizePathForProcessing(absolutePath);
|
|
225
|
+
trackedPaths.has(normalized) || untracked.push(fileInfo);
|
|
226
|
+
}
|
|
227
|
+
return untracked.sort((a, b) => a.workspacePath.localeCompare(b.workspacePath));
|
|
228
|
+
}
|
|
229
|
+
function groupUntrackedFiles(files) {
|
|
230
|
+
let platformGroups = /* @__PURE__ */ new Map(), categoryGroups = /* @__PURE__ */ new Map();
|
|
231
|
+
for (let file of files)
|
|
232
|
+
platformGroups.has(file.platform) || platformGroups.set(file.platform, []), platformGroups.get(file.platform).push(file), categoryGroups.has(file.category) || categoryGroups.set(file.category, []), categoryGroups.get(file.category).push(file);
|
|
233
|
+
return {
|
|
234
|
+
files,
|
|
235
|
+
platformGroups,
|
|
236
|
+
categoryGroups,
|
|
237
|
+
totalFiles: files.length
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function createEmptyResult() {
|
|
241
|
+
return {
|
|
242
|
+
files: [],
|
|
243
|
+
platformGroups: /* @__PURE__ */ new Map(),
|
|
244
|
+
categoryGroups: /* @__PURE__ */ new Map(),
|
|
245
|
+
totalFiles: 0
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export {
|
|
250
|
+
classifySourceKey,
|
|
251
|
+
scanUntrackedFiles
|
|
252
|
+
};
|
|
253
|
+
//# sourceMappingURL=chunk-VKNJG4JN.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../core/src/core/resources/source-key-classifier.ts", "../../core/src/core/list/untracked-files-scanner.ts"],
|
|
4
|
+
"sourcesContent": ["import { DIR_TO_TYPE, type ResourceTypeId } from './resource-registry.js';\n\nexport function classifySourceKey(sourceKey: string): { resourceType: ResourceTypeId; resourceName: string } {\n const normalized = sourceKey.replace(/\\\\/g, '/').replace(/\\/$/, '');\n const parts = normalized.split('/');\n\n if (parts.length === 1 && (sourceKey === 'mcp.json' || sourceKey === 'mcp.jsonc')) {\n return { resourceType: 'mcp', resourceName: 'configs' };\n }\n\n const firstDir = parts[0];\n const singularType = DIR_TO_TYPE[firstDir];\n\n if (!singularType) {\n const name = parts[parts.length - 1].replace(/\\.[^.]+$/, '') || sourceKey;\n return { resourceType: 'other', resourceName: name };\n }\n\n if (singularType === 'skill') {\n const skillName = parts.length > 1 ? parts[1] : 'unnamed';\n return { resourceType: 'skill', resourceName: skillName };\n }\n\n const fileName = parts[parts.length - 1];\n const nameWithoutExt = fileName.replace(/\\.[^.]+$/, '') || fileName;\n return { resourceType: singularType, resourceName: nameWithoutExt };\n}\n", "/**\n * Untracked Files Scanner\n * \n * Discovers files in workspace that match platform patterns but are not tracked\n * in the workspace index (.openpackage/openpackage.index.yml).\n * \n * Uses static-prefix extraction to determine minimal walk roots from patterns,\n * then delegates to fast-glob for efficient, bounded directory traversal.\n * This prevents unbounded walks when workspaceRoot is ~ (home directory).\n */\n\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport fg from 'fast-glob';\nimport { minimatch } from 'minimatch';\nimport type { Platform } from '../platforms.js';\nimport { getDetectedPlatforms, getPlatformDefinition } from '../platforms.js';\nimport { readWorkspaceIndex } from '../../utils/workspace-index-yml.js';\nimport { resolveDeclaredPath } from '../../utils/path-resolution.js';\nimport { normalizePathForProcessing } from '../../utils/path-normalization.js';\nimport { normalizePlatforms } from '../platform/platform-mapper.js';\nimport { logger } from '../../utils/logger.js';\nimport type { Flow, SwitchExpression } from '../../types/flows.js';\n\n/**\n * Represents a file discovered in the workspace but not tracked in the index\n */\nexport interface UntrackedFile {\n /** Absolute path to the file */\n absolutePath: string;\n /** Path relative to workspace root */\n workspacePath: string;\n /** Platform that detected this file */\n platform: Platform;\n /** Flow pattern that matched this file */\n flowPattern: string;\n /** Category derived from pattern (rules, commands, agents, etc.) */\n category: string;\n}\n\n/**\n * Result of scanning for untracked files\n */\nexport interface UntrackedScanResult {\n /** All untracked files discovered */\n files: UntrackedFile[];\n /** Files grouped by platform */\n platformGroups: Map<Platform, UntrackedFile[]>;\n /** Files grouped by category */\n categoryGroups: Map<string, UntrackedFile[]>;\n /** Total count of untracked files */\n totalFiles: number;\n}\n\n/**\n * Pattern info extracted from a flow\n */\ninterface PatternInfo {\n pattern: string;\n platform: Platform;\n flow: Flow;\n category: string;\n}\n\n/**\n * Scan workspace for files that match platform patterns but are not tracked in index\n * \n * @param workspaceRoot - Root directory of the workspace\n * @param platformFilter - Optional array of platform names to filter by\n * @returns Scan result with all untracked files\n */\nexport async function scanUntrackedFiles(\n workspaceRoot: string,\n platformFilter?: string[]\n): Promise<UntrackedScanResult> {\n logger.debug('Starting untracked files scan', { workspaceRoot, platformFilter });\n\n // Step 1: Detect platforms in workspace\n let platforms = await getDetectedPlatforms(workspaceRoot);\n \n // Apply platform filter if specified\n const normalizedFilter = normalizePlatforms(platformFilter);\n if (normalizedFilter && normalizedFilter.length > 0) {\n platforms = platforms.filter(p => normalizedFilter.includes(p.toLowerCase()));\n logger.debug(`Filtered to platforms: ${platforms.join(', ') || 'none'}`);\n } else {\n logger.debug(`Detected platforms: ${platforms.join(', ') || 'none'}`);\n }\n \n if (platforms.length === 0) {\n logger.debug('No platforms detected in workspace');\n return createEmptyResult();\n }\n\n // Step 2: Extract patterns from platform flows\n const patterns = extractPatternsFromPlatforms(platforms, workspaceRoot);\n logger.debug(`Extracted ${patterns.length} patterns from ${platforms.length} platforms`);\n\n // Step 3: Discover files matching patterns\n const discoveredFiles = await discoverFilesFromPatterns(patterns, workspaceRoot);\n logger.debug(`Discovered ${discoveredFiles.size} unique files from patterns`);\n\n // Step 4: Load tracked files from workspace index\n const trackedPaths = await loadTrackedFilePaths(workspaceRoot);\n logger.debug(`Loaded ${trackedPaths.size} tracked files from index`);\n\n // Step 5: Filter to untracked files only\n const untrackedFiles = filterUntrackedFiles(discoveredFiles, trackedPaths);\n logger.debug(`Filtered to ${untrackedFiles.length} untracked files`);\n\n // Step 6: Group results\n return groupUntrackedFiles(untrackedFiles);\n}\n\n/**\n * Extract patterns from all platform export flows\n * Export flows represent package \u2192 workspace direction (the 'to' field is workspace location)\n */\nfunction extractPatternsFromPlatforms(\n platforms: Platform[],\n workspaceRoot: string\n): PatternInfo[] {\n const patterns: PatternInfo[] = [];\n\n for (const platform of platforms) {\n const definition = getPlatformDefinition(platform, workspaceRoot);\n \n // Process export flows (these define workspace file locations)\n for (const flow of definition.export) {\n const patternStrings = extractToPatterns(flow, workspaceRoot);\n \n for (const pattern of patternStrings) {\n // Extract category from the 'from' field (universal format) instead of 'to'\n const category = extractCategoryFromFlow(flow);\n patterns.push({\n pattern,\n platform,\n flow,\n category\n });\n }\n }\n }\n\n return patterns;\n}\n\n/**\n * Extract category from flow's 'from' pattern (universal format)\n * The 'from' field represents the universal resource type which is consistent\n * across all platforms, unlike the 'to' field which is platform-specific.\n */\nfunction extractCategoryFromFlow(flow: Flow): string {\n const fromField = flow.from;\n \n // Handle string pattern\n let fromPattern: string;\n if (typeof fromField === 'string') {\n fromPattern = fromField;\n } else if (Array.isArray(fromField)) {\n // Use first pattern from array\n fromPattern = fromField[0] || '';\n } else if (typeof fromField === 'object' && '$switch' in fromField) {\n // For switch expressions, we can't determine the exact pattern without context\n // Fall back to extracting from all case patterns\n const switchExpr = fromField as SwitchExpression;\n \n // Try default first\n if (switchExpr.$switch.default) {\n if (typeof switchExpr.$switch.default === 'string') {\n fromPattern = switchExpr.$switch.default;\n } else if (typeof switchExpr.$switch.default === 'object' && 'pattern' in switchExpr.$switch.default) {\n fromPattern = switchExpr.$switch.default.pattern;\n } else {\n return 'other';\n }\n } else if (switchExpr.$switch.cases && switchExpr.$switch.cases.length > 0) {\n // Use first case as fallback\n const firstCase = switchExpr.$switch.cases[0].value;\n if (typeof firstCase === 'string') {\n fromPattern = firstCase;\n } else if (typeof firstCase === 'object' && 'pattern' in firstCase) {\n fromPattern = firstCase.pattern;\n } else {\n return 'other';\n }\n } else {\n return 'other';\n }\n } else if (typeof fromField === 'object' && 'pattern' in fromField) {\n // Handle object with pattern field (e.g., { pattern: \"agents/**/*.md\", schema: \"...\" })\n const patternObj = fromField as { pattern: string };\n fromPattern = patternObj.pattern;\n } else {\n return 'other';\n }\n \n // Extract first directory component from pattern\n // Examples:\n // \"skills/**/*\" \u2192 \"skills\"\n // \"rules/**/*.md\" \u2192 \"rules\"\n // \"commands/**/*.md\" \u2192 \"commands\"\n // \"mcp.jsonc\" \u2192 \"mcps\"\n // \"AGENTS.md\" \u2192 \"agents\"\n const parts = fromPattern.split('/');\n const firstPart = parts[0];\n \n // Handle file-based resources\n if (firstPart.includes('.')) {\n // Special cases for known files\n if (firstPart === 'mcp.jsonc' || firstPart === 'mcp.json') {\n return 'mcps';\n }\n if (firstPart === 'AGENTS.md') {\n return 'agents';\n }\n if (firstPart === 'CLAUDE.md' || firstPart === 'QWEN.md' || firstPart === 'WARP.md') {\n return 'agents';\n }\n // For other files, extract base name\n const baseName = firstPart.replace(/\\.[^.]+$/, '').toLowerCase();\n return baseName || 'other';\n }\n \n // For directory-based resources, return the directory name\n return firstPart || 'other';\n}\n\n/**\n * Extract 'to' patterns from a flow (handling switch expressions)\n * Resolves switch expressions based on workspaceRoot context\n */\nfunction extractToPatterns(flow: Flow, workspaceRoot: string): string[] {\n const toField = flow.to;\n\n // Handle switch expressions - resolve based on workspaceRoot\n if (typeof toField === 'object' && '$switch' in toField) {\n const switchExpr = toField as SwitchExpression;\n const patterns: string[] = [];\n \n // Check if we're in global mode\n const normalizedRoot = workspaceRoot.replace(/\\/+$/, '');\n const isGlobal = normalizedRoot === homedir();\n \n // Try to match a case first\n if (switchExpr.$switch.cases) {\n for (const caseItem of switchExpr.$switch.cases) {\n // Check if this case matches our context\n if (caseItem.pattern === '~/' && isGlobal) {\n // Extract the actual pattern value\n if (typeof caseItem.value === 'string') {\n return [caseItem.value];\n } else if (typeof caseItem.value === 'object' && 'pattern' in caseItem.value) {\n return [caseItem.value.pattern];\n }\n }\n }\n }\n \n // Fall back to default\n if (switchExpr.$switch.default) {\n if (typeof switchExpr.$switch.default === 'string') {\n return [switchExpr.$switch.default];\n } else if (typeof switchExpr.$switch.default === 'object' && 'pattern' in switchExpr.$switch.default) {\n return [switchExpr.$switch.default.pattern];\n }\n }\n \n // If no match, collect all possible patterns for safety\n if (switchExpr.$switch.cases) {\n for (const caseItem of switchExpr.$switch.cases) {\n if (typeof caseItem.value === 'string') {\n patterns.push(caseItem.value);\n } else if (typeof caseItem.value === 'object' && 'pattern' in caseItem.value) {\n patterns.push(caseItem.value.pattern);\n }\n }\n }\n \n return patterns;\n }\n\n // Handle object with pattern field\n if (typeof toField === 'object' && 'pattern' in toField && typeof toField.pattern === 'string') {\n return [toField.pattern];\n }\n\n // Handle string pattern\n if (typeof toField === 'string') {\n return [toField];\n }\n\n // Handle array patterns\n if (Array.isArray(toField)) {\n return toField.filter((p): p is string => typeof p === 'string');\n }\n\n return [];\n}\n\n/**\n * Extract category from pattern (e.g., \"rules\", \"commands\", \"agents\")\n */\nfunction extractCategoryFromPattern(pattern: string): string {\n // Remove leading dot and platform root dir (e.g., \".claude/rules/...\" -> \"rules\")\n const normalized = pattern.replace(/^\\.[^/]+\\//, '');\n \n // Extract first directory component\n const parts = normalized.split('/');\n if (parts.length > 1) {\n return parts[0];\n }\n \n // For root-level files, use \"config\" or filename without extension\n if (pattern.includes('.')) {\n const filename = pattern.split('/').pop() || pattern;\n const baseName = filename.replace(/^\\.[^.]*\\./, '').split('.')[0];\n return baseName || 'config';\n }\n \n return 'other';\n}\n\n/**\n * Extract the static (non-glob) prefix directory from a pattern.\n * Consumes path segments until a segment containing glob metacharacters is found.\n * \n * Examples:\n * \".claude/rules/*.md\" -> { root: \".claude/rules\", rootOnly: false }\n * \".cursor/rules/*.md\" -> { root: \".cursor/rules\", rootOnly: false }\n * \"AGENTS.md\" -> { root: null, rootOnly: true }\n * \"**\\/*.md\" -> { root: null, rootOnly: false } (unsafe)\n */\nexport function extractStaticWalkRoot(pattern: string): { root: string | null; rootOnly: boolean } {\n const normalized = pattern.replace(/\\\\/g, '/');\n\n if (!normalized.includes('/')) {\n return { root: null, rootOnly: true };\n }\n\n const segments = normalized.split('/');\n const hasGlobMeta = (seg: string) => /[*?\\[\\]{}()!+@]/.test(seg);\n const staticSegments: string[] = [];\n\n for (const seg of segments) {\n if (!seg) continue;\n if (hasGlobMeta(seg)) break;\n staticSegments.push(seg);\n }\n\n if (staticSegments.length === 0) {\n return { root: null, rootOnly: false };\n }\n\n return { root: staticSegments.join('/'), rootOnly: false };\n}\n\nconst IGNORED_DIRS = ['**/.openpackage/**', '**/node_modules/**', '**/.git/**'];\n\n/**\n * Check if workspaceRoot is a \"dangerous\" unbounded directory (home or filesystem root)\n */\nfunction isDangerousRoot(workspaceRoot: string): boolean {\n const normalized = workspaceRoot.replace(/\\/+$/, '');\n return normalized === homedir() || normalized === '/' || normalized === '';\n}\n\n/**\n * Discover files matching all patterns using fast-glob with static-prefix scoping.\n * \n * Strategy:\n * 1. Extract static walk roots from each pattern to avoid unbounded traversal\n * 2. Group patterns by walk root for efficient single-pass scanning\n * 3. Use fast-glob scoped to each walk root\n * 4. For root-only patterns (e.g. \"AGENTS.md\"), scan only immediate children\n * 5. Skip unsafe patterns (no static prefix) when workspaceRoot is ~ or /\n */\nasync function discoverFilesFromPatterns(\n patterns: PatternInfo[],\n workspaceRoot: string\n): Promise<Map<string, UntrackedFile>> {\n const filesMap = new Map<string, UntrackedFile>();\n const dangerous = isDangerousRoot(workspaceRoot);\n\n const rootOnlyPatterns: PatternInfo[] = [];\n const unsafePatterns: PatternInfo[] = [];\n const rootedGroups = new Map<string, PatternInfo[]>();\n\n for (const patternInfo of patterns) {\n const { root, rootOnly } = extractStaticWalkRoot(patternInfo.pattern);\n\n if (rootOnly) {\n rootOnlyPatterns.push(patternInfo);\n } else if (root === null) {\n unsafePatterns.push(patternInfo);\n } else {\n if (!rootedGroups.has(root)) {\n rootedGroups.set(root, []);\n }\n rootedGroups.get(root)!.push(patternInfo);\n }\n }\n\n if (unsafePatterns.length > 0) {\n if (dangerous) {\n logger.debug(\n `Skipping ${unsafePatterns.length} unsafe patterns for dangerous root ${workspaceRoot}: ` +\n unsafePatterns.map(p => p.pattern).join(', ')\n );\n } else {\n rootedGroups.set('', unsafePatterns);\n }\n }\n\n if (rootOnlyPatterns.length > 0) {\n try {\n const rootLevelGlobs = rootOnlyPatterns.map(p => p.pattern);\n const matched = await fg(rootLevelGlobs, {\n cwd: workspaceRoot,\n dot: true,\n onlyFiles: true,\n deep: 1,\n ignore: IGNORED_DIRS,\n });\n\n for (const relativePath of matched) {\n addMatchToMap(filesMap, relativePath, rootOnlyPatterns, workspaceRoot);\n }\n } catch (error) {\n logger.debug('Error scanning root-only patterns', { error });\n }\n }\n\n for (const [root, groupPatterns] of rootedGroups) {\n try {\n const scopedGlobs = groupPatterns.map(p => {\n if (root && p.pattern.startsWith(root + '/')) {\n return p.pattern.slice(root.length + 1);\n }\n return p.pattern;\n });\n\n const matched = await fg(scopedGlobs, {\n cwd: root ? join(workspaceRoot, root) : workspaceRoot,\n dot: true,\n onlyFiles: true,\n ignore: IGNORED_DIRS,\n });\n\n for (const matchedRelative of matched) {\n const relativePath = root ? `${root}/${matchedRelative}` : matchedRelative;\n addMatchToMap(filesMap, relativePath, groupPatterns, workspaceRoot);\n }\n } catch (error) {\n logger.debug(`Error scanning rooted group \"${root}\"`, { error });\n }\n }\n\n return filesMap;\n}\n\n/**\n * Add a matched file path to the results map, attributing it to the first matching pattern\n */\nfunction addMatchToMap(\n filesMap: Map<string, UntrackedFile>,\n relativePath: string,\n patterns: PatternInfo[],\n workspaceRoot: string\n): void {\n const absolutePath = join(workspaceRoot, relativePath);\n const normalizedPath = normalizePathForProcessing(absolutePath);\n\n if (filesMap.has(normalizedPath)) return;\n\n const matchingPattern = patterns.find(p =>\n minimatch(relativePath, p.pattern, { dot: true })\n ) || patterns[0];\n\n filesMap.set(normalizedPath, {\n absolutePath: normalizedPath,\n workspacePath: normalizePathForProcessing(relativePath),\n platform: matchingPattern.platform,\n flowPattern: matchingPattern.pattern,\n category: matchingPattern.category,\n });\n}\n\n/**\n * Load all tracked file paths from workspace index\n * Returns Set of normalized absolute paths\n */\nasync function loadTrackedFilePaths(workspaceRoot: string): Promise<Set<string>> {\n const trackedPaths = new Set<string>();\n\n try {\n const { index } = await readWorkspaceIndex(workspaceRoot);\n \n // Extract all target paths from all packages\n for (const [packageName, packageData] of Object.entries(index.packages)) {\n const filesMapping = packageData.files || {};\n \n for (const [sourceKey, targets] of Object.entries(filesMapping)) {\n if (!Array.isArray(targets)) continue;\n \n for (const target of targets) {\n // Handle both string and object mappings\n const targetPath = typeof target === 'string' ? target : target.target;\n \n // Resolve target path to absolute\n const resolved = resolveDeclaredPath(targetPath, workspaceRoot);\n const normalized = normalizePathForProcessing(resolved.absolute);\n trackedPaths.add(normalized);\n }\n }\n }\n } catch (error) {\n logger.debug('Failed to load workspace index', { error });\n }\n\n return trackedPaths;\n}\n\n/**\n * Filter discovered files to only untracked ones\n */\nfunction filterUntrackedFiles(\n discoveredFiles: Map<string, UntrackedFile>,\n trackedPaths: Set<string>\n): UntrackedFile[] {\n const untracked: UntrackedFile[] = [];\n\n for (const [absolutePath, fileInfo] of discoveredFiles) {\n const normalized = normalizePathForProcessing(absolutePath);\n \n if (!trackedPaths.has(normalized)) {\n untracked.push(fileInfo);\n }\n }\n\n // Sort by workspace path for consistent output\n return untracked.sort((a, b) => a.workspacePath.localeCompare(b.workspacePath));\n}\n\n/**\n * Group untracked files by platform and category\n */\nfunction groupUntrackedFiles(files: UntrackedFile[]): UntrackedScanResult {\n const platformGroups = new Map<Platform, UntrackedFile[]>();\n const categoryGroups = new Map<string, UntrackedFile[]>();\n\n for (const file of files) {\n // Group by platform\n if (!platformGroups.has(file.platform)) {\n platformGroups.set(file.platform, []);\n }\n platformGroups.get(file.platform)!.push(file);\n\n // Group by category\n if (!categoryGroups.has(file.category)) {\n categoryGroups.set(file.category, []);\n }\n categoryGroups.get(file.category)!.push(file);\n }\n\n return {\n files,\n platformGroups,\n categoryGroups,\n totalFiles: files.length\n };\n}\n\n/**\n * Create an empty result\n */\nfunction createEmptyResult(): UntrackedScanResult {\n return {\n files: [],\n platformGroups: new Map(),\n categoryGroups: new Map(),\n totalFiles: 0\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resolvePlatformKey
|
|
4
|
+
} from "./chunk-N43IXOND.js";
|
|
5
|
+
|
|
6
|
+
// ../core/src/core/markdown-frontmatter.ts
|
|
7
|
+
import * as yaml from "js-yaml";
|
|
8
|
+
var FRONTMATTER_BOUNDARY = "---";
|
|
9
|
+
function splitFrontmatter(content) {
|
|
10
|
+
if (!content.trim().startsWith(FRONTMATTER_BOUNDARY))
|
|
11
|
+
return { frontmatter: null, body: content };
|
|
12
|
+
let firstLineBreak = content.indexOf(`
|
|
13
|
+
`);
|
|
14
|
+
if (firstLineBreak === -1)
|
|
15
|
+
return { frontmatter: null, body: content };
|
|
16
|
+
let endMarkerIndex = content.indexOf(`
|
|
17
|
+
${FRONTMATTER_BOUNDARY}`, firstLineBreak + 1);
|
|
18
|
+
if (endMarkerIndex === -1)
|
|
19
|
+
return { frontmatter: null, body: content };
|
|
20
|
+
let rawFrontmatter = content.slice(firstLineBreak + 1, endMarkerIndex).trim(), parsed = null;
|
|
21
|
+
if (rawFrontmatter.length > 0)
|
|
22
|
+
try {
|
|
23
|
+
parsed = yaml.load(rawFrontmatter);
|
|
24
|
+
} catch {
|
|
25
|
+
parsed = null;
|
|
26
|
+
}
|
|
27
|
+
let bodyStart = endMarkerIndex + FRONTMATTER_BOUNDARY.length + 1, remaining = content.slice(bodyStart), body = remaining.startsWith(`
|
|
28
|
+
`) ? remaining.slice(1) : remaining;
|
|
29
|
+
return {
|
|
30
|
+
frontmatter: parsed,
|
|
31
|
+
body,
|
|
32
|
+
rawFrontmatter
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function dumpYaml(data) {
|
|
36
|
+
return yaml.dump(data, {
|
|
37
|
+
indent: 2,
|
|
38
|
+
flowLevel: -1,
|
|
39
|
+
// Use block style for all structures (better readability)
|
|
40
|
+
sortKeys: !1,
|
|
41
|
+
quotingType: '"',
|
|
42
|
+
lineWidth: -1
|
|
43
|
+
// Disable line wrapping to prevent folded scalar style (>-)
|
|
44
|
+
}).trim();
|
|
45
|
+
}
|
|
46
|
+
function normalizeYamlNode(node) {
|
|
47
|
+
if (node == null)
|
|
48
|
+
return null;
|
|
49
|
+
if (typeof node == "string")
|
|
50
|
+
return node.trim();
|
|
51
|
+
if (Array.isArray(node))
|
|
52
|
+
return node.map(normalizeYamlNode);
|
|
53
|
+
if (typeof node == "object") {
|
|
54
|
+
let entries = Object.entries(node).map(([key, value]) => [key.trim(), normalizeYamlNode(value)]).sort((a, b) => a[0].localeCompare(b[0])), normalized = {};
|
|
55
|
+
for (let [key, value] of entries)
|
|
56
|
+
normalized[key] = value;
|
|
57
|
+
return normalized;
|
|
58
|
+
}
|
|
59
|
+
return node;
|
|
60
|
+
}
|
|
61
|
+
function deepEqualYaml(a, b) {
|
|
62
|
+
return JSON.stringify(normalizeYamlNode(a)) === JSON.stringify(normalizeYamlNode(b));
|
|
63
|
+
}
|
|
64
|
+
function deepMerge(base, override) {
|
|
65
|
+
if (Array.isArray(base) && Array.isArray(override))
|
|
66
|
+
return override.slice();
|
|
67
|
+
if (isPlainObject(base) && isPlainObject(override)) {
|
|
68
|
+
let result = { ...base };
|
|
69
|
+
for (let [key, value] of Object.entries(override))
|
|
70
|
+
key in result ? result[key] = deepMerge(result[key], value) : result[key] = value;
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
return override !== void 0 ? override : base;
|
|
74
|
+
}
|
|
75
|
+
function isPlainObject(value) {
|
|
76
|
+
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
77
|
+
}
|
|
78
|
+
function cloneYaml(value) {
|
|
79
|
+
return value === void 0 ? value : JSON.parse(JSON.stringify(value));
|
|
80
|
+
}
|
|
81
|
+
function composeMarkdown(frontmatter, body) {
|
|
82
|
+
let normalizedBody = frontmatter ? body : body.replace(/^\n+/, "");
|
|
83
|
+
if (!frontmatter || Object.keys(frontmatter).length === 0)
|
|
84
|
+
return normalizedBody;
|
|
85
|
+
let yamlContent = dumpYaml(frontmatter), needsLeadingNewline = normalizedBody.startsWith(`
|
|
86
|
+
`) ? "" : `
|
|
87
|
+
`;
|
|
88
|
+
return `---
|
|
89
|
+
${yamlContent}
|
|
90
|
+
---${needsLeadingNewline}${normalizedBody}`;
|
|
91
|
+
}
|
|
92
|
+
function extractInlinePlatformOverrides(frontmatter, cwd) {
|
|
93
|
+
let overridesByPlatform = /* @__PURE__ */ new Map();
|
|
94
|
+
if (!isPlainObject(frontmatter))
|
|
95
|
+
return { common: {}, overridesByPlatform };
|
|
96
|
+
let { openpackage, ...rest } = frontmatter, common = cloneYaml(rest);
|
|
97
|
+
if (isPlainObject(openpackage))
|
|
98
|
+
for (let [key, value] of Object.entries(openpackage)) {
|
|
99
|
+
let platform = resolvePlatformKey(key, cwd);
|
|
100
|
+
platform && isPlainObject(value) && overridesByPlatform.set(platform, cloneYaml(value));
|
|
101
|
+
}
|
|
102
|
+
return { common, overridesByPlatform };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export {
|
|
106
|
+
splitFrontmatter,
|
|
107
|
+
dumpYaml,
|
|
108
|
+
deepEqualYaml,
|
|
109
|
+
deepMerge,
|
|
110
|
+
composeMarkdown,
|
|
111
|
+
extractInlinePlatformOverrides
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=chunk-VQ2KY6CK.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../core/src/core/markdown-frontmatter.ts"],
|
|
4
|
+
"sourcesContent": ["import * as yaml from 'js-yaml';\nimport type { Platform } from '../types/platform.js';\nimport { resolvePlatformKey } from './platforms.js';\n\nexport interface FrontmatterSplitResult<T = any> {\n frontmatter: T | null;\n body: string;\n rawFrontmatter?: string;\n}\n\nconst FRONTMATTER_BOUNDARY = '---';\n\n/**\n * Split markdown content into parsed frontmatter (if present) and body.\n */\nexport function splitFrontmatter<T = any>(content: string): FrontmatterSplitResult<T> {\n if (!content.trim().startsWith(FRONTMATTER_BOUNDARY)) {\n return { frontmatter: null, body: content };\n }\n\n const firstLineBreak = content.indexOf('\\n');\n if (firstLineBreak === -1) {\n return { frontmatter: null, body: content };\n }\n\n const endMarkerIndex = content.indexOf(`\\n${FRONTMATTER_BOUNDARY}`, firstLineBreak + 1);\n if (endMarkerIndex === -1) {\n return { frontmatter: null, body: content };\n }\n\n const rawFrontmatter = content\n .slice(firstLineBreak + 1, endMarkerIndex)\n .trim();\n\n let parsed: T | null = null;\n if (rawFrontmatter.length > 0) {\n try {\n parsed = yaml.load(rawFrontmatter) as T;\n } catch {\n // Leave parsed as null if the YAML cannot be parsed\n parsed = null;\n }\n }\n\n const bodyStart = endMarkerIndex + FRONTMATTER_BOUNDARY.length + 1; // +1 for newline\n const remaining = content.slice(bodyStart);\n const body = remaining.startsWith('\\n') ? remaining.slice(1) : remaining;\n\n return {\n frontmatter: parsed,\n body,\n rawFrontmatter\n };\n}\n\n/**\n * Remove frontmatter from markdown content (if any) and return the body.\n */\nexport function stripFrontmatter(content: string): string {\n return splitFrontmatter(content).body;\n}\n\n/**\n * Serialize YAML data with consistent formatting.\n * Arrays are rendered in compact flow style: [item1, item2, item3]\n */\nexport function dumpYaml(data: any): string {\n return yaml\n .dump(data, {\n indent: 2,\n flowLevel: -1, // Use block style for all structures (better readability)\n sortKeys: false,\n quotingType: '\"',\n lineWidth: -1 // Disable line wrapping to prevent folded scalar style (>-)\n })\n .trim();\n}\n\n/**\n * Normalize YAML node for comparisons (trim strings, sort object keys).\n */\nfunction normalizeYamlNode(node: any): any {\n if (node === null || node === undefined) {\n return null;\n }\n\n if (typeof node === 'string') {\n return node.trim();\n }\n\n if (Array.isArray(node)) {\n return node.map(normalizeYamlNode);\n }\n\n if (typeof node === 'object') {\n const entries = Object.entries(node as Record<string, any>)\n .map(([key, value]) => [key.trim(), normalizeYamlNode(value)] as const)\n .sort((a, b) => a[0].localeCompare(b[0]));\n\n const normalized: Record<string, any> = {};\n for (const [key, value] of entries) {\n normalized[key] = value;\n }\n return normalized;\n }\n\n return node;\n}\n\n/**\n * Deep equality for YAML data structures (ignores key order, trims strings).\n */\nexport function deepEqualYaml(a: any, b: any): boolean {\n return JSON.stringify(normalizeYamlNode(a)) === JSON.stringify(normalizeYamlNode(b));\n}\n\n/**\n * Deep merge two YAML-compatible data structures.\n * Arrays are replaced entirely, objects are merged recursively.\n */\nexport function deepMerge(base: any, override: any): any {\n if (Array.isArray(base) && Array.isArray(override)) {\n return override.slice();\n }\n\n if (isPlainObject(base) && isPlainObject(override)) {\n const result: Record<string, any> = { ...base };\n for (const [key, value] of Object.entries(override)) {\n if (key in result) {\n result[key] = deepMerge(result[key], value);\n } else {\n result[key] = value;\n }\n }\n return result;\n }\n\n if (override !== undefined) {\n return override;\n }\n\n return base;\n}\n\nexport function isPlainObject(value: any): value is Record<string, any> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Clone a YAML-compatible data structure deeply.\n */\nexport function cloneYaml<T>(value: T): T {\n if (value === undefined) {\n return value;\n }\n return JSON.parse(JSON.stringify(value));\n}\n\n/**\n * Compose markdown content with optional frontmatter.\n * If frontmatter is provided, wraps it in YAML frontmatter delimiters.\n */\nexport function composeMarkdown(\n frontmatter: Record<string, any> | undefined,\n body: string\n): string {\n const normalizedBody = frontmatter ? body : body.replace(/^\\n+/, '');\n\n if (!frontmatter || Object.keys(frontmatter).length === 0) {\n return normalizedBody;\n }\n\n const yamlContent = dumpYaml(frontmatter);\n const needsLeadingNewline = normalizedBody.startsWith('\\n') ? '' : '\\n';\n return `---\\n${yamlContent}\\n---${needsLeadingNewline}${normalizedBody}`;\n}\n\n/**\n * Normalize frontmatter value to a plain object.\n * Returns empty object if value is not a plain object.\n */\nexport function normalizeFrontmatter(value: any): Record<string, any> {\n if (isPlainObject(value)) {\n return cloneYaml(value);\n }\n return {};\n}\n\n/**\n * Remove keys present in `keys` from `target`, returning a new structure.\n * Keys are removed only when the value matches (deep equality with trimming).\n * Returns undefined when all keys are removed.\n */\nexport function subtractKeys(target: any, keys: any): any {\n if (!isPlainObject(target)) {\n if (deepEqualYaml(target, keys)) {\n return undefined;\n }\n return target;\n }\n\n const result: Record<string, any> = {};\n let removed = false;\n\n for (const [key, value] of Object.entries(target)) {\n if (keys && Object.prototype.hasOwnProperty.call(keys, key)) {\n const keyToRemove = keys[key];\n\n if (isPlainObject(value) && isPlainObject(keyToRemove)) {\n const nested = subtractKeys(value, keyToRemove);\n if (nested !== undefined) {\n result[key] = nested;\n } else {\n removed = true;\n }\n continue;\n }\n\n if (Array.isArray(value) && Array.isArray(keyToRemove)) {\n if (!deepEqualYaml(value, keyToRemove)) {\n result[key] = value;\n } else {\n removed = true;\n }\n continue;\n }\n\n if (deepEqualYaml(value, keyToRemove)) {\n removed = true;\n continue;\n }\n }\n\n result[key] = value;\n }\n\n if (!removed && Object.keys(result).length === Object.keys(target).length) {\n return target;\n }\n\n if (Object.keys(result).length === 0) {\n return undefined;\n }\n\n return result;\n}\n\nexport function extractInlinePlatformOverrides(\n frontmatter: Record<string, any> | null | undefined,\n cwd?: string\n): {\n common: Record<string, any>;\n overridesByPlatform: Map<Platform, Record<string, any>>;\n} {\n const overridesByPlatform = new Map<Platform, Record<string, any>>();\n if (!isPlainObject(frontmatter)) {\n return { common: {}, overridesByPlatform };\n }\n\n // Collect shared/common keys (everything except the reserved openpackage block)\n const { openpackage, ...rest } = frontmatter;\n // Use cloneYaml(rest) to ensure deep copy, simpler than iterating.\n const common: Record<string, any> = cloneYaml(rest);\n\n // Collect platform overrides from the reserved openpackage block\n if (isPlainObject(openpackage)) {\n for (const [key, value] of Object.entries(openpackage)) {\n const platform = resolvePlatformKey(key, cwd);\n if (platform && isPlainObject(value)) {\n overridesByPlatform.set(platform, cloneYaml(value));\n }\n }\n }\n\n return { common, overridesByPlatform };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|