@skaile/workspaces 5.7.0 → 5.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +114 -0
- package/dist/app-sdk/index.js +1 -1
- package/dist/{asset-feeds-K36CR52Q.js → asset-feeds-EYRZR4K5.js} +54 -30
- package/dist/asset-feeds-EYRZR4K5.js.map +1 -0
- package/dist/asset-manager/catalog-deployer.js +9 -9
- package/dist/asset-manager/index.js +15 -15
- package/dist/asset-manager/installer.js +11 -11
- package/dist/asset-manager/renderers.js +10 -10
- package/dist/asset-manager/src/index.d.ts +268 -24
- package/dist/asset-manager/src/index.d.ts.map +1 -1
- package/dist/asset-manager/src/install-agent.d.ts +11 -0
- package/dist/asset-manager/src/install-agent.d.ts.map +1 -1
- package/dist/asset-manager/src/installer.d.ts +2 -2
- package/dist/asset-manager/src/installer.d.ts.map +1 -1
- package/dist/bridge/drivers/claude-sdk.js +147 -211
- package/dist/bridge/drivers/claude-sdk.js.map +1 -1
- package/dist/bridge/drivers/codex.js +90 -66
- package/dist/bridge/drivers/codex.js.map +1 -1
- package/dist/bridge/drivers/continue.js +14 -15
- package/dist/bridge/drivers/continue.js.map +1 -1
- package/dist/bridge/drivers/echo.js +4 -4
- package/dist/bridge/drivers/gemini.js +8 -8
- package/dist/bridge/drivers/goose.js +14 -15
- package/dist/bridge/drivers/goose.js.map +1 -1
- package/dist/bridge/drivers/omp.js +68 -104
- package/dist/bridge/drivers/omp.js.map +1 -1
- package/dist/bridge/drivers/opencode.js +14 -15
- package/dist/bridge/drivers/opencode.js.map +1 -1
- package/dist/bridge/drivers/qwen.js +8 -8
- package/dist/bridge/index.js +16 -17
- package/dist/bridge/src/codex/managed-driver.d.ts +13 -10
- package/dist/bridge/src/codex/managed-driver.d.ts.map +1 -1
- package/dist/bridge/src/drivers/_subprocess-cli.d.ts +12 -2
- package/dist/bridge/src/drivers/_subprocess-cli.d.ts.map +1 -1
- package/dist/bridge/src/drivers/claude-sdk.d.ts +37 -62
- package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
- package/dist/bridge/src/drivers/codex.d.ts +26 -10
- package/dist/bridge/src/drivers/codex.d.ts.map +1 -1
- package/dist/bridge/src/drivers/continue.d.ts +2 -2
- package/dist/bridge/src/drivers/continue.d.ts.map +1 -1
- package/dist/bridge/src/drivers/gemini.d.ts +2 -2
- package/dist/bridge/src/drivers/gemini.d.ts.map +1 -1
- package/dist/bridge/src/drivers/goose.d.ts +2 -2
- package/dist/bridge/src/drivers/goose.d.ts.map +1 -1
- package/dist/bridge/src/drivers/omp.d.ts +24 -35
- package/dist/bridge/src/drivers/omp.d.ts.map +1 -1
- package/dist/bridge/src/drivers/opencode.d.ts +2 -2
- package/dist/bridge/src/drivers/opencode.d.ts.map +1 -1
- package/dist/bridge/src/drivers/recovery-policy.d.ts +79 -0
- package/dist/bridge/src/drivers/recovery-policy.d.ts.map +1 -0
- package/dist/bridge/src/index.d.ts +1 -0
- package/dist/bridge/src/index.d.ts.map +1 -1
- package/dist/bridge/src/reconfigure-ledger.d.ts +117 -0
- package/dist/bridge/src/reconfigure-ledger.d.ts.map +1 -0
- package/dist/bridge/src/types.d.ts +57 -6
- package/dist/bridge/src/types.d.ts.map +1 -1
- package/dist/{chunk-WIEC3ZE4.js → chunk-2FRUUDZY.js} +5 -5
- package/dist/{chunk-WIEC3ZE4.js.map → chunk-2FRUUDZY.js.map} +1 -1
- package/dist/{chunk-O4Z7MAW7.js → chunk-2LWYNQK7.js} +3 -3
- package/dist/{chunk-O4Z7MAW7.js.map → chunk-2LWYNQK7.js.map} +1 -1
- package/dist/{chunk-OOLT6HGP.js → chunk-36AFURKZ.js} +7 -7
- package/dist/{chunk-OOLT6HGP.js.map → chunk-36AFURKZ.js.map} +1 -1
- package/dist/{chunk-DFFD4BFG.js → chunk-4MQS7CAF.js} +174 -86
- package/dist/chunk-4MQS7CAF.js.map +1 -0
- package/dist/{chunk-RNPHRRLG.js → chunk-4PTSR4UU.js} +3 -3
- package/dist/{chunk-RNPHRRLG.js.map → chunk-4PTSR4UU.js.map} +1 -1
- package/dist/{chunk-34C42MJX.js → chunk-6GRX5L6A.js} +5 -5
- package/dist/{chunk-34C42MJX.js.map → chunk-6GRX5L6A.js.map} +1 -1
- package/dist/{chunk-NFGRW3L7.js → chunk-7RGTAEG6.js} +3 -3
- package/dist/{chunk-NFGRW3L7.js.map → chunk-7RGTAEG6.js.map} +1 -1
- package/dist/{chunk-BTK7ECLH.js → chunk-AWQYXZVG.js} +15 -6
- package/dist/chunk-AWQYXZVG.js.map +1 -0
- package/dist/{chunk-XBSQ4KMC.js → chunk-B4X2N7JQ.js} +205 -3
- package/dist/chunk-B4X2N7JQ.js.map +1 -0
- package/dist/{chunk-FRHE7FFB.js → chunk-B6GIW55K.js} +5 -3
- package/dist/chunk-B6GIW55K.js.map +1 -0
- package/dist/{chunk-JLSCA5T5.js → chunk-BJNUNQAW.js} +3 -3
- package/dist/{chunk-JLSCA5T5.js.map → chunk-BJNUNQAW.js.map} +1 -1
- package/dist/{chunk-RVIZQ5XD.js → chunk-BTE2V4IW.js} +3 -3
- package/dist/{chunk-RVIZQ5XD.js.map → chunk-BTE2V4IW.js.map} +1 -1
- package/dist/{chunk-EB4XN3KE.js → chunk-CGT45WN7.js} +3 -3
- package/dist/{chunk-EB4XN3KE.js.map → chunk-CGT45WN7.js.map} +1 -1
- package/dist/{chunk-47ZD34KB.js → chunk-CIFS5K6T.js} +3 -3
- package/dist/{chunk-47ZD34KB.js.map → chunk-CIFS5K6T.js.map} +1 -1
- package/dist/{chunk-FAP63KV7.js → chunk-CKQEIY43.js} +4 -4
- package/dist/{chunk-FAP63KV7.js.map → chunk-CKQEIY43.js.map} +1 -1
- package/dist/{chunk-AVCUPPG6.js → chunk-EF7NPDDU.js} +4 -4
- package/dist/{chunk-AVCUPPG6.js.map → chunk-EF7NPDDU.js.map} +1 -1
- package/dist/chunk-EPBKISS5.js +84 -0
- package/dist/chunk-EPBKISS5.js.map +1 -0
- package/dist/{chunk-THEJJBOU.js → chunk-F2EKONM7.js} +3 -3
- package/dist/{chunk-THEJJBOU.js.map → chunk-F2EKONM7.js.map} +1 -1
- package/dist/{chunk-DMLDYFDS.js → chunk-F3RDEH5U.js} +7 -4
- package/dist/chunk-F3RDEH5U.js.map +1 -0
- package/dist/{chunk-SZWRPEF7.js → chunk-FTJJO3EM.js} +39 -29
- package/dist/chunk-FTJJO3EM.js.map +1 -0
- package/dist/{chunk-PSA6ONFB.js → chunk-FVJK4QWM.js} +4 -4
- package/dist/{chunk-PSA6ONFB.js.map → chunk-FVJK4QWM.js.map} +1 -1
- package/dist/{chunk-LBQ4BBX4.js → chunk-FZNG4V4J.js} +16 -30
- package/dist/chunk-FZNG4V4J.js.map +1 -0
- package/dist/{chunk-SWO25LTO.js → chunk-GB7WDMH2.js} +4 -4
- package/dist/{chunk-SWO25LTO.js.map → chunk-GB7WDMH2.js.map} +1 -1
- package/dist/{chunk-NARITJS2.js → chunk-GCICGXDD.js} +3 -3
- package/dist/{chunk-NARITJS2.js.map → chunk-GCICGXDD.js.map} +1 -1
- package/dist/{chunk-TTPSDC2G.js → chunk-GTILM2CI.js} +34 -13
- package/dist/chunk-GTILM2CI.js.map +1 -0
- package/dist/{chunk-EU3Q5AQ4.js → chunk-GXXFLBUQ.js} +23 -32
- package/dist/chunk-GXXFLBUQ.js.map +1 -0
- package/dist/{chunk-D5HOETOB.js → chunk-H7QUDDKH.js} +981 -126
- package/dist/chunk-H7QUDDKH.js.map +1 -0
- package/dist/{chunk-GIC3G5YG.js → chunk-HG34RNTK.js} +7 -13
- package/dist/chunk-HG34RNTK.js.map +1 -0
- package/dist/{chunk-LXY4BUA3.js → chunk-HYDRDNKN.js} +9 -5
- package/dist/chunk-HYDRDNKN.js.map +1 -0
- package/dist/{chunk-N6FBTXQ5.js → chunk-I6NLLJHZ.js} +2 -2
- package/dist/{chunk-N6FBTXQ5.js.map → chunk-I6NLLJHZ.js.map} +1 -1
- package/dist/{chunk-NWQB7UTY.js → chunk-IONAUNWB.js} +3 -3
- package/dist/{chunk-NWQB7UTY.js.map → chunk-IONAUNWB.js.map} +1 -1
- package/dist/{chunk-CT6NQSA4.js → chunk-ISHJITXJ.js} +3 -3
- package/dist/{chunk-CT6NQSA4.js.map → chunk-ISHJITXJ.js.map} +1 -1
- package/dist/chunk-IZCR27MU.js +60 -0
- package/dist/chunk-IZCR27MU.js.map +1 -0
- package/dist/{chunk-LCU5U5IW.js → chunk-JAKOMFC6.js} +67 -19
- package/dist/chunk-JAKOMFC6.js.map +1 -0
- package/dist/{chunk-VOOI7B2L.js → chunk-LEMHVDET.js} +86 -66
- package/dist/chunk-LEMHVDET.js.map +1 -0
- package/dist/{chunk-37FTLYFP.js → chunk-LNFKL23K.js} +3 -3
- package/dist/{chunk-37FTLYFP.js.map → chunk-LNFKL23K.js.map} +1 -1
- package/dist/{chunk-6UFFKMVC.js → chunk-LSXHED6I.js} +6 -6
- package/dist/{chunk-6UFFKMVC.js.map → chunk-LSXHED6I.js.map} +1 -1
- package/dist/{chunk-XUUYAS3Z.js → chunk-M3WPBTGJ.js} +3 -3
- package/dist/{chunk-XUUYAS3Z.js.map → chunk-M3WPBTGJ.js.map} +1 -1
- package/dist/{chunk-QZLWJETK.js → chunk-MGGFBZWA.js} +3 -3
- package/dist/{chunk-QZLWJETK.js.map → chunk-MGGFBZWA.js.map} +1 -1
- package/dist/{chunk-53MSCGR2.js → chunk-NPLPCRW5.js} +5 -5
- package/dist/{chunk-53MSCGR2.js.map → chunk-NPLPCRW5.js.map} +1 -1
- package/dist/{chunk-QCI6D7E4.js → chunk-NUELZWCF.js} +266 -170
- package/dist/chunk-NUELZWCF.js.map +1 -0
- package/dist/{chunk-BWZF2ZIF.js → chunk-OFBIWVCR.js} +3 -3
- package/dist/{chunk-BWZF2ZIF.js.map → chunk-OFBIWVCR.js.map} +1 -1
- package/dist/{chunk-IZLQ4GDO.js → chunk-P23M65LB.js} +43 -21
- package/dist/chunk-P23M65LB.js.map +1 -0
- package/dist/{chunk-G67BOI2J.js → chunk-PMECEZK3.js} +15 -9
- package/dist/chunk-PMECEZK3.js.map +1 -0
- package/dist/{chunk-GWXFSLBK.js → chunk-PTSGWKHR.js} +4 -4
- package/dist/{chunk-GWXFSLBK.js.map → chunk-PTSGWKHR.js.map} +1 -1
- package/dist/{chunk-OKGUDNDT.js → chunk-Q6E6FM7P.js} +35 -33
- package/dist/chunk-Q6E6FM7P.js.map +1 -0
- package/dist/{chunk-CWM3MYGX.js → chunk-QOP6KDFR.js} +8 -9
- package/dist/chunk-QOP6KDFR.js.map +1 -0
- package/dist/{chunk-O7VPNKYN.js → chunk-QVNRCDTV.js} +23 -7
- package/dist/chunk-QVNRCDTV.js.map +1 -0
- package/dist/{chunk-UX3K4RKE.js → chunk-S53LOR7B.js} +3 -3
- package/dist/{chunk-UX3K4RKE.js.map → chunk-S53LOR7B.js.map} +1 -1
- package/dist/{chunk-KNWCFEWU.js → chunk-SH5D7U7N.js} +20 -7
- package/dist/{chunk-KNWCFEWU.js.map → chunk-SH5D7U7N.js.map} +1 -1
- package/dist/{chunk-KM7XWC4Y.js → chunk-UAROCOXF.js} +3 -3
- package/dist/{chunk-KM7XWC4Y.js.map → chunk-UAROCOXF.js.map} +1 -1
- package/dist/{chunk-JMKB7IB4.js → chunk-UMVKJM4Q.js} +4 -4
- package/dist/chunk-UMVKJM4Q.js.map +1 -0
- package/dist/{chunk-HCYS7GFP.js → chunk-V2DXZYBB.js} +3 -3
- package/dist/{chunk-HCYS7GFP.js.map → chunk-V2DXZYBB.js.map} +1 -1
- package/dist/{chunk-IUUYRXT6.js → chunk-W5DWWE4Y.js} +4 -4
- package/dist/{chunk-IUUYRXT6.js.map → chunk-W5DWWE4Y.js.map} +1 -1
- package/dist/{chunk-FK6HPLQA.js → chunk-WTQ3TATB.js} +3 -3
- package/dist/{chunk-FK6HPLQA.js.map → chunk-WTQ3TATB.js.map} +1 -1
- package/dist/{chunk-7FJQT3GT.js → chunk-Y4N2NUZD.js} +4 -4
- package/dist/{chunk-7FJQT3GT.js.map → chunk-Y4N2NUZD.js.map} +1 -1
- package/dist/{chunk-6VRJH4MR.js → chunk-Y7QA2OLD.js} +6 -6
- package/dist/{chunk-6VRJH4MR.js.map → chunk-Y7QA2OLD.js.map} +1 -1
- package/dist/{chunk-74EEFB52.js → chunk-YSHVQGUS.js} +115 -27
- package/dist/chunk-YSHVQGUS.js.map +1 -0
- package/dist/{chunk-6C654TFI.js → chunk-ZAOGFXDO.js} +36 -8
- package/dist/chunk-ZAOGFXDO.js.map +1 -0
- package/dist/{chunk-MKLBK7HI.js → chunk-ZKSJMZKD.js} +17 -13
- package/dist/chunk-ZKSJMZKD.js.map +1 -0
- package/dist/cli/index.js +373 -188
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/asset-feeds.d.ts +5 -2
- package/dist/cli/src/asset-feeds.d.ts.map +1 -1
- package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/catalog.d.ts +15 -2
- package/dist/cli/src/commands/catalog.d.ts.map +1 -1
- package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/library-index.d.ts +8 -0
- package/dist/cli/src/commands/library-index.d.ts.map +1 -1
- package/dist/cli/src/commands/library-publish.d.ts.map +1 -1
- package/dist/cli/src/commands/manage.d.ts.map +1 -1
- package/dist/cli/src/commands/outdated.d.ts +7 -2
- package/dist/cli/src/commands/outdated.d.ts.map +1 -1
- package/dist/cli/src/commands/project.d.ts +2 -0
- package/dist/cli/src/commands/project.d.ts.map +1 -1
- package/dist/cli/src/commands/publish-core.d.ts +10 -1
- package/dist/cli/src/commands/publish-core.d.ts.map +1 -1
- package/dist/cli/src/commands/session.d.ts.map +1 -1
- package/dist/cli/src/commands/source.d.ts +14 -0
- package/dist/cli/src/commands/source.d.ts.map +1 -1
- package/dist/cli/src/commands/tree.d.ts.map +1 -1
- package/dist/cli/src/commands/update.d.ts.map +1 -1
- package/dist/cli/src/commands/validate.d.ts.map +1 -1
- package/dist/cli/src/flow-discovery.d.ts +8 -5
- package/dist/cli/src/flow-discovery.d.ts.map +1 -1
- package/dist/cli/src/open-library.d.ts +0 -11
- package/dist/cli/src/open-library.d.ts.map +1 -1
- package/dist/cli/src/skill-checks.d.ts +11 -2
- package/dist/cli/src/skill-checks.d.ts.map +1 -1
- package/dist/connectors/config.js +5 -5
- package/dist/connectors/index.js +25 -26
- package/dist/connectors/src/access-policy.d.ts +33 -0
- package/dist/connectors/src/access-policy.d.ts.map +1 -0
- package/dist/connectors/src/connector-manager.d.ts.map +1 -1
- package/dist/connectors/src/index.d.ts +2 -0
- package/dist/connectors/src/index.d.ts.map +1 -1
- package/dist/connectors-O6Y6VESP.js +44 -0
- package/dist/{connectors-SSOTIDHT.js.map → connectors-O6Y6VESP.js.map} +1 -1
- package/dist/connectors-shared/index.js +2 -2
- package/dist/core/index.js +8 -8
- package/dist/core/logging.js +1 -1
- package/dist/core/manifest.js +2 -2
- package/dist/core/models.js +1 -1
- package/dist/core/publish-manifest.js +2 -2
- package/dist/core/ref.js +1 -1
- package/dist/core/runtime-assets.js +5 -5
- package/dist/core/src/index.d.ts +3 -3
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/core/src/logging/config.d.ts +9 -1
- package/dist/core/src/logging/config.d.ts.map +1 -1
- package/dist/core/src/manifest.d.ts +11 -1
- package/dist/core/src/manifest.d.ts.map +1 -1
- package/dist/core/src/models.d.ts +14 -6
- package/dist/core/src/models.d.ts.map +1 -1
- package/dist/core/src/repo-manager.d.ts +41 -6
- package/dist/core/src/repo-manager.d.ts.map +1 -1
- package/dist/core/src/store.d.ts +16 -2
- package/dist/core/src/store.d.ts.map +1 -1
- package/dist/core/src/workspace-config.d.ts +10 -1
- package/dist/core/src/workspace-config.d.ts.map +1 -1
- package/dist/core/store.js +1 -1
- package/dist/core/workspace-config.js +4 -4
- package/dist/deploy/index.js +8 -8
- package/dist/discovery/index.js +5 -5
- package/dist/{ensure-sources-277VI7R3.js → ensure-sources-SKLNM4UZ.js} +18 -18
- package/dist/{ensure-sources-277VI7R3.js.map → ensure-sources-SKLNM4UZ.js.map} +1 -1
- package/dist/factory-assets/connectors/box.js +25 -26
- package/dist/factory-assets/connectors/deploy.js +25 -26
- package/dist/factory-assets/connectors/devserver.js +25 -26
- package/dist/factory-assets/connectors/flow/adapter.d.ts +6 -0
- package/dist/factory-assets/connectors/flow/adapter.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/adapter.js +25 -26
- package/dist/factory-assets/connectors/flow/contract/expression.d.ts +3 -0
- package/dist/factory-assets/connectors/flow/contract/expression.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/contract/output-fields.d.ts +1 -1
- package/dist/factory-assets/connectors/flow/contract/output-fields.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/contract/schema.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/contract.js +4 -4
- package/dist/factory-assets/connectors/flow/engine/flow-output.d.ts +4 -3
- package/dist/factory-assets/connectors/flow/engine/flow-output.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/engine/output-schema.d.ts +6 -1
- package/dist/factory-assets/connectors/flow/engine/output-schema.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/engine.js +12 -12
- package/dist/factory-assets/connectors/flow/inline-sub-flow-host.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/prompt-fragments.js +3 -3
- package/dist/factory-assets/connectors/flow/run-flow.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/run-flow.js +27 -28
- package/dist/factory-assets/connectors/flow.js +25 -26
- package/dist/factory-assets/connectors/git/config.d.ts.map +1 -1
- package/dist/factory-assets/connectors/git.js +25 -26
- package/dist/factory-assets/connectors/gmail.js +25 -26
- package/dist/factory-assets/connectors/googledrive.js +25 -26
- package/dist/factory-assets/connectors/local.js +25 -26
- package/dist/factory-assets/connectors/mattermost.js +25 -26
- package/dist/factory-assets/connectors/memory.js +25 -26
- package/dist/factory-assets/connectors/minio.js +25 -26
- package/dist/factory-assets/connectors/postgres.js +25 -26
- package/dist/factory-assets/connectors/s3.js +25 -26
- package/dist/factory-assets/connectors/sharepoint.js +25 -26
- package/dist/factory-assets/connectors/sqlite.js +25 -26
- package/dist/factory-assets/connectors/static-server.js +25 -26
- package/dist/factory-assets/connectors/tunnel.js +25 -26
- package/dist/factory-assets/connectors/webdav.js +25 -26
- package/dist/factory-assets/connectors/xstate-store.js +25 -26
- package/dist/factory-assets/connectors/xstate.js +25 -26
- package/dist/factory-assets/skills/skaile-author-asset/SKILL.md +10 -7
- package/dist/{flows-J2UEU2QM.js → flows-CBYRSAGS.js} +13 -13
- package/dist/{flows-J2UEU2QM.js.map → flows-CBYRSAGS.js.map} +1 -1
- package/dist/{helpers-KC5O7CML.js → helpers-MWZDRBLD.js} +18 -18
- package/dist/{helpers-KC5O7CML.js.map → helpers-MWZDRBLD.js.map} +1 -1
- package/dist/library/index.js +12 -12
- package/dist/library/install.js +3 -3
- package/dist/library/src/index.d.ts +3 -1
- package/dist/library/src/index.d.ts.map +1 -1
- package/dist/library/src/local/scan-authoring-libraries.d.ts +43 -0
- package/dist/library/src/local/scan-authoring-libraries.d.ts.map +1 -0
- package/dist/library/src/manifest-writer.d.ts +26 -3
- package/dist/library/src/manifest-writer.d.ts.map +1 -1
- package/dist/library/src/sync/git-driver.d.ts.map +1 -1
- package/dist/{library-publish-FGXF5TJO.js → library-publish-PICMDSB2.js} +73 -37
- package/dist/library-publish-PICMDSB2.js.map +1 -0
- package/dist/open-library-OG457THY.js +40 -0
- package/dist/{open-library-P3D337NH.js.map → open-library-OG457THY.js.map} +1 -1
- package/dist/open-registry-ZUZJ7MS7.js +32 -0
- package/dist/{open-registry-Z3P2X2AB.js.map → open-registry-ZUZJ7MS7.js.map} +1 -1
- package/dist/paths-FQ64OLJG.js +22 -0
- package/dist/{paths-JKEKXM52.js.map → paths-FQ64OLJG.js.map} +1 -1
- package/dist/{plugin-store-WI4MZJLP.js → plugin-store-MPAMD5OT.js} +10 -10
- package/dist/{plugin-store-WI4MZJLP.js.map → plugin-store-MPAMD5OT.js.map} +1 -1
- package/dist/project-2GFT5LEZ.js +41 -0
- package/dist/{project-WFUDVYNN.js.map → project-2GFT5LEZ.js.map} +1 -1
- package/dist/resolver/index.js +9 -9
- package/dist/runner/index.js +40 -41
- package/dist/runner/src/logging-bootstrap.d.ts +6 -0
- package/dist/runner/src/logging-bootstrap.d.ts.map +1 -1
- package/dist/runner/src/reconfigure-handler.d.ts +38 -17
- package/dist/runner/src/reconfigure-handler.d.ts.map +1 -1
- package/dist/runner/src/serve.d.ts.map +1 -1
- package/dist/runner/src/session-capability-wiring.d.ts +0 -2
- package/dist/runner/src/session-capability-wiring.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +15 -15
- package/dist/sdk/bridge.js +16 -17
- package/dist/sdk/core.js +8 -8
- package/dist/sdk/flow.js +12 -12
- package/dist/sdk/index.js +68 -45
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/resolver.js +9 -9
- package/dist/sdk/runner.js +40 -41
- package/dist/sdk/session.js +2 -2
- package/dist/sdk/src/agent-session.d.ts +8 -0
- package/dist/sdk/src/agent-session.d.ts.map +1 -1
- package/dist/sdk/store.js +2 -1
- package/dist/sdk/types.js +1 -1
- package/dist/session/index.js +2 -2
- package/dist/{setup-RAMLTORM.js → setup-WHMCSIF2.js} +26 -27
- package/dist/setup-WHMCSIF2.js.map +1 -0
- package/dist/skills-TVO26Y4V.js +26 -0
- package/dist/{skills-EOHZ2DZ4.js.map → skills-TVO26Y4V.js.map} +1 -1
- package/dist/source-LKOFTOEK.js +41 -0
- package/dist/{source-FYVSFYEI.js.map → source-LKOFTOEK.js.map} +1 -1
- package/dist/{source-manifest-publish-4FPIPPLV.js → source-manifest-publish-L5J3QXER.js} +27 -27
- package/dist/{source-manifest-publish-4FPIPPLV.js.map → source-manifest-publish-L5J3QXER.js.map} +1 -1
- package/dist/store/index.js +2 -1
- package/dist/store/src/store.d.ts +8 -5
- package/dist/store/src/store.d.ts.map +1 -1
- package/dist/tui/index.js +40 -41
- package/dist/tui/index.js.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/manifests.js +1 -1
- package/dist/types/src/ask-slots.d.ts +68 -0
- package/dist/types/src/ask-slots.d.ts.map +1 -0
- package/dist/types/src/delivery.d.ts.map +1 -1
- package/dist/types/src/events.d.ts +29 -1
- package/dist/types/src/events.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/manifests/index.d.ts +1 -1
- package/dist/types/src/manifests/index.d.ts.map +1 -1
- package/dist/types/src/manifests/preset.d.ts +4 -0
- package/dist/types/src/manifests/preset.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +12 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/dist/workspace-plugin/adapters/mcp.js +32 -33
- package/dist/workspace-plugin/adapters/omp.js +14 -14
- package/dist/workspace-plugin/index.js +2 -2
- package/package.json +1 -1
- package/dist/asset-feeds-K36CR52Q.js.map +0 -1
- package/dist/chunk-6C654TFI.js.map +0 -1
- package/dist/chunk-74EEFB52.js.map +0 -1
- package/dist/chunk-BTK7ECLH.js.map +0 -1
- package/dist/chunk-CWM3MYGX.js.map +0 -1
- package/dist/chunk-D5HOETOB.js.map +0 -1
- package/dist/chunk-DFFD4BFG.js.map +0 -1
- package/dist/chunk-DMLDYFDS.js.map +0 -1
- package/dist/chunk-EINLFFP6.js +0 -59
- package/dist/chunk-EINLFFP6.js.map +0 -1
- package/dist/chunk-EU3Q5AQ4.js.map +0 -1
- package/dist/chunk-FRHE7FFB.js.map +0 -1
- package/dist/chunk-G67BOI2J.js.map +0 -1
- package/dist/chunk-GIC3G5YG.js.map +0 -1
- package/dist/chunk-IZLQ4GDO.js.map +0 -1
- package/dist/chunk-JMKB7IB4.js.map +0 -1
- package/dist/chunk-LBQ4BBX4.js.map +0 -1
- package/dist/chunk-LCU5U5IW.js.map +0 -1
- package/dist/chunk-LXY4BUA3.js.map +0 -1
- package/dist/chunk-MKLBK7HI.js.map +0 -1
- package/dist/chunk-O7VPNKYN.js.map +0 -1
- package/dist/chunk-OKGUDNDT.js.map +0 -1
- package/dist/chunk-QCI6D7E4.js.map +0 -1
- package/dist/chunk-SZWRPEF7.js.map +0 -1
- package/dist/chunk-TTPSDC2G.js.map +0 -1
- package/dist/chunk-VOOI7B2L.js.map +0 -1
- package/dist/chunk-XBSQ4KMC.js.map +0 -1
- package/dist/connectors-SSOTIDHT.js +0 -45
- package/dist/library-publish-FGXF5TJO.js.map +0 -1
- package/dist/open-library-P3D337NH.js +0 -40
- package/dist/open-registry-Z3P2X2AB.js +0 -32
- package/dist/paths-JKEKXM52.js +0 -22
- package/dist/project-WFUDVYNN.js +0 -41
- package/dist/setup-RAMLTORM.js.map +0 -1
- package/dist/skills-EOHZ2DZ4.js +0 -26
- package/dist/source-FYVSFYEI.js +0 -41
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { getStoreManifestsDir } from './chunk-
|
|
2
|
-
import { readManifestSourceConfig, discoverAssetsInTree } from './chunk-
|
|
3
|
-
import { installAgent, installTargetOf, deployAll, removeAsset,
|
|
1
|
+
import { getStoreManifestsDir } from './chunk-4MQS7CAF.js';
|
|
2
|
+
import { readManifestSourceConfig, isManifestMode, discoverAssetsInTree } from './chunk-Y7QA2OLD.js';
|
|
3
|
+
import { installAgent, installTargetOf, canonicalEntryRef, deployAll, removeAsset, createScaffold } from './chunk-YSHVQGUS.js';
|
|
4
4
|
import { appendHistory, getRecentHistory, clearHistory } from './chunk-KTBKW2FI.js';
|
|
5
5
|
import { commitChanges } from './chunk-UQ6LFBPZ.js';
|
|
6
|
-
import { driverTargetSupportsAgents, CODEX_IDENTITY_DIR } from './chunk-
|
|
7
|
-
import { resolveConfiguredDriverTarget, GLOBAL_INSTALL_DIR_NAME, resolveLibraryDir, buildLibraryLockEntries,
|
|
8
|
-
import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-
|
|
9
|
-
import { deployedBase, deployedDir, isDeployed } from './chunk-
|
|
10
|
-
import { resolveSkWorkspaceConfig, effectiveAgentInstances, resolveAgentDefinitionDir, loadMcpServerDeclarations, resolveGlobalHarnesses, resolveGlobalSkWorkspaceConfig, getGlobalCacheDir, sourceCacheKey, getRepoCommit, matchPin,
|
|
6
|
+
import { driverTargetSupportsAgents, CODEX_IDENTITY_DIR } from './chunk-EF7NPDDU.js';
|
|
7
|
+
import { resolveConfiguredDriverTarget, GLOBAL_INSTALL_DIR_NAME, resolveLibraryDir, buildLibraryLockEntries, buildLockFile, writeLock, readLock, verifyLock, mergeLockFile, extractForPatch, generatePatch, savePatch, applyPatch } from './chunk-36AFURKZ.js';
|
|
8
|
+
import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-GB7WDMH2.js';
|
|
9
|
+
import { deployedBase, deployedDir, isDeployed, deployedPaths } from './chunk-PMECEZK3.js';
|
|
10
|
+
import { resolveSkWorkspaceConfig, effectiveAgentInstances, resolveAgentDefinitionDir, loadMcpServerDeclarations, resolveGlobalHarnesses, resolveGlobalSkWorkspaceConfig, getGlobalCacheDir, sourceCacheKey, getRepoCommit, matchPin, resolveAll, buildProvenanceIndex, ensureRepo, sourceShortName, scanRepo, SKAILE_YAML_DEFAULT, checkRepoStatus, coerceVersion, resolveAsset, readLinks, MAX_PRESET_DEPTH, PresetDepthError, storeManifestSlug } from './chunk-JAKOMFC6.js';
|
|
11
11
|
import { globalSkaileDir, globalCacheRoot, migrateLegacyDir } from './chunk-L5VSIPQD.js';
|
|
12
12
|
import { DRIVER_TARGETS } from './chunk-CPSIPIX7.js';
|
|
13
|
-
import { scanDirectory, parseRequires } from './chunk-
|
|
14
|
-
import { parseAssetRef, parseAssetRefLoose, assetRefToStr, slugifyAssetName } from './chunk-
|
|
13
|
+
import { scanDirectory, parseRequires } from './chunk-GTILM2CI.js';
|
|
14
|
+
import { parseAssetRef, parseAssetRefLoose, assetRefToStr, slugifyAssetName, depToStr } from './chunk-QVNRCDTV.js';
|
|
15
15
|
import { spawnSync } from 'child_process';
|
|
16
16
|
import { existsSync, rmSync, readdirSync, lstatSync, unlinkSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
17
|
-
import path, { join, resolve, dirname, sep, posix } from 'path';
|
|
17
|
+
import path, { join, resolve, dirname, sep, relative, posix } from 'path';
|
|
18
18
|
import { gt } from 'semver';
|
|
19
19
|
import { stringify, parse } from 'yaml';
|
|
20
20
|
import fs from 'fs/promises';
|
|
@@ -375,6 +375,26 @@ function libraryDiskHashes(libPath, cache, registry) {
|
|
|
375
375
|
}
|
|
376
376
|
return hashes;
|
|
377
377
|
}
|
|
378
|
+
function withLibraryFiles(entry, libPath, cache, registry) {
|
|
379
|
+
let byManifest = cache.get(libPath);
|
|
380
|
+
if (!byManifest) {
|
|
381
|
+
byManifest = /* @__PURE__ */ new Map();
|
|
382
|
+
const sourceConfig = readManifestSourceConfig(libPath, "library");
|
|
383
|
+
if (sourceConfig && isManifestMode(sourceConfig)) {
|
|
384
|
+
for (const a of discoverAssetsInTree(libPath, { sourceConfig, registry }).assets) {
|
|
385
|
+
const { assetRoot, files: files2 } = a.fileFilter;
|
|
386
|
+
byManifest.set(
|
|
387
|
+
resolve(a.manifestPath),
|
|
388
|
+
filesUnderManifestDir(files2, relative(assetRoot, a.manifestPath).split(sep).join("/"))
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
cache.set(libPath, byManifest);
|
|
393
|
+
}
|
|
394
|
+
const files = byManifest.get(resolve(entry.source));
|
|
395
|
+
if (files) entry.files = files;
|
|
396
|
+
return entry;
|
|
397
|
+
}
|
|
378
398
|
function newestLibraryDef(snap, libraryName, id) {
|
|
379
399
|
const lib = snap?.libraries.find((l) => l.name === libraryName);
|
|
380
400
|
if (!snap || !lib) return void 0;
|
|
@@ -386,6 +406,17 @@ function newestLibraryDef(snap, libraryName, id) {
|
|
|
386
406
|
}
|
|
387
407
|
return best;
|
|
388
408
|
}
|
|
409
|
+
function libraryPreference(isDefaultLib) {
|
|
410
|
+
return (a, b) => {
|
|
411
|
+
const va = coerceVersion(a.entry.version ?? "");
|
|
412
|
+
const vb = coerceVersion(b.entry.version ?? "");
|
|
413
|
+
if (gt(va, vb)) return -1;
|
|
414
|
+
if (gt(vb, va)) return 1;
|
|
415
|
+
const da = isDefaultLib.get(a.library) ? 0 : 1;
|
|
416
|
+
const db = isDefaultLib.get(b.library) ? 0 : 1;
|
|
417
|
+
return da - db || a.library.localeCompare(b.library);
|
|
418
|
+
};
|
|
419
|
+
}
|
|
389
420
|
function qualifyDepRef(ref, fallback) {
|
|
390
421
|
const hash = ref.indexOf("#");
|
|
391
422
|
const head = hash === -1 ? ref : ref.slice(0, hash);
|
|
@@ -407,7 +438,7 @@ function libraryEntryDepRefs(e) {
|
|
|
407
438
|
}
|
|
408
439
|
for (const r of e.requires ?? []) {
|
|
409
440
|
const p = r.publisher ?? publisher;
|
|
410
|
-
if (p) refs.add(assetRefToStr({ kind: r.kind, name: r.name, publisher: p }));
|
|
441
|
+
if (p) refs.add(assetRefToStr({ kind: r.kind, name: r.name, publisher: p, pin: r.pin }));
|
|
411
442
|
}
|
|
412
443
|
return [...refs];
|
|
413
444
|
}
|
|
@@ -489,6 +520,56 @@ function parseRefTolerant(ref) {
|
|
|
489
520
|
return { kind, name, publisher: void 0 };
|
|
490
521
|
}
|
|
491
522
|
}
|
|
523
|
+
function keptLockEntries(prev, missing) {
|
|
524
|
+
const out = { assets: {}, sources: [], refs: /* @__PURE__ */ new Set() };
|
|
525
|
+
if (!prev) return out;
|
|
526
|
+
for (const ref of missing) {
|
|
527
|
+
const want = parseRefTolerant(ref.split(" ")[0] ?? ref);
|
|
528
|
+
if (!want) continue;
|
|
529
|
+
for (const [key, entry] of Object.entries(prev.assets)) {
|
|
530
|
+
if (entry.library?.installed) continue;
|
|
531
|
+
const id = parseCanonicalLockKey(key);
|
|
532
|
+
if (id.kind !== want.kind || id.name !== want.name) continue;
|
|
533
|
+
if (want.publisher && id.publisher !== want.publisher) continue;
|
|
534
|
+
out.assets[key] = entry;
|
|
535
|
+
out.refs.add(ref);
|
|
536
|
+
const src = entry.source ? prev.sources.find((s) => s.url === entry.source?.url) : void 0;
|
|
537
|
+
if (src) out.sources.push(src);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return out;
|
|
541
|
+
}
|
|
542
|
+
function withKeptLockEntries(lock, kept) {
|
|
543
|
+
if (Object.keys(kept.assets).length === 0) return lock;
|
|
544
|
+
const sources = new Map(lock.sources.map((s) => [s.url, s]));
|
|
545
|
+
for (const s of kept.sources) if (!sources.has(s.url)) sources.set(s.url, s);
|
|
546
|
+
return {
|
|
547
|
+
...lock,
|
|
548
|
+
// v4 once a library-origin entry is present (see buildLockFile).
|
|
549
|
+
schema_version: lock.schema_version === 4 || Object.values(kept.assets).some((e) => e.library) ? 4 : 3,
|
|
550
|
+
assets: { ...lock.assets, ...kept.assets },
|
|
551
|
+
sources: [...sources.values()].sort((a, b) => a.url.localeCompare(b.url))
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
function relockedRefs(prev, next) {
|
|
555
|
+
if (!prev) return [];
|
|
556
|
+
const fingerprint = (e) => [e.library?.version ?? "", e.library?.sha256 ?? e.sha256, e.source?.commit ?? ""].join("\0");
|
|
557
|
+
const out = [];
|
|
558
|
+
for (const [key, entry] of Object.entries(next.assets)) {
|
|
559
|
+
if (entry.library?.installed) continue;
|
|
560
|
+
const id = parseCanonicalLockKey(key);
|
|
561
|
+
const before = prev.assets[key] ? [key, prev.assets[key]] : Object.entries(prev.assets).find(([k]) => {
|
|
562
|
+
const o = parseCanonicalLockKey(k);
|
|
563
|
+
return o.kind === id.kind && o.name === id.name && o.publisher === id.publisher;
|
|
564
|
+
});
|
|
565
|
+
if (!before) continue;
|
|
566
|
+
if (before[0] !== key || fingerprint(before[1]) !== fingerprint(entry)) out.push(key);
|
|
567
|
+
}
|
|
568
|
+
return out;
|
|
569
|
+
}
|
|
570
|
+
function unregisteredLibraryFix(library, ref) {
|
|
571
|
+
return `register library "${library}" again with \`skaile library init ${library} --path <dir>\`, or drop the dependency with \`skaile remove ${ref}\``;
|
|
572
|
+
}
|
|
492
573
|
function memberIdentity(ref) {
|
|
493
574
|
const parsed = parseRefTolerant(ref.trim());
|
|
494
575
|
if (!parsed) return null;
|
|
@@ -828,6 +909,46 @@ var AssetManager = class {
|
|
|
828
909
|
const resolved = /* @__PURE__ */ new Set();
|
|
829
910
|
const libraryOf = /* @__PURE__ */ new Map();
|
|
830
911
|
if (missing.length === 0) return { entries: [], resolved, libraryOf };
|
|
912
|
+
const scan = await this.scanLibraries();
|
|
913
|
+
if (!scan) return { entries: [], resolved, libraryOf };
|
|
914
|
+
const { byKey, isDefaultLib, libraryDir } = scan;
|
|
915
|
+
const entries = [];
|
|
916
|
+
const fileSets = /* @__PURE__ */ new Map();
|
|
917
|
+
const allCandidates = [...byKey.values()].flat();
|
|
918
|
+
for (const ref of missing) {
|
|
919
|
+
const parsed = parseRefTolerant(ref);
|
|
920
|
+
if (!parsed) continue;
|
|
921
|
+
const hash = ref.indexOf("#");
|
|
922
|
+
const pin = parsed.pin ?? (hash >= 0 ? ref.slice(hash + 1) : void 0);
|
|
923
|
+
const key = parsed.publisher ? `${parsed.kind}:@${parsed.publisher}/${parsed.name}` : void 0;
|
|
924
|
+
const pool = key ? byKey.get(key) ?? [] : allCandidates.filter((c) => c.entry.kind === parsed.kind && c.entry.name === parsed.name);
|
|
925
|
+
const candidates = pool.filter((c) => !pin || matchPin(pin, c.entry.version ?? ""));
|
|
926
|
+
if (candidates.length === 0) continue;
|
|
927
|
+
candidates.sort(libraryPreference(isDefaultLib));
|
|
928
|
+
const hit = candidates[0];
|
|
929
|
+
if (!opts.quiet) {
|
|
930
|
+
this.warnLibraryCollision(
|
|
931
|
+
`${hit.entry.kind}:@${hit.entry.publisher}/${hit.entry.name}`,
|
|
932
|
+
candidates,
|
|
933
|
+
hit
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
withLibraryFiles(hit.entry, libraryDir.get(hit.library), fileSets, this.registry);
|
|
937
|
+
entries.push(hit.entry);
|
|
938
|
+
libraryOf.set(hit.entry, hit.library);
|
|
939
|
+
resolved.add(ref);
|
|
940
|
+
}
|
|
941
|
+
return { entries, resolved, libraryOf };
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Scan every candidate library (the set {@link resolveLibraryEntries} resolves from)
|
|
945
|
+
* into `kind:@publisher/name` → every holder, across all libraries and versions.
|
|
946
|
+
*
|
|
947
|
+
* @param minRoots - Return `null` without scanning when fewer candidate libraries
|
|
948
|
+
* exist (a cross-library question needs at least two).
|
|
949
|
+
* @returns `null` when there is no candidate library or none holds an asset.
|
|
950
|
+
*/
|
|
951
|
+
async scanLibraries(minRoots = 1) {
|
|
831
952
|
const roots = [];
|
|
832
953
|
for (const l of (await this.loadLibraryIndex())?.libraries ?? []) {
|
|
833
954
|
if (l.name === GLOBAL_INSTALL_DIR_NAME) continue;
|
|
@@ -849,8 +970,9 @@ var AssetManager = class {
|
|
|
849
970
|
}
|
|
850
971
|
} catch {
|
|
851
972
|
}
|
|
852
|
-
if (roots.length === 0
|
|
973
|
+
if (roots.length === 0 || roots.length < minRoots) return null;
|
|
853
974
|
const byKey = /* @__PURE__ */ new Map();
|
|
975
|
+
const libraryDir = new Map(roots.map((r) => [r.name, r.dir]));
|
|
854
976
|
const isDefaultLib = new Map(roots.map((r) => [r.name, r.isDefault]));
|
|
855
977
|
for (const { name, dir } of roots) {
|
|
856
978
|
const publisher = readDeclaredPublisher(dir) ?? slugifyAssetName(name);
|
|
@@ -861,56 +983,49 @@ var AssetManager = class {
|
|
|
861
983
|
else byKey.set(key, [{ entry, library: name }]);
|
|
862
984
|
}
|
|
863
985
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
hit
|
|
891
|
-
);
|
|
892
|
-
}
|
|
893
|
-
entries.push(hit.entry);
|
|
894
|
-
libraryOf.set(hit.entry, hit.library);
|
|
895
|
-
resolved.add(ref);
|
|
986
|
+
return byKey.size === 0 ? null : { byKey, isDefaultLib, libraryDir };
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Every ref that more than one registered library holds, with one row per holder
|
|
990
|
+
* (all libraries, all versions) in the order `add` prefers them: the first row is
|
|
991
|
+
* the one `add <ref>` deploys. The local index keeps a single row per ref and
|
|
992
|
+
* version, so `search` reads this to show equal-version copies in both libraries.
|
|
993
|
+
*
|
|
994
|
+
* @returns `kind:@publisher/name` → holders; refs held by one library are absent.
|
|
995
|
+
*/
|
|
996
|
+
async libraryHolders() {
|
|
997
|
+
const out = /* @__PURE__ */ new Map();
|
|
998
|
+
const scan = await this.scanLibraries(2);
|
|
999
|
+
if (!scan) return out;
|
|
1000
|
+
for (const [key, candidates] of scan.byKey) {
|
|
1001
|
+
if (new Set(candidates.map((c) => c.library)).size < 2) continue;
|
|
1002
|
+
const sorted = [...candidates].sort(libraryPreference(scan.isDefaultLib));
|
|
1003
|
+
out.set(
|
|
1004
|
+
key,
|
|
1005
|
+
sorted.map((c, i) => ({
|
|
1006
|
+
library: c.library,
|
|
1007
|
+
version: c.entry.version ?? "",
|
|
1008
|
+
description: c.entry.description ?? "",
|
|
1009
|
+
picked: i === 0
|
|
1010
|
+
}))
|
|
1011
|
+
);
|
|
896
1012
|
}
|
|
897
|
-
return
|
|
1013
|
+
return out;
|
|
898
1014
|
}
|
|
899
1015
|
/**
|
|
900
|
-
*
|
|
901
|
-
* ref at once (one library scan, one lock read)
|
|
902
|
-
* - `
|
|
903
|
-
*
|
|
904
|
-
*
|
|
905
|
-
*
|
|
906
|
-
*
|
|
907
|
-
* one. An unrelated asset that merely shares kind + name does not qualify.
|
|
1016
|
+
* Where each missed publisher-qualified ref went when its publisher changed, for every
|
|
1017
|
+
* ref at once (one library scan, one lock read):
|
|
1018
|
+
* - `moved` when a registered library holds the same kind + name under another publisher;
|
|
1019
|
+
* - `lockedAs` when the lock holds the same kind + name under another publisher, records
|
|
1020
|
+
* the library it came from, and that library now holds the asset under yet another
|
|
1021
|
+
* publisher than the locked one. An unrelated asset that merely shares kind + name does
|
|
1022
|
+
* not qualify.
|
|
908
1023
|
*
|
|
909
1024
|
* @param refs - Missed refs; a trailing `(reason)` after the first space is ignored.
|
|
910
|
-
* @returns
|
|
1025
|
+
* @returns one finding per ref that has one. Never warns.
|
|
911
1026
|
*/
|
|
912
|
-
async
|
|
913
|
-
const out =
|
|
1027
|
+
async publisherChangeFindings(refs) {
|
|
1028
|
+
const out = /* @__PURE__ */ new Map();
|
|
914
1029
|
const wanted = /* @__PURE__ */ new Map();
|
|
915
1030
|
for (const ref of refs) {
|
|
916
1031
|
const parsed = parseRefTolerant(ref.split(" ")[0] ?? ref);
|
|
@@ -925,20 +1040,83 @@ var AssetManager = class {
|
|
|
925
1040
|
for (const [ref, w] of wanted) {
|
|
926
1041
|
const moved = lib.entries.find((e) => e.kind === w.kind && e.name === w.name);
|
|
927
1042
|
const movedLibrary = moved ? lib.libraryOf.get(moved) : void 0;
|
|
928
|
-
const
|
|
1043
|
+
const finding = {};
|
|
929
1044
|
for (const [key, entry] of lockEntries) {
|
|
930
1045
|
const id = parseCanonicalLockKey(key);
|
|
931
1046
|
if (id.kind === w.kind && id.name === w.name && id.publisher && id.publisher !== w.publisher && entry.library && moved && movedLibrary === entry.library.name && moved.publisher !== id.publisher) {
|
|
932
|
-
|
|
933
|
-
`locked as ${id.kind}:@${id.publisher}/${id.name}; run skaile install to re-resolve`
|
|
934
|
-
);
|
|
1047
|
+
finding.lockedAs = `${id.kind}:@${id.publisher}/${id.name}`;
|
|
935
1048
|
break;
|
|
936
1049
|
}
|
|
937
1050
|
}
|
|
938
1051
|
if (moved && moved.publisher !== w.publisher) {
|
|
939
|
-
|
|
1052
|
+
finding.moved = {
|
|
1053
|
+
ref: `${moved.kind}:@${moved.publisher}/${moved.name}`,
|
|
1054
|
+
...movedLibrary ? { library: movedLibrary } : {}
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
if (finding.lockedAs || finding.moved) out.set(ref, finding);
|
|
1058
|
+
}
|
|
1059
|
+
return out;
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Explain misses caused by a publisher change, as parenthesized hint text per ref:
|
|
1063
|
+
* `did you mean <ref>?` when a registered library holds the same kind + name under
|
|
1064
|
+
* another publisher, and `locked as <lockRef>; run skaile install to re-resolve` when
|
|
1065
|
+
* the lock holds it under the library's previous publisher (see
|
|
1066
|
+
* {@link AssetManager.publisherChangeFindings}).
|
|
1067
|
+
*
|
|
1068
|
+
* @param refs - Missed refs; a trailing `(reason)` after the first space is ignored.
|
|
1069
|
+
* @returns hint text per ref, only for refs that have one. Never warns.
|
|
1070
|
+
*/
|
|
1071
|
+
async publisherChangeHints(refs) {
|
|
1072
|
+
const out = {};
|
|
1073
|
+
for (const [ref, f] of await this.publisherChangeFindings(refs)) {
|
|
1074
|
+
const hints = [];
|
|
1075
|
+
if (f.lockedAs) hints.push(`locked as ${f.lockedAs}; run skaile install to re-resolve`);
|
|
1076
|
+
if (f.moved) hints.push(`did you mean ${f.moved.ref}?`);
|
|
1077
|
+
out[ref] = hints.map((h) => ` (${h})`).join("");
|
|
1078
|
+
}
|
|
1079
|
+
return out;
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* What the user has to change for each ref that is locked from a library but resolves
|
|
1083
|
+
* nowhere any more, where `skaile install` cannot help: the library is not registered
|
|
1084
|
+
* (renamed away or removed), the library now publishes the asset under another
|
|
1085
|
+
* publisher, or the library no longer holds it. A ref the lock does not tie to a
|
|
1086
|
+
* library has no entry.
|
|
1087
|
+
*
|
|
1088
|
+
* @param refs - Declared or locked refs, `kind:@publisher/name` (a trailing `(reason)`
|
|
1089
|
+
* after the first space is ignored).
|
|
1090
|
+
* @returns a phrase per ref that follows the ref name, without parentheses.
|
|
1091
|
+
*/
|
|
1092
|
+
async unresolvedFixes(refs) {
|
|
1093
|
+
const out = /* @__PURE__ */ new Map();
|
|
1094
|
+
if (refs.length === 0) return out;
|
|
1095
|
+
const lockEntries = Object.entries(this.tryReadLock()?.assets ?? {});
|
|
1096
|
+
const snap = await this.loadLibraryIndex();
|
|
1097
|
+
const findings = await this.publisherChangeFindings(refs);
|
|
1098
|
+
for (const ref of refs) {
|
|
1099
|
+
const want = parseRefTolerant(ref.split(" ")[0] ?? ref);
|
|
1100
|
+
if (!want) continue;
|
|
1101
|
+
const origin = lockEntries.map(([key, e]) => ({ id: parseCanonicalLockKey(key), library: e.library })).find(
|
|
1102
|
+
({ id, library }) => library && !library.installed && id.kind === want.kind && id.name === want.name && (!want.publisher || id.publisher === want.publisher)
|
|
1103
|
+
)?.library;
|
|
1104
|
+
if (!origin) continue;
|
|
1105
|
+
const plain = want.publisher ? `${want.kind}:@${want.publisher}/${want.name}` : `${want.kind}:${want.name}`;
|
|
1106
|
+
const moved = findings.get(ref)?.moved;
|
|
1107
|
+
if (moved?.library && want.publisher) {
|
|
1108
|
+
out.set(
|
|
1109
|
+
ref,
|
|
1110
|
+
`did you mean ${moved.ref}? Change the ref in skaile.yaml to it, or keep the old ref with \`skaile library set ${moved.library} publisher=${want.publisher}\``
|
|
1111
|
+
);
|
|
1112
|
+
} else if (!this.libraryPath(origin.name, snap)) {
|
|
1113
|
+
out.set(ref, unregisteredLibraryFix(origin.name, plain));
|
|
1114
|
+
} else {
|
|
1115
|
+
out.set(
|
|
1116
|
+
ref,
|
|
1117
|
+
`library "${origin.name}" no longer holds it \u2014 restore it there, or drop the dependency with \`skaile remove ${plain}\``
|
|
1118
|
+
);
|
|
940
1119
|
}
|
|
941
|
-
if (hints.length > 0) out[ref] = hints.map((h) => ` (${h})`).join("");
|
|
942
1120
|
}
|
|
943
1121
|
return out;
|
|
944
1122
|
}
|
|
@@ -958,6 +1136,56 @@ var AssetManager = class {
|
|
|
958
1136
|
if (this.onLibraryCollision) this.onLibraryCollision(msg);
|
|
959
1137
|
else console.warn(`skaile: ${msg}`);
|
|
960
1138
|
}
|
|
1139
|
+
/** Kind, name and bare publisher of a deploy entry; the publisher comes from its canonical ref. */
|
|
1140
|
+
entryIdentity(entry) {
|
|
1141
|
+
const ref = parseAssetRefLoose(canonicalEntryRef(entry));
|
|
1142
|
+
return {
|
|
1143
|
+
kind: entry.kind,
|
|
1144
|
+
name: entry.name,
|
|
1145
|
+
publisher: ref?.publisher ?? entry.publisher?.replace(/^@/, "")
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Refuse assets of one kind and name from different publishers: they deploy into the
|
|
1150
|
+
* same folder, so the later one would silently overwrite the earlier. Throws one line
|
|
1151
|
+
* naming the folder and the asset that holds it.
|
|
1152
|
+
*
|
|
1153
|
+
* @param incoming - Assets about to be deployed. Two of them clashing is refused.
|
|
1154
|
+
* @param held - Assets the project already declares or has locked; one of them
|
|
1155
|
+
* clashing with an incoming asset is refused when its folder is on disk.
|
|
1156
|
+
*/
|
|
1157
|
+
assertNoFolderCollision(incoming, held = []) {
|
|
1158
|
+
const refOf = (a) => assetRefToStr({ kind: a.kind, name: a.name, publisher: a.publisher });
|
|
1159
|
+
const differs = (a, b) => !!a.publisher && !!b.publisher && a.publisher !== b.publisher;
|
|
1160
|
+
const shown = (dir) => this.global ? dir : relative(this.projectDir, dir);
|
|
1161
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1162
|
+
for (const a of incoming) {
|
|
1163
|
+
if (!a.kind || !a.name) continue;
|
|
1164
|
+
const component = installTargetOf(this.registry, a.kind);
|
|
1165
|
+
if (!component) continue;
|
|
1166
|
+
const slot = `${component}/${a.name}`;
|
|
1167
|
+
const prior = seen.get(slot);
|
|
1168
|
+
if (prior && differs(prior, a)) {
|
|
1169
|
+
const dir2 = deployedDir(component, a.name, this.driverTarget, this.global, this.projectDir);
|
|
1170
|
+
throw new Error(
|
|
1171
|
+
`${refOf(prior)} and ${refOf(a)} both deploy to ${shown(dir2)} \u2014 keep only one of them`
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
if (!prior) seen.set(slot, a);
|
|
1175
|
+
const holder = held.find(
|
|
1176
|
+
(h) => !!h.kind && h.name === a.name && installTargetOf(this.registry, h.kind) === component && differs(h, a)
|
|
1177
|
+
);
|
|
1178
|
+
if (!holder) continue;
|
|
1179
|
+
const target = this.targetHarnesses().find(
|
|
1180
|
+
(t) => isDeployed(component, a.name, t, this.global, this.projectDir)
|
|
1181
|
+
);
|
|
1182
|
+
if (!target) continue;
|
|
1183
|
+
const dir = deployedDir(component, a.name, target, this.global, this.projectDir);
|
|
1184
|
+
throw new Error(
|
|
1185
|
+
`${refOf(a)} would overwrite ${shown(dir)}, which ${refOf(holder)} already holds \u2014 run skaile remove ${refOf(holder)} first`
|
|
1186
|
+
);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
961
1189
|
/**
|
|
962
1190
|
* Open the local index and snapshot its libraries + asset definitions.
|
|
963
1191
|
* Best-effort: no index file (never indexed), or any open/guard failure,
|
|
@@ -1022,6 +1250,7 @@ var AssetManager = class {
|
|
|
1022
1250
|
if (locked.length === 0) return { entries, missing };
|
|
1023
1251
|
const snap = await this.loadLibraryIndex();
|
|
1024
1252
|
const diskHashes = /* @__PURE__ */ new Map();
|
|
1253
|
+
const fileSets = /* @__PURE__ */ new Map();
|
|
1025
1254
|
for (const [ref, e] of locked) {
|
|
1026
1255
|
const origin = e.library;
|
|
1027
1256
|
const { publisher, kind, name } = parseCanonicalLockKey(ref);
|
|
@@ -1032,7 +1261,7 @@ var AssetManager = class {
|
|
|
1032
1261
|
const libPath = this.libraryPath(origin.name, snap);
|
|
1033
1262
|
if (!libPath) {
|
|
1034
1263
|
missing.push(
|
|
1035
|
-
`${ref} (library "${origin.name}" is not registered \u2014 renamed or removed?
|
|
1264
|
+
`${ref} (library "${origin.name}" is not registered \u2014 renamed or removed? ${unregisteredLibraryFix(origin.name, `${kind}:@${publisher}/${name}`)}; \`skaile install\` re-locks it when another library holds it now)`
|
|
1036
1265
|
);
|
|
1037
1266
|
continue;
|
|
1038
1267
|
}
|
|
@@ -1060,7 +1289,7 @@ var AssetManager = class {
|
|
|
1060
1289
|
continue;
|
|
1061
1290
|
}
|
|
1062
1291
|
}
|
|
1063
|
-
entries.push(found);
|
|
1292
|
+
entries.push(withLibraryFiles(found, libPath, fileSets, this.registry));
|
|
1064
1293
|
}
|
|
1065
1294
|
return { entries, missing };
|
|
1066
1295
|
}
|
|
@@ -1099,7 +1328,8 @@ var AssetManager = class {
|
|
|
1099
1328
|
stores: opts.stores,
|
|
1100
1329
|
storeFetcher: this.storeFetcherFor(opts.stores),
|
|
1101
1330
|
projectDir: this.projectDir,
|
|
1102
|
-
knownKinds: this.knownKinds
|
|
1331
|
+
knownKinds: this.knownKinds,
|
|
1332
|
+
declaredRefs: opts.declaredRefs
|
|
1103
1333
|
});
|
|
1104
1334
|
if (first.missing.length === 0) return first;
|
|
1105
1335
|
const fallback = await this.globalStoreFallback(opts.stores);
|
|
@@ -1112,7 +1342,8 @@ var AssetManager = class {
|
|
|
1112
1342
|
stores,
|
|
1113
1343
|
storeFetcher: this.storeFetcherFor(stores),
|
|
1114
1344
|
projectDir: this.projectDir,
|
|
1115
|
-
knownKinds: this.knownKinds
|
|
1345
|
+
knownKinds: this.knownKinds,
|
|
1346
|
+
declaredRefs: opts.declaredRefs
|
|
1116
1347
|
});
|
|
1117
1348
|
return retry.missing.length < first.missing.length ? retry : first;
|
|
1118
1349
|
} catch {
|
|
@@ -1146,16 +1377,50 @@ var AssetManager = class {
|
|
|
1146
1377
|
const missing = /* @__PURE__ */ new Set();
|
|
1147
1378
|
const seen = /* @__PURE__ */ new Set();
|
|
1148
1379
|
const covered = /* @__PURE__ */ new Set();
|
|
1380
|
+
const declaredById = /* @__PURE__ */ new Map();
|
|
1381
|
+
for (const d of opts.declaredRefs ?? []) {
|
|
1382
|
+
const id = refIdentity(d);
|
|
1383
|
+
if (id !== null) declaredById.set(id, d);
|
|
1384
|
+
}
|
|
1385
|
+
const presetParent = /* @__PURE__ */ new Map();
|
|
1149
1386
|
const absorb = (hit) => {
|
|
1150
1387
|
const next = [];
|
|
1151
1388
|
for (const e of hit.entries) {
|
|
1152
|
-
lib.entries.push(e);
|
|
1153
1389
|
const origin = hit.libraryOf.get(e);
|
|
1154
|
-
if (origin) lib.libraryOf.set(e, origin);
|
|
1155
1390
|
const id = `${e.publisher}/${e.kind}:${e.name}`;
|
|
1156
1391
|
seen.add(id);
|
|
1157
1392
|
covered.add(id);
|
|
1158
|
-
|
|
1393
|
+
const deps2 = libraryEntryDepRefs(e);
|
|
1394
|
+
if (e.kind === "preset") {
|
|
1395
|
+
const chain = [id];
|
|
1396
|
+
for (let up = presetParent.get(id); up !== void 0; up = presetParent.get(up)) {
|
|
1397
|
+
chain.unshift(up);
|
|
1398
|
+
}
|
|
1399
|
+
if (chain.length > MAX_PRESET_DEPTH) {
|
|
1400
|
+
throw new PresetDepthError("depth", canonicalEntryRef(e), chain);
|
|
1401
|
+
}
|
|
1402
|
+
for (const dep of deps2) {
|
|
1403
|
+
const depId = refIdentity(dep);
|
|
1404
|
+
if (depId === null || !depId.includes("/preset:")) continue;
|
|
1405
|
+
if (chain.includes(depId)) throw new PresetDepthError("cycle", dep, [...chain, depId]);
|
|
1406
|
+
if (!presetParent.has(depId)) presetParent.set(depId, id);
|
|
1407
|
+
}
|
|
1408
|
+
presets.push({
|
|
1409
|
+
ref: canonicalEntryRef(e),
|
|
1410
|
+
assets: deps2.filter((d) => !d.startsWith("preset:")).length,
|
|
1411
|
+
skipped: e.skippedItems ?? 0,
|
|
1412
|
+
...origin ? { library: origin } : {}
|
|
1413
|
+
});
|
|
1414
|
+
} else {
|
|
1415
|
+
lib.entries.push(e);
|
|
1416
|
+
if (origin) lib.libraryOf.set(e, origin);
|
|
1417
|
+
}
|
|
1418
|
+
next.push(
|
|
1419
|
+
...deps2.map((dep) => {
|
|
1420
|
+
const depId = refIdentity(dep);
|
|
1421
|
+
return depId !== null && declaredById.get(depId) || dep;
|
|
1422
|
+
})
|
|
1423
|
+
);
|
|
1159
1424
|
}
|
|
1160
1425
|
for (const r of hit.resolved) lib.resolved.add(r);
|
|
1161
1426
|
return next;
|
|
@@ -1175,7 +1440,7 @@ var AssetManager = class {
|
|
|
1175
1440
|
const libraryTried = new Set(
|
|
1176
1441
|
fresh.filter((ref) => {
|
|
1177
1442
|
const id = refIdentity(ref);
|
|
1178
|
-
return id !== null &&
|
|
1443
|
+
return id !== null && (opts.provenanceIndex.get(id)?.length ?? 0) === 0;
|
|
1179
1444
|
})
|
|
1180
1445
|
);
|
|
1181
1446
|
const hit = await this.resolveLibraryEntries([...libraryTried]);
|
|
@@ -1371,7 +1636,7 @@ var AssetManager = class {
|
|
|
1371
1636
|
async install(opts) {
|
|
1372
1637
|
const { repositories, sources, stores, dependencies, overrides, patches } = this.loadConfig();
|
|
1373
1638
|
if (opts?.locked) {
|
|
1374
|
-
return this.installLocked(repositories, patches);
|
|
1639
|
+
return this.installLocked(repositories, patches, dependencies);
|
|
1375
1640
|
}
|
|
1376
1641
|
const cloneError = this.ensureSourceClones(repositories, sources);
|
|
1377
1642
|
if (cloneError) return cloneError;
|
|
@@ -1381,13 +1646,30 @@ var AssetManager = class {
|
|
|
1381
1646
|
});
|
|
1382
1647
|
const { resolved, missing, overridesApplied, lib, presets } = await this.resolveLibraryFirst(
|
|
1383
1648
|
dependencies,
|
|
1384
|
-
{ provenanceIndex, overrides, stores }
|
|
1649
|
+
{ provenanceIndex, overrides, stores, declaredRefs: dependencies }
|
|
1385
1650
|
);
|
|
1651
|
+
this.assertNoFolderCollision([...resolved, ...lib.entries.map((e) => this.entryIdentity(e))]);
|
|
1386
1652
|
const stillMissing = missing.filter((m) => !lib.resolved.has(m));
|
|
1387
1653
|
const missingHints = await this.publisherChangeHints(stillMissing);
|
|
1654
|
+
const prevLock = this.tryReadLock();
|
|
1655
|
+
const kept = keptLockEntries(prevLock, stillMissing);
|
|
1656
|
+
const fixes = await this.unresolvedFixes(stillMissing);
|
|
1657
|
+
for (const ref of /* @__PURE__ */ new Set([...kept.refs, ...fixes.keys()])) {
|
|
1658
|
+
const fix = fixes.get(ref);
|
|
1659
|
+
const notes = [
|
|
1660
|
+
kept.refs.has(ref) ? "the deployed copy and its lock entry are kept" : void 0,
|
|
1661
|
+
fix
|
|
1662
|
+
].filter((n) => n !== void 0);
|
|
1663
|
+
missingHints[ref] = `${fix ? "" : missingHints[ref] ?? ""} (${notes.join("; ")})`;
|
|
1664
|
+
}
|
|
1388
1665
|
const directLock = this.directInstallLockEntries();
|
|
1389
1666
|
const libraryLock = { ...directLock, ...await this.libraryLockEntries(lib) };
|
|
1390
|
-
const
|
|
1667
|
+
const freshLock = buildLockFile(resolved, overridesApplied, libraryLock);
|
|
1668
|
+
await this.keepRequiredByKept(prevLock, kept, Object.keys(freshLock.assets));
|
|
1669
|
+
const removed = this.reconcileRemovedAssets(
|
|
1670
|
+
resolved,
|
|
1671
|
+
/* @__PURE__ */ new Set([...Object.keys(libraryLock), ...Object.keys(kept.assets)])
|
|
1672
|
+
);
|
|
1391
1673
|
const entries = [...await this.buildCatalogEntries(resolved, repositories), ...lib.entries];
|
|
1392
1674
|
const deployed = [
|
|
1393
1675
|
...new Set(
|
|
@@ -1399,8 +1681,11 @@ var AssetManager = class {
|
|
|
1399
1681
|
await this.renderDriverMcpConfig();
|
|
1400
1682
|
const agentRender = this.renderAgentInstances();
|
|
1401
1683
|
const lockWritten = resolved.length > 0 || lib.entries.length > 0 || existsSync(this.lockPath);
|
|
1684
|
+
let relocked = [];
|
|
1402
1685
|
if (lockWritten) {
|
|
1403
|
-
|
|
1686
|
+
const lockData = withKeptLockEntries(freshLock, kept);
|
|
1687
|
+
relocked = relockedRefs(prevLock, lockData);
|
|
1688
|
+
writeLock(this.lockPath, lockData);
|
|
1404
1689
|
}
|
|
1405
1690
|
this.recordInstallHistory(deployed, removed);
|
|
1406
1691
|
const { npmInstalled, npmFailed } = await this.installRuntimeAssetDeps();
|
|
@@ -1409,6 +1694,7 @@ var AssetManager = class {
|
|
|
1409
1694
|
removed,
|
|
1410
1695
|
missing: stillMissing,
|
|
1411
1696
|
...Object.keys(missingHints).length > 0 ? { missingHints } : {},
|
|
1697
|
+
...relocked.length > 0 ? { relocked } : {},
|
|
1412
1698
|
lockWritten,
|
|
1413
1699
|
npmInstalled,
|
|
1414
1700
|
npmFailed,
|
|
@@ -1416,6 +1702,49 @@ var AssetManager = class {
|
|
|
1416
1702
|
...agentRender
|
|
1417
1703
|
};
|
|
1418
1704
|
}
|
|
1705
|
+
/**
|
|
1706
|
+
* Extend `kept` (see {@link keptLockEntries}) with every previous lock entry a kept asset
|
|
1707
|
+
* requires, transitively, that the new lock (`freshKeys`) does not already carry. The lock
|
|
1708
|
+
* records no edges, so they are read from the kept asset's deployed copy, where the
|
|
1709
|
+
* requirement is publisher-qualified the same way a library scan does it. A copy that
|
|
1710
|
+
* cannot be read has no known requirements.
|
|
1711
|
+
*/
|
|
1712
|
+
async keepRequiredByKept(prev, kept, freshKeys) {
|
|
1713
|
+
if (!prev) return;
|
|
1714
|
+
const fresh = freshKeys.map(parseCanonicalLockKey);
|
|
1715
|
+
const queue = Object.keys(kept.assets);
|
|
1716
|
+
for (const key of queue) {
|
|
1717
|
+
for (const dep of await this.deployedRequirements(key)) {
|
|
1718
|
+
const want = memberIdentity(dep);
|
|
1719
|
+
if (!want) continue;
|
|
1720
|
+
const matches = (id) => id.kind === want.kind && id.name === want.name && (!want.publisher || !id.publisher || id.publisher === want.publisher);
|
|
1721
|
+
if (fresh.some(matches)) continue;
|
|
1722
|
+
for (const [depKey, entry] of Object.entries(prev.assets)) {
|
|
1723
|
+
if (depKey in kept.assets || entry.library?.installed) continue;
|
|
1724
|
+
if (!matches(parseCanonicalLockKey(depKey))) continue;
|
|
1725
|
+
kept.assets[depKey] = entry;
|
|
1726
|
+
queue.push(depKey);
|
|
1727
|
+
const src = entry.source ? prev.sources.find((s) => s.url === entry.source?.url) : void 0;
|
|
1728
|
+
if (src) kept.sources.push(src);
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
/** Publisher-qualified refs the deployed copy of the asset behind lock `key` requires. */
|
|
1734
|
+
async deployedRequirements(key) {
|
|
1735
|
+
const { kind, name, publisher } = parseCanonicalLockKey(key);
|
|
1736
|
+
const component = kind ? this.installTarget(kind) : void 0;
|
|
1737
|
+
if (!kind || !name || !component) return [];
|
|
1738
|
+
const dir = deployedDir(component, name, this.driverTarget, this.global, this.projectDir);
|
|
1739
|
+
if (!existsSync(dir)) return [];
|
|
1740
|
+
try {
|
|
1741
|
+
const scanned = await scanDirectory(dir, publisher ?? "", { knownKinds: this.knownKinds });
|
|
1742
|
+
const own = scanned.find((e) => e.kind === kind && e.name === name);
|
|
1743
|
+
return own ? libraryEntryDepRefs(own) : [];
|
|
1744
|
+
} catch {
|
|
1745
|
+
return [];
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1419
1748
|
/**
|
|
1420
1749
|
* Ensure all source clones are present/up to date. Returns an early
|
|
1421
1750
|
* {@link InstallResult} describing the failed source on the first error, or
|
|
@@ -1480,6 +1809,7 @@ var AssetManager = class {
|
|
|
1480
1809
|
for (const ref of Object.keys(oldLock.assets)) {
|
|
1481
1810
|
if (!resolvedRefs.has(ref)) {
|
|
1482
1811
|
const { kind, name } = parseCanonicalLockKey(ref);
|
|
1812
|
+
if (kind === "preset") continue;
|
|
1483
1813
|
if (kind && name) {
|
|
1484
1814
|
for (const t of this.targetHarnesses()) removeAsset(kind, name, this.deployOptsFor(t));
|
|
1485
1815
|
removed.push(ref);
|
|
@@ -1605,11 +1935,12 @@ var AssetManager = class {
|
|
|
1605
1935
|
}
|
|
1606
1936
|
return { npmInstalled, npmFailed };
|
|
1607
1937
|
}
|
|
1608
|
-
async installLocked(repositories, patches) {
|
|
1938
|
+
async installLocked(repositories, patches, dependencies) {
|
|
1609
1939
|
const lock = this.tryReadLock();
|
|
1610
1940
|
if (!lock) {
|
|
1611
1941
|
throw new Error("No lock file found. Run `skaile install` first.");
|
|
1612
1942
|
}
|
|
1943
|
+
this.assertNoFolderCollision(Object.keys(lock.assets).map(parseCanonicalLockKey));
|
|
1613
1944
|
const declBySlug = new Map(Object.entries(repositories));
|
|
1614
1945
|
const factoryUrl = normalizeRepoUrl(FACTORY_SOURCE_URL);
|
|
1615
1946
|
const factoryDir = Object.values(repositories).find((d) => d.factory)?.path ?? null;
|
|
@@ -1634,6 +1965,16 @@ var AssetManager = class {
|
|
|
1634
1965
|
throw new Error(`Lock file verification failed:
|
|
1635
1966
|
${issues.join("\n ")}`);
|
|
1636
1967
|
}
|
|
1968
|
+
const presetGaps = await this.declaredPresetGaps(dependencies, lock);
|
|
1969
|
+
if (presetGaps.size > 0) {
|
|
1970
|
+
const lines = [...presetGaps].flatMap(
|
|
1971
|
+
([preset, gaps2]) => gaps2.map((g) => `${preset} item ${g.ref}`)
|
|
1972
|
+
);
|
|
1973
|
+
throw new Error(
|
|
1974
|
+
`Lock file does not pin every item of the declared presets (not resolved by \`skaile install\`):
|
|
1975
|
+
${lines.join("\n ")}`
|
|
1976
|
+
);
|
|
1977
|
+
}
|
|
1637
1978
|
const resolved = [];
|
|
1638
1979
|
for (const [ref, entry] of Object.entries(lock.assets)) {
|
|
1639
1980
|
if (!entry.source) continue;
|
|
@@ -1672,10 +2013,20 @@ var AssetManager = class {
|
|
|
1672
2013
|
];
|
|
1673
2014
|
await this.renderDriverMcpConfig();
|
|
1674
2015
|
const agentRender = this.renderAgentInstances();
|
|
2016
|
+
const alreadyMissing = new Set(
|
|
2017
|
+
library.missing.map((m) => {
|
|
2018
|
+
const p = parseRefTolerant(m.split(" ")[0] ?? m);
|
|
2019
|
+
return p ? `${p.kind}:${p.name}` : m;
|
|
2020
|
+
})
|
|
2021
|
+
);
|
|
2022
|
+
const gaps = (await this.lockGaps()).filter((g) => {
|
|
2023
|
+
const p = parseRefTolerant(g.ref);
|
|
2024
|
+
return !(p && alreadyMissing.has(`${p.kind}:${p.name}`));
|
|
2025
|
+
}).map((g) => g.message);
|
|
1675
2026
|
return {
|
|
1676
2027
|
deployed,
|
|
1677
2028
|
removed: [],
|
|
1678
|
-
missing: library.missing,
|
|
2029
|
+
missing: [...library.missing, ...gaps],
|
|
1679
2030
|
lockWritten: false,
|
|
1680
2031
|
...agentRender
|
|
1681
2032
|
};
|
|
@@ -1693,27 +2044,41 @@ var AssetManager = class {
|
|
|
1693
2044
|
* store/factory sources. Defaults to copy.
|
|
1694
2045
|
* @param opts.onLibraryOrigin - Called once per deployed library-origin asset with its
|
|
1695
2046
|
* canonical ref and the name of the library it was resolved from.
|
|
2047
|
+
* @param opts.onPresets - Called once with the presets expanded into this add (the
|
|
2048
|
+
* added preset and any it nests); a library-held preset names its library.
|
|
1696
2049
|
* @returns Array of asset refs that were deployed in this call.
|
|
1697
|
-
* @throws When the asset cannot be found in any configured repository
|
|
2050
|
+
* @throws When the asset cannot be found in any configured repository, or when a
|
|
2051
|
+
* preset's items do not all resolve (nothing is deployed or recorded then).
|
|
1698
2052
|
*/
|
|
1699
2053
|
async add(ref, opts) {
|
|
1700
|
-
const { repositories, sources, stores, overrides, patches } = this.loadConfig();
|
|
1701
|
-
parseAssetRef(ref);
|
|
2054
|
+
const { repositories, sources, stores, dependencies, overrides, patches } = this.loadConfig();
|
|
2055
|
+
const parsed = parseAssetRef(ref);
|
|
1702
2056
|
this.ensureSourceClonesQuiet(repositories, sources);
|
|
1703
2057
|
const provenanceIndex = await buildProvenanceIndex(this.buildClones(repositories), {
|
|
1704
2058
|
projectDir: this.projectDir,
|
|
1705
2059
|
knownKinds: this.knownKinds
|
|
1706
2060
|
});
|
|
1707
|
-
const { resolved, missing, overridesApplied, lib } = await this.resolveLibraryFirst(
|
|
1708
|
-
|
|
1709
|
-
overrides,
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
if (resolved.length === 0 && lib.entries.length === 0) {
|
|
2061
|
+
const { resolved, missing, overridesApplied, lib, presets } = await this.resolveLibraryFirst(
|
|
2062
|
+
[ref],
|
|
2063
|
+
{ provenanceIndex, overrides, stores, declaredRefs: dependencies }
|
|
2064
|
+
);
|
|
2065
|
+
if (resolved.length === 0 && lib.entries.length === 0 && presets.length === 0) {
|
|
1713
2066
|
throw new Error(
|
|
1714
2067
|
`Asset not found: ${ref}${(await this.publisherChangeHints([ref]))[ref] ?? ""}${missing.length ? ` (missing: ${missing.join(", ")})` : ""}`
|
|
1715
2068
|
);
|
|
1716
2069
|
}
|
|
2070
|
+
if (parsed.kind === "preset" && missing.length > 0) {
|
|
2071
|
+
throw new Error(
|
|
2072
|
+
`Preset ${ref} has items that do not resolve: ${missing.join(", ")} \u2014 nothing was added`
|
|
2073
|
+
);
|
|
2074
|
+
}
|
|
2075
|
+
this.assertNoFolderCollision(
|
|
2076
|
+
[...resolved, ...lib.entries.map((e) => this.entryIdentity(e))],
|
|
2077
|
+
[
|
|
2078
|
+
...Object.keys(this.tryReadLock()?.assets ?? {}).map(parseCanonicalLockKey),
|
|
2079
|
+
...dependencies.map((d) => parseAssetRefLoose(d) ?? {})
|
|
2080
|
+
]
|
|
2081
|
+
);
|
|
1717
2082
|
if (missing.length > 0) {
|
|
1718
2083
|
console.warn(
|
|
1719
2084
|
`skaile: ${ref} was added without unresolved dependencies: ${missing.join(", ")}`
|
|
@@ -1734,6 +2099,7 @@ var AssetManager = class {
|
|
|
1734
2099
|
if (origin && deployed.includes(deployedRef)) opts.onLibraryOrigin(deployedRef, origin);
|
|
1735
2100
|
}
|
|
1736
2101
|
}
|
|
2102
|
+
if (presets.length > 0) opts?.onPresets?.(presets);
|
|
1737
2103
|
this.addDependencyToConfig(ref);
|
|
1738
2104
|
await this.renderDriverMcpConfig();
|
|
1739
2105
|
this.renderAgentInstances();
|
|
@@ -1802,7 +2168,7 @@ var AssetManager = class {
|
|
|
1802
2168
|
const out = [];
|
|
1803
2169
|
const seen = /* @__PURE__ */ new Set();
|
|
1804
2170
|
for (const p of await this.search(void 0, "preset")) {
|
|
1805
|
-
const members = [...p.dependencies, ...p.requires.map(
|
|
2171
|
+
const members = [...p.dependencies, ...p.requires.map(depToStr)];
|
|
1806
2172
|
if (!members.some((m) => sameAsset(memberIdentity(m), target))) continue;
|
|
1807
2173
|
const publisher = p.publisher?.replace(/^@/, "");
|
|
1808
2174
|
const presetId = { kind: "preset", name: p.name, publisher };
|
|
@@ -1988,20 +2354,103 @@ var AssetManager = class {
|
|
|
1988
2354
|
* more (e.g. its library file was deleted): the declaration and lock entry
|
|
1989
2355
|
* would otherwise be stuck behind a "not deployed" refusal.
|
|
1990
2356
|
*
|
|
2357
|
+
* Removes only `ref` itself; use {@link removeWithDependencies} to also drop the
|
|
2358
|
+
* dependencies it leaves orphaned.
|
|
2359
|
+
*
|
|
1991
2360
|
* Deliberately does NOT re-render the driver target's MCP config: the render
|
|
1992
2361
|
* step is async (the declaration resolver is), and making this synchronous
|
|
1993
2362
|
* method async would break every external caller. A removed MCP server's
|
|
1994
2363
|
* generated entry is dropped by the next {@link AssetManager.install} — see
|
|
1995
2364
|
* {@link renderMcpServerConfig}.
|
|
1996
2365
|
*
|
|
1997
|
-
* @param ref - Asset ref
|
|
2366
|
+
* @param ref - Asset ref: `kind:@publisher/name`, or the short `kind:name` /
|
|
2367
|
+
* `name` form when exactly one declared, locked or deployed asset matches it.
|
|
1998
2368
|
* @returns `true` if anything changed (files undeployed, declaration or lock
|
|
1999
2369
|
* entry removed), `false` if the asset was neither deployed nor declared.
|
|
2000
2370
|
* A `preset:` ref has no deployed files: only its declaration goes — its
|
|
2001
2371
|
* expanded items leave with the next `skaile install`.
|
|
2372
|
+
* @throws When `ref` is malformed, or a short ref matches several assets (the
|
|
2373
|
+
* message lists them).
|
|
2002
2374
|
*/
|
|
2003
2375
|
remove(ref) {
|
|
2004
|
-
const
|
|
2376
|
+
const target = this.resolveRemoveTarget(ref);
|
|
2377
|
+
return target ? this.removeResolved(target) : false;
|
|
2378
|
+
}
|
|
2379
|
+
/**
|
|
2380
|
+
* {@link remove} `ref`, then drop the dependencies that removal left orphaned:
|
|
2381
|
+
* locked assets `ref` required (directly or through one another) that
|
|
2382
|
+
* `skaile.yaml` no longer declares and no remaining locked asset requires. A
|
|
2383
|
+
* preset's items count as its requirements. They are undeployed and unlocked;
|
|
2384
|
+
* a dependency still declared or required elsewhere stays.
|
|
2385
|
+
*
|
|
2386
|
+
* @returns `changed` as {@link remove}; `pruned` the canonical refs
|
|
2387
|
+
* (`kind:@publisher/name`) of the dependencies dropped as well.
|
|
2388
|
+
*/
|
|
2389
|
+
async removeWithDependencies(ref) {
|
|
2390
|
+
const target = this.resolveRemoveTarget(ref);
|
|
2391
|
+
if (!target) return { changed: false, pruned: [] };
|
|
2392
|
+
const asked = target.publisher ? assetRefToStr({ kind: target.kind, name: target.name, publisher: target.publisher }) : `${target.kind}:${target.name}`;
|
|
2393
|
+
let entry = null;
|
|
2394
|
+
try {
|
|
2395
|
+
entry = await this.info(asked);
|
|
2396
|
+
} catch {
|
|
2397
|
+
}
|
|
2398
|
+
const requiredRefs = entry ? libraryEntryDepRefs(entry) : [];
|
|
2399
|
+
const changed = this.removeResolved(target);
|
|
2400
|
+
if (!changed || requiredRefs.length === 0) return { changed, pruned: [] };
|
|
2401
|
+
return { changed, pruned: await this.pruneOrphans(requiredRefs) };
|
|
2402
|
+
}
|
|
2403
|
+
/**
|
|
2404
|
+
* Resolve the identity {@link remove} acts on. A publisher-qualified ref is taken
|
|
2405
|
+
* as written; a short ref (`kind:name`, or just `name`) is matched on kind + name
|
|
2406
|
+
* against the declared dependencies, the lock and the deployed assets, like
|
|
2407
|
+
* `why` / `diff` do.
|
|
2408
|
+
*
|
|
2409
|
+
* @returns the identity, or `null` when a name-only ref matches nothing.
|
|
2410
|
+
* @throws On a malformed ref, or when a short ref matches more than one asset.
|
|
2411
|
+
*/
|
|
2412
|
+
resolveRemoveTarget(ref) {
|
|
2413
|
+
const trimmed = ref.trim();
|
|
2414
|
+
try {
|
|
2415
|
+
return parseAssetRef(trimmed);
|
|
2416
|
+
} catch (err) {
|
|
2417
|
+
if (!(err instanceof Error) || !err.message.startsWith("publisher required")) throw err;
|
|
2418
|
+
const colon = trimmed.indexOf(":");
|
|
2419
|
+
const rawKind = colon === -1 ? void 0 : trimmed.slice(0, colon).trim();
|
|
2420
|
+
const kind = rawKind === "mcp" ? "mcp-server" : rawKind;
|
|
2421
|
+
const hash = trimmed.indexOf("#", colon + 1);
|
|
2422
|
+
const name = trimmed.slice(colon + 1, hash === -1 ? void 0 : hash).trim();
|
|
2423
|
+
if (!name || /[@/\s]/.test(name)) throw err;
|
|
2424
|
+
const found = [];
|
|
2425
|
+
const note = (id) => {
|
|
2426
|
+
if (!id?.kind || id.name !== name || kind && id.kind !== kind) return;
|
|
2427
|
+
found.push({ kind: id.kind, name: id.name, publisher: id.publisher });
|
|
2428
|
+
};
|
|
2429
|
+
try {
|
|
2430
|
+
for (const dep of this.loadConfig().dependencies) note(memberIdentity(dep));
|
|
2431
|
+
} catch {
|
|
2432
|
+
}
|
|
2433
|
+
for (const key of Object.keys(this.tryReadLock()?.assets ?? {})) {
|
|
2434
|
+
note(parseCanonicalLockKey(key));
|
|
2435
|
+
}
|
|
2436
|
+
for (const e of this.listDeployed()) note(e);
|
|
2437
|
+
const qualified = found.filter((f) => f.publisher);
|
|
2438
|
+
const distinct = /* @__PURE__ */ new Map();
|
|
2439
|
+
for (const f of found) {
|
|
2440
|
+
if (!f.publisher && qualified.some((q) => q.kind === f.kind)) continue;
|
|
2441
|
+
distinct.set(`${f.kind}:${f.publisher ?? ""}/${f.name}`, f);
|
|
2442
|
+
}
|
|
2443
|
+
const matches = [...distinct.values()];
|
|
2444
|
+
if (matches.length > 1) {
|
|
2445
|
+
const list = matches.map((m) => m.publisher ? `${m.kind}:@${m.publisher}/${m.name}` : `${m.kind}:${m.name}`).join(", ");
|
|
2446
|
+
throw new Error(`"${ref}" matches several assets (${list}) \u2014 name one with its full ref.`);
|
|
2447
|
+
}
|
|
2448
|
+
if (matches.length === 1) return matches[0];
|
|
2449
|
+
return kind ? { kind, name } : null;
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
/** Undeploy `parsed` from every target harness and drop its declaration and lock entry. */
|
|
2453
|
+
removeResolved(parsed) {
|
|
2005
2454
|
let undeployed = false;
|
|
2006
2455
|
for (const t of this.targetHarnesses()) {
|
|
2007
2456
|
if (removeAsset(parsed.kind, parsed.name, this.deployOptsFor(t))) undeployed = true;
|
|
@@ -2019,6 +2468,38 @@ var AssetManager = class {
|
|
|
2019
2468
|
}
|
|
2020
2469
|
return changed;
|
|
2021
2470
|
}
|
|
2471
|
+
/**
|
|
2472
|
+
* Drop the locked assets among `requiredRefs` (and what they require in turn) that
|
|
2473
|
+
* nothing needs any more: not declared in `skaile.yaml`, not required by a locked
|
|
2474
|
+
* asset outside that set. Call after the requiring asset is gone.
|
|
2475
|
+
*
|
|
2476
|
+
* @returns the canonical refs of the assets dropped.
|
|
2477
|
+
*/
|
|
2478
|
+
async pruneOrphans(requiredRefs) {
|
|
2479
|
+
const lock = this.tryReadLock();
|
|
2480
|
+
if (!lock) return [];
|
|
2481
|
+
const { requires, roots, findKey } = await this.lockedGraph(lock);
|
|
2482
|
+
const closure = (seeds) => {
|
|
2483
|
+
const out = new Set(seeds);
|
|
2484
|
+
for (const node of out) for (const dep of requires.get(node) ?? []) out.add(dep);
|
|
2485
|
+
return out;
|
|
2486
|
+
};
|
|
2487
|
+
const candidates = closure(requiredRefs.map(findKey).filter((k) => !!k));
|
|
2488
|
+
const needed = closure([
|
|
2489
|
+
...roots,
|
|
2490
|
+
...Object.keys(lock.assets).filter((k) => !candidates.has(k))
|
|
2491
|
+
]);
|
|
2492
|
+
const pruned = [];
|
|
2493
|
+
for (const key of candidates) {
|
|
2494
|
+
if (needed.has(key) || !lock.assets[key]) continue;
|
|
2495
|
+
const { kind, name, publisher } = parseCanonicalLockKey(key);
|
|
2496
|
+
if (!kind || !name) continue;
|
|
2497
|
+
this.removeResolved({ kind, name, publisher });
|
|
2498
|
+
this.pruneLockEntry({ kind, name, publisher });
|
|
2499
|
+
pruned.push(publisher ? assetRefToStr({ kind, name, publisher }) : `${kind}:${name}`);
|
|
2500
|
+
}
|
|
2501
|
+
return pruned;
|
|
2502
|
+
}
|
|
2022
2503
|
/**
|
|
2023
2504
|
* Drop every lock entry matching a removed asset's identity, version-agnostic so
|
|
2024
2505
|
* a content-sha pseudo-version key is pruned too. Symmetric with {@link add}'s
|
|
@@ -2199,9 +2680,15 @@ var AssetManager = class {
|
|
|
2199
2680
|
for (const { kind, name, component: k } of tracked.values()) {
|
|
2200
2681
|
const legacy = deployedDir(k, name, "claude-code", false, this.projectDir);
|
|
2201
2682
|
if (legacy === deployedDir(k, name, this.driverTarget, false, this.projectDir)) continue;
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2683
|
+
const found = deployedPaths(k, name, "claude-code", false, this.projectDir).find((p) => {
|
|
2684
|
+
try {
|
|
2685
|
+
lstatSync(p);
|
|
2686
|
+
return true;
|
|
2687
|
+
} catch {
|
|
2688
|
+
return false;
|
|
2689
|
+
}
|
|
2690
|
+
});
|
|
2691
|
+
if (found) out.push({ kind, name, path: found });
|
|
2205
2692
|
}
|
|
2206
2693
|
return out.sort((a, b) => a.kind.localeCompare(b.kind) || a.name.localeCompare(b.name));
|
|
2207
2694
|
}
|
|
@@ -2235,6 +2722,7 @@ var AssetManager = class {
|
|
|
2235
2722
|
const dependencies = resolveSkWorkspaceConfig(this.projectDir).dependencies ?? [];
|
|
2236
2723
|
const lock = this.tryReadLock();
|
|
2237
2724
|
const lockKeys = lock ? Object.keys(lock.assets).map(parseCanonicalLockKey) : [];
|
|
2725
|
+
const presetGaps = await this.declaredPresetGaps(dependencies, lock);
|
|
2238
2726
|
let wiredMcps;
|
|
2239
2727
|
const wiredMcpNames = async () => {
|
|
2240
2728
|
if (wiredMcps === void 0) {
|
|
@@ -2257,7 +2745,7 @@ var AssetManager = class {
|
|
|
2257
2745
|
continue;
|
|
2258
2746
|
}
|
|
2259
2747
|
if (kind && parsed.kind !== kind) continue;
|
|
2260
|
-
const locked = parsed.kind === "preset" ? lock !== null : lockKeys.some(
|
|
2748
|
+
const locked = parsed.kind === "preset" ? lock !== null && !presetGaps.get(ref)?.length : lockKeys.some(
|
|
2261
2749
|
(k) => k.kind === parsed.kind && k.name === parsed.name && (!parsed.publisher || k.publisher === parsed.publisher)
|
|
2262
2750
|
);
|
|
2263
2751
|
let state;
|
|
@@ -2285,6 +2773,38 @@ var AssetManager = class {
|
|
|
2285
2773
|
}
|
|
2286
2774
|
return out;
|
|
2287
2775
|
}
|
|
2776
|
+
/**
|
|
2777
|
+
* Library-locked assets whose deployed directory lacks files the deploy writes —
|
|
2778
|
+
* a deleted `build.py` / `scripts/` helper next to an intact `SKILL.md`. The
|
|
2779
|
+
* expected set is the library entry's file set (every file under its manifest
|
|
2780
|
+
* `root:`), the same bytes the lock hashes; only presence is checked, so a
|
|
2781
|
+
* local edit never counts. An asset with no deployed directory is not listed
|
|
2782
|
+
* (`listDeclared` reports it as drift); an agent is rendered, not copied, so it
|
|
2783
|
+
* has no file mirror to compare. `skaile install` restores what is listed.
|
|
2784
|
+
*
|
|
2785
|
+
* @returns One {@link IncompleteDeploy} per affected asset; empty when healthy
|
|
2786
|
+
* or when the project has no lock.
|
|
2787
|
+
*/
|
|
2788
|
+
async incompleteDeploys() {
|
|
2789
|
+
const lock = this.tryReadLock();
|
|
2790
|
+
if (!lock) return [];
|
|
2791
|
+
const locked = Object.entries(lock.assets).filter(([, e]) => e.library !== void 0 && !e.library.installed).map(([key]) => key);
|
|
2792
|
+
if (locked.length === 0) return [];
|
|
2793
|
+
const lib = await this.resolveLibraryEntries(locked, { quiet: true });
|
|
2794
|
+
const out = [];
|
|
2795
|
+
for (const entry of lib.entries) {
|
|
2796
|
+
const component = this.installTarget(entry.kind);
|
|
2797
|
+
if (!entry.files || !component || component === "agent") continue;
|
|
2798
|
+
const dest = join(
|
|
2799
|
+
deployedBase(component, this.driverTarget, this.global, this.projectDir),
|
|
2800
|
+
entry.name
|
|
2801
|
+
);
|
|
2802
|
+
if (!existsSync(dest)) continue;
|
|
2803
|
+
const missing = entry.files.filter((rel) => !existsSync(join(dest, rel)));
|
|
2804
|
+
if (missing.length > 0) out.push({ ref: canonicalEntryRef(entry), missing });
|
|
2805
|
+
}
|
|
2806
|
+
return out;
|
|
2807
|
+
}
|
|
2288
2808
|
/**
|
|
2289
2809
|
* Per-harness reconciliation of the **global** declared deps
|
|
2290
2810
|
* (`~/.skaile/skaile.yaml`) against each global harness's deploy dir. The
|
|
@@ -2382,29 +2902,115 @@ var AssetManager = class {
|
|
|
2382
2902
|
}
|
|
2383
2903
|
return repoStatuses;
|
|
2384
2904
|
}
|
|
2905
|
+
/**
|
|
2906
|
+
* Requirement graph of the locked assets, for {@link tree} / {@link why} / removal pruning.
|
|
2907
|
+
*
|
|
2908
|
+
* The lock records no edges, so they are rebuilt from each locked asset's own
|
|
2909
|
+
* declaration (`requires`, manifest `dependencies`, a preset's items) — the same
|
|
2910
|
+
* source the install walk reads, via {@link info}. An asset that no source or
|
|
2911
|
+
* library can be found for has no known requirements. Nodes are lock keys, plus
|
|
2912
|
+
* each declared `preset:` that the lock does not carry (a preset is expanded at
|
|
2913
|
+
* install, never locked), keyed by its declared ref.
|
|
2914
|
+
*
|
|
2915
|
+
* @returns `requires` (node → the lock keys it requires), `roots` (nodes
|
|
2916
|
+
* `skaile.yaml` declares) and `findKey` (a ref → its lock key, version-agnostic).
|
|
2917
|
+
*/
|
|
2918
|
+
async lockedGraph(lock) {
|
|
2919
|
+
const locked = Object.keys(lock.assets).map((key) => ({ key, ...parseCanonicalLockKey(key) }));
|
|
2920
|
+
const findKey = (ref) => {
|
|
2921
|
+
const id = memberIdentity(ref);
|
|
2922
|
+
if (!id) return void 0;
|
|
2923
|
+
return locked.find(
|
|
2924
|
+
(l) => l.kind === id.kind && l.name === id.name && (!id.publisher || !l.publisher || l.publisher === id.publisher)
|
|
2925
|
+
)?.key;
|
|
2926
|
+
};
|
|
2927
|
+
const requires = /* @__PURE__ */ new Map();
|
|
2928
|
+
const link = async (node, ref) => {
|
|
2929
|
+
const out = [];
|
|
2930
|
+
try {
|
|
2931
|
+
const entry = await this.info(ref);
|
|
2932
|
+
for (const dep of entry ? libraryEntryDepRefs(entry) : []) {
|
|
2933
|
+
const key = findKey(dep);
|
|
2934
|
+
if (key && key !== node && !out.includes(key)) out.push(key);
|
|
2935
|
+
}
|
|
2936
|
+
} catch {
|
|
2937
|
+
}
|
|
2938
|
+
requires.set(node, out);
|
|
2939
|
+
};
|
|
2940
|
+
for (const l of locked) {
|
|
2941
|
+
await link(
|
|
2942
|
+
l.key,
|
|
2943
|
+
l.publisher ? `${l.kind}:@${l.publisher}/${l.name}` : `${l.kind}:${l.name}`
|
|
2944
|
+
);
|
|
2945
|
+
}
|
|
2946
|
+
const roots = [];
|
|
2947
|
+
let declared = [];
|
|
2948
|
+
try {
|
|
2949
|
+
declared = this.loadConfig().dependencies;
|
|
2950
|
+
} catch {
|
|
2951
|
+
}
|
|
2952
|
+
for (const dep of declared) {
|
|
2953
|
+
const key = findKey(dep);
|
|
2954
|
+
if (key) {
|
|
2955
|
+
if (!roots.includes(key)) roots.push(key);
|
|
2956
|
+
} else if (memberIdentity(dep)?.kind === "preset" && !roots.includes(dep)) {
|
|
2957
|
+
await link(dep, dep);
|
|
2958
|
+
roots.push(dep);
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
return { requires, roots, findKey };
|
|
2962
|
+
}
|
|
2385
2963
|
/**
|
|
2386
2964
|
* Build the resolved dependency tree from the lock file.
|
|
2387
2965
|
*
|
|
2966
|
+
* Required assets nest under the asset that requires them (see {@link lockedGraph});
|
|
2967
|
+
* an asset required by several parents appears under each, and a dependency cycle
|
|
2968
|
+
* is cut where it would repeat.
|
|
2969
|
+
*
|
|
2388
2970
|
* @returns Root {@link DependencyNode} with `ref === "project"` whose children
|
|
2389
|
-
* are the directly-declared
|
|
2971
|
+
* are the directly-declared assets, followed by locked assets nothing requires,
|
|
2972
|
+
* each with the assets it requires as children.
|
|
2390
2973
|
* Returns a single node with `ref === "(no lock file)"` when no lock exists.
|
|
2391
2974
|
*/
|
|
2392
|
-
tree() {
|
|
2975
|
+
async tree() {
|
|
2393
2976
|
const lock = this.tryReadLock();
|
|
2394
2977
|
if (!lock) return { ref: "(no lock file)", children: [] };
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2978
|
+
const { requires, roots } = await this.lockedGraph(lock);
|
|
2979
|
+
const required = new Set([...requires.values()].flat());
|
|
2980
|
+
const build = (ref, path2) => ({
|
|
2981
|
+
ref,
|
|
2982
|
+
children: (requires.get(ref) ?? []).filter((child) => !path2.has(child)).map((child) => build(child, /* @__PURE__ */ new Set([...path2, child])))
|
|
2983
|
+
});
|
|
2984
|
+
const shown = /* @__PURE__ */ new Set();
|
|
2985
|
+
const top = [];
|
|
2986
|
+
const addTop = (ref) => {
|
|
2987
|
+
const node = build(ref, /* @__PURE__ */ new Set([ref]));
|
|
2988
|
+
top.push(node);
|
|
2989
|
+
const walk = (n) => {
|
|
2990
|
+
shown.add(n.ref);
|
|
2991
|
+
for (const c of n.children) walk(c);
|
|
2992
|
+
};
|
|
2993
|
+
walk(node);
|
|
2398
2994
|
};
|
|
2995
|
+
const lockKeys = Object.keys(lock.assets);
|
|
2996
|
+
for (const ref of roots) addTop(ref);
|
|
2997
|
+
for (const ref of lockKeys) if (!roots.includes(ref) && !required.has(ref)) addTop(ref);
|
|
2998
|
+
for (const ref of lockKeys) if (!shown.has(ref)) addTop(ref);
|
|
2999
|
+
return { ref: "project", children: top };
|
|
2399
3000
|
}
|
|
2400
3001
|
/**
|
|
2401
|
-
* Explain why an asset is installed by tracing its dependency chain
|
|
3002
|
+
* Explain why an asset is installed by tracing its dependency chain.
|
|
3003
|
+
*
|
|
3004
|
+
* The chain is read from the requirement graph ({@link lockedGraph}): the asset,
|
|
3005
|
+
* then the asset that requires it, and so on up to a dependency `skaile.yaml`
|
|
3006
|
+
* declares (the shortest such path; cycles are not followed twice).
|
|
2402
3007
|
*
|
|
2403
3008
|
* @param ref - Asset ref in `kind:name` form.
|
|
2404
|
-
* @returns Chain of refs from the asset back to `"direct (skaile.yaml)"
|
|
2405
|
-
*
|
|
3009
|
+
* @returns Chain of refs from the asset back to `"direct (skaile.yaml)"`; an asset
|
|
3010
|
+
* no declared dependency reaches ends in `"not required by a declared dependency"`
|
|
3011
|
+
* instead. `[]` when the asset is not in the lock file.
|
|
2406
3012
|
*/
|
|
2407
|
-
why(ref) {
|
|
3013
|
+
async why(ref) {
|
|
2408
3014
|
const lock = this.tryReadLock();
|
|
2409
3015
|
if (!lock) return [];
|
|
2410
3016
|
const bare = (s) => s.includes("#") ? s.slice(0, s.indexOf("#")) : s;
|
|
@@ -2417,7 +3023,29 @@ var AssetManager = class {
|
|
|
2417
3023
|
};
|
|
2418
3024
|
const key = lock.assets[ref] ? ref : Object.keys(lock.assets).find(matchesIdentity);
|
|
2419
3025
|
if (!key) return [];
|
|
2420
|
-
|
|
3026
|
+
const { requires, roots } = await this.lockedGraph(lock);
|
|
3027
|
+
if (roots.includes(key)) return [key, "direct (skaile.yaml)"];
|
|
3028
|
+
const requirers = /* @__PURE__ */ new Map();
|
|
3029
|
+
for (const [node, deps] of requires) {
|
|
3030
|
+
for (const dep of deps) requirers.set(dep, [...requirers.get(dep) ?? [], node]);
|
|
3031
|
+
}
|
|
3032
|
+
const child = /* @__PURE__ */ new Map();
|
|
3033
|
+
const seen = /* @__PURE__ */ new Set([key]);
|
|
3034
|
+
const queue = [key];
|
|
3035
|
+
for (let node = queue.shift(); node !== void 0; node = queue.shift()) {
|
|
3036
|
+
for (const parent of requirers.get(node) ?? []) {
|
|
3037
|
+
if (seen.has(parent)) continue;
|
|
3038
|
+
seen.add(parent);
|
|
3039
|
+
child.set(parent, node);
|
|
3040
|
+
if (roots.includes(parent)) {
|
|
3041
|
+
const chain = [];
|
|
3042
|
+
for (let c = parent; c !== void 0; c = child.get(c)) chain.push(c);
|
|
3043
|
+
return [...chain.reverse(), "direct (skaile.yaml)"];
|
|
3044
|
+
}
|
|
3045
|
+
queue.push(parent);
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
return [key, "not required by a declared dependency"];
|
|
2421
3049
|
}
|
|
2422
3050
|
/**
|
|
2423
3051
|
* List installed assets that have a newer upstream available.
|
|
@@ -2431,13 +3059,16 @@ var AssetManager = class {
|
|
|
2431
3059
|
* than the locked one (`latestVersion`, `library` set), or the same version with
|
|
2432
3060
|
* different bytes (`contentChanged`). `behind` is 0. An unregistered library is a
|
|
2433
3061
|
* `problem` row.
|
|
3062
|
+
* - **Lock gaps** — every {@link AssetManager.lockGaps} gap (a declared dependency or a
|
|
3063
|
+
* deployed asset's `requires` with no lock entry, a lock that contradicts a
|
|
3064
|
+
* `skaile.yaml` pin) as a `problem` row, so `outdated` agrees with `check`.
|
|
2434
3065
|
*
|
|
2435
3066
|
* @returns Array of {@link OutdatedEntry} objects.
|
|
2436
3067
|
*/
|
|
2437
3068
|
async outdated() {
|
|
2438
3069
|
const { repositories } = this.loadConfig();
|
|
2439
3070
|
const lock = this.tryReadLock();
|
|
2440
|
-
if (!lock) return [];
|
|
3071
|
+
if (!lock) return this.addLockGapRows([]);
|
|
2441
3072
|
const result = [];
|
|
2442
3073
|
const reported = /* @__PURE__ */ new Set();
|
|
2443
3074
|
const commitCounts = /* @__PURE__ */ new Map();
|
|
@@ -2479,6 +3110,9 @@ var AssetManager = class {
|
|
|
2479
3110
|
if (!publisher || !kind || !name) continue;
|
|
2480
3111
|
const libPath = this.libraryPath(origin.name, snap);
|
|
2481
3112
|
if (!libPath) {
|
|
3113
|
+
const canonical = `${kind}:@${publisher}/${name}`;
|
|
3114
|
+
const heldElsewhere = (await this.resolveLibraryEntries([canonical], { quiet: true })).resolved.size > 0;
|
|
3115
|
+
const fix = heldElsewhere ? void 0 : (await this.unresolvedFixes([canonical])).get(canonical) ?? unregisteredLibraryFix(origin.name, canonical);
|
|
2482
3116
|
result.push({
|
|
2483
3117
|
kind,
|
|
2484
3118
|
name,
|
|
@@ -2486,7 +3120,12 @@ var AssetManager = class {
|
|
|
2486
3120
|
currentVersion: origin.version,
|
|
2487
3121
|
behind: 0,
|
|
2488
3122
|
library: origin.name,
|
|
2489
|
-
|
|
3123
|
+
...fix === void 0 ? {
|
|
3124
|
+
problem: `library "${origin.name}" is not registered (renamed?) \u2014 run \`skaile install\` to re-lock it against the library that holds it now`
|
|
3125
|
+
} : {
|
|
3126
|
+
problem: `library "${origin.name}" is not registered (renamed or removed?) \u2014 ${fix}`,
|
|
3127
|
+
manualFix: true
|
|
3128
|
+
}
|
|
2490
3129
|
});
|
|
2491
3130
|
reported.add(ref);
|
|
2492
3131
|
continue;
|
|
@@ -2550,7 +3189,30 @@ var AssetManager = class {
|
|
|
2550
3189
|
problem: "deployed copy missing"
|
|
2551
3190
|
});
|
|
2552
3191
|
}
|
|
2553
|
-
return result;
|
|
3192
|
+
return this.addLockGapRows(result);
|
|
3193
|
+
}
|
|
3194
|
+
/**
|
|
3195
|
+
* Append one `problem` row per {@link AssetManager.lockGaps} gap whose asset is not
|
|
3196
|
+
* listed yet, so `outdated` reports the same set `check` and `install --locked` fail on.
|
|
3197
|
+
*/
|
|
3198
|
+
async addLockGapRows(rows) {
|
|
3199
|
+
const listed = new Set(rows.map((r) => `${r.kind}:${r.name}`));
|
|
3200
|
+
for (const gap of await this.lockGaps()) {
|
|
3201
|
+
const parsed = parseRefTolerant(gap.ref);
|
|
3202
|
+
const id = parsed ? `${parsed.kind}:${parsed.name}` : gap.ref;
|
|
3203
|
+
if (listed.has(id)) continue;
|
|
3204
|
+
listed.add(id);
|
|
3205
|
+
rows.push({
|
|
3206
|
+
kind: parsed?.kind ?? "",
|
|
3207
|
+
name: parsed?.name ?? gap.ref,
|
|
3208
|
+
publisher: parsed?.publisher ?? "",
|
|
3209
|
+
currentVersion: "",
|
|
3210
|
+
behind: 0,
|
|
3211
|
+
problem: gap.reason,
|
|
3212
|
+
...gap.manualFix ? { manualFix: true } : {}
|
|
3213
|
+
});
|
|
3214
|
+
}
|
|
3215
|
+
return rows;
|
|
2554
3216
|
}
|
|
2555
3217
|
/**
|
|
2556
3218
|
* Produce a unified diff from the deployed asset to its catalog source: `-` lines
|
|
@@ -2578,10 +3240,20 @@ var AssetManager = class {
|
|
|
2578
3240
|
parsed.name
|
|
2579
3241
|
);
|
|
2580
3242
|
if (!existsSync(deployedPath)) return { status: "not-deployed" };
|
|
2581
|
-
const
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
3243
|
+
const pairs = entry.files ? entry.files.map((rel) => [join(deployedPath, rel), join(dirname(entry.source), rel)]) : [[deployedPath, entry.source]];
|
|
3244
|
+
const diffs = [];
|
|
3245
|
+
for (const [from, to] of pairs) {
|
|
3246
|
+
const r = spawnSync("diff", [entry.files ? "-uN" : "-ruN", from, to], {
|
|
3247
|
+
encoding: "utf8"
|
|
3248
|
+
});
|
|
3249
|
+
if (r.status === 1) diffs.push(r.stdout);
|
|
3250
|
+
else if (r.status !== 0) {
|
|
3251
|
+
throw new Error(
|
|
3252
|
+
`diff failed for ${ref}: ${r.stderr || r.error?.message || "unknown error"}`
|
|
3253
|
+
);
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
return diffs.length > 0 ? { status: "differs", diff: diffs.join("") } : { status: "identical" };
|
|
2585
3257
|
}
|
|
2586
3258
|
// ── Lock ───────────────────────────────────────────────────────────────
|
|
2587
3259
|
/**
|
|
@@ -2602,7 +3274,8 @@ var AssetManager = class {
|
|
|
2602
3274
|
const { resolved, overridesApplied, lib } = await this.resolveLibraryFirst(dependencies, {
|
|
2603
3275
|
provenanceIndex,
|
|
2604
3276
|
overrides,
|
|
2605
|
-
stores
|
|
3277
|
+
stores,
|
|
3278
|
+
declaredRefs: dependencies
|
|
2606
3279
|
});
|
|
2607
3280
|
const libraryLock = await this.libraryLockEntries(lib);
|
|
2608
3281
|
const lockData = buildLockFile(resolved, overridesApplied, libraryLock);
|
|
@@ -2709,7 +3382,7 @@ var AssetManager = class {
|
|
|
2709
3382
|
* @returns Array of {@link DepIssue} objects. An empty array means the workspace is healthy.
|
|
2710
3383
|
*/
|
|
2711
3384
|
async doctor() {
|
|
2712
|
-
const { repositories } = this.loadConfig();
|
|
3385
|
+
const { repositories, dependencies } = this.loadConfig();
|
|
2713
3386
|
const deployed = this.listDeployed();
|
|
2714
3387
|
const issues = [];
|
|
2715
3388
|
const lock = this.tryReadLock();
|
|
@@ -2725,20 +3398,23 @@ var AssetManager = class {
|
|
|
2725
3398
|
);
|
|
2726
3399
|
if (!full) {
|
|
2727
3400
|
if (publisher) {
|
|
3401
|
+
const canonical = `${entry.kind}:@${publisher}/${entry.name}`;
|
|
3402
|
+
const fix = (await this.unresolvedFixes([canonical])).get(canonical);
|
|
2728
3403
|
issues.push({
|
|
2729
3404
|
assetKind: entry.kind,
|
|
2730
3405
|
assetName: entry.name,
|
|
2731
3406
|
depKind: entry.kind,
|
|
2732
3407
|
depName: entry.name,
|
|
2733
3408
|
inRepos: false,
|
|
2734
|
-
unresolved: true
|
|
3409
|
+
unresolved: true,
|
|
3410
|
+
...fix ? { fix } : {}
|
|
2735
3411
|
});
|
|
2736
3412
|
}
|
|
2737
3413
|
continue;
|
|
2738
3414
|
}
|
|
2739
3415
|
const gaps = [];
|
|
2740
3416
|
for (const req of full.requires) {
|
|
2741
|
-
const dep = memberIdentity(
|
|
3417
|
+
const dep = memberIdentity(depToStr(req));
|
|
2742
3418
|
if (!dep) continue;
|
|
2743
3419
|
const depComponent = this.installTarget(dep.kind);
|
|
2744
3420
|
if (depComponent && !isDeployed(depComponent, dep.name, this.driverTarget, this.global, this.projectDir)) {
|
|
@@ -2749,18 +3425,191 @@ var AssetManager = class {
|
|
|
2749
3425
|
assetKind: entry.kind,
|
|
2750
3426
|
assetName: entry.name,
|
|
2751
3427
|
depKind: req.kind,
|
|
2752
|
-
depName: req.name,
|
|
3428
|
+
depName: req.publisher ? `@${req.publisher}/${req.name}` : req.name,
|
|
2753
3429
|
inRepos
|
|
2754
3430
|
};
|
|
2755
3431
|
issues.push(issue);
|
|
2756
|
-
if (!inRepos) gaps.push({ issue, ref:
|
|
3432
|
+
if (!inRepos) gaps.push({ issue, ref: depToStr(req) });
|
|
2757
3433
|
}
|
|
2758
3434
|
}
|
|
2759
3435
|
const inLibrary = await this.resolveLibraryEntries(gaps.map((g) => g.ref));
|
|
2760
3436
|
for (const g of gaps) g.issue.inRepos = inLibrary.resolved.has(g.ref);
|
|
2761
3437
|
}
|
|
3438
|
+
for (const [presetRef, gaps] of await this.declaredPresetGaps(dependencies, lock)) {
|
|
3439
|
+
const preset = parseRefTolerant(presetRef);
|
|
3440
|
+
if (!preset) continue;
|
|
3441
|
+
for (const g of gaps) {
|
|
3442
|
+
const item = parseRefTolerant(g.ref);
|
|
3443
|
+
if (!item) continue;
|
|
3444
|
+
issues.push({
|
|
3445
|
+
assetKind: "preset",
|
|
3446
|
+
assetName: preset.name,
|
|
3447
|
+
depKind: item.kind,
|
|
3448
|
+
depName: item.publisher ? `@${item.publisher}/${item.name}` : item.name,
|
|
3449
|
+
inRepos: g.resolvable
|
|
3450
|
+
});
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
2762
3453
|
return issues;
|
|
2763
3454
|
}
|
|
3455
|
+
/**
|
|
3456
|
+
* Everything the lock does not cover or contradicts, in one list: the set
|
|
3457
|
+
* `skaile check`, `skaile install --locked` and `skaile outdated` all report.
|
|
3458
|
+
*
|
|
3459
|
+
* - `declared` — a `skaile.yaml` dependency with no lock entry (library or source gone,
|
|
3460
|
+
* unresolvable ref, never installed);
|
|
3461
|
+
* - `invalid` — a `dependencies:` entry that is not a parseable ref;
|
|
3462
|
+
* - `drift` — declared + locked but its deployed files are missing;
|
|
3463
|
+
* - `pin` — a declared `#pin` that no lock entry for that asset satisfies;
|
|
3464
|
+
* - `requires` — a deployed asset's `requires` that is not deployed (so not locked either);
|
|
3465
|
+
* - `unresolved` — a lock-managed asset that no source or library holds any more.
|
|
3466
|
+
*
|
|
3467
|
+
* Project mode only: a global manager (`global: true`) returns `[]`. A project without
|
|
3468
|
+
* `skaile.yaml` has no declared set, so only the `requires` / `unresolved` gaps of
|
|
3469
|
+
* deployed assets can appear.
|
|
3470
|
+
*
|
|
3471
|
+
* @returns One {@link LockGap} per gap; empty when the lock covers everything declared.
|
|
3472
|
+
*/
|
|
3473
|
+
async lockGaps() {
|
|
3474
|
+
if (this.global) return [];
|
|
3475
|
+
const gaps = [];
|
|
3476
|
+
const issues = await this.doctor();
|
|
3477
|
+
for (const i of issues) {
|
|
3478
|
+
if (i.unresolved) {
|
|
3479
|
+
const ref = `${i.assetKind}:${i.assetName}`;
|
|
3480
|
+
const reason = `is locked but no source or library provides it any more \u2014 its requirements cannot be checked${i.fix ? ` (${i.fix})` : ""}`;
|
|
3481
|
+
gaps.push({
|
|
3482
|
+
type: "unresolved",
|
|
3483
|
+
ref,
|
|
3484
|
+
reason,
|
|
3485
|
+
message: `${ref} ${reason}`,
|
|
3486
|
+
...i.fix ? { manualFix: true } : {}
|
|
3487
|
+
});
|
|
3488
|
+
continue;
|
|
3489
|
+
}
|
|
3490
|
+
const asset = `${i.assetKind}:${i.assetName}`;
|
|
3491
|
+
const dep = `${i.depKind}:${i.depName}`;
|
|
3492
|
+
const fix = i.inRepos ? "fixable" : "not found";
|
|
3493
|
+
gaps.push({
|
|
3494
|
+
type: "requires",
|
|
3495
|
+
ref: dep,
|
|
3496
|
+
reason: `is required by ${asset} but neither deployed nor locked (${fix})`,
|
|
3497
|
+
message: `${asset} requires ${dep} (${fix})`
|
|
3498
|
+
});
|
|
3499
|
+
}
|
|
3500
|
+
let declared = [];
|
|
3501
|
+
try {
|
|
3502
|
+
declared = await this.listDeclared();
|
|
3503
|
+
} catch {
|
|
3504
|
+
return gaps;
|
|
3505
|
+
}
|
|
3506
|
+
const unlocked = declared.filter((d) => d.state === "declared").map((d) => d.ref);
|
|
3507
|
+
const hints = await this.publisherChangeHints(unlocked);
|
|
3508
|
+
const lockKeys = Object.keys(this.tryReadLock()?.assets ?? {});
|
|
3509
|
+
for (const d of declared) {
|
|
3510
|
+
if (d.kind === "preset" && issues.some((i) => i.assetKind === "preset" && i.assetName === d.name)) {
|
|
3511
|
+
continue;
|
|
3512
|
+
}
|
|
3513
|
+
let gap;
|
|
3514
|
+
if (d.state === "invalid") {
|
|
3515
|
+
gap = {
|
|
3516
|
+
type: "invalid",
|
|
3517
|
+
reason: "is not a valid asset ref (expected kind:@<publisher>/<name>#<version>)"
|
|
3518
|
+
};
|
|
3519
|
+
} else if (d.state === "drift") {
|
|
3520
|
+
gap = {
|
|
3521
|
+
type: "drift",
|
|
3522
|
+
reason: "is declared and locked but not materialized \u2014 run `skaile install`"
|
|
3523
|
+
};
|
|
3524
|
+
} else if (d.state === "declared") {
|
|
3525
|
+
const hint = hints[d.ref];
|
|
3526
|
+
gap = hint ? { type: "declared", reason: `is declared but does not resolve${hint}`, manualFix: true } : {
|
|
3527
|
+
type: "declared",
|
|
3528
|
+
reason: "is declared but does not resolve \u2014 run `skaile install`"
|
|
3529
|
+
};
|
|
3530
|
+
} else {
|
|
3531
|
+
const want = parseAssetRef(d.ref);
|
|
3532
|
+
if (!want.pin || want.kind === "preset") continue;
|
|
3533
|
+
const held = lockKeys.map((key) => ({ key, id: parseCanonicalLockKey(key) })).filter(
|
|
3534
|
+
({ id }) => id.kind === want.kind && id.name === want.name && (!want.publisher || id.publisher === want.publisher)
|
|
3535
|
+
);
|
|
3536
|
+
if (held.length > 0 && !held.some(({ id }) => !id.version || matchPin(want.pin, id.version))) {
|
|
3537
|
+
gap = {
|
|
3538
|
+
type: "pin",
|
|
3539
|
+
reason: `is pinned in skaile.yaml but the lock holds ${held.map((h) => h.key).join(", ")} \u2014 run \`skaile install\``
|
|
3540
|
+
};
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
if (gap) gaps.push({ ...gap, ref: d.ref, message: `${d.ref} ${gap.reason}` });
|
|
3544
|
+
}
|
|
3545
|
+
return gaps;
|
|
3546
|
+
}
|
|
3547
|
+
/**
|
|
3548
|
+
* Items of each declared `preset:` dependency that the lock does not cover.
|
|
3549
|
+
*
|
|
3550
|
+
* A preset is never locked itself; the lock lists only its expanded items, so an
|
|
3551
|
+
* item missing from the lock never resolved (or was declared after the last
|
|
3552
|
+
* install). Presets are read from the local sources and libraries (nested presets
|
|
3553
|
+
* followed); one only a store holds cannot be read without the network and
|
|
3554
|
+
* reports no gaps. Without a lock nothing is reported: `list` and `check` already
|
|
3555
|
+
* show a never-installed declaration as `declared`.
|
|
3556
|
+
*
|
|
3557
|
+
* @param declared - The `dependencies:` refs as written in `skaile.yaml`.
|
|
3558
|
+
* @param lock - The current lock, or `null` when none exists.
|
|
3559
|
+
* @returns Declared preset ref → its uncovered items; `resolvable` is `true` when a
|
|
3560
|
+
* local source or library offers the item (so `skaile install` can fix it).
|
|
3561
|
+
* Presets without gaps are absent.
|
|
3562
|
+
*/
|
|
3563
|
+
async declaredPresetGaps(declared, lock) {
|
|
3564
|
+
const gaps = /* @__PURE__ */ new Map();
|
|
3565
|
+
if (!lock) return gaps;
|
|
3566
|
+
const presetRefs = declared.filter((d) => parseRefTolerant(d)?.kind === "preset");
|
|
3567
|
+
if (presetRefs.length === 0) return gaps;
|
|
3568
|
+
const { repositories } = this.loadConfig();
|
|
3569
|
+
const provenanceIndex = await buildProvenanceIndex(this.buildClones(repositories), {
|
|
3570
|
+
projectDir: this.projectDir,
|
|
3571
|
+
knownKinds: this.knownKinds
|
|
3572
|
+
});
|
|
3573
|
+
const lockKeys = Object.keys(lock.assets).map(parseCanonicalLockKey);
|
|
3574
|
+
const sourceCandidate = (ref) => {
|
|
3575
|
+
const p = parseRefTolerant(ref);
|
|
3576
|
+
if (!p?.publisher) return void 0;
|
|
3577
|
+
const hash = ref.indexOf("#");
|
|
3578
|
+
const pin = p.pin ?? (hash >= 0 ? ref.slice(hash + 1) : void 0);
|
|
3579
|
+
return (provenanceIndex.get(`${p.publisher}/${p.kind}:${p.name}`) ?? []).filter((c) => matchPin(pin, c.version)).sort((a, b) => {
|
|
3580
|
+
const va = coerceVersion(a.version);
|
|
3581
|
+
const vb = coerceVersion(b.version);
|
|
3582
|
+
return gt(va, vb) ? -1 : gt(vb, va) ? 1 : 0;
|
|
3583
|
+
})[0];
|
|
3584
|
+
};
|
|
3585
|
+
const itemsOf = async (ref) => {
|
|
3586
|
+
const src = sourceCandidate(ref);
|
|
3587
|
+
if (src) return (src.deps ?? []).map((d) => qualifyDepRef(d, src.publisher));
|
|
3588
|
+
const entry = (await this.resolveLibraryEntries([ref], { quiet: true })).entries[0];
|
|
3589
|
+
return entry ? libraryEntryDepRefs(entry) : null;
|
|
3590
|
+
};
|
|
3591
|
+
const resolvableLocally = async (ref) => sourceCandidate(ref) !== void 0 || (await this.resolveLibraryEntries([ref], { quiet: true })).resolved.has(ref);
|
|
3592
|
+
const isLocked = (item) => lockKeys.some(
|
|
3593
|
+
(k) => k.kind === item.kind && k.name === item.name && (!item.publisher || k.publisher === item.publisher)
|
|
3594
|
+
);
|
|
3595
|
+
for (const presetRef of presetRefs) {
|
|
3596
|
+
const out = [];
|
|
3597
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3598
|
+
const walk = async (ref) => {
|
|
3599
|
+
if (visited.has(ref)) return;
|
|
3600
|
+
visited.add(ref);
|
|
3601
|
+
for (const item of await itemsOf(ref) ?? []) {
|
|
3602
|
+
const p = parseRefTolerant(item);
|
|
3603
|
+
if (!p) continue;
|
|
3604
|
+
if (p.kind === "preset") await walk(item);
|
|
3605
|
+
else if (!isLocked(p)) out.push({ ref: item, resolvable: await resolvableLocally(item) });
|
|
3606
|
+
}
|
|
3607
|
+
};
|
|
3608
|
+
await walk(presetRef);
|
|
3609
|
+
if (out.length > 0) gaps.set(presetRef, out);
|
|
3610
|
+
}
|
|
3611
|
+
return gaps;
|
|
3612
|
+
}
|
|
2764
3613
|
// ── Scaffold ───────────────────────────────────────────────────────────
|
|
2765
3614
|
/**
|
|
2766
3615
|
* Create a minimal asset scaffold directory (delegates to {@link createScaffold}).
|
|
@@ -2829,15 +3678,21 @@ var AssetManager = class {
|
|
|
2829
3678
|
const { kind, name } = parseCanonicalLockKey(ref);
|
|
2830
3679
|
const component = kind ? this.installTarget(kind) : void 0;
|
|
2831
3680
|
if (!kind || !name || !component) continue;
|
|
2832
|
-
const dest
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
3681
|
+
for (const dest of deployedPaths(
|
|
3682
|
+
component,
|
|
3683
|
+
name,
|
|
3684
|
+
this.driverTarget,
|
|
3685
|
+
this.global,
|
|
3686
|
+
this.projectDir
|
|
3687
|
+
)) {
|
|
3688
|
+
try {
|
|
3689
|
+
const stat = lstatSync(dest);
|
|
3690
|
+
if (stat.isSymbolicLink()) unlinkSync(dest);
|
|
3691
|
+
else rmSync(dest, { recursive: true, force: true });
|
|
3692
|
+
} catch {
|
|
3693
|
+
}
|
|
2840
3694
|
}
|
|
3695
|
+
removed.push(ref);
|
|
2841
3696
|
}
|
|
2842
3697
|
return removed;
|
|
2843
3698
|
}
|
|
@@ -2973,5 +3828,5 @@ var AssetManager = class {
|
|
|
2973
3828
|
};
|
|
2974
3829
|
|
|
2975
3830
|
export { AssetManager, FACTORY_SOURCE_URL, MissingManifestError, installAgentInstances, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, renderMcpServerConfig, softDepName };
|
|
2976
|
-
//# sourceMappingURL=chunk-
|
|
2977
|
-
//# sourceMappingURL=chunk-
|
|
3831
|
+
//# sourceMappingURL=chunk-H7QUDDKH.js.map
|
|
3832
|
+
//# sourceMappingURL=chunk-H7QUDDKH.js.map
|