@skaile/workspaces 5.8.0 → 5.10.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 +102 -0
- package/dist/app-sdk/index.js +1 -1
- package/dist/{asset-feeds-EYRZR4K5.js → asset-feeds-ELEBTNUS.js} +18 -18
- package/dist/{asset-feeds-EYRZR4K5.js.map → asset-feeds-ELEBTNUS.js.map} +1 -1
- package/dist/asset-manager/catalog-deployer.js +8 -8
- package/dist/asset-manager/index.js +14 -14
- package/dist/asset-manager/installer.js +10 -10
- package/dist/asset-manager/renderers.js +9 -9
- package/dist/asset-manager/src/index.d.ts +300 -36
- package/dist/asset-manager/src/index.d.ts.map +1 -1
- package/dist/asset-manager/src/install-agent.d.ts +3 -1
- package/dist/asset-manager/src/install-agent.d.ts.map +1 -1
- package/dist/asset-manager/src/install-instances.d.ts +31 -1
- package/dist/asset-manager/src/install-instances.d.ts.map +1 -1
- package/dist/asset-manager/src/installer.d.ts +20 -0
- package/dist/asset-manager/src/installer.d.ts.map +1 -1
- package/dist/asset-manager/src/renderers.d.ts +4 -5
- package/dist/asset-manager/src/renderers.d.ts.map +1 -1
- package/dist/bridge/drivers/claude-sdk.js +170 -17
- package/dist/bridge/drivers/claude-sdk.js.map +1 -1
- package/dist/bridge/drivers/codex.js +13 -11
- package/dist/bridge/drivers/codex.js.map +1 -1
- package/dist/bridge/drivers/continue.js +10 -10
- package/dist/bridge/drivers/echo.js +4 -4
- package/dist/bridge/drivers/gemini.js +7 -7
- package/dist/bridge/drivers/goose.js +10 -10
- package/dist/bridge/drivers/omp.js +7 -5
- package/dist/bridge/drivers/omp.js.map +1 -1
- package/dist/bridge/drivers/opencode.js +10 -10
- package/dist/bridge/drivers/qwen.js +7 -7
- package/dist/bridge/index.js +14 -14
- package/dist/bridge/src/codex/managed-driver.d.ts.map +1 -1
- package/dist/bridge/src/drivers/claude-sdk.d.ts +31 -1
- package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
- package/dist/bridge/src/drivers/claude-tool-allowlist.d.ts +43 -0
- package/dist/bridge/src/drivers/claude-tool-allowlist.d.ts.map +1 -0
- package/dist/bridge/src/drivers/omp.d.ts.map +1 -1
- package/dist/bridge/src/types.d.ts +20 -1
- package/dist/bridge/src/types.d.ts.map +1 -1
- package/dist/{chunk-36AFURKZ.js → chunk-2FMEGSBN.js} +38 -11
- package/dist/chunk-2FMEGSBN.js.map +1 -0
- package/dist/{chunk-GCICGXDD.js → chunk-2H73V6XR.js} +3 -3
- package/dist/{chunk-GCICGXDD.js.map → chunk-2H73V6XR.js.map} +1 -1
- package/dist/{chunk-H7QUDDKH.js → chunk-2JMLDZLP.js} +1069 -182
- package/dist/chunk-2JMLDZLP.js.map +1 -0
- package/dist/{chunk-B6GIW55K.js → chunk-32XKCNCL.js} +6 -3
- package/dist/chunk-32XKCNCL.js.map +1 -0
- package/dist/{chunk-4MQS7CAF.js → chunk-3BEY4WK3.js} +371 -175
- package/dist/chunk-3BEY4WK3.js.map +1 -0
- package/dist/{chunk-SH5D7U7N.js → chunk-3KHYGOEY.js} +3 -3
- package/dist/{chunk-SH5D7U7N.js.map → chunk-3KHYGOEY.js.map} +1 -1
- package/dist/{chunk-CGT45WN7.js → chunk-3MKPZZRE.js} +3 -3
- package/dist/{chunk-CGT45WN7.js.map → chunk-3MKPZZRE.js.map} +1 -1
- package/dist/{chunk-QVNRCDTV.js → chunk-4OV5DSBB.js} +4 -4
- package/dist/chunk-4OV5DSBB.js.map +1 -0
- package/dist/{chunk-GXXFLBUQ.js → chunk-4P3KTUZH.js} +33 -33
- package/dist/chunk-4P3KTUZH.js.map +1 -0
- package/dist/{chunk-I6NLLJHZ.js → chunk-5QI2JYJC.js} +2 -2
- package/dist/{chunk-I6NLLJHZ.js.map → chunk-5QI2JYJC.js.map} +1 -1
- package/dist/{chunk-EF7NPDDU.js → chunk-6HHE63CO.js} +31 -17
- package/dist/chunk-6HHE63CO.js.map +1 -0
- package/dist/{chunk-FTJJO3EM.js → chunk-7CR6HT2X.js} +10 -10
- package/dist/{chunk-FTJJO3EM.js.map → chunk-7CR6HT2X.js.map} +1 -1
- package/dist/{chunk-FZNG4V4J.js → chunk-7I5VRVDP.js} +3 -3
- package/dist/{chunk-FZNG4V4J.js.map → chunk-7I5VRVDP.js.map} +1 -1
- package/dist/{chunk-HG34RNTK.js → chunk-CLTHEKHR.js} +10 -9
- package/dist/chunk-CLTHEKHR.js.map +1 -0
- package/dist/{chunk-UMVKJM4Q.js → chunk-DALV4HHP.js} +18 -3
- package/dist/chunk-DALV4HHP.js.map +1 -0
- package/dist/{chunk-F3RDEH5U.js → chunk-F4NJDSR7.js} +6 -5
- package/dist/chunk-F4NJDSR7.js.map +1 -0
- package/dist/{chunk-LSXHED6I.js → chunk-FRPBSUFH.js} +6 -6
- package/dist/{chunk-LSXHED6I.js.map → chunk-FRPBSUFH.js.map} +1 -1
- package/dist/{chunk-W5DWWE4Y.js → chunk-G54USEUP.js} +4 -4
- package/dist/{chunk-W5DWWE4Y.js.map → chunk-G54USEUP.js.map} +1 -1
- package/dist/{chunk-Y7QA2OLD.js → chunk-GEWAIQZ5.js} +24 -20
- package/dist/chunk-GEWAIQZ5.js.map +1 -0
- package/dist/{chunk-GB7WDMH2.js → chunk-GFCXNFTW.js} +4 -4
- package/dist/{chunk-GB7WDMH2.js.map → chunk-GFCXNFTW.js.map} +1 -1
- package/dist/{chunk-AWQYXZVG.js → chunk-HJ5MCB3L.js} +28 -4
- package/dist/chunk-HJ5MCB3L.js.map +1 -0
- package/dist/{chunk-2LWYNQK7.js → chunk-HOHUEKES.js} +3 -3
- package/dist/{chunk-2LWYNQK7.js.map → chunk-HOHUEKES.js.map} +1 -1
- package/dist/{chunk-ZKSJMZKD.js → chunk-IJHH4DSW.js} +8 -8
- package/dist/{chunk-ZKSJMZKD.js.map → chunk-IJHH4DSW.js.map} +1 -1
- package/dist/{chunk-BTE2V4IW.js → chunk-IXWODEED.js} +40 -7
- package/dist/chunk-IXWODEED.js.map +1 -0
- package/dist/{chunk-OFBIWVCR.js → chunk-JFXQEVLF.js} +3 -3
- package/dist/{chunk-OFBIWVCR.js.map → chunk-JFXQEVLF.js.map} +1 -1
- package/dist/{chunk-JAKOMFC6.js → chunk-JZCSNEHK.js} +77 -31
- package/dist/chunk-JZCSNEHK.js.map +1 -0
- package/dist/{chunk-CKQEIY43.js → chunk-MVQ3Q2HM.js} +4 -4
- package/dist/{chunk-CKQEIY43.js.map → chunk-MVQ3Q2HM.js.map} +1 -1
- package/dist/{chunk-LEMHVDET.js → chunk-NRDSGLCQ.js} +188 -33
- package/dist/chunk-NRDSGLCQ.js.map +1 -0
- package/dist/{chunk-V2DXZYBB.js → chunk-NWDSLXOX.js} +3 -3
- package/dist/{chunk-V2DXZYBB.js.map → chunk-NWDSLXOX.js.map} +1 -1
- package/dist/{chunk-6GRX5L6A.js → chunk-OBVJ7RPW.js} +4 -4
- package/dist/{chunk-6GRX5L6A.js.map → chunk-OBVJ7RPW.js.map} +1 -1
- package/dist/{chunk-PTSGWKHR.js → chunk-OOWHXOK6.js} +4 -4
- package/dist/{chunk-PTSGWKHR.js.map → chunk-OOWHXOK6.js.map} +1 -1
- package/dist/{chunk-YSHVQGUS.js → chunk-PE36IF2D.js} +119 -30
- package/dist/chunk-PE36IF2D.js.map +1 -0
- package/dist/{chunk-S53LOR7B.js → chunk-QG3HOJEK.js} +3 -3
- package/dist/{chunk-S53LOR7B.js.map → chunk-QG3HOJEK.js.map} +1 -1
- package/dist/{chunk-2FRUUDZY.js → chunk-SBFW3CJH.js} +5 -5
- package/dist/{chunk-2FRUUDZY.js.map → chunk-SBFW3CJH.js.map} +1 -1
- package/dist/{chunk-UAROCOXF.js → chunk-SX5U422E.js} +3 -3
- package/dist/{chunk-UAROCOXF.js.map → chunk-SX5U422E.js.map} +1 -1
- package/dist/{chunk-QOP6KDFR.js → chunk-TH4CTXHX.js} +6 -6
- package/dist/{chunk-QOP6KDFR.js.map → chunk-TH4CTXHX.js.map} +1 -1
- package/dist/{chunk-F2EKONM7.js → chunk-TRSQP3JD.js} +3 -3
- package/dist/{chunk-F2EKONM7.js.map → chunk-TRSQP3JD.js.map} +1 -1
- package/dist/{chunk-FVJK4QWM.js → chunk-V5TZH4GF.js} +4 -4
- package/dist/{chunk-FVJK4QWM.js.map → chunk-V5TZH4GF.js.map} +1 -1
- package/dist/{chunk-HYDRDNKN.js → chunk-V7PQZOBR.js} +5 -5
- package/dist/{chunk-HYDRDNKN.js.map → chunk-V7PQZOBR.js.map} +1 -1
- package/dist/{chunk-IONAUNWB.js → chunk-VLXDXRRX.js} +3 -3
- package/dist/{chunk-IONAUNWB.js.map → chunk-VLXDXRRX.js.map} +1 -1
- package/dist/{chunk-CIFS5K6T.js → chunk-VMKMFS2Q.js} +28 -7
- package/dist/chunk-VMKMFS2Q.js.map +1 -0
- package/dist/{chunk-Y4N2NUZD.js → chunk-WBYDAL6X.js} +4 -4
- package/dist/{chunk-Y4N2NUZD.js.map → chunk-WBYDAL6X.js.map} +1 -1
- package/dist/{chunk-WTQ3TATB.js → chunk-X4BAYGMT.js} +3 -3
- package/dist/{chunk-WTQ3TATB.js.map → chunk-X4BAYGMT.js.map} +1 -1
- package/dist/{chunk-NPLPCRW5.js → chunk-XCNK4UE5.js} +5 -5
- package/dist/{chunk-NPLPCRW5.js.map → chunk-XCNK4UE5.js.map} +1 -1
- package/dist/{chunk-OJ4N4T4H.js → chunk-XDVR7QIT.js} +20 -6
- package/dist/chunk-XDVR7QIT.js.map +1 -0
- package/dist/{chunk-GTILM2CI.js → chunk-Y34MSWEZ.js} +43 -12
- package/dist/chunk-Y34MSWEZ.js.map +1 -0
- package/dist/{chunk-4PTSR4UU.js → chunk-Y63UQZ7P.js} +3 -3
- package/dist/{chunk-4PTSR4UU.js.map → chunk-Y63UQZ7P.js.map} +1 -1
- package/dist/chunk-YBQONMH2.js +465 -0
- package/dist/chunk-YBQONMH2.js.map +1 -0
- package/dist/{chunk-P23M65LB.js → chunk-Z2K6BGUR.js} +71 -24
- package/dist/chunk-Z2K6BGUR.js.map +1 -0
- package/dist/{chunk-BJNUNQAW.js → chunk-ZGQTS3Y4.js} +3 -3
- package/dist/{chunk-BJNUNQAW.js.map → chunk-ZGQTS3Y4.js.map} +1 -1
- package/dist/cli/index.js +913 -720
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/catalog.d.ts +8 -5
- package/dist/cli/src/commands/catalog.d.ts.map +1 -1
- package/dist/cli/src/commands/diff.d.ts +3 -1
- package/dist/cli/src/commands/diff.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 +34 -2
- 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 +6 -5
- package/dist/cli/src/commands/manage.d.ts.map +1 -1
- package/dist/cli/src/commands/migrate-assets.d.ts.map +1 -1
- package/dist/cli/src/commands/outdated.d.ts +7 -5
- package/dist/cli/src/commands/outdated.d.ts.map +1 -1
- package/dist/cli/src/commands/project.d.ts +11 -8
- package/dist/cli/src/commands/project.d.ts.map +1 -1
- package/dist/cli/src/commands/source.d.ts +30 -1
- package/dist/cli/src/commands/source.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/commands/why.d.ts.map +1 -1
- package/dist/cli/src/skill-checks.d.ts +47 -2
- package/dist/cli/src/skill-checks.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/src/client.d.ts +10 -3
- package/dist/client/src/client.d.ts.map +1 -1
- package/dist/connectors/config.js +5 -5
- package/dist/connectors/index.js +18 -18
- package/dist/{connectors-O6Y6VESP.js → connectors-OXP2JBGI.js} +21 -21
- package/dist/{connectors-O6Y6VESP.js.map → connectors-OXP2JBGI.js.map} +1 -1
- package/dist/connectors-shared/index.js +2 -2
- package/dist/core/index.js +7 -7
- 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 +2 -1
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/core/src/lock.d.ts +5 -2
- package/dist/core/src/lock.d.ts.map +1 -1
- package/dist/core/src/logging/sinks/sqlite-runtime.d.ts.map +1 -1
- package/dist/core/src/manifest.d.ts.map +1 -1
- package/dist/core/src/models.d.ts +21 -5
- package/dist/core/src/models.d.ts.map +1 -1
- package/dist/core/src/publish-manifest.d.ts +19 -3
- package/dist/core/src/publish-manifest.d.ts.map +1 -1
- package/dist/core/src/repo-manager.d.ts.map +1 -1
- package/dist/core/src/requirements.d.ts +26 -0
- package/dist/core/src/requirements.d.ts.map +1 -0
- package/dist/core/src/walker.d.ts.map +1 -1
- package/dist/core/src/workspace-config.d.ts +18 -0
- package/dist/core/src/workspace-config.d.ts.map +1 -1
- package/dist/core/src/workspace-yaml-editor.d.ts +4 -1
- package/dist/core/src/workspace-yaml-editor.d.ts.map +1 -1
- package/dist/core/workspace-config.js +4 -4
- package/dist/deploy/index.js +7 -7
- package/dist/discovery/index.js +5 -5
- package/dist/discovery/src/builtin-providers.d.ts.map +1 -1
- package/dist/discovery/src/discover-manifest.d.ts.map +1 -1
- package/dist/discovery/src/discover.d.ts.map +1 -1
- package/dist/discovery/src/source-config.d.ts.map +1 -1
- package/dist/discovery/src/tree-entries.d.ts.map +1 -1
- package/dist/{ensure-sources-SKLNM4UZ.js → ensure-sources-5ISVIA4T.js} +17 -17
- package/dist/{ensure-sources-SKLNM4UZ.js.map → ensure-sources-5ISVIA4T.js.map} +1 -1
- package/dist/factory-assets/connectors/box.js +18 -18
- package/dist/factory-assets/connectors/deploy.js +18 -18
- package/dist/factory-assets/connectors/devserver.js +18 -18
- package/dist/factory-assets/connectors/flow/adapter.js +18 -18
- package/dist/factory-assets/connectors/flow/engine.js +8 -8
- package/dist/factory-assets/connectors/flow/run-flow.js +20 -20
- package/dist/factory-assets/connectors/flow.js +18 -18
- package/dist/factory-assets/connectors/git.js +18 -18
- package/dist/factory-assets/connectors/gmail.js +18 -18
- package/dist/factory-assets/connectors/googledrive.js +18 -18
- package/dist/factory-assets/connectors/local.js +18 -18
- package/dist/factory-assets/connectors/mattermost.js +18 -18
- package/dist/factory-assets/connectors/memory.js +18 -18
- package/dist/factory-assets/connectors/minio.js +18 -18
- package/dist/factory-assets/connectors/postgres.js +18 -18
- package/dist/factory-assets/connectors/s3.js +18 -18
- package/dist/factory-assets/connectors/sharepoint.js +18 -18
- package/dist/factory-assets/connectors/sqlite.js +18 -18
- package/dist/factory-assets/connectors/static-server.js +18 -18
- package/dist/factory-assets/connectors/tunnel.js +18 -18
- package/dist/factory-assets/connectors/webdav.js +18 -18
- package/dist/factory-assets/connectors/xstate-store.js +18 -18
- package/dist/factory-assets/connectors/xstate.js +18 -18
- package/dist/factory-assets/skills/authoring-skaile-manifests/SKILL.md +9 -3
- package/dist/{flows-CBYRSAGS.js → flows-HMSE76PO.js} +12 -12
- package/dist/{flows-CBYRSAGS.js.map → flows-HMSE76PO.js.map} +1 -1
- package/dist/{helpers-MWZDRBLD.js → helpers-X6URBGSF.js} +17 -17
- package/dist/{helpers-MWZDRBLD.js.map → helpers-X6URBGSF.js.map} +1 -1
- package/dist/library/index.js +11 -11
- package/dist/library/install.js +3 -3
- package/dist/library/src/index.d.ts +2 -1
- package/dist/library/src/index.d.ts.map +1 -1
- package/dist/library/src/local/library-dir.d.ts +42 -0
- package/dist/library/src/local/library-dir.d.ts.map +1 -0
- package/dist/library/src/local/library-manager.d.ts +10 -1
- package/dist/library/src/local/library-manager.d.ts.map +1 -1
- package/dist/library/src/local/library.d.ts +2 -2
- package/dist/library/src/local/library.d.ts.map +1 -1
- package/dist/library/src/local/local-catalog-source.d.ts +9 -0
- package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
- package/dist/library/src/manifest-writer.d.ts +55 -4
- package/dist/library/src/manifest-writer.d.ts.map +1 -1
- package/dist/library/src/remote/cache.d.ts +18 -1
- package/dist/library/src/remote/cache.d.ts.map +1 -1
- package/dist/library/src/remote/remote-catalog-source.d.ts.map +1 -1
- package/dist/library/src/remote/rest-catalog-source.d.ts.map +1 -1
- package/dist/library/src/sync/git-driver.d.ts +5 -6
- package/dist/library/src/sync/git-driver.d.ts.map +1 -1
- package/dist/{library-publish-PICMDSB2.js → library-publish-OS3JDW4S.js} +123 -41
- package/dist/library-publish-OS3JDW4S.js.map +1 -0
- package/dist/open-library-4QSUORI6.js +40 -0
- package/dist/{open-library-OG457THY.js.map → open-library-4QSUORI6.js.map} +1 -1
- package/dist/open-registry-VCKS3MP5.js +32 -0
- package/dist/{open-registry-ZUZJ7MS7.js.map → open-registry-VCKS3MP5.js.map} +1 -1
- package/dist/paths-BVO56A25.js +22 -0
- package/dist/{paths-FQ64OLJG.js.map → paths-BVO56A25.js.map} +1 -1
- package/dist/{plugin-store-MPAMD5OT.js → plugin-store-X7GPWGBG.js} +9 -9
- package/dist/{plugin-store-MPAMD5OT.js.map → plugin-store-X7GPWGBG.js.map} +1 -1
- package/dist/{project-2GFT5LEZ.js → project-PAXP46RD.js} +20 -20
- package/dist/{project-2GFT5LEZ.js.map → project-PAXP46RD.js.map} +1 -1
- package/dist/resolver/index.js +8 -8
- package/dist/runner/index.js +32 -32
- package/dist/runner/src/agent.d.ts.map +1 -1
- package/dist/runner/src/context-usage/compose.d.ts.map +1 -1
- package/dist/runner/src/platform-blocks.d.ts +55 -0
- package/dist/runner/src/platform-blocks.d.ts.map +1 -0
- package/dist/runner/src/serve.d.ts.map +1 -1
- package/dist/runner/src/session-builder.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +14 -14
- package/dist/sdk/bridge.js +14 -14
- package/dist/sdk/client.js +1 -1
- package/dist/sdk/core.js +7 -7
- package/dist/sdk/flow.js +8 -8
- package/dist/sdk/index.js +33 -33
- package/dist/sdk/resolver.js +8 -8
- package/dist/sdk/runner.js +32 -32
- package/dist/sdk/session.js +2 -2
- package/dist/sdk/types.js +1 -1
- package/dist/session/index.js +2 -2
- package/dist/session/src/dispatcher.d.ts +25 -4
- package/dist/session/src/dispatcher.d.ts.map +1 -1
- package/dist/session/src/index.d.ts +1 -1
- package/dist/session/src/index.d.ts.map +1 -1
- package/dist/{setup-WHMCSIF2.js → setup-BV55VHWC.js} +24 -24
- package/dist/{setup-WHMCSIF2.js.map → setup-BV55VHWC.js.map} +1 -1
- package/dist/{skills-TVO26Y4V.js → skills-EDFUCJPX.js} +13 -13
- package/dist/{skills-TVO26Y4V.js.map → skills-EDFUCJPX.js.map} +1 -1
- package/dist/source-E4VAT5RZ.js +41 -0
- package/dist/{source-LKOFTOEK.js.map → source-E4VAT5RZ.js.map} +1 -1
- package/dist/{source-manifest-publish-L5J3QXER.js → source-manifest-publish-CLEE6TNH.js} +23 -23
- package/dist/{source-manifest-publish-L5J3QXER.js.map → source-manifest-publish-CLEE6TNH.js.map} +1 -1
- package/dist/tui/index.js +32 -32
- package/dist/types/index.js +1 -1
- package/dist/types/manifests.js +1 -1
- package/dist/types/src/events.d.ts +1 -1
- package/dist/types/src/events.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/manifests/agent.d.ts +2 -0
- package/dist/types/src/manifests/agent.d.ts.map +1 -1
- package/dist/types/src/manifests/contract.d.ts +2 -0
- package/dist/types/src/manifests/contract.d.ts.map +1 -1
- package/dist/types/src/manifests/index.d.ts +3 -3
- package/dist/types/src/manifests/index.d.ts.map +1 -1
- package/dist/types/src/manifests/prompt.d.ts +2 -0
- package/dist/types/src/manifests/prompt.d.ts.map +1 -1
- package/dist/types/src/protocol.d.ts +43 -1
- package/dist/types/src/protocol.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +17 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/dist/workspace-plugin/adapters/mcp.js +25 -25
- package/dist/workspace-plugin/adapters/omp.js +14 -14
- package/dist/workspace-plugin/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-36AFURKZ.js.map +0 -1
- package/dist/chunk-4MQS7CAF.js.map +0 -1
- package/dist/chunk-AWQYXZVG.js.map +0 -1
- package/dist/chunk-B6GIW55K.js.map +0 -1
- package/dist/chunk-BTE2V4IW.js.map +0 -1
- package/dist/chunk-CIFS5K6T.js.map +0 -1
- package/dist/chunk-EF7NPDDU.js.map +0 -1
- package/dist/chunk-F3RDEH5U.js.map +0 -1
- package/dist/chunk-GTILM2CI.js.map +0 -1
- package/dist/chunk-GXXFLBUQ.js.map +0 -1
- package/dist/chunk-H7QUDDKH.js.map +0 -1
- package/dist/chunk-HG34RNTK.js.map +0 -1
- package/dist/chunk-JAKOMFC6.js.map +0 -1
- package/dist/chunk-LEMHVDET.js.map +0 -1
- package/dist/chunk-OJ4N4T4H.js.map +0 -1
- package/dist/chunk-P23M65LB.js.map +0 -1
- package/dist/chunk-QVNRCDTV.js.map +0 -1
- package/dist/chunk-UMVKJM4Q.js.map +0 -1
- package/dist/chunk-Y7QA2OLD.js.map +0 -1
- package/dist/chunk-YSHVQGUS.js.map +0 -1
- package/dist/chunk-ZAOGFXDO.js +0 -112
- package/dist/chunk-ZAOGFXDO.js.map +0 -1
- package/dist/library-publish-PICMDSB2.js.map +0 -1
- package/dist/open-library-OG457THY.js +0 -40
- package/dist/open-registry-ZUZJ7MS7.js +0 -32
- package/dist/paths-FQ64OLJG.js +0 -22
- package/dist/source-LKOFTOEK.js +0 -41
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import { getStoreManifestsDir } from './chunk-
|
|
2
|
-
import { readManifestSourceConfig, isManifestMode, discoverAssetsInTree } from './chunk-
|
|
3
|
-
import {
|
|
1
|
+
import { unregisteredLibraryNames, scanUnlistedAssets, getStoreManifestsDir, missingLibraryDirMessage } from './chunk-3BEY4WK3.js';
|
|
2
|
+
import { readManifestSourceConfig, isManifestMode, discoverAssetsInTree } from './chunk-GEWAIQZ5.js';
|
|
3
|
+
import { installTargetOf, canonicalEntryRef, deployAll, removeAsset, diffDeployedAgent, createScaffold, installAgent } from './chunk-PE36IF2D.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, buildLockFile, writeLock, readLock, verifyLock, mergeLockFile, extractForPatch, generatePatch, savePatch, applyPatch } from './chunk-
|
|
8
|
-
import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-
|
|
6
|
+
import { driverTargetSupportsAgents, CODEX_IDENTITY_DIR } from './chunk-6HHE63CO.js';
|
|
7
|
+
import { resolveConfiguredDriverTarget, GLOBAL_INSTALL_DIR_NAME, resolveLibraryDir, buildLibraryLockEntries, buildLockFile, writeLock, readLock, verifyLock, mergeLockFile, extractForPatch, generatePatch, savePatch, applyPatch } from './chunk-2FMEGSBN.js';
|
|
8
|
+
import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-GFCXNFTW.js';
|
|
9
9
|
import { deployedBase, deployedDir, isDeployed, deployedPaths } from './chunk-PMECEZK3.js';
|
|
10
|
-
import { resolveSkWorkspaceConfig, effectiveAgentInstances,
|
|
10
|
+
import { resolveSkWorkspaceConfig, effectiveAgentInstances, loadMcpServerDeclarations, resolveGlobalHarnesses, resolveGlobalSkWorkspaceConfig, getGlobalCacheDir, sourceCacheKey, getRepoCommit, matchPin, buildProvenanceIndex, coerceVersion, sourceShortName, resolveAll, ensureRepo, scanRepo, SKAILE_YAML_DEFAULT, checkRepoStatus, resolveAsset, readLinks, MAX_PRESET_DEPTH, PresetDepthError, DEFAULT_AGENT_INSTANCE_ID, resolveAgentDefinitionDir, storeManifestSlug } from './chunk-JZCSNEHK.js';
|
|
11
11
|
import { globalSkaileDir, globalCacheRoot, migrateLegacyDir } from './chunk-L5VSIPQD.js';
|
|
12
12
|
import { DRIVER_TARGETS } from './chunk-CPSIPIX7.js';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { loadSkPublishManifest } from './chunk-IXWODEED.js';
|
|
14
|
+
import { scanDirectory, parseRequires, dedupeRequirements } from './chunk-Y34MSWEZ.js';
|
|
15
|
+
import { parseAssetRef, parseAssetRefLoose, assetRefToStr, slugifyAssetName, depToStr } from './chunk-4OV5DSBB.js';
|
|
15
16
|
import { spawnSync } from 'child_process';
|
|
16
17
|
import { existsSync, rmSync, readdirSync, lstatSync, unlinkSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
17
|
-
import path, {
|
|
18
|
+
import path, { resolve, dirname, sep, join, relative, posix } from 'path';
|
|
18
19
|
import { gt } from 'semver';
|
|
19
20
|
import { stringify, parse } from 'yaml';
|
|
20
21
|
import fs from 'fs/promises';
|
|
@@ -36,9 +37,79 @@ function writeLedger(projectDir, ledger) {
|
|
|
36
37
|
writeFileSync(p, `${JSON.stringify(ledger, null, 2)}
|
|
37
38
|
`, "utf-8");
|
|
38
39
|
}
|
|
40
|
+
function bindInstance(projectDir, id, instance) {
|
|
41
|
+
const errors = [];
|
|
42
|
+
let srcDir;
|
|
43
|
+
const addHint = instance.ref.startsWith("agent:") ? ` \u2014 add the agent first: run skaile add ${instance.ref}` : "";
|
|
44
|
+
try {
|
|
45
|
+
srcDir = resolveAgentDefinitionDir(projectDir, instance.ref);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
errors.push(
|
|
48
|
+
`agent instance "${id}": ${err instanceof Error ? err.message : String(err)}${addHint}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
if (srcDir !== void 0 && !existsSync(join(srcDir, "agent.yaml"))) {
|
|
52
|
+
errors.push(
|
|
53
|
+
`agent instance "${id}": ${instance.ref} resolves to ${srcDir}, which has no agent.yaml`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return { srcDir, errors };
|
|
57
|
+
}
|
|
58
|
+
function unboundAgentInstances(projectDir, driverTarget) {
|
|
59
|
+
if (!driverTargetSupportsAgents(driverTarget)) return [];
|
|
60
|
+
let instances;
|
|
61
|
+
try {
|
|
62
|
+
instances = effectiveAgentInstances(resolveSkWorkspaceConfig(projectDir));
|
|
63
|
+
} catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
const out = [];
|
|
67
|
+
for (const [id, instance] of Object.entries(instances)) {
|
|
68
|
+
const { errors } = bindInstance(projectDir, id, instance);
|
|
69
|
+
if (errors.length > 0) out.push({ id, ref: instance.ref, error: errors.join("; ") });
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
function removeAgentInstanceRenderings(opts) {
|
|
74
|
+
const { projectDir, driverTarget, ids } = opts;
|
|
75
|
+
if (!driverTargetSupportsAgents(driverTarget) || ids.length === 0) return [];
|
|
76
|
+
const ledger = readLedger(projectDir);
|
|
77
|
+
const previous = ledger.targets[driverTarget];
|
|
78
|
+
if (!previous) return [];
|
|
79
|
+
const gone = new Set(ids);
|
|
80
|
+
const claimed = new Set(
|
|
81
|
+
Object.entries(previous).filter(([id]) => !gone.has(id)).flatMap(([, files]) => files)
|
|
82
|
+
);
|
|
83
|
+
const agentDeployDir = deployedBase("agent", driverTarget, false, projectDir);
|
|
84
|
+
const removable = [resolve(agentDeployDir), resolve(dirname(agentDeployDir), CODEX_IDENTITY_DIR)];
|
|
85
|
+
const root = resolve(projectDir);
|
|
86
|
+
const removed = [];
|
|
87
|
+
for (const id of gone) {
|
|
88
|
+
for (const rel of previous[id] ?? []) {
|
|
89
|
+
if (claimed.has(rel)) continue;
|
|
90
|
+
const abs = resolve(root, rel);
|
|
91
|
+
if (!removable.some((dir) => abs.startsWith(dir + sep)) || !existsSync(abs)) continue;
|
|
92
|
+
rmSync(abs, { recursive: true, force: true });
|
|
93
|
+
removed.push(rel);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const owned = Object.fromEntries(Object.entries(previous).filter(([id]) => !gone.has(id)));
|
|
97
|
+
const nextTargets = { ...ledger.targets };
|
|
98
|
+
if (Object.keys(owned).length > 0) nextTargets[driverTarget] = owned;
|
|
99
|
+
else delete nextTargets[driverTarget];
|
|
100
|
+
if (JSON.stringify(nextTargets) !== JSON.stringify(ledger.targets)) {
|
|
101
|
+
writeLedger(projectDir, { version: 1, targets: nextTargets });
|
|
102
|
+
}
|
|
103
|
+
return removed;
|
|
104
|
+
}
|
|
39
105
|
function installAgentInstances(opts) {
|
|
40
106
|
const { projectDir, driverTarget, log } = opts;
|
|
41
|
-
const result = {
|
|
107
|
+
const result = {
|
|
108
|
+
instances: [],
|
|
109
|
+
removed: [],
|
|
110
|
+
warnings: [],
|
|
111
|
+
errors: []
|
|
112
|
+
};
|
|
42
113
|
if (!driverTargetSupportsAgents(driverTarget)) return result;
|
|
43
114
|
const wsConfig = opts.wsConfig ?? resolveSkWorkspaceConfig(projectDir);
|
|
44
115
|
const instances = effectiveAgentInstances(wsConfig);
|
|
@@ -48,20 +119,9 @@ function installAgentInstances(opts) {
|
|
|
48
119
|
const previous = ledger.targets[driverTarget] ?? {};
|
|
49
120
|
const owned = {};
|
|
50
121
|
for (const [id, instance] of Object.entries(instances)) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
} catch (err) {
|
|
55
|
-
result.warnings.push(
|
|
56
|
-
`agent instance "${id}": ${err instanceof Error ? err.message : String(err)}`
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
if (srcDir === void 0 || !existsSync(join(srcDir, "agent.yaml"))) {
|
|
60
|
-
if (srcDir !== void 0) {
|
|
61
|
-
result.warnings.push(
|
|
62
|
-
`agent instance "${id}": ${instance.ref} resolves to ${srcDir}, which has no agent.yaml`
|
|
63
|
-
);
|
|
64
|
-
}
|
|
122
|
+
const { srcDir, errors } = bindInstance(projectDir, id, instance);
|
|
123
|
+
result.errors.push(...errors);
|
|
124
|
+
if (srcDir === void 0 || errors.length > 0) {
|
|
65
125
|
if (previous[id]) owned[id] = previous[id];
|
|
66
126
|
continue;
|
|
67
127
|
}
|
|
@@ -273,7 +333,30 @@ async function renderMcpServerConfig(projectDir, driverTarget, opts) {
|
|
|
273
333
|
|
|
274
334
|
// asset-manager/src/index.ts
|
|
275
335
|
function normalizeRepoUrl(url) {
|
|
276
|
-
return url.trim().replace(/^git@([^:]+):/, "https://$1/").replace(/^[a-z]+:\/\//i, "").replace(/\.git$/i, "").replace(/\/+$/, "").toLowerCase();
|
|
336
|
+
return url.trim().replace(/^git@([^:]+):/, "https://$1/").replace(/^[a-z]+:\/\//i, "").replace(/\/+$/, "").replace(/\.git$/i, "").replace(/\/+$/, "").toLowerCase();
|
|
337
|
+
}
|
|
338
|
+
function withoutUrlSecrets(url) {
|
|
339
|
+
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(url)) return url;
|
|
340
|
+
try {
|
|
341
|
+
const parsed = new URL(url);
|
|
342
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:" || parsed.password) {
|
|
343
|
+
parsed.username = "";
|
|
344
|
+
}
|
|
345
|
+
parsed.password = "";
|
|
346
|
+
parsed.search = "";
|
|
347
|
+
parsed.hash = "";
|
|
348
|
+
return parsed.toString();
|
|
349
|
+
} catch {
|
|
350
|
+
return url.replace(/[?#].*$/, "").replace(/^([a-z][a-z0-9+.-]*:\/\/).*@/i, "$1");
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function libraryRemoteUrl(library) {
|
|
354
|
+
const config = library.backendConfig;
|
|
355
|
+
if (library.backend !== "git" || !("url" in config) || typeof config.url !== "string") {
|
|
356
|
+
return void 0;
|
|
357
|
+
}
|
|
358
|
+
const url = config.url.trim();
|
|
359
|
+
return url ? withoutUrlSecrets(url) : void 0;
|
|
277
360
|
}
|
|
278
361
|
function storeOverlayPathForUrl(url) {
|
|
279
362
|
return join(getStoreManifestsDir(), `${storeManifestSlug(url)}.yaml`);
|
|
@@ -375,6 +458,26 @@ function libraryDiskHashes(libPath, cache, registry) {
|
|
|
375
458
|
}
|
|
376
459
|
return hashes;
|
|
377
460
|
}
|
|
461
|
+
function manifestFileHasAssetsArray(libPath) {
|
|
462
|
+
try {
|
|
463
|
+
const doc = parse(readFileSync(join(libPath, "skaile.manifest.yaml"), "utf8"));
|
|
464
|
+
return Array.isArray(doc?.assets);
|
|
465
|
+
} catch {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
function isUnlistedLibraryAsset(entry, libPath) {
|
|
470
|
+
const manifest = loadSkPublishManifest(libPath);
|
|
471
|
+
const listed = manifest?.assets ?? [];
|
|
472
|
+
if (!manifest || manifest.source) return false;
|
|
473
|
+
if (listed.length === 0 && !manifestFileHasAssetsArray(libPath)) return false;
|
|
474
|
+
const file = resolve(entry.source);
|
|
475
|
+
return !listed.some((a) => {
|
|
476
|
+
if (!a.root || a.source) return false;
|
|
477
|
+
const root = resolve(libPath, a.root);
|
|
478
|
+
return file === root || file.startsWith(root + sep);
|
|
479
|
+
});
|
|
480
|
+
}
|
|
378
481
|
function withLibraryFiles(entry, libPath, cache, registry) {
|
|
379
482
|
let byManifest = cache.get(libPath);
|
|
380
483
|
if (!byManifest) {
|
|
@@ -539,6 +642,10 @@ function keptLockEntries(prev, missing) {
|
|
|
539
642
|
}
|
|
540
643
|
return out;
|
|
541
644
|
}
|
|
645
|
+
function presetsLockSlice(presets) {
|
|
646
|
+
const refs = [...new Set(presets.map((p) => p.ref))].sort();
|
|
647
|
+
return refs.length > 0 ? { presets: refs } : {};
|
|
648
|
+
}
|
|
542
649
|
function withKeptLockEntries(lock, kept) {
|
|
543
650
|
if (Object.keys(kept.assets).length === 0) return lock;
|
|
544
651
|
const sources = new Map(lock.sources.map((s) => [s.url, s]));
|
|
@@ -567,8 +674,16 @@ function relockedRefs(prev, next) {
|
|
|
567
674
|
}
|
|
568
675
|
return out;
|
|
569
676
|
}
|
|
570
|
-
function unregisteredLibraryFix(
|
|
571
|
-
|
|
677
|
+
function unregisteredLibraryFix(origin, ref) {
|
|
678
|
+
const register = origin.url ? `\`skaile library init ${origin.name} --git ${origin.url}\` (no registered library has the remote ${origin.url} either)` : `\`skaile library init ${origin.name} --path <dir>\``;
|
|
679
|
+
return `register library "${origin.name}" again with ${register}, or drop the dependency with \`skaile remove ${ref}\``;
|
|
680
|
+
}
|
|
681
|
+
function lockedLibraryProblem(lookup, origin, ref) {
|
|
682
|
+
return lookup.state === "dir-missing" ? missingLibraryDirMessage({ name: origin.name, path: lookup.path }) : `library "${origin.name}" is not registered \u2014 renamed or removed? ${unregisteredLibraryFix(origin, ref)}`;
|
|
683
|
+
}
|
|
684
|
+
function gapIdentity(ref) {
|
|
685
|
+
const p = parseRefTolerant(ref);
|
|
686
|
+
return p ? `${p.kind}:${p.name}` : ref;
|
|
572
687
|
}
|
|
573
688
|
function memberIdentity(ref) {
|
|
574
689
|
const parsed = parseRefTolerant(ref.trim());
|
|
@@ -726,13 +841,14 @@ var AssetManager = class {
|
|
|
726
841
|
}
|
|
727
842
|
/** Deploy options for one harness. In global mode, `driverTarget` is the
|
|
728
843
|
* fan-out target (not the constructor's `driverTarget`, which is project-only). */
|
|
729
|
-
deployOptsFor(target, link) {
|
|
844
|
+
deployOptsFor(target, link, onSkippedSymlink) {
|
|
730
845
|
return {
|
|
731
846
|
registry: this.registry,
|
|
732
847
|
driverTarget: target,
|
|
733
848
|
global: this.global,
|
|
734
849
|
cwd: this.projectDir,
|
|
735
|
-
link: link === true
|
|
850
|
+
link: link === true,
|
|
851
|
+
...onSkippedSymlink ? { onSkippedSymlink: (entry, p) => onSkippedSymlink(canonicalEntryRef(entry), p) } : {}
|
|
736
852
|
};
|
|
737
853
|
}
|
|
738
854
|
/**
|
|
@@ -759,8 +875,8 @@ var AssetManager = class {
|
|
|
759
875
|
* Render every agent instance of `skaile.yaml` into the driver target's native
|
|
760
876
|
* agent files (`.claude/agents/<id>.md`, …) and prune the renderings of
|
|
761
877
|
* instances that left the config. Runs after the skills deploy, so composed
|
|
762
|
-
* skills resolve. Project scope only.
|
|
763
|
-
* is warned and swallowed.
|
|
878
|
+
* skills resolve. Project scope only. An instance whose `ref` resolves to no agent is
|
|
879
|
+
* reported in `agentInstanceErrors`; any other render error is warned and swallowed.
|
|
764
880
|
*/
|
|
765
881
|
renderAgentInstances() {
|
|
766
882
|
if (this.global) return {};
|
|
@@ -769,8 +885,12 @@ var AssetManager = class {
|
|
|
769
885
|
projectDir: this.projectDir,
|
|
770
886
|
driverTarget: this.driverTarget
|
|
771
887
|
});
|
|
772
|
-
for (const w of result.warnings) console.warn(`skaile: ${w}`);
|
|
773
|
-
return {
|
|
888
|
+
for (const w of [...result.warnings, ...result.errors]) console.warn(`skaile: ${w}`);
|
|
889
|
+
return {
|
|
890
|
+
agentInstances: result.instances,
|
|
891
|
+
agentFilesRemoved: result.removed,
|
|
892
|
+
...result.errors.length > 0 ? { agentInstanceErrors: result.errors } : {}
|
|
893
|
+
};
|
|
774
894
|
} catch (err) {
|
|
775
895
|
console.warn(
|
|
776
896
|
`skaile: could not render agent instances for ${this.driverTarget}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -902,6 +1022,8 @@ var AssetManager = class {
|
|
|
902
1022
|
*
|
|
903
1023
|
* @param opts.quiet - Skip the cross-library collision warning (a lookup that only
|
|
904
1024
|
* builds an error hint must not warn).
|
|
1025
|
+
* @param opts.library - Resolve only from this library (the one a lock entry names), not
|
|
1026
|
+
* from every registered one. Never warns: no choice is made between libraries.
|
|
905
1027
|
* @returns the matched deploy entries, the set of `missing` refs covered, and
|
|
906
1028
|
* each entry's originating library name.
|
|
907
1029
|
*/
|
|
@@ -914,6 +1036,7 @@ var AssetManager = class {
|
|
|
914
1036
|
const { byKey, isDefaultLib, libraryDir } = scan;
|
|
915
1037
|
const entries = [];
|
|
916
1038
|
const fileSets = /* @__PURE__ */ new Map();
|
|
1039
|
+
let snap;
|
|
917
1040
|
const allCandidates = [...byKey.values()].flat();
|
|
918
1041
|
for (const ref of missing) {
|
|
919
1042
|
const parsed = parseRefTolerant(ref);
|
|
@@ -921,21 +1044,33 @@ var AssetManager = class {
|
|
|
921
1044
|
const hash = ref.indexOf("#");
|
|
922
1045
|
const pin = parsed.pin ?? (hash >= 0 ? ref.slice(hash + 1) : void 0);
|
|
923
1046
|
const key = parsed.publisher ? `${parsed.kind}:@${parsed.publisher}/${parsed.name}` : void 0;
|
|
924
|
-
const pool = key ? byKey.get(key) ?? [] : allCandidates.filter(
|
|
1047
|
+
const pool = (key ? byKey.get(key) ?? [] : allCandidates.filter(
|
|
1048
|
+
(c) => c.entry.kind === parsed.kind && c.entry.name === parsed.name
|
|
1049
|
+
)).filter((c) => !opts.library || c.library === opts.library);
|
|
925
1050
|
const candidates = pool.filter((c) => !pin || matchPin(pin, c.entry.version ?? ""));
|
|
926
1051
|
if (candidates.length === 0) continue;
|
|
927
1052
|
candidates.sort(libraryPreference(isDefaultLib));
|
|
928
1053
|
const hit = candidates[0];
|
|
929
|
-
if (!opts.quiet) {
|
|
1054
|
+
if (!opts.quiet && !opts.library) {
|
|
930
1055
|
this.warnLibraryCollision(
|
|
931
1056
|
`${hit.entry.kind}:@${hit.entry.publisher}/${hit.entry.name}`,
|
|
932
1057
|
candidates,
|
|
933
1058
|
hit
|
|
934
1059
|
);
|
|
935
1060
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1061
|
+
let entry = hit.entry;
|
|
1062
|
+
if (!entry.version) {
|
|
1063
|
+
if (snap === void 0) snap = await this.loadLibraryIndex();
|
|
1064
|
+
const def = newestLibraryDef(snap, hit.library, {
|
|
1065
|
+
kind: entry.kind,
|
|
1066
|
+
publisher: entry.publisher ?? "",
|
|
1067
|
+
name: entry.name
|
|
1068
|
+
});
|
|
1069
|
+
if (def?.version) entry = { ...entry, version: def.version };
|
|
1070
|
+
}
|
|
1071
|
+
withLibraryFiles(entry, libraryDir.get(hit.library), fileSets, this.registry);
|
|
1072
|
+
entries.push(entry);
|
|
1073
|
+
libraryOf.set(entry, hit.library);
|
|
939
1074
|
resolved.add(ref);
|
|
940
1075
|
}
|
|
941
1076
|
return { entries, resolved, libraryOf };
|
|
@@ -955,11 +1090,12 @@ var AssetManager = class {
|
|
|
955
1090
|
if (existsSync(l.path)) roots.push({ name: l.name, dir: l.path, isDefault: l.isDefault });
|
|
956
1091
|
}
|
|
957
1092
|
const registered = new Set(roots.map((r) => r.name));
|
|
1093
|
+
const unregistered = unregisteredLibraryNames();
|
|
958
1094
|
try {
|
|
959
1095
|
const librariesRoot = resolveLibraryDir();
|
|
960
1096
|
if (existsSync(librariesRoot)) {
|
|
961
1097
|
for (const dirent of readdirSync(librariesRoot, { withFileTypes: true })) {
|
|
962
|
-
if (dirent.isDirectory() && dirent.name !== GLOBAL_INSTALL_DIR_NAME && !registered.has(dirent.name)) {
|
|
1098
|
+
if (dirent.isDirectory() && dirent.name !== GLOBAL_INSTALL_DIR_NAME && !registered.has(dirent.name) && !unregistered.has(dirent.name)) {
|
|
963
1099
|
roots.push({
|
|
964
1100
|
name: dirent.name,
|
|
965
1101
|
dir: join(librariesRoot, dirent.name),
|
|
@@ -1012,10 +1148,117 @@ var AssetManager = class {
|
|
|
1012
1148
|
}
|
|
1013
1149
|
return out;
|
|
1014
1150
|
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Every asset a registered library holds, read from the library directories themselves
|
|
1153
|
+
* (not the local index, which keeps one row per ref and version and loses a ref when
|
|
1154
|
+
* another library re-publishes it). One row per holder, all versions.
|
|
1155
|
+
*
|
|
1156
|
+
* @returns `[]` when no library holds an asset. Never warns.
|
|
1157
|
+
*/
|
|
1158
|
+
async libraryAssets() {
|
|
1159
|
+
const scan = await this.scanLibraries();
|
|
1160
|
+
if (!scan) return [];
|
|
1161
|
+
return [...scan.byKey.values()].flat();
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Every origin that holds `ref` (`kind:@publisher/name`) with the version it holds, in
|
|
1165
|
+
* the order `add <ref>` prefers them, so the first row is the one `add` deploys: the
|
|
1166
|
+
* project's source clones and the bundled factory source (highest version first), then
|
|
1167
|
+
* the registered libraries. `add`, `info` and `search` all read this, so the three name
|
|
1168
|
+
* one origin for one ref. Stores are not asked (no network).
|
|
1169
|
+
*
|
|
1170
|
+
* @returns one row per origin and version; `[]` for a ref without a publisher or one
|
|
1171
|
+
* nothing holds. Never warns.
|
|
1172
|
+
*/
|
|
1173
|
+
async refOrigins(ref) {
|
|
1174
|
+
const parsed = parseRefTolerant(ref);
|
|
1175
|
+
if (!parsed?.publisher) return [];
|
|
1176
|
+
const key = `${parsed.kind}:@${parsed.publisher}/${parsed.name}`;
|
|
1177
|
+
return (await this.collectOrigins(key)).get(key) ?? [];
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Every ref (`kind:@publisher/name`) that several origins hold at different versions,
|
|
1181
|
+
* with its origins in {@link refOrigins} order. A ref the origins hold at one version
|
|
1182
|
+
* has nothing to choose between and is left out.
|
|
1183
|
+
*/
|
|
1184
|
+
async competingOrigins() {
|
|
1185
|
+
const out = /* @__PURE__ */ new Map();
|
|
1186
|
+
for (const [key, origins] of await this.collectOrigins()) {
|
|
1187
|
+
if (new Set(origins.map((o) => o.version)).size > 1) out.set(key, origins);
|
|
1188
|
+
}
|
|
1189
|
+
return out;
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* The origins of {@link refOrigins} for every ref, or for the one `only` names
|
|
1193
|
+
* (`kind:@publisher/name`), keyed by `kind:@publisher/name`.
|
|
1194
|
+
*/
|
|
1195
|
+
async collectOrigins(only) {
|
|
1196
|
+
const { repositories, sources } = this.loadConfig();
|
|
1197
|
+
this.ensureSourceClonesQuiet(repositories, sources);
|
|
1198
|
+
const clones = this.buildClones(repositories);
|
|
1199
|
+
const cloneDirs = new Set(clones.map((c) => resolve(c.localPath)));
|
|
1200
|
+
const index = await buildProvenanceIndex(clones, {
|
|
1201
|
+
projectDir: this.projectDir,
|
|
1202
|
+
knownKinds: this.knownKinds
|
|
1203
|
+
});
|
|
1204
|
+
const factoryUrl = normalizeRepoUrl(FACTORY_SOURCE_URL);
|
|
1205
|
+
const hasFactory = Object.values(repositories).some((d) => d.factory);
|
|
1206
|
+
const out = /* @__PURE__ */ new Map();
|
|
1207
|
+
const originsOf = (key) => {
|
|
1208
|
+
let list = out.get(key);
|
|
1209
|
+
if (!list) {
|
|
1210
|
+
list = [];
|
|
1211
|
+
out.set(key, list);
|
|
1212
|
+
}
|
|
1213
|
+
return list;
|
|
1214
|
+
};
|
|
1215
|
+
for (const candidates of index.values()) {
|
|
1216
|
+
const first = candidates[0];
|
|
1217
|
+
if (!first) continue;
|
|
1218
|
+
const key = `${first.kind}:@${first.publisher}/${first.name}`;
|
|
1219
|
+
if (only !== void 0 && key !== only) continue;
|
|
1220
|
+
const held = [...candidates].sort((a, b) => {
|
|
1221
|
+
const va = coerceVersion(a.version);
|
|
1222
|
+
const vb = coerceVersion(b.version);
|
|
1223
|
+
if (gt(va, vb)) return -1;
|
|
1224
|
+
if (gt(vb, va)) return 1;
|
|
1225
|
+
return a.sourceUrl.localeCompare(b.sourceUrl);
|
|
1226
|
+
});
|
|
1227
|
+
for (const c of held) {
|
|
1228
|
+
const factory = hasFactory && normalizeRepoUrl(c.sourceUrl) === factoryUrl;
|
|
1229
|
+
originsOf(key).push({
|
|
1230
|
+
kind: factory ? "factory" : "source",
|
|
1231
|
+
label: factory ? "factory" : sourceShortName(c.sourceUrl),
|
|
1232
|
+
version: c.version,
|
|
1233
|
+
description: c.description ?? ""
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
const scan = await this.scanLibraries();
|
|
1238
|
+
const prefer = libraryPreference(scan?.isDefaultLib ?? /* @__PURE__ */ new Map());
|
|
1239
|
+
for (const [key, holders] of scan?.byKey ?? []) {
|
|
1240
|
+
if (only !== void 0 && key !== only) continue;
|
|
1241
|
+
for (const c of [...holders].sort(prefer)) {
|
|
1242
|
+
const dir = scan?.libraryDir.get(c.library);
|
|
1243
|
+
if (dir && cloneDirs.has(resolve(dir))) continue;
|
|
1244
|
+
originsOf(key).push({
|
|
1245
|
+
kind: "library",
|
|
1246
|
+
label: c.library,
|
|
1247
|
+
version: c.entry.version ?? "",
|
|
1248
|
+
description: c.entry.description ?? ""
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
return out;
|
|
1253
|
+
}
|
|
1015
1254
|
/**
|
|
1016
1255
|
* Where each missed publisher-qualified ref went when its publisher changed, for every
|
|
1017
1256
|
* ref at once (one library scan, one lock read):
|
|
1018
|
-
* - `moved` when a registered library holds the same kind + name under another publisher
|
|
1257
|
+
* - `moved` when a registered library holds the same kind + name under another publisher.
|
|
1258
|
+
* When the lock ties the missed ref to a library, only that library is looked at (an
|
|
1259
|
+
* asset of the same name in another library is a different asset). Without a lock
|
|
1260
|
+
* entry, a library asset the project already declares or locks under its own ref is
|
|
1261
|
+
* not offered, and two candidate publishers are ambiguous: no hint;
|
|
1019
1262
|
* - `lockedAs` when the lock holds the same kind + name under another publisher, records
|
|
1020
1263
|
* the library it came from, and that library now holds the asset under yet another
|
|
1021
1264
|
* publisher than the locked one. An unrelated asset that merely shares kind + name does
|
|
@@ -1035,11 +1278,28 @@ var AssetManager = class {
|
|
|
1035
1278
|
}
|
|
1036
1279
|
if (wanted.size === 0) return out;
|
|
1037
1280
|
const lockEntries = Object.entries(this.tryReadLock()?.assets ?? {});
|
|
1038
|
-
const
|
|
1039
|
-
|
|
1281
|
+
const scan = await this.scanLibraries();
|
|
1282
|
+
if (!scan) return out;
|
|
1283
|
+
const held = /* @__PURE__ */ new Set();
|
|
1284
|
+
for (const [key] of lockEntries) {
|
|
1285
|
+
const { publisher, kind, name } = parseCanonicalLockKey(key);
|
|
1286
|
+
if (publisher && kind && name) held.add(`${publisher}/${kind}:${name}`);
|
|
1287
|
+
}
|
|
1288
|
+
for (const d of this.loadConfig().dependencies) {
|
|
1289
|
+
const id = refIdentity(d);
|
|
1290
|
+
if (id !== null) held.add(id);
|
|
1291
|
+
}
|
|
1040
1292
|
for (const [ref, w] of wanted) {
|
|
1041
|
-
const
|
|
1042
|
-
|
|
1293
|
+
const origin = lockEntries.map(([key, e]) => ({ id: parseCanonicalLockKey(key), library: e.library })).find(
|
|
1294
|
+
({ id, library }) => library && !library.installed && id.kind === w.kind && id.name === w.name && id.publisher === w.publisher
|
|
1295
|
+
)?.library?.name;
|
|
1296
|
+
const pool = [...scan.byKey.values()].flat().filter(
|
|
1297
|
+
(c) => c.entry.kind === w.kind && c.entry.name === w.name && c.entry.publisher !== w.publisher && (origin ? c.library === origin : !held.has(`${c.entry.publisher}/${c.entry.kind}:${c.entry.name}`))
|
|
1298
|
+
);
|
|
1299
|
+
const publishers = new Set(pool.map((c) => c.entry.publisher));
|
|
1300
|
+
const best = publishers.size === 1 ? pool.sort(libraryPreference(scan.isDefaultLib))[0] : void 0;
|
|
1301
|
+
const moved = best?.entry;
|
|
1302
|
+
const movedLibrary = best?.library;
|
|
1043
1303
|
const finding = {};
|
|
1044
1304
|
for (const [key, entry] of lockEntries) {
|
|
1045
1305
|
const id = parseCanonicalLockKey(key);
|
|
@@ -1104,17 +1364,20 @@ var AssetManager = class {
|
|
|
1104
1364
|
if (!origin) continue;
|
|
1105
1365
|
const plain = want.publisher ? `${want.kind}:@${want.publisher}/${want.name}` : `${want.kind}:${want.name}`;
|
|
1106
1366
|
const moved = findings.get(ref)?.moved;
|
|
1367
|
+
const lookup = this.lockedLibrary(origin, snap);
|
|
1107
1368
|
if (moved?.library && want.publisher) {
|
|
1108
1369
|
out.set(
|
|
1109
1370
|
ref,
|
|
1110
1371
|
`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
1372
|
);
|
|
1112
|
-
} else if (
|
|
1113
|
-
out.set(ref,
|
|
1373
|
+
} else if (lookup.state === "dir-missing") {
|
|
1374
|
+
out.set(ref, lockedLibraryProblem(lookup, origin, plain));
|
|
1375
|
+
} else if (lookup.state === "unregistered") {
|
|
1376
|
+
out.set(ref, unregisteredLibraryFix(origin, plain));
|
|
1114
1377
|
} else {
|
|
1115
1378
|
out.set(
|
|
1116
1379
|
ref,
|
|
1117
|
-
`library "${
|
|
1380
|
+
`library "${lookup.name}" no longer holds it \u2014 restore it there, or drop the dependency with \`skaile remove ${plain}\``
|
|
1118
1381
|
);
|
|
1119
1382
|
}
|
|
1120
1383
|
}
|
|
@@ -1214,27 +1477,120 @@ var AssetManager = class {
|
|
|
1214
1477
|
* preferring it would lock a stale version after an in-place bump. The hash is
|
|
1215
1478
|
* computed from the files on disk, so it matches what `install --locked`
|
|
1216
1479
|
* re-hashes.
|
|
1480
|
+
*
|
|
1481
|
+
* A git-backed library also records its remote URL. When the previous lock names the
|
|
1482
|
+
* library under another name that {@link lockedLibrary} matched to this one by URL (a
|
|
1483
|
+
* teammate registered the same remote under a different name), the entry keeps the locked
|
|
1484
|
+
* name and URL: the lock does not change because it was installed on another machine.
|
|
1217
1485
|
*/
|
|
1218
1486
|
async libraryLockEntries(lib) {
|
|
1219
1487
|
if (lib.entries.length === 0) return {};
|
|
1220
1488
|
const snap = await this.loadLibraryIndex();
|
|
1489
|
+
const previous = Object.entries(this.tryReadLock()?.assets ?? {}).filter(
|
|
1490
|
+
([, e]) => e.library !== void 0 && !e.library.installed
|
|
1491
|
+
);
|
|
1221
1492
|
const diskHashes = /* @__PURE__ */ new Map();
|
|
1222
1493
|
return buildLibraryLockEntries(
|
|
1223
1494
|
lib.entries.map((e) => {
|
|
1224
1495
|
const name = lib.libraryOf.get(e) ?? "";
|
|
1225
1496
|
const publisher = e.publisher ?? "";
|
|
1226
1497
|
const def = newestLibraryDef(snap, name, { kind: e.kind, publisher, name: e.name });
|
|
1227
|
-
const libPath = this.libraryPath(name, snap);
|
|
1498
|
+
const libPath = this.libraryPath({ name }, snap);
|
|
1228
1499
|
const sha256 = (libPath ? libraryDiskHashes(libPath, diskHashes, this.registry).get(`${e.kind}:${e.name}`) : void 0) ?? def?.sha256;
|
|
1500
|
+
const registered = snap?.libraries.find((l) => l.name === name);
|
|
1501
|
+
let lockName = name;
|
|
1502
|
+
let url = registered ? libraryRemoteUrl(registered) : void 0;
|
|
1503
|
+
const locked = previous.find(([key]) => {
|
|
1504
|
+
const id = parseCanonicalLockKey(key);
|
|
1505
|
+
return id.kind === e.kind && id.name === e.name && id.publisher === publisher;
|
|
1506
|
+
})?.[1].library;
|
|
1507
|
+
if (locked) {
|
|
1508
|
+
const lookup = this.lockedLibrary(locked, snap);
|
|
1509
|
+
if (lookup.state === "ok" && lookup.name === name) {
|
|
1510
|
+
lockName = locked.name;
|
|
1511
|
+
if (locked.url && url && normalizeRepoUrl(locked.url) === normalizeRepoUrl(url)) {
|
|
1512
|
+
url = locked.url;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1229
1516
|
return {
|
|
1230
1517
|
kind: e.kind,
|
|
1231
1518
|
publisher,
|
|
1232
1519
|
name: e.name,
|
|
1233
|
-
library: {
|
|
1520
|
+
library: {
|
|
1521
|
+
name: lockName,
|
|
1522
|
+
version: e.version || def?.version || "0.0.0",
|
|
1523
|
+
sha256,
|
|
1524
|
+
...url ? { url } : {}
|
|
1525
|
+
}
|
|
1234
1526
|
};
|
|
1235
1527
|
})
|
|
1236
1528
|
);
|
|
1237
1529
|
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Lock keys that `skaile.yaml` still wants: the entries a declared ref names, plus every
|
|
1532
|
+
* entry such an asset requires, transitively. All keys when a `preset:` is declared.
|
|
1533
|
+
*/
|
|
1534
|
+
async declaredLockKeys(lock, declared) {
|
|
1535
|
+
const keys = Object.keys(lock.assets);
|
|
1536
|
+
const wanted = declared.map((d) => parseRefTolerant(d.split(" ")[0] ?? d));
|
|
1537
|
+
if (wanted.some((w) => w?.kind === "preset")) return new Set(keys);
|
|
1538
|
+
const matching = (want) => keys.filter((key) => {
|
|
1539
|
+
const id = parseCanonicalLockKey(key);
|
|
1540
|
+
return id.kind === want.kind && id.name === want.name && (!want.publisher || !id.publisher || id.publisher === want.publisher);
|
|
1541
|
+
});
|
|
1542
|
+
const inScope = /* @__PURE__ */ new Set();
|
|
1543
|
+
const queue = [];
|
|
1544
|
+
const add = (key) => {
|
|
1545
|
+
if (inScope.has(key)) return;
|
|
1546
|
+
inScope.add(key);
|
|
1547
|
+
queue.push(key);
|
|
1548
|
+
};
|
|
1549
|
+
for (const w of wanted) if (w) matching(w).forEach(add);
|
|
1550
|
+
for (const key of queue) {
|
|
1551
|
+
for (const dep of await this.deployedRequirementsOf(parseCanonicalLockKey(key))) {
|
|
1552
|
+
const want = memberIdentity(dep);
|
|
1553
|
+
if (want) matching(want).forEach(add);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
return inScope;
|
|
1557
|
+
}
|
|
1558
|
+
/**
|
|
1559
|
+
* The `Missing:` lines of every library-origin lock entry whose library cannot supply
|
|
1560
|
+
* assets on this machine (not registered, or registered with its directory gone). Plain
|
|
1561
|
+
* `install` stops on a non-empty list, the same lines `install --locked` prints: it must
|
|
1562
|
+
* not re-resolve a locked asset from another origin. The ONE function that decides "the
|
|
1563
|
+
* locked library is not here", so a lock-recorded URL fallback extends it in one place.
|
|
1564
|
+
*
|
|
1565
|
+
* Only entries `skaile.yaml` still declares, or that a declared asset requires
|
|
1566
|
+
* (transitively, read from the deployed copy), count. A stale entry nothing declares is
|
|
1567
|
+
* pruned by `install` as usual, so a removed dependency whose library is gone can be
|
|
1568
|
+
* cleaned up. With a declared `preset:` every entry counts: the lock records no edge
|
|
1569
|
+
* from a preset to its items, and the preset's own library may be the one that is gone.
|
|
1570
|
+
*
|
|
1571
|
+
* @param declared - The `dependencies:` refs as written in `skaile.yaml`.
|
|
1572
|
+
*/
|
|
1573
|
+
async unavailableLockedLibraries(lock, declared) {
|
|
1574
|
+
const inScope = await this.declaredLockKeys(lock, declared);
|
|
1575
|
+
const locked = Object.entries(lock.assets).filter(
|
|
1576
|
+
([key, e]) => e.library !== void 0 && !e.library.installed && inScope.has(key)
|
|
1577
|
+
);
|
|
1578
|
+
if (locked.length === 0) return [];
|
|
1579
|
+
const snap = await this.loadLibraryIndex();
|
|
1580
|
+
const lines = [];
|
|
1581
|
+
for (const [ref, e] of locked) {
|
|
1582
|
+
const { publisher, kind, name } = parseCanonicalLockKey(ref);
|
|
1583
|
+
if (!publisher || !kind || !name) continue;
|
|
1584
|
+
const lookup = this.lockedLibrary(e.library, snap);
|
|
1585
|
+
if (lookup.state === "ok") continue;
|
|
1586
|
+
const component = this.installTarget(kind);
|
|
1587
|
+
const deployed = component !== void 0 && isDeployed(component, name, this.driverTarget, this.global, this.projectDir);
|
|
1588
|
+
const problem = lockedLibraryProblem(lookup, e.library, `${kind}:@${publisher}/${name}`);
|
|
1589
|
+
const kept = deployed ? "the deployed copy and its lock entry are kept" : "its lock entry is kept; no deployed copy exists";
|
|
1590
|
+
lines.push(`${ref} (${problem}; ${kept})`);
|
|
1591
|
+
}
|
|
1592
|
+
return lines;
|
|
1593
|
+
}
|
|
1238
1594
|
/**
|
|
1239
1595
|
* Re-resolve every library-origin lock entry from its named library, for
|
|
1240
1596
|
* `install --locked`. An entry is restored only when its library is still
|
|
@@ -1258,25 +1614,26 @@ var AssetManager = class {
|
|
|
1258
1614
|
missing.push(`${ref} (unparseable lock key)`);
|
|
1259
1615
|
continue;
|
|
1260
1616
|
}
|
|
1261
|
-
const
|
|
1262
|
-
if (
|
|
1617
|
+
const lookup = this.lockedLibrary(origin, snap);
|
|
1618
|
+
if (lookup.state !== "ok") {
|
|
1263
1619
|
missing.push(
|
|
1264
|
-
`${ref} (
|
|
1620
|
+
`${ref} (${lockedLibraryProblem(lookup, origin, `${kind}:@${publisher}/${name}`)})`
|
|
1265
1621
|
);
|
|
1266
1622
|
continue;
|
|
1267
1623
|
}
|
|
1624
|
+
const libPath = lookup.path;
|
|
1268
1625
|
const found = (await scanDirectory(libPath, publisher, { knownKinds: this.knownKinds })).find(
|
|
1269
1626
|
(x) => x.kind === kind && x.name === name
|
|
1270
1627
|
);
|
|
1271
1628
|
if (!found) {
|
|
1272
|
-
missing.push(`${ref} (not found in library "${
|
|
1629
|
+
missing.push(`${ref} (not found in library "${lookup.name}")`);
|
|
1273
1630
|
continue;
|
|
1274
1631
|
}
|
|
1275
|
-
const def = newestLibraryDef(snap,
|
|
1632
|
+
const def = newestLibraryDef(snap, lookup.name, { kind, publisher, name });
|
|
1276
1633
|
const current = found.version || def?.version || "0.0.0";
|
|
1277
1634
|
if (current !== origin.version) {
|
|
1278
1635
|
missing.push(
|
|
1279
|
-
`${ref} (library "${
|
|
1636
|
+
`${ref} (library "${lookup.name}" is at ${current}, locked ${origin.version})`
|
|
1280
1637
|
);
|
|
1281
1638
|
continue;
|
|
1282
1639
|
}
|
|
@@ -1284,29 +1641,103 @@ var AssetManager = class {
|
|
|
1284
1641
|
const onDisk = libraryDiskHashes(libPath, diskHashes, this.registry).get(`${kind}:${name}`);
|
|
1285
1642
|
if (onDisk !== void 0 && onDisk !== origin.sha256) {
|
|
1286
1643
|
missing.push(
|
|
1287
|
-
`${ref} (library "${
|
|
1644
|
+
`${ref} (library "${lookup.name}" content changed since lock \u2014 or the lock predates the one shared asset hash; re-lock with \`skaile install\`)`
|
|
1288
1645
|
);
|
|
1289
1646
|
continue;
|
|
1290
1647
|
}
|
|
1291
1648
|
}
|
|
1649
|
+
found.version = current;
|
|
1292
1650
|
entries.push(withLibraryFiles(found, libPath, fileSets, this.registry));
|
|
1293
1651
|
}
|
|
1294
1652
|
return { entries, missing };
|
|
1295
1653
|
}
|
|
1296
1654
|
/**
|
|
1297
|
-
*
|
|
1298
|
-
*
|
|
1655
|
+
* Whether a deployed copy exists for the lock entries `install` kept for the unresolved
|
|
1656
|
+
* `ref`. A kind with no install target has no deployed copy.
|
|
1657
|
+
*/
|
|
1658
|
+
keptCopyDeployed(kept, ref) {
|
|
1659
|
+
const want = parseRefTolerant(ref.split(" ")[0] ?? ref);
|
|
1660
|
+
if (!want) return false;
|
|
1661
|
+
return Object.keys(kept.assets).some((key) => {
|
|
1662
|
+
const id = parseCanonicalLockKey(key);
|
|
1663
|
+
if (id.kind !== want.kind || id.name !== want.name) return false;
|
|
1664
|
+
if (want.publisher && id.publisher !== want.publisher) return false;
|
|
1665
|
+
const component = this.installTarget(id.kind);
|
|
1666
|
+
return component !== void 0 && isDeployed(component, id.name, this.driverTarget, this.global, this.projectDir);
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
/**
|
|
1670
|
+
* How the library `origin` names stands on this machine. THE one lookup of a locked library
|
|
1671
|
+
* ("is it registered here?"): `check`, `outdated`, `install` and `install --locked` all ask it.
|
|
1672
|
+
*
|
|
1673
|
+
* - registered in the index under its name: `ok` at its registered path, or `dir-missing` when
|
|
1674
|
+
* that directory is gone;
|
|
1675
|
+
* - not registered: a directory `<libraries dir>/<name>` nobody unregistered still counts as a
|
|
1676
|
+
* hand-made library (`ok`). One `library remove` unregistered without `--purge` does not
|
|
1677
|
+
* (it stays on disk but no longer resolves), and neither does the reserved `installed` folder.
|
|
1678
|
+
* - otherwise, when the lock recorded the library's remote URL: another registered library
|
|
1679
|
+
* whose git remote is the same repository (`.git` suffix, trailing `/` and the
|
|
1680
|
+
* `git@host:o/r` / `https://host/o/r` forms do not matter) and whose directory exists is
|
|
1681
|
+
* `ok`, with `name` set to the name it is registered under here. The library name is
|
|
1682
|
+
* machine-local; the remote is what a clone shares.
|
|
1299
1683
|
*/
|
|
1300
|
-
|
|
1301
|
-
|
|
1684
|
+
lockedLibrary(origin, snap) {
|
|
1685
|
+
const { name } = origin;
|
|
1686
|
+
if (name === GLOBAL_INSTALL_DIR_NAME) return { state: "unregistered" };
|
|
1687
|
+
let byName = { state: "unregistered" };
|
|
1302
1688
|
const registered = snap?.libraries.find((l) => l.name === name)?.path;
|
|
1303
|
-
if (registered
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1689
|
+
if (registered) {
|
|
1690
|
+
byName = existsSync(registered) ? { state: "ok", path: registered, name } : { state: "dir-missing", path: registered };
|
|
1691
|
+
} else {
|
|
1692
|
+
try {
|
|
1693
|
+
const guess = join(resolveLibraryDir(), name);
|
|
1694
|
+
if (existsSync(guess) && !unregisteredLibraryNames().has(name)) {
|
|
1695
|
+
byName = { state: "ok", path: guess, name };
|
|
1696
|
+
}
|
|
1697
|
+
} catch {
|
|
1698
|
+
}
|
|
1309
1699
|
}
|
|
1700
|
+
if (byName.state === "ok" || !origin.url) return byName;
|
|
1701
|
+
const wanted = normalizeRepoUrl(origin.url);
|
|
1702
|
+
const byUrl = snap?.libraries.find((l) => {
|
|
1703
|
+
const url = libraryRemoteUrl(l);
|
|
1704
|
+
return l.name !== name && url !== void 0 && normalizeRepoUrl(url) === wanted && existsSync(l.path);
|
|
1705
|
+
});
|
|
1706
|
+
return byUrl ? { state: "ok", path: byUrl.path, name: byUrl.name } : byName;
|
|
1707
|
+
}
|
|
1708
|
+
/** On-disk root of the library `origin` names; `null` unless {@link lockedLibrary} says `ok`. */
|
|
1709
|
+
libraryPath(origin, snap) {
|
|
1710
|
+
const found = this.lockedLibrary(origin, snap);
|
|
1711
|
+
return found.state === "ok" ? found.path : null;
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Where each library-origin lock entry of this project resolves on this machine: identity
|
|
1715
|
+
* `kind:publisher/name` (no scope sigil, no version) → the name the locked library is
|
|
1716
|
+
* registered under here. The name differs from the locked one when the lock's remote URL
|
|
1717
|
+
* matched another registered library ({@link lockedLibrary}). A deployed entry whose library
|
|
1718
|
+
* resolves nowhere (not registered, directory gone) maps to `null`.
|
|
1719
|
+
*
|
|
1720
|
+
* Direct `asset install` entries (`library.installed`) are included and resolved the same
|
|
1721
|
+
* way, but they map to the locked library name when that lookup fails: such a copy sits in
|
|
1722
|
+
* the project and does not depend on the library still being registered. A missing or
|
|
1723
|
+
* unreadable lock yields an empty map. `skaile manage` uses it to tick the right library row.
|
|
1724
|
+
*/
|
|
1725
|
+
async lockedLibraryNames() {
|
|
1726
|
+
const out = /* @__PURE__ */ new Map();
|
|
1727
|
+
const locked = Object.entries(this.tryReadLock()?.assets ?? {}).filter(
|
|
1728
|
+
([, e]) => e.library !== void 0
|
|
1729
|
+
);
|
|
1730
|
+
if (locked.length === 0) return out;
|
|
1731
|
+
const snap = await this.loadLibraryIndex();
|
|
1732
|
+
for (const [key, e] of locked) {
|
|
1733
|
+
const { publisher, kind, name } = parseCanonicalLockKey(key);
|
|
1734
|
+
if (!publisher || !kind || !name) continue;
|
|
1735
|
+
const origin = e.library;
|
|
1736
|
+
const lookup = this.lockedLibrary(origin, snap);
|
|
1737
|
+
const resolved = lookup.state === "ok" ? lookup.name : origin.installed ? origin.name : null;
|
|
1738
|
+
out.set(`${kind}:${publisher}/${name}`, resolved);
|
|
1739
|
+
}
|
|
1740
|
+
return out;
|
|
1310
1741
|
}
|
|
1311
1742
|
// ── Store fetch-then-deploy ────────────────────────────────────────────
|
|
1312
1743
|
/** A candidate's stable identity key (`<publisher>/<kind>:<name>@<version>`). */
|
|
@@ -1443,7 +1874,9 @@ var AssetManager = class {
|
|
|
1443
1874
|
return id !== null && (opts.provenanceIndex.get(id)?.length ?? 0) === 0;
|
|
1444
1875
|
})
|
|
1445
1876
|
);
|
|
1446
|
-
const hit = await this.resolveLibraryEntries([...libraryTried]
|
|
1877
|
+
const hit = await this.resolveLibraryEntries([...libraryTried], {
|
|
1878
|
+
quiet: !opts.warnCollisions
|
|
1879
|
+
});
|
|
1447
1880
|
const next = absorb(hit);
|
|
1448
1881
|
const rest = fresh.filter((ref) => !hit.resolved.has(ref));
|
|
1449
1882
|
if (rest.length > 0) {
|
|
@@ -1458,7 +1891,8 @@ var AssetManager = class {
|
|
|
1458
1891
|
for (const o of r.overridesApplied) overridesApplied.add(o);
|
|
1459
1892
|
presets.push(...r.presets);
|
|
1460
1893
|
const hit2 = await this.resolveLibraryEntries(
|
|
1461
|
-
r.missing.filter((m) => !libraryTried.has(m))
|
|
1894
|
+
r.missing.filter((m) => !libraryTried.has(m)),
|
|
1895
|
+
{ quiet: !opts.warnCollisions }
|
|
1462
1896
|
);
|
|
1463
1897
|
next.push(...absorb(hit2));
|
|
1464
1898
|
for (const m of r.missing) if (!hit2.resolved.has(m)) missing.add(m);
|
|
@@ -1638,6 +2072,20 @@ var AssetManager = class {
|
|
|
1638
2072
|
if (opts?.locked) {
|
|
1639
2073
|
return this.installLocked(repositories, patches, dependencies);
|
|
1640
2074
|
}
|
|
2075
|
+
const lockForLibraries = this.tryReadLock();
|
|
2076
|
+
if (lockForLibraries) {
|
|
2077
|
+
const unavailable = await this.unavailableLockedLibraries(lockForLibraries, dependencies);
|
|
2078
|
+
if (unavailable.length > 0) {
|
|
2079
|
+
return {
|
|
2080
|
+
deployed: [],
|
|
2081
|
+
removed: [],
|
|
2082
|
+
missing: unavailable,
|
|
2083
|
+
lockWritten: false,
|
|
2084
|
+
npmInstalled: [],
|
|
2085
|
+
npmFailed: []
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
1641
2089
|
const cloneError = this.ensureSourceClones(repositories, sources);
|
|
1642
2090
|
if (cloneError) return cloneError;
|
|
1643
2091
|
const provenanceIndex = await buildProvenanceIndex(this.buildClones(repositories), {
|
|
@@ -1657,16 +2105,19 @@ var AssetManager = class {
|
|
|
1657
2105
|
for (const ref of /* @__PURE__ */ new Set([...kept.refs, ...fixes.keys()])) {
|
|
1658
2106
|
const fix = fixes.get(ref);
|
|
1659
2107
|
const notes = [
|
|
1660
|
-
kept.refs.has(ref) ? "the deployed copy and its lock entry are kept" : void 0,
|
|
2108
|
+
kept.refs.has(ref) ? this.keptCopyDeployed(kept, ref) ? "the deployed copy and its lock entry are kept" : "its lock entry is kept; no deployed copy exists" : void 0,
|
|
1661
2109
|
fix
|
|
1662
2110
|
].filter((n) => n !== void 0);
|
|
1663
2111
|
missingHints[ref] = `${fix ? "" : missingHints[ref] ?? ""} (${notes.join("; ")})`;
|
|
1664
2112
|
}
|
|
1665
2113
|
const directLock = this.directInstallLockEntries();
|
|
1666
2114
|
const libraryLock = { ...directLock, ...await this.libraryLockEntries(lib) };
|
|
1667
|
-
const freshLock =
|
|
2115
|
+
const freshLock = {
|
|
2116
|
+
...buildLockFile(resolved, overridesApplied, libraryLock),
|
|
2117
|
+
...presetsLockSlice(presets)
|
|
2118
|
+
};
|
|
1668
2119
|
await this.keepRequiredByKept(prevLock, kept, Object.keys(freshLock.assets));
|
|
1669
|
-
const removed = this.reconcileRemovedAssets(
|
|
2120
|
+
const { removed, replaced } = this.reconcileRemovedAssets(
|
|
1670
2121
|
resolved,
|
|
1671
2122
|
/* @__PURE__ */ new Set([...Object.keys(libraryLock), ...Object.keys(kept.assets)])
|
|
1672
2123
|
);
|
|
@@ -1680,12 +2131,13 @@ var AssetManager = class {
|
|
|
1680
2131
|
];
|
|
1681
2132
|
await this.renderDriverMcpConfig();
|
|
1682
2133
|
const agentRender = this.renderAgentInstances();
|
|
1683
|
-
const
|
|
2134
|
+
const lockWanted = resolved.length > 0 || lib.entries.length > 0 || existsSync(this.lockPath);
|
|
2135
|
+
let lockWritten = false;
|
|
1684
2136
|
let relocked = [];
|
|
1685
|
-
if (
|
|
2137
|
+
if (lockWanted) {
|
|
1686
2138
|
const lockData = withKeptLockEntries(freshLock, kept);
|
|
1687
2139
|
relocked = relockedRefs(prevLock, lockData);
|
|
1688
|
-
writeLock(this.lockPath, lockData);
|
|
2140
|
+
lockWritten = writeLock(this.lockPath, lockData);
|
|
1689
2141
|
}
|
|
1690
2142
|
this.recordInstallHistory(deployed, removed);
|
|
1691
2143
|
const { npmInstalled, npmFailed } = await this.installRuntimeAssetDeps();
|
|
@@ -1695,6 +2147,7 @@ var AssetManager = class {
|
|
|
1695
2147
|
missing: stillMissing,
|
|
1696
2148
|
...Object.keys(missingHints).length > 0 ? { missingHints } : {},
|
|
1697
2149
|
...relocked.length > 0 ? { relocked } : {},
|
|
2150
|
+
...replaced.length > 0 ? { replaced } : {},
|
|
1698
2151
|
lockWritten,
|
|
1699
2152
|
npmInstalled,
|
|
1700
2153
|
npmFailed,
|
|
@@ -1714,7 +2167,7 @@ var AssetManager = class {
|
|
|
1714
2167
|
const fresh = freshKeys.map(parseCanonicalLockKey);
|
|
1715
2168
|
const queue = Object.keys(kept.assets);
|
|
1716
2169
|
for (const key of queue) {
|
|
1717
|
-
for (const dep of await this.
|
|
2170
|
+
for (const dep of await this.deployedRequirementsOf(parseCanonicalLockKey(key))) {
|
|
1718
2171
|
const want = memberIdentity(dep);
|
|
1719
2172
|
if (!want) continue;
|
|
1720
2173
|
const matches = (id) => id.kind === want.kind && id.name === want.name && (!want.publisher || !id.publisher || id.publisher === want.publisher);
|
|
@@ -1730,9 +2183,14 @@ var AssetManager = class {
|
|
|
1730
2183
|
}
|
|
1731
2184
|
}
|
|
1732
2185
|
}
|
|
1733
|
-
/**
|
|
1734
|
-
|
|
1735
|
-
|
|
2186
|
+
/**
|
|
2187
|
+
* Publisher-qualified refs the deployed copy of `id` requires, read from its own
|
|
2188
|
+
* manifest file (`metadata.requires`, a manifest `dependencies:` entry): the one place
|
|
2189
|
+
* the requirements stay knowable when no source or library holds the asset any more.
|
|
2190
|
+
* A copy that is not deployed or cannot be read has no known requirements.
|
|
2191
|
+
*/
|
|
2192
|
+
async deployedRequirementsOf(id) {
|
|
2193
|
+
const { kind, name, publisher } = id;
|
|
1736
2194
|
const component = kind ? this.installTarget(kind) : void 0;
|
|
1737
2195
|
if (!kind || !name || !component) return [];
|
|
1738
2196
|
const dir = deployedDir(component, name, this.driverTarget, this.global, this.projectDir);
|
|
@@ -1805,21 +2263,32 @@ var AssetManager = class {
|
|
|
1805
2263
|
...keep
|
|
1806
2264
|
]);
|
|
1807
2265
|
const removed = [];
|
|
2266
|
+
const replaced = [];
|
|
1808
2267
|
if (oldLock) {
|
|
1809
2268
|
for (const ref of Object.keys(oldLock.assets)) {
|
|
1810
2269
|
if (!resolvedRefs.has(ref)) {
|
|
1811
|
-
const { kind, name } = parseCanonicalLockKey(ref);
|
|
2270
|
+
const { kind, name, publisher, version } = parseCanonicalLockKey(ref);
|
|
1812
2271
|
if (kind === "preset") continue;
|
|
1813
2272
|
if (kind && name) {
|
|
1814
2273
|
for (const t of this.targetHarnesses()) removeAsset(kind, name, this.deployOptsFor(t));
|
|
1815
|
-
|
|
2274
|
+
const successor = [...resolvedRefs].find((r) => {
|
|
2275
|
+
const o = parseCanonicalLockKey(r);
|
|
2276
|
+
return o.kind === kind && o.name === name && o.publisher === publisher;
|
|
2277
|
+
});
|
|
2278
|
+
if (successor) {
|
|
2279
|
+
replaced.push({
|
|
2280
|
+
ref: `${kind}:${publisher ? `@${publisher}/` : ""}${name}`,
|
|
2281
|
+
from: version ?? "",
|
|
2282
|
+
to: parseCanonicalLockKey(successor).version ?? ""
|
|
2283
|
+
});
|
|
2284
|
+
} else removed.push(ref);
|
|
1816
2285
|
} else {
|
|
1817
2286
|
console.warn(`skaile: cannot reconcile unparseable lock key "${ref}" \u2014 left in place.`);
|
|
1818
2287
|
}
|
|
1819
2288
|
}
|
|
1820
2289
|
}
|
|
1821
2290
|
}
|
|
1822
|
-
return removed;
|
|
2291
|
+
return { removed, replaced };
|
|
1823
2292
|
}
|
|
1824
2293
|
/** Append `add`/`remove` history entries for a completed install reconcile. */
|
|
1825
2294
|
recordInstallHistory(deployed, removed) {
|
|
@@ -2019,7 +2488,8 @@ var AssetManager = class {
|
|
|
2019
2488
|
return p ? `${p.kind}:${p.name}` : m;
|
|
2020
2489
|
})
|
|
2021
2490
|
);
|
|
2022
|
-
const gaps = (await this.
|
|
2491
|
+
const gaps = (await this.projectState()).gaps.filter((g) => {
|
|
2492
|
+
if (g.type === "agent") return false;
|
|
2023
2493
|
const p = parseRefTolerant(g.ref);
|
|
2024
2494
|
return !(p && alreadyMissing.has(`${p.kind}:${p.name}`));
|
|
2025
2495
|
}).map((g) => g.message);
|
|
@@ -2031,6 +2501,64 @@ var AssetManager = class {
|
|
|
2031
2501
|
...agentRender
|
|
2032
2502
|
};
|
|
2033
2503
|
}
|
|
2504
|
+
/**
|
|
2505
|
+
* Parse the ref `add` was given. A ref the grammar rejects fails with the parser's message
|
|
2506
|
+
* minus its manifest-migration advice (it points at a skill that is not for `add`), and:
|
|
2507
|
+
* - a publisher-less ref (`report-html`, `skill:report-html`) names the assets of that
|
|
2508
|
+
* kind and name that `add` can resolve (a source, the bundled factory source or a
|
|
2509
|
+
* library holds them), so `Did you mean` never names an asset that does not resolve;
|
|
2510
|
+
* - a `@version` suffix (`skill:@acme/x@1.0.0`) says the pin is written `#<version>`.
|
|
2511
|
+
*/
|
|
2512
|
+
async parseAddRef(ref, repositories, sources) {
|
|
2513
|
+
try {
|
|
2514
|
+
return parseAssetRef(ref);
|
|
2515
|
+
} catch (err) {
|
|
2516
|
+
if (!(err instanceof Error)) throw err;
|
|
2517
|
+
const advice = " Run the `migrate-skaile-manifest` skill on legacy manifests.";
|
|
2518
|
+
const plain = err.message.endsWith(advice) ? err.message.slice(0, -advice.length) : err.message;
|
|
2519
|
+
if (plain.startsWith("publisher required")) {
|
|
2520
|
+
const matches = await this.resolvableMatches(ref, repositories, sources);
|
|
2521
|
+
const hint = matches.length === 0 ? "" : matches.length === 1 ? ` Did you mean ${matches[0]}?` : ` Did you mean one of: ${matches.join(", ")}?`;
|
|
2522
|
+
throw new Error(`${plain}${hint}`);
|
|
2523
|
+
}
|
|
2524
|
+
const pinned = /^(.*\/[^@#/]+)@([^@#/]+)$/.exec(ref.trim());
|
|
2525
|
+
if (pinned && plain.startsWith("invalid asset name")) {
|
|
2526
|
+
throw new Error(`${plain} To pin a version, write ${pinned[1]}#${pinned[2]}.`);
|
|
2527
|
+
}
|
|
2528
|
+
throw new Error(plain);
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
/**
|
|
2532
|
+
* The publisher-qualified refs of the assets named like the publisher-less `ref` that
|
|
2533
|
+
* `add` resolves: held by a source clone, the bundled factory source or a registered
|
|
2534
|
+
* library. A ref without a kind means a skill, as the grammar says.
|
|
2535
|
+
*/
|
|
2536
|
+
async resolvableMatches(ref, repositories, sources) {
|
|
2537
|
+
const trimmed = ref.trim();
|
|
2538
|
+
const colon = trimmed.indexOf(":");
|
|
2539
|
+
const rawKind = colon === -1 ? "skill" : trimmed.slice(0, colon).trim();
|
|
2540
|
+
const kind = rawKind === "mcp" ? "mcp-server" : rawKind;
|
|
2541
|
+
const hash = trimmed.indexOf("#", colon + 1);
|
|
2542
|
+
const name = trimmed.slice(colon + 1, hash === -1 ? void 0 : hash).trim();
|
|
2543
|
+
if (!name || /[@/\s]/.test(name)) return [];
|
|
2544
|
+
const found = /* @__PURE__ */ new Set();
|
|
2545
|
+
const note = (c) => {
|
|
2546
|
+
if (c.kind === kind && c.name === name && c.publisher) {
|
|
2547
|
+
found.add(assetRefToStr({ kind, name, publisher: c.publisher.replace(/^@/, "") }));
|
|
2548
|
+
}
|
|
2549
|
+
};
|
|
2550
|
+
try {
|
|
2551
|
+
this.ensureSourceClonesQuiet(repositories, sources);
|
|
2552
|
+
const index = await buildProvenanceIndex(this.buildClones(repositories), {
|
|
2553
|
+
projectDir: this.projectDir,
|
|
2554
|
+
knownKinds: this.knownKinds
|
|
2555
|
+
});
|
|
2556
|
+
for (const candidates of index.values()) for (const c of candidates) note(c);
|
|
2557
|
+
for (const { entry } of await this.libraryAssets()) note(entry);
|
|
2558
|
+
} catch {
|
|
2559
|
+
}
|
|
2560
|
+
return [...found].sort();
|
|
2561
|
+
}
|
|
2034
2562
|
/**
|
|
2035
2563
|
* Add a single asset (and its transitive dependencies) to the workspace.
|
|
2036
2564
|
*
|
|
@@ -2052,7 +2580,7 @@ var AssetManager = class {
|
|
|
2052
2580
|
*/
|
|
2053
2581
|
async add(ref, opts) {
|
|
2054
2582
|
const { repositories, sources, stores, dependencies, overrides, patches } = this.loadConfig();
|
|
2055
|
-
const parsed =
|
|
2583
|
+
const parsed = await this.parseAddRef(ref, repositories, sources);
|
|
2056
2584
|
this.ensureSourceClonesQuiet(repositories, sources);
|
|
2057
2585
|
const provenanceIndex = await buildProvenanceIndex(this.buildClones(repositories), {
|
|
2058
2586
|
projectDir: this.projectDir,
|
|
@@ -2060,9 +2588,24 @@ var AssetManager = class {
|
|
|
2060
2588
|
});
|
|
2061
2589
|
const { resolved, missing, overridesApplied, lib, presets } = await this.resolveLibraryFirst(
|
|
2062
2590
|
[ref],
|
|
2063
|
-
{ provenanceIndex, overrides, stores, declaredRefs: dependencies }
|
|
2591
|
+
{ provenanceIndex, overrides, stores, declaredRefs: dependencies, warnCollisions: true }
|
|
2064
2592
|
);
|
|
2065
2593
|
if (resolved.length === 0 && lib.entries.length === 0 && presets.length === 0) {
|
|
2594
|
+
const snap = await this.loadLibraryIndex();
|
|
2595
|
+
const bare = (p) => (p ?? "").replace(/^@/, "");
|
|
2596
|
+
for (const l of snap?.libraries ?? []) {
|
|
2597
|
+
const libPath = this.libraryPath({ name: l.name }, snap);
|
|
2598
|
+
if (!libPath || !manifestFileHasAssetsArray(libPath)) continue;
|
|
2599
|
+
const unlisted = await scanUnlistedAssets(libPath, l.name, this.registry);
|
|
2600
|
+
const hit = unlisted.find(
|
|
2601
|
+
(u) => !u.registeredAt && u.entry.kind === parsed.kind && u.entry.name === parsed.name && (!parsed.publisher || bare(u.entry.publisher) === bare(parsed.publisher))
|
|
2602
|
+
);
|
|
2603
|
+
if (hit) {
|
|
2604
|
+
throw new Error(
|
|
2605
|
+
`${canonicalEntryRef(hit.entry)} is in library "${l.name}" but not listed in its skaile.manifest.yaml, so only part of its files would be deployed. Run \`skaile library index ${l.name}\`, then add it again.`
|
|
2606
|
+
);
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2066
2609
|
throw new Error(
|
|
2067
2610
|
`Asset not found: ${ref}${(await this.publisherChangeHints([ref]))[ref] ?? ""}${missing.length ? ` (missing: ${missing.join(", ")})` : ""}`
|
|
2068
2611
|
);
|
|
@@ -2072,6 +2615,18 @@ var AssetManager = class {
|
|
|
2072
2615
|
`Preset ${ref} has items that do not resolve: ${missing.join(", ")} \u2014 nothing was added`
|
|
2073
2616
|
);
|
|
2074
2617
|
}
|
|
2618
|
+
if (lib.entries.length > 0) {
|
|
2619
|
+
const snap = await this.loadLibraryIndex();
|
|
2620
|
+
for (const e of lib.entries) {
|
|
2621
|
+
const origin = lib.libraryOf.get(e);
|
|
2622
|
+
const libPath = origin ? this.libraryPath({ name: origin }, snap) : null;
|
|
2623
|
+
if (origin && libPath && isUnlistedLibraryAsset(e, libPath)) {
|
|
2624
|
+
throw new Error(
|
|
2625
|
+
`${canonicalEntryRef(e)} is in library "${origin}" but not listed in its skaile.manifest.yaml, so only part of its files would be deployed. Run \`skaile library index ${origin}\`, then add it again.`
|
|
2626
|
+
);
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2075
2630
|
this.assertNoFolderCollision(
|
|
2076
2631
|
[...resolved, ...lib.entries.map((e) => this.entryIdentity(e))],
|
|
2077
2632
|
[
|
|
@@ -2088,7 +2643,12 @@ var AssetManager = class {
|
|
|
2088
2643
|
const deployed = [
|
|
2089
2644
|
...new Set(
|
|
2090
2645
|
this.targetHarnesses().flatMap(
|
|
2091
|
-
(t) => deployAll(
|
|
2646
|
+
(t) => deployAll(
|
|
2647
|
+
entries,
|
|
2648
|
+
repositories,
|
|
2649
|
+
patches,
|
|
2650
|
+
this.deployOptsFor(t, opts?.link, opts?.onSkippedSymlink)
|
|
2651
|
+
)
|
|
2092
2652
|
)
|
|
2093
2653
|
)
|
|
2094
2654
|
];
|
|
@@ -2104,7 +2664,10 @@ var AssetManager = class {
|
|
|
2104
2664
|
await this.renderDriverMcpConfig();
|
|
2105
2665
|
this.renderAgentInstances();
|
|
2106
2666
|
if (resolved.length > 0 || lib.entries.length > 0) {
|
|
2107
|
-
const fresh =
|
|
2667
|
+
const fresh = {
|
|
2668
|
+
...buildLockFile(resolved, overridesApplied, await this.libraryLockEntries(lib)),
|
|
2669
|
+
...presetsLockSlice(presets)
|
|
2670
|
+
};
|
|
2108
2671
|
writeLock(this.lockPath, mergeLockFile(this.tryReadLock(), fresh));
|
|
2109
2672
|
}
|
|
2110
2673
|
for (const d of deployed) {
|
|
@@ -2383,19 +2946,39 @@ var AssetManager = class {
|
|
|
2383
2946
|
* preset's items count as its requirements. They are undeployed and unlocked;
|
|
2384
2947
|
* a dependency still declared or required elsewhere stays.
|
|
2385
2948
|
*
|
|
2949
|
+
* An asset another locked asset (or a declared preset) requires is kept and reported in
|
|
2950
|
+
* `blocked`, nothing changes, unless `opts.force` (see {@link requiredByOthers}).
|
|
2951
|
+
*
|
|
2386
2952
|
* @returns `changed` as {@link remove}; `pruned` the canonical refs
|
|
2387
|
-
* (`kind:@publisher/name`) of the dependencies dropped as well
|
|
2953
|
+
* (`kind:@publisher/name`) of the dependencies dropped as well; `blocked` when the
|
|
2954
|
+
* removal was refused.
|
|
2388
2955
|
*/
|
|
2389
|
-
async removeWithDependencies(ref) {
|
|
2956
|
+
async removeWithDependencies(ref, opts) {
|
|
2390
2957
|
const target = this.resolveRemoveTarget(ref);
|
|
2391
2958
|
if (!target) return { changed: false, pruned: [] };
|
|
2959
|
+
if (!opts?.force) {
|
|
2960
|
+
const blocked = await this.requiredByOthers(target);
|
|
2961
|
+
if (blocked) return { changed: false, pruned: [], blocked };
|
|
2962
|
+
}
|
|
2392
2963
|
const asked = target.publisher ? assetRefToStr({ kind: target.kind, name: target.name, publisher: target.publisher }) : `${target.kind}:${target.name}`;
|
|
2393
2964
|
let entry = null;
|
|
2394
2965
|
try {
|
|
2395
2966
|
entry = await this.info(asked);
|
|
2396
2967
|
} catch {
|
|
2397
2968
|
}
|
|
2398
|
-
|
|
2969
|
+
let requiredRefs;
|
|
2970
|
+
if (entry) {
|
|
2971
|
+
requiredRefs = libraryEntryDepRefs(entry);
|
|
2972
|
+
} else {
|
|
2973
|
+
const lockedAs = Object.keys(this.tryReadLock()?.assets ?? {}).map(parseCanonicalLockKey).find(
|
|
2974
|
+
(id) => id.kind === target.kind && id.name === target.name && (!target.publisher || id.publisher === target.publisher)
|
|
2975
|
+
);
|
|
2976
|
+
requiredRefs = await this.deployedRequirementsOf({
|
|
2977
|
+
kind: target.kind,
|
|
2978
|
+
name: target.name,
|
|
2979
|
+
publisher: target.publisher ?? lockedAs?.publisher
|
|
2980
|
+
});
|
|
2981
|
+
}
|
|
2399
2982
|
const changed = this.removeResolved(target);
|
|
2400
2983
|
if (!changed || requiredRefs.length === 0) return { changed, pruned: [] };
|
|
2401
2984
|
return { changed, pruned: await this.pruneOrphans(requiredRefs) };
|
|
@@ -2449,6 +3032,31 @@ var AssetManager = class {
|
|
|
2449
3032
|
return kind ? { kind, name } : null;
|
|
2450
3033
|
}
|
|
2451
3034
|
}
|
|
3035
|
+
/**
|
|
3036
|
+
* The reverse guard of {@link removeWithDependencies}: which other locked assets (and
|
|
3037
|
+
* declared presets) require `target`. Their requirements are read the way {@link lockedGraph}
|
|
3038
|
+
* reads them for pruning. Never touches the project.
|
|
3039
|
+
*
|
|
3040
|
+
* @returns `ref` and `requiredBy` (both `kind:@publisher/name`, version-agnostic), or `null`
|
|
3041
|
+
* when `target` is not locked or nothing else requires it.
|
|
3042
|
+
*/
|
|
3043
|
+
async requiredByOthers(target) {
|
|
3044
|
+
const lock = this.tryReadLock();
|
|
3045
|
+
if (!lock) return null;
|
|
3046
|
+
const { requires, findKey } = await this.lockedGraph(lock);
|
|
3047
|
+
const targetKey = findKey(
|
|
3048
|
+
target.publisher ? assetRefToStr({ kind: target.kind, name: target.name, publisher: target.publisher }) : `${target.kind}:${target.name}`
|
|
3049
|
+
);
|
|
3050
|
+
if (!targetKey) return null;
|
|
3051
|
+
const display = (node) => {
|
|
3052
|
+
if (!lock.assets[node]) return node;
|
|
3053
|
+
const { kind, name, publisher } = parseCanonicalLockKey(node);
|
|
3054
|
+
if (!kind || !name) return node;
|
|
3055
|
+
return publisher ? assetRefToStr({ kind, name, publisher }) : `${kind}:${name}`;
|
|
3056
|
+
};
|
|
3057
|
+
const requiredBy = [...requires].filter(([node, deps]) => node !== targetKey && deps.includes(targetKey)).map(([node]) => display(node));
|
|
3058
|
+
return requiredBy.length > 0 ? { ref: display(targetKey), requiredBy } : null;
|
|
3059
|
+
}
|
|
2452
3060
|
/** Undeploy `parsed` from every target harness and drop its declaration and lock entry. */
|
|
2453
3061
|
removeResolved(parsed) {
|
|
2454
3062
|
let undeployed = false;
|
|
@@ -2456,8 +3064,9 @@ var AssetManager = class {
|
|
|
2456
3064
|
if (removeAsset(parsed.kind, parsed.name, this.deployOptsFor(t))) undeployed = true;
|
|
2457
3065
|
}
|
|
2458
3066
|
const undeclared = this.removeDependencyFromConfig(parsed);
|
|
2459
|
-
const
|
|
2460
|
-
const
|
|
3067
|
+
const unbound = this.removeAgentBindings(parsed);
|
|
3068
|
+
const unlocked = undeployed || undeclared || unbound ? this.pruneLockEntry(parsed) : false;
|
|
3069
|
+
const changed = undeployed || undeclared || unbound || unlocked;
|
|
2461
3070
|
if (changed) {
|
|
2462
3071
|
appendHistory(this.projectDir, {
|
|
2463
3072
|
ref: `${parsed.kind}:${parsed.name}`,
|
|
@@ -2518,6 +3127,17 @@ var AssetManager = class {
|
|
|
2518
3127
|
changed = true;
|
|
2519
3128
|
}
|
|
2520
3129
|
}
|
|
3130
|
+
if (parsed.kind === "preset" && lock.presets) {
|
|
3131
|
+
const kept = lock.presets.filter((key) => {
|
|
3132
|
+
const id = parseCanonicalLockKey(key);
|
|
3133
|
+
return !(id.kind === parsed.kind && id.name === parsed.name && (!parsed.publisher || id.publisher === parsed.publisher));
|
|
3134
|
+
});
|
|
3135
|
+
if (kept.length !== lock.presets.length) {
|
|
3136
|
+
if (kept.length > 0) lock.presets = kept;
|
|
3137
|
+
else delete lock.presets;
|
|
3138
|
+
changed = true;
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
2521
3141
|
if (changed) writeLock(this.lockPath, lock);
|
|
2522
3142
|
return changed;
|
|
2523
3143
|
}
|
|
@@ -2578,6 +3198,7 @@ var AssetManager = class {
|
|
|
2578
3198
|
const { repositories } = this.loadConfig();
|
|
2579
3199
|
const parsed = parseRefTolerant(ref);
|
|
2580
3200
|
if (!parsed) return null;
|
|
3201
|
+
let best;
|
|
2581
3202
|
for (const [name, decl] of Object.entries(repositories)) {
|
|
2582
3203
|
const repoDir = this.resolveRepoDir(decl, name);
|
|
2583
3204
|
if (!repoDir) continue;
|
|
@@ -2585,9 +3206,12 @@ var AssetManager = class {
|
|
|
2585
3206
|
const match = entries.find(
|
|
2586
3207
|
(e) => e.kind === parsed.kind && e.name === parsed.name && (!parsed.publisher || e.publisher === parsed.publisher)
|
|
2587
3208
|
);
|
|
2588
|
-
if (match)
|
|
3209
|
+
if (match && (!best || gt(coerceVersion(match.version ?? ""), coerceVersion(best.version ?? "")))) {
|
|
3210
|
+
best = match;
|
|
3211
|
+
}
|
|
2589
3212
|
}
|
|
2590
|
-
|
|
3213
|
+
if (best) return best;
|
|
3214
|
+
const lib = await this.resolveLibraryEntries([ref], { quiet: true });
|
|
2591
3215
|
return lib.entries[0] ?? null;
|
|
2592
3216
|
}
|
|
2593
3217
|
/**
|
|
@@ -2929,7 +3553,8 @@ var AssetManager = class {
|
|
|
2929
3553
|
const out = [];
|
|
2930
3554
|
try {
|
|
2931
3555
|
const entry = await this.info(ref);
|
|
2932
|
-
|
|
3556
|
+
const deps = entry ? libraryEntryDepRefs(entry) : lock.assets[node] ? await this.deployedRequirementsOf(parseCanonicalLockKey(node)) : [];
|
|
3557
|
+
for (const dep of deps) {
|
|
2933
3558
|
const key = findKey(dep);
|
|
2934
3559
|
if (key && key !== node && !out.includes(key)) out.push(key);
|
|
2935
3560
|
}
|
|
@@ -3057,11 +3682,12 @@ var AssetManager = class {
|
|
|
3057
3682
|
* - **Library assets** — a library-origin lock entry whose library files on disk
|
|
3058
3683
|
* (not the index, which lags until `skaile library index`) hold a newer version
|
|
3059
3684
|
* than the locked one (`latestVersion`, `library` set), or the same version with
|
|
3060
|
-
* different bytes (`contentChanged`). `behind` is 0.
|
|
3061
|
-
*
|
|
3062
|
-
*
|
|
3063
|
-
*
|
|
3064
|
-
* `
|
|
3685
|
+
* different bytes (`contentChanged`). `behind` is 0.
|
|
3686
|
+
* - **Project state** — every {@link AssetManager.projectState} gap (an unregistered or
|
|
3687
|
+
* renamed library, a missing deployed copy, a declared dependency or a deployed asset's
|
|
3688
|
+
* `requires` with no lock entry, a lock that contradicts a `skaile.yaml` pin) as a
|
|
3689
|
+
* `problem` row, so `outdated` lists what `check`, `doctor` and `install --locked` fail
|
|
3690
|
+
* on. An asset that also has a version row is listed once, with that row.
|
|
3065
3691
|
*
|
|
3066
3692
|
* @returns Array of {@link OutdatedEntry} objects.
|
|
3067
3693
|
*/
|
|
@@ -3070,7 +3696,6 @@ var AssetManager = class {
|
|
|
3070
3696
|
const lock = this.tryReadLock();
|
|
3071
3697
|
if (!lock) return this.addLockGapRows([]);
|
|
3072
3698
|
const result = [];
|
|
3073
|
-
const reported = /* @__PURE__ */ new Set();
|
|
3074
3699
|
const commitCounts = /* @__PURE__ */ new Map();
|
|
3075
3700
|
for (const src of lock.sources) {
|
|
3076
3701
|
const slug = sourceCacheKey(src.url);
|
|
@@ -3094,7 +3719,6 @@ var AssetManager = class {
|
|
|
3094
3719
|
currentVersion: version ?? "",
|
|
3095
3720
|
behind
|
|
3096
3721
|
});
|
|
3097
|
-
reported.add(ref);
|
|
3098
3722
|
}
|
|
3099
3723
|
}
|
|
3100
3724
|
const libraryAssets = Object.entries(lock.assets).filter(
|
|
@@ -3108,28 +3732,9 @@ var AssetManager = class {
|
|
|
3108
3732
|
const origin = entry.library;
|
|
3109
3733
|
const { publisher, kind, name } = parseCanonicalLockKey(ref);
|
|
3110
3734
|
if (!publisher || !kind || !name) continue;
|
|
3111
|
-
const
|
|
3112
|
-
if (
|
|
3113
|
-
|
|
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);
|
|
3116
|
-
result.push({
|
|
3117
|
-
kind,
|
|
3118
|
-
name,
|
|
3119
|
-
publisher,
|
|
3120
|
-
currentVersion: origin.version,
|
|
3121
|
-
behind: 0,
|
|
3122
|
-
library: origin.name,
|
|
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
|
-
}
|
|
3129
|
-
});
|
|
3130
|
-
reported.add(ref);
|
|
3131
|
-
continue;
|
|
3132
|
-
}
|
|
3735
|
+
const lookup = this.lockedLibrary(origin, snap);
|
|
3736
|
+
if (lookup.state !== "ok") continue;
|
|
3737
|
+
const libPath = lookup.path;
|
|
3133
3738
|
const scanKey = `${libPath}\0${publisher}`;
|
|
3134
3739
|
let scanned = scans.get(scanKey);
|
|
3135
3740
|
if (!scanned) {
|
|
@@ -3138,7 +3743,7 @@ var AssetManager = class {
|
|
|
3138
3743
|
}
|
|
3139
3744
|
const found = scanned.find((x) => x.kind === kind && x.name === name);
|
|
3140
3745
|
if (!found) continue;
|
|
3141
|
-
const diskVersion = found.version || newestLibraryDef(snap,
|
|
3746
|
+
const diskVersion = found.version || newestLibraryDef(snap, lookup.name, { kind, publisher, name })?.version;
|
|
3142
3747
|
if (diskVersion && gt(coerceVersion(diskVersion), coerceVersion(origin.version))) {
|
|
3143
3748
|
result.push({
|
|
3144
3749
|
kind,
|
|
@@ -3147,9 +3752,8 @@ var AssetManager = class {
|
|
|
3147
3752
|
currentVersion: origin.version,
|
|
3148
3753
|
behind: 0,
|
|
3149
3754
|
latestVersion: diskVersion,
|
|
3150
|
-
library:
|
|
3755
|
+
library: lookup.name
|
|
3151
3756
|
});
|
|
3152
|
-
reported.add(ref);
|
|
3153
3757
|
continue;
|
|
3154
3758
|
}
|
|
3155
3759
|
if (origin.sha256) {
|
|
@@ -3163,41 +3767,24 @@ var AssetManager = class {
|
|
|
3163
3767
|
publisher,
|
|
3164
3768
|
currentVersion: origin.version,
|
|
3165
3769
|
behind: 0,
|
|
3166
|
-
library:
|
|
3770
|
+
library: lookup.name,
|
|
3167
3771
|
contentChanged: true
|
|
3168
3772
|
});
|
|
3169
|
-
reported.add(ref);
|
|
3170
3773
|
}
|
|
3171
3774
|
}
|
|
3172
3775
|
}
|
|
3173
3776
|
}
|
|
3174
|
-
for (const [ref, entry] of Object.entries(lock.assets)) {
|
|
3175
|
-
if (reported.has(ref) || entry.library?.installed) continue;
|
|
3176
|
-
const { publisher, kind, name, version } = parseCanonicalLockKey(ref);
|
|
3177
|
-
const component = kind ? this.installTarget(kind) : void 0;
|
|
3178
|
-
if (!kind || !name || !component) continue;
|
|
3179
|
-
if (isDeployed(component, name, this.driverTarget, this.global, this.projectDir)) {
|
|
3180
|
-
continue;
|
|
3181
|
-
}
|
|
3182
|
-
result.push({
|
|
3183
|
-
kind,
|
|
3184
|
-
name,
|
|
3185
|
-
publisher: publisher ?? "",
|
|
3186
|
-
currentVersion: entry.library?.version ?? version ?? "",
|
|
3187
|
-
behind: 0,
|
|
3188
|
-
...entry.library ? { library: entry.library.name } : {},
|
|
3189
|
-
problem: "deployed copy missing"
|
|
3190
|
-
});
|
|
3191
|
-
}
|
|
3192
3777
|
return this.addLockGapRows(result);
|
|
3193
3778
|
}
|
|
3194
3779
|
/**
|
|
3195
|
-
*
|
|
3196
|
-
* listed yet, so `outdated`
|
|
3780
|
+
* Add one `problem` row per {@link AssetManager.projectState} gap whose asset is not
|
|
3781
|
+
* listed yet, so `outdated` lists the same assets `check`, `doctor` and `install --locked`
|
|
3782
|
+
* fail on. An asset that is behind its source and also broken is listed once, with its
|
|
3783
|
+
* version row.
|
|
3197
3784
|
*/
|
|
3198
3785
|
async addLockGapRows(rows) {
|
|
3199
3786
|
const listed = new Set(rows.map((r) => `${r.kind}:${r.name}`));
|
|
3200
|
-
for (const gap of await this.
|
|
3787
|
+
for (const gap of (await this.projectState()).gaps) {
|
|
3201
3788
|
const parsed = parseRefTolerant(gap.ref);
|
|
3202
3789
|
const id = parsed ? `${parsed.kind}:${parsed.name}` : gap.ref;
|
|
3203
3790
|
if (listed.has(id)) continue;
|
|
@@ -3214,6 +3801,33 @@ var AssetManager = class {
|
|
|
3214
3801
|
}
|
|
3215
3802
|
return rows;
|
|
3216
3803
|
}
|
|
3804
|
+
/**
|
|
3805
|
+
* The deploy entry of a library-origin asset from the library its lock entry records,
|
|
3806
|
+
* at the locked version when that library still holds it (else its newest). Other
|
|
3807
|
+
* libraries holding the same ref are not consulted: the lock already chose.
|
|
3808
|
+
*
|
|
3809
|
+
* @param want - Kind, name and optional publisher of the asset.
|
|
3810
|
+
* @returns `null` when the lock has no library-origin entry for it, or the recorded
|
|
3811
|
+
* library is gone or no longer holds it (callers fall back to a general lookup).
|
|
3812
|
+
*/
|
|
3813
|
+
async lockedLibraryEntry(want) {
|
|
3814
|
+
const snap = await this.loadLibraryIndex();
|
|
3815
|
+
for (const [key, e] of Object.entries(this.tryReadLock()?.assets ?? {})) {
|
|
3816
|
+
const id = parseCanonicalLockKey(key);
|
|
3817
|
+
if (!e.library || e.library.installed || !id.publisher) continue;
|
|
3818
|
+
if (id.kind !== want.kind || id.name !== want.name) continue;
|
|
3819
|
+
if (want.publisher && id.publisher !== want.publisher) continue;
|
|
3820
|
+
const canonical = `${id.kind}:@${id.publisher}/${id.name}`;
|
|
3821
|
+
const refs = e.library.version ? [`${canonical}#${e.library.version}`, canonical] : [canonical];
|
|
3822
|
+
const lookup = this.lockedLibrary(e.library, snap);
|
|
3823
|
+
const library = lookup.state === "ok" ? lookup.name : e.library.name;
|
|
3824
|
+
for (const r of refs) {
|
|
3825
|
+
const hit = (await this.resolveLibraryEntries([r], { library })).entries[0];
|
|
3826
|
+
if (hit) return hit;
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
return null;
|
|
3830
|
+
}
|
|
3217
3831
|
/**
|
|
3218
3832
|
* Produce a unified diff from the deployed asset to its catalog source: `-` lines
|
|
3219
3833
|
* are in the deployed copy only (local edits `update` would overwrite), `+` lines
|
|
@@ -3231,10 +3845,15 @@ var AssetManager = class {
|
|
|
3231
3845
|
async diff(ref) {
|
|
3232
3846
|
const parsed = parseRefTolerant(ref);
|
|
3233
3847
|
if (!parsed) return { status: "not-found" };
|
|
3234
|
-
const entry = await this.info(ref);
|
|
3848
|
+
const entry = await this.lockedLibraryEntry(parsed) ?? await this.info(ref);
|
|
3235
3849
|
if (!entry || !existsSync(entry.source)) return { status: "not-found" };
|
|
3236
3850
|
const component = this.installTarget(parsed.kind);
|
|
3237
3851
|
if (!component) return { status: "not-deployed" };
|
|
3852
|
+
if (component === "agent") {
|
|
3853
|
+
const diff = diffDeployedAgent(entry, this.deployOptsFor(this.driverTarget));
|
|
3854
|
+
if (diff === null) return { status: "not-deployed" };
|
|
3855
|
+
return diff === "" ? { status: "identical" } : { status: "differs", diff };
|
|
3856
|
+
}
|
|
3238
3857
|
const deployedPath = join(
|
|
3239
3858
|
deployedBase(component, this.driverTarget, this.global, this.projectDir),
|
|
3240
3859
|
parsed.name
|
|
@@ -3413,7 +4032,10 @@ var AssetManager = class {
|
|
|
3413
4032
|
continue;
|
|
3414
4033
|
}
|
|
3415
4034
|
const gaps = [];
|
|
3416
|
-
|
|
4035
|
+
const requirements = dedupeRequirements(full.requires, publisher).map(
|
|
4036
|
+
(r) => r.publisher || !publisher ? r : { ...r, publisher }
|
|
4037
|
+
);
|
|
4038
|
+
for (const req of requirements) {
|
|
3417
4039
|
const dep = memberIdentity(depToStr(req));
|
|
3418
4040
|
if (!dep) continue;
|
|
3419
4041
|
const depComponent = this.installTarget(dep.kind);
|
|
@@ -3432,7 +4054,10 @@ var AssetManager = class {
|
|
|
3432
4054
|
if (!inRepos) gaps.push({ issue, ref: depToStr(req) });
|
|
3433
4055
|
}
|
|
3434
4056
|
}
|
|
3435
|
-
const inLibrary = await this.resolveLibraryEntries(
|
|
4057
|
+
const inLibrary = await this.resolveLibraryEntries(
|
|
4058
|
+
gaps.map((g) => g.ref),
|
|
4059
|
+
{ quiet: true }
|
|
4060
|
+
);
|
|
3436
4061
|
for (const g of gaps) g.issue.inRepos = inLibrary.resolved.has(g.ref);
|
|
3437
4062
|
}
|
|
3438
4063
|
for (const [presetRef, gaps] of await this.declaredPresetGaps(dependencies, lock)) {
|
|
@@ -3453,30 +4078,48 @@ var AssetManager = class {
|
|
|
3453
4078
|
return issues;
|
|
3454
4079
|
}
|
|
3455
4080
|
/**
|
|
3456
|
-
*
|
|
3457
|
-
* `skaile check`, `skaile
|
|
4081
|
+
* The project's state as one verdict: every way the project differs from what it
|
|
4082
|
+
* declares and locks. `skaile check`, `skaile doctor`, `skaile outdated`, `skaile diff`
|
|
4083
|
+
* and `skaile install --locked` all take their verdict and exit code from this one list,
|
|
4084
|
+
* so one situation reads the same in all five.
|
|
3458
4085
|
*
|
|
3459
4086
|
* - `declared` — a `skaile.yaml` dependency with no lock entry (library or source gone,
|
|
3460
4087
|
* unresolvable ref, never installed);
|
|
3461
4088
|
* - `invalid` — a `dependencies:` entry that is not a parseable ref;
|
|
3462
|
-
* - `drift` —
|
|
4089
|
+
* - `drift` — a locked asset whose deployed files are missing;
|
|
3463
4090
|
* - `pin` — a declared `#pin` that no lock entry for that asset satisfies;
|
|
3464
|
-
* - `requires` — a deployed asset's `requires`
|
|
3465
|
-
*
|
|
4091
|
+
* - `requires` — a deployed asset's `requires` (or a declared preset's item) that is not
|
|
4092
|
+
* deployed (so not locked either);
|
|
4093
|
+
* - `unresolved` — a lock-managed deployed asset that no source or library holds any more;
|
|
4094
|
+
* - `library` — a locked library asset whose library is not registered (renamed or
|
|
4095
|
+
* removed) or no longer holds it, while another library holds it now;
|
|
4096
|
+
* - `incomplete` — a deployed library asset that lacks files of its library entry;
|
|
4097
|
+
* - `content` — a locked library asset whose files in the library changed since the lock
|
|
4098
|
+
* (or whose lock hash predates the one shared asset hash); `skaile install` re-locks it;
|
|
4099
|
+
* - `agent` — an `agents.<id>.ref` (or `agent.definition`) that binds to no agent.
|
|
3466
4100
|
*
|
|
3467
|
-
*
|
|
3468
|
-
* `
|
|
3469
|
-
*
|
|
4101
|
+
* An asset appears once for what the lock says about it (`unresolved`, else `library`,
|
|
4102
|
+
* else `drift`). A declared ref no registered library or source holds names
|
|
4103
|
+
* `skaile library init` / `skaile remove`, never `skaile install`: `install` has nothing
|
|
4104
|
+
* to resolve it from.
|
|
3470
4105
|
*
|
|
3471
|
-
*
|
|
4106
|
+
* Project mode only: a global manager (`global: true`) has no gaps. A project without
|
|
4107
|
+
* `skaile.yaml` has no declared set, so only the lock and deployed-asset gaps can appear.
|
|
4108
|
+
*
|
|
4109
|
+
* @returns The {@link ProjectState}; `gaps` is empty when the project is as declared and locked.
|
|
3472
4110
|
*/
|
|
3473
|
-
async
|
|
3474
|
-
if (this.global) return [];
|
|
4111
|
+
async projectState() {
|
|
4112
|
+
if (this.global) return { gaps: [], requirements: [] };
|
|
4113
|
+
const lock = this.tryReadLock();
|
|
4114
|
+
const lockedIds = Object.keys(lock?.assets ?? {}).map(parseCanonicalLockKey);
|
|
4115
|
+
const requirements = await this.doctor();
|
|
3475
4116
|
const gaps = [];
|
|
3476
|
-
const
|
|
3477
|
-
for (const i of issues) {
|
|
4117
|
+
for (const i of requirements) {
|
|
3478
4118
|
if (i.unresolved) {
|
|
3479
|
-
const
|
|
4119
|
+
const publisher = lockedIds.find(
|
|
4120
|
+
(id) => id.kind === i.assetKind && id.name === i.assetName
|
|
4121
|
+
)?.publisher;
|
|
4122
|
+
const ref = publisher ? `${i.assetKind}:@${publisher}/${i.assetName}` : `${i.assetKind}:${i.assetName}`;
|
|
3480
4123
|
const reason = `is locked but no source or library provides it any more \u2014 its requirements cannot be checked${i.fix ? ` (${i.fix})` : ""}`;
|
|
3481
4124
|
gaps.push({
|
|
3482
4125
|
type: "unresolved",
|
|
@@ -3489,25 +4132,183 @@ var AssetManager = class {
|
|
|
3489
4132
|
}
|
|
3490
4133
|
const asset = `${i.assetKind}:${i.assetName}`;
|
|
3491
4134
|
const dep = `${i.depKind}:${i.depName}`;
|
|
3492
|
-
|
|
4135
|
+
if (i.inRepos) {
|
|
4136
|
+
gaps.push({
|
|
4137
|
+
type: "requires",
|
|
4138
|
+
ref: dep,
|
|
4139
|
+
asset,
|
|
4140
|
+
reason: `is required by ${asset} but neither deployed nor locked (fixable)`,
|
|
4141
|
+
message: `${asset} requires ${dep} (fixable)`
|
|
4142
|
+
});
|
|
4143
|
+
} else {
|
|
4144
|
+
const fix = `register the library that holds it with \`skaile library init <name> --path <dir>\`, or drop ${asset} with \`skaile remove ${asset}\``;
|
|
4145
|
+
gaps.push({
|
|
4146
|
+
type: "requires",
|
|
4147
|
+
ref: dep,
|
|
4148
|
+
asset,
|
|
4149
|
+
reason: `is required by ${asset} but neither deployed nor locked (not found \u2014 ${fix})`,
|
|
4150
|
+
message: `${asset} requires ${dep} (not found \u2014 ${fix})`,
|
|
4151
|
+
manualFix: true
|
|
4152
|
+
});
|
|
4153
|
+
}
|
|
4154
|
+
}
|
|
4155
|
+
const named = new Set(
|
|
4156
|
+
gaps.filter((g) => g.type === "unresolved").map((g) => gapIdentity(g.ref))
|
|
4157
|
+
);
|
|
4158
|
+
for (const gap of await this.libraryOriginGaps(named)) {
|
|
4159
|
+
gaps.push(gap);
|
|
4160
|
+
named.add(gapIdentity(gap.ref));
|
|
4161
|
+
}
|
|
4162
|
+
for (const gap of this.undeployedLockGaps(lock, named)) {
|
|
4163
|
+
gaps.push(gap);
|
|
4164
|
+
named.add(gapIdentity(gap.ref));
|
|
4165
|
+
}
|
|
4166
|
+
gaps.push(...await this.declaredGaps(requirements, named));
|
|
4167
|
+
for (const d of await this.incompleteDeploys()) {
|
|
4168
|
+
const reason = `is deployed without ${d.missing.join(", ")} \u2014 run \`skaile install\` to restore it`;
|
|
4169
|
+
gaps.push({ type: "incomplete", ref: d.ref, reason, message: `${d.ref} ${reason}` });
|
|
4170
|
+
}
|
|
4171
|
+
for (const u of unboundAgentInstances(this.projectDir, this.driverTarget)) {
|
|
4172
|
+
const reason = u.ref.startsWith("agent:") ? `is bound by agent instance "${u.id}" but no agent was added for it \u2014 run \`skaile add ${u.ref}\` first, or drop the binding from skaile.yaml` : `is bound by agent instance "${u.id}" but resolves to no agent.yaml \u2014 fix the path, or drop the binding from skaile.yaml`;
|
|
3493
4173
|
gaps.push({
|
|
3494
|
-
type: "
|
|
3495
|
-
ref:
|
|
3496
|
-
reason
|
|
3497
|
-
message: `${
|
|
4174
|
+
type: "agent",
|
|
4175
|
+
ref: u.ref,
|
|
4176
|
+
reason,
|
|
4177
|
+
message: `${u.ref} ${reason}`,
|
|
4178
|
+
manualFix: true
|
|
3498
4179
|
});
|
|
3499
4180
|
}
|
|
3500
|
-
|
|
4181
|
+
return { gaps, requirements };
|
|
4182
|
+
}
|
|
4183
|
+
/** @deprecated Use `(await projectState()).gaps`; removed in the next major. */
|
|
4184
|
+
async lockGaps() {
|
|
4185
|
+
return (await this.projectState()).gaps;
|
|
4186
|
+
}
|
|
4187
|
+
/**
|
|
4188
|
+
* The {@link ProjectState} gaps that name `ref`: as the gap's own ref, or as the asset
|
|
4189
|
+
* whose requirement is unmet. A ref without a publisher matches any publisher.
|
|
4190
|
+
*
|
|
4191
|
+
* @param ref - Asset ref in `kind:name` or `kind:@publisher/name` form.
|
|
4192
|
+
*/
|
|
4193
|
+
async gapsOf(ref) {
|
|
4194
|
+
const want = parseRefTolerant(ref);
|
|
4195
|
+
if (!want) return [];
|
|
4196
|
+
const names = (gapRef) => {
|
|
4197
|
+
const p = parseRefTolerant(gapRef);
|
|
4198
|
+
return p !== null && p.kind === want.kind && p.name === want.name && (!want.publisher || !p.publisher || p.publisher === want.publisher);
|
|
4199
|
+
};
|
|
4200
|
+
return (await this.projectState()).gaps.filter(
|
|
4201
|
+
(g) => names(g.ref) || g.asset && names(g.asset)
|
|
4202
|
+
);
|
|
4203
|
+
}
|
|
4204
|
+
/**
|
|
4205
|
+
* Locked library assets whose library cannot supply them: the library is not registered
|
|
4206
|
+
* (renamed or removed) or no longer holds the asset. Another library holding it makes the
|
|
4207
|
+
* gap fixable by `skaile install` (it re-locks); otherwise the user registers the library
|
|
4208
|
+
* again or drops the dependency.
|
|
4209
|
+
*
|
|
4210
|
+
* @param named - `kind:name` identities already reported; they are skipped.
|
|
4211
|
+
*/
|
|
4212
|
+
async libraryOriginGaps(named) {
|
|
4213
|
+
const locked = Object.entries(this.tryReadLock()?.assets ?? {}).filter(
|
|
4214
|
+
([, e]) => e.library !== void 0 && !e.library.installed
|
|
4215
|
+
);
|
|
4216
|
+
if (locked.length === 0) return [];
|
|
4217
|
+
const snap = await this.loadLibraryIndex();
|
|
4218
|
+
const scans = /* @__PURE__ */ new Map();
|
|
4219
|
+
const diskHashes = /* @__PURE__ */ new Map();
|
|
4220
|
+
const gaps = [];
|
|
4221
|
+
for (const [key, entry] of locked) {
|
|
4222
|
+
const origin = entry.library;
|
|
4223
|
+
const { publisher, kind, name } = parseCanonicalLockKey(key);
|
|
4224
|
+
if (!publisher || !kind || !name || named.has(`${kind}:${name}`)) continue;
|
|
4225
|
+
const ref = `${kind}:@${publisher}/${name}`;
|
|
4226
|
+
const lookup = this.lockedLibrary(origin, snap);
|
|
4227
|
+
const libPath = lookup.state === "ok" ? lookup.path : null;
|
|
4228
|
+
if (lookup.state === "ok" && libPath) {
|
|
4229
|
+
const scanKey = `${libPath}\0${publisher}`;
|
|
4230
|
+
let scanned = scans.get(scanKey);
|
|
4231
|
+
if (!scanned) {
|
|
4232
|
+
scanned = await scanDirectory(libPath, publisher, { knownKinds: this.knownKinds });
|
|
4233
|
+
scans.set(scanKey, scanned);
|
|
4234
|
+
}
|
|
4235
|
+
const found = scanned.find((x) => x.kind === kind && x.name === name);
|
|
4236
|
+
if (found) {
|
|
4237
|
+
const onDisk = origin.sha256 ? libraryDiskHashes(libPath, diskHashes, this.registry).get(`${kind}:${name}`) : void 0;
|
|
4238
|
+
if (onDisk !== void 0 && onDisk !== origin.sha256) {
|
|
4239
|
+
const diskVersion = found.version || newestLibraryDef(snap, lookup.name, { kind, publisher, name })?.version;
|
|
4240
|
+
if (!diskVersion || !gt(coerceVersion(diskVersion), coerceVersion(origin.version))) {
|
|
4241
|
+
const reason2 = `is locked, but library "${lookup.name}" content changed since lock \u2014 or the lock predates the one shared asset hash; run \`skaile install\` to re-lock it`;
|
|
4242
|
+
gaps.push({ type: "content", ref, reason: reason2, message: `${ref} ${reason2}` });
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
continue;
|
|
4246
|
+
}
|
|
4247
|
+
}
|
|
4248
|
+
if (lookup.state === "dir-missing") {
|
|
4249
|
+
const reason2 = `is locked, but ${lockedLibraryProblem(lookup, origin, ref)}`;
|
|
4250
|
+
gaps.push({ type: "library", ref, reason: reason2, message: `${ref} ${reason2}`, manualFix: true });
|
|
4251
|
+
continue;
|
|
4252
|
+
}
|
|
4253
|
+
if (lookup.state === "unregistered") {
|
|
4254
|
+
const reason2 = `is locked, but library "${origin.name}" is not registered (renamed or removed?) \u2014 ${unregisteredLibraryFix(origin, ref)}`;
|
|
4255
|
+
gaps.push({ type: "library", ref, reason: reason2, message: `${ref} ${reason2}`, manualFix: true });
|
|
4256
|
+
continue;
|
|
4257
|
+
}
|
|
4258
|
+
const heldElsewhere = (await this.resolveLibraryEntries([ref], { quiet: true })).resolved.size > 0;
|
|
4259
|
+
if (heldElsewhere) {
|
|
4260
|
+
const reason2 = `is locked, but library "${lookup.name}" no longer holds it \u2014 run \`skaile install\` to re-lock it against the library that holds it now`;
|
|
4261
|
+
gaps.push({ type: "library", ref, reason: reason2, message: `${ref} ${reason2}` });
|
|
4262
|
+
continue;
|
|
4263
|
+
}
|
|
4264
|
+
const reason = `is locked, but library "${lookup.name}" no longer holds it \u2014 restore it there, or drop the dependency with \`skaile remove ${ref}\``;
|
|
4265
|
+
gaps.push({ type: "library", ref, reason, message: `${ref} ${reason}`, manualFix: true });
|
|
4266
|
+
}
|
|
4267
|
+
return gaps;
|
|
4268
|
+
}
|
|
4269
|
+
/**
|
|
4270
|
+
* Locked assets (declared or required by one) whose deployed copy is gone: `skaile install`
|
|
4271
|
+
* restores them. Same deployability rule as {@link AssetManager.listDeclared}'s `drift`.
|
|
4272
|
+
*
|
|
4273
|
+
* @param named - `kind:name` identities already reported; they are skipped.
|
|
4274
|
+
*/
|
|
4275
|
+
undeployedLockGaps(lock, named) {
|
|
4276
|
+
const gaps = [];
|
|
4277
|
+
for (const [key, entry] of Object.entries(lock?.assets ?? {})) {
|
|
4278
|
+
if (entry.library?.installed) continue;
|
|
4279
|
+
const { publisher, kind, name } = parseCanonicalLockKey(key);
|
|
4280
|
+
const component = kind ? this.installTarget(kind) : void 0;
|
|
4281
|
+
if (!kind || !name || !component || named.has(`${kind}:${name}`)) continue;
|
|
4282
|
+
if (isDeployed(component, name, this.driverTarget, this.global, this.projectDir)) continue;
|
|
4283
|
+
const ref = publisher ? `${kind}:@${publisher}/${name}` : `${kind}:${name}`;
|
|
4284
|
+
const reason = "is locked but its deployed copy is missing \u2014 run `skaile install`";
|
|
4285
|
+
gaps.push({ type: "drift", ref, reason, message: `${ref} ${reason}` });
|
|
4286
|
+
}
|
|
4287
|
+
return gaps;
|
|
4288
|
+
}
|
|
4289
|
+
/**
|
|
4290
|
+
* The `skaile.yaml` side of {@link AssetManager.projectState}: declared refs that do not
|
|
4291
|
+
* parse, never resolved into the lock, are not materialized, or contradict a `#pin`.
|
|
4292
|
+
* A project with no (or an unreadable) `skaile.yaml` has no declared set to reconcile.
|
|
4293
|
+
*
|
|
4294
|
+
* @param requirements - What {@link AssetManager.doctor} found; a declared preset whose
|
|
4295
|
+
* items it already named needs no second line.
|
|
4296
|
+
* @param named - `kind:name` identities already reported; a declared asset among them
|
|
4297
|
+
* needs no `drift` line.
|
|
4298
|
+
*/
|
|
4299
|
+
async declaredGaps(requirements, named) {
|
|
4300
|
+
let declared;
|
|
3501
4301
|
try {
|
|
3502
4302
|
declared = await this.listDeclared();
|
|
3503
4303
|
} catch {
|
|
3504
|
-
return
|
|
4304
|
+
return [];
|
|
3505
4305
|
}
|
|
4306
|
+
const gaps = [];
|
|
3506
4307
|
const unlocked = declared.filter((d) => d.state === "declared").map((d) => d.ref);
|
|
3507
4308
|
const hints = await this.publisherChangeHints(unlocked);
|
|
3508
4309
|
const lockKeys = Object.keys(this.tryReadLock()?.assets ?? {});
|
|
3509
4310
|
for (const d of declared) {
|
|
3510
|
-
if (d.kind === "preset" &&
|
|
4311
|
+
if (d.kind === "preset" && requirements.some((i) => i.assetKind === "preset" && i.assetName === d.name)) {
|
|
3511
4312
|
continue;
|
|
3512
4313
|
}
|
|
3513
4314
|
let gap;
|
|
@@ -3517,19 +4318,41 @@ var AssetManager = class {
|
|
|
3517
4318
|
reason: "is not a valid asset ref (expected kind:@<publisher>/<name>#<version>)"
|
|
3518
4319
|
};
|
|
3519
4320
|
} else if (d.state === "drift") {
|
|
4321
|
+
if (named.has(`${d.kind}:${d.name}`)) continue;
|
|
3520
4322
|
gap = {
|
|
3521
4323
|
type: "drift",
|
|
3522
4324
|
reason: "is declared and locked but not materialized \u2014 run `skaile install`"
|
|
3523
4325
|
};
|
|
3524
4326
|
} else if (d.state === "declared") {
|
|
3525
4327
|
const hint = hints[d.ref];
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
4328
|
+
if (hint) {
|
|
4329
|
+
gap = {
|
|
4330
|
+
type: "declared",
|
|
4331
|
+
reason: `is declared but does not resolve${hint}`,
|
|
4332
|
+
manualFix: true
|
|
4333
|
+
};
|
|
4334
|
+
} else if (await this.declaredRefResolvable(d.ref)) {
|
|
4335
|
+
gap = { type: "declared", reason: "is declared but not locked \u2014 run `skaile install`" };
|
|
4336
|
+
} else {
|
|
4337
|
+
gap = {
|
|
4338
|
+
type: "declared",
|
|
4339
|
+
reason: `is declared but no library or source holds it \u2014 register the library that holds it with \`skaile library init <name> --path <dir>\`, or drop it with \`skaile remove ${d.ref.split("#")[0]}\``,
|
|
4340
|
+
manualFix: true
|
|
4341
|
+
};
|
|
4342
|
+
}
|
|
3530
4343
|
} else {
|
|
3531
4344
|
const want = parseAssetRef(d.ref);
|
|
3532
|
-
if (
|
|
4345
|
+
if (want.kind === "preset") {
|
|
4346
|
+
if (this.presetRecorded(want) || await this.info(d.ref) !== null) continue;
|
|
4347
|
+
gap = await this.declaredRefResolvable(d.ref) ? { type: "declared", reason: "is declared but not locked \u2014 run `skaile install`" } : {
|
|
4348
|
+
type: "declared",
|
|
4349
|
+
reason: `is declared but no library or source holds it \u2014 register the library that holds it with \`skaile library init <name> --path <dir>\`, or drop it with \`skaile remove ${d.ref.split("#")[0]}\``,
|
|
4350
|
+
manualFix: true
|
|
4351
|
+
};
|
|
4352
|
+
gaps.push({ ...gap, ref: d.ref, message: `${d.ref} ${gap.reason}` });
|
|
4353
|
+
continue;
|
|
4354
|
+
}
|
|
4355
|
+
if (!want.pin) continue;
|
|
3533
4356
|
const held = lockKeys.map((key) => ({ key, id: parseCanonicalLockKey(key) })).filter(
|
|
3534
4357
|
({ id }) => id.kind === want.kind && id.name === want.name && (!want.publisher || id.publisher === want.publisher)
|
|
3535
4358
|
);
|
|
@@ -3544,6 +4367,22 @@ var AssetManager = class {
|
|
|
3544
4367
|
}
|
|
3545
4368
|
return gaps;
|
|
3546
4369
|
}
|
|
4370
|
+
/** Whether the lock's `presets` slice records `want` (kind, name and, when both carry one, publisher). */
|
|
4371
|
+
presetRecorded(want) {
|
|
4372
|
+
return (this.tryReadLock()?.presets ?? []).some((ref) => {
|
|
4373
|
+
const p = parseRefTolerant(ref);
|
|
4374
|
+
return p !== null && p.kind === want.kind && p.name === want.name && (!want.publisher || !p.publisher || p.publisher === want.publisher);
|
|
4375
|
+
});
|
|
4376
|
+
}
|
|
4377
|
+
/**
|
|
4378
|
+
* Whether `skaile install` can resolve a declared ref: a source or library holds it, or the
|
|
4379
|
+
* project declares a store that may. The global catalog is not asked: a check never goes
|
|
4380
|
+
* to the network.
|
|
4381
|
+
*/
|
|
4382
|
+
async declaredRefResolvable(ref) {
|
|
4383
|
+
if (await this.info(ref) !== null) return true;
|
|
4384
|
+
return this.loadConfig().stores.length > 0;
|
|
4385
|
+
}
|
|
3547
4386
|
/**
|
|
3548
4387
|
* Items of each declared `preset:` dependency that the lock does not cover.
|
|
3549
4388
|
*
|
|
@@ -3810,6 +4649,54 @@ var AssetManager = class {
|
|
|
3810
4649
|
writeFileSync(configPath, stringify(raw, { lineWidth: 120 }));
|
|
3811
4650
|
return true;
|
|
3812
4651
|
}
|
|
4652
|
+
/**
|
|
4653
|
+
* Drop the agent instances of `skaile.yaml` (`agents.<id>`, or the `agent.definition`
|
|
4654
|
+
* default) whose `ref` binds to `target`, and the native agent files an install rendered for
|
|
4655
|
+
* them. Only an `agent` target has bindings; project mode only. A `ref` without a publisher
|
|
4656
|
+
* matches any publisher, and a pin is ignored.
|
|
4657
|
+
*
|
|
4658
|
+
* @returns `true` when a binding was removed.
|
|
4659
|
+
*/
|
|
4660
|
+
removeAgentBindings(target) {
|
|
4661
|
+
if (this.global || target.kind !== "agent") return false;
|
|
4662
|
+
const configPath = join(this.stateRoot, "skaile.yaml");
|
|
4663
|
+
if (!existsSync(configPath)) return false;
|
|
4664
|
+
let raw;
|
|
4665
|
+
try {
|
|
4666
|
+
raw = parse(readFileSync(configPath, "utf8"));
|
|
4667
|
+
} catch {
|
|
4668
|
+
return false;
|
|
4669
|
+
}
|
|
4670
|
+
if (!raw || typeof raw !== "object") return false;
|
|
4671
|
+
const wantPub = target.publisher?.replace(/^@/, "");
|
|
4672
|
+
const binds = (ref) => {
|
|
4673
|
+
const p = typeof ref === "string" ? parseRefTolerant(ref) : null;
|
|
4674
|
+
if (!p || p.kind !== "agent" || p.name !== target.name) return false;
|
|
4675
|
+
const havePub = p.publisher?.replace(/^@/, "");
|
|
4676
|
+
return wantPub === void 0 || havePub === void 0 || havePub === wantPub;
|
|
4677
|
+
};
|
|
4678
|
+
const ids = [];
|
|
4679
|
+
const instances = raw.agents;
|
|
4680
|
+
if (instances && typeof instances === "object") {
|
|
4681
|
+
for (const [id, instance] of Object.entries(instances)) {
|
|
4682
|
+
if (!binds(instance?.ref)) continue;
|
|
4683
|
+
ids.push(id);
|
|
4684
|
+
delete instances[id];
|
|
4685
|
+
}
|
|
4686
|
+
if (Object.keys(instances).length === 0) delete raw.agents;
|
|
4687
|
+
}
|
|
4688
|
+
if (raw.agent && typeof raw.agent === "object" && binds(raw.agent.definition)) {
|
|
4689
|
+
ids.push(DEFAULT_AGENT_INSTANCE_ID);
|
|
4690
|
+
delete raw.agent.definition;
|
|
4691
|
+
if (Object.keys(raw.agent).length === 0) delete raw.agent;
|
|
4692
|
+
}
|
|
4693
|
+
if (ids.length === 0) return false;
|
|
4694
|
+
writeFileSync(configPath, stringify(raw, { lineWidth: 120 }));
|
|
4695
|
+
for (const driverTarget of this.targetHarnesses()) {
|
|
4696
|
+
removeAgentInstanceRenderings({ projectDir: this.projectDir, driverTarget, ids });
|
|
4697
|
+
}
|
|
4698
|
+
return true;
|
|
4699
|
+
}
|
|
3813
4700
|
resolveRepoDir(decl, name) {
|
|
3814
4701
|
const links = readLinks(this.projectDir);
|
|
3815
4702
|
if (links[name]) {
|
|
@@ -3828,5 +4715,5 @@ var AssetManager = class {
|
|
|
3828
4715
|
};
|
|
3829
4716
|
|
|
3830
4717
|
export { AssetManager, FACTORY_SOURCE_URL, MissingManifestError, installAgentInstances, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, renderMcpServerConfig, softDepName };
|
|
3831
|
-
//# sourceMappingURL=chunk-
|
|
3832
|
-
//# sourceMappingURL=chunk-
|
|
4718
|
+
//# sourceMappingURL=chunk-2JMLDZLP.js.map
|
|
4719
|
+
//# sourceMappingURL=chunk-2JMLDZLP.js.map
|