@skaile/workspaces 5.10.0 → 5.12.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 +146 -0
- package/README.md +14 -2
- package/dist/{asset-feeds-ELEBTNUS.js → asset-feeds-AM6PSSGM.js} +24 -21
- package/dist/asset-feeds-AM6PSSGM.js.map +1 -0
- package/dist/asset-manager/catalog-deployer.js +8 -8
- package/dist/asset-manager/fragments.js +1 -1
- package/dist/asset-manager/index.js +16 -16
- package/dist/asset-manager/installer.js +11 -11
- package/dist/asset-manager/renderers.js +9 -9
- package/dist/asset-manager/src/fragments.d.ts +5 -0
- package/dist/asset-manager/src/fragments.d.ts.map +1 -1
- package/dist/asset-manager/src/index.d.ts +197 -11
- package/dist/asset-manager/src/index.d.ts.map +1 -1
- package/dist/asset-manager/src/install-agent.d.ts +9 -1
- package/dist/asset-manager/src/install-agent.d.ts.map +1 -1
- package/dist/asset-manager/src/install-instances.d.ts.map +1 -1
- package/dist/asset-manager/src/installer.d.ts +33 -3
- package/dist/asset-manager/src/installer.d.ts.map +1 -1
- package/dist/asset-manager/src/renderers.d.ts +5 -0
- package/dist/asset-manager/src/renderers.d.ts.map +1 -1
- package/dist/bridge/drivers/claude-sdk.js +16 -13
- package/dist/bridge/drivers/claude-sdk.js.map +1 -1
- package/dist/bridge/drivers/codex.js +43 -16
- package/dist/bridge/drivers/codex.js.map +1 -1
- package/dist/bridge/drivers/continue.js +10 -10
- package/dist/bridge/drivers/echo.js +2 -2
- package/dist/bridge/drivers/gemini.js +7 -7
- package/dist/bridge/drivers/goose.js +10 -10
- package/dist/bridge/drivers/omp.js +52 -9
- 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 +12 -12
- package/dist/bridge/src/codex/config-toml.d.ts +8 -3
- package/dist/bridge/src/codex/config-toml.d.ts.map +1 -1
- package/dist/bridge/src/codex/managed-driver.d.ts.map +1 -1
- package/dist/bridge/src/drivers/claude-sdk.d.ts +1 -1
- package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
- package/dist/bridge/src/drivers/codex.d.ts.map +1 -1
- package/dist/bridge/src/drivers/omp-models-yml.d.ts.map +1 -1
- package/dist/bridge/src/drivers/omp.d.ts +9 -0
- package/dist/bridge/src/drivers/omp.d.ts.map +1 -1
- package/dist/bridge/src/provider-materialize/credential-env.d.ts +15 -0
- package/dist/bridge/src/provider-materialize/credential-env.d.ts.map +1 -1
- package/dist/{chunk-7CR6HT2X.js → chunk-27L6BBAT.js} +9 -9
- package/dist/{chunk-7CR6HT2X.js.map → chunk-27L6BBAT.js.map} +1 -1
- package/dist/{chunk-QG3HOJEK.js → chunk-2JFIFDDO.js} +3 -3
- package/dist/{chunk-QG3HOJEK.js.map → chunk-2JFIFDDO.js.map} +1 -1
- package/dist/{chunk-IJHH4DSW.js → chunk-2X3JBVGD.js} +11 -10
- package/dist/chunk-2X3JBVGD.js.map +1 -0
- package/dist/{chunk-G54USEUP.js → chunk-3HUV2LJF.js} +4 -4
- package/dist/{chunk-G54USEUP.js.map → chunk-3HUV2LJF.js.map} +1 -1
- package/dist/{chunk-JFXQEVLF.js → chunk-3LVB3HGH.js} +3 -3
- package/dist/{chunk-JFXQEVLF.js.map → chunk-3LVB3HGH.js.map} +1 -1
- package/dist/{chunk-32XKCNCL.js → chunk-6VLHITAM.js} +146 -4
- package/dist/chunk-6VLHITAM.js.map +1 -0
- package/dist/{chunk-GEWAIQZ5.js → chunk-7CR2OZPA.js} +10 -12
- package/dist/chunk-7CR2OZPA.js.map +1 -0
- package/dist/{chunk-6HHE63CO.js → chunk-7QWQTA5S.js} +89 -12
- package/dist/chunk-7QWQTA5S.js.map +1 -0
- package/dist/{chunk-7I5VRVDP.js → chunk-7XWUJC3A.js} +4 -4
- package/dist/{chunk-7I5VRVDP.js.map → chunk-7XWUJC3A.js.map} +1 -1
- package/dist/{chunk-3BEY4WK3.js → chunk-C3BMXXTN.js} +203 -31
- package/dist/chunk-C3BMXXTN.js.map +1 -0
- package/dist/{chunk-IXWODEED.js → chunk-CTP3XBMF.js} +47 -8
- package/dist/chunk-CTP3XBMF.js.map +1 -0
- package/dist/{chunk-HOHUEKES.js → chunk-DCHQ6BAZ.js} +3 -3
- package/dist/{chunk-HOHUEKES.js.map → chunk-DCHQ6BAZ.js.map} +1 -1
- package/dist/{chunk-DALV4HHP.js → chunk-DKXNKFKP.js} +3 -2
- package/dist/{chunk-DALV4HHP.js.map → chunk-DKXNKFKP.js.map} +1 -1
- package/dist/{chunk-3MKPZZRE.js → chunk-G3X4MLDB.js} +3 -3
- package/dist/{chunk-3MKPZZRE.js.map → chunk-G3X4MLDB.js.map} +1 -1
- package/dist/{chunk-SBFW3CJH.js → chunk-GWD3QNVS.js} +5 -5
- package/dist/{chunk-SBFW3CJH.js.map → chunk-GWD3QNVS.js.map} +1 -1
- package/dist/chunk-H5U7LNTJ.js +122 -0
- package/dist/chunk-H5U7LNTJ.js.map +1 -0
- package/dist/{chunk-SX5U422E.js → chunk-HYMERG57.js} +3 -3
- package/dist/{chunk-SX5U422E.js.map → chunk-HYMERG57.js.map} +1 -1
- package/dist/{chunk-V5TZH4GF.js → chunk-ICIYSJBQ.js} +4 -4
- package/dist/{chunk-V5TZH4GF.js.map → chunk-ICIYSJBQ.js.map} +1 -1
- package/dist/{chunk-YBQONMH2.js → chunk-ID745F3R.js} +353 -193
- package/dist/chunk-ID745F3R.js.map +1 -0
- package/dist/{chunk-CLTHEKHR.js → chunk-JQ3DXNQV.js} +4 -4
- package/dist/{chunk-CLTHEKHR.js.map → chunk-JQ3DXNQV.js.map} +1 -1
- package/dist/chunk-K4VOEYOR.js +21 -0
- package/dist/chunk-K4VOEYOR.js.map +1 -0
- package/dist/{chunk-XCNK4UE5.js → chunk-KVSDRB35.js} +5 -5
- package/dist/{chunk-XCNK4UE5.js.map → chunk-KVSDRB35.js.map} +1 -1
- package/dist/{chunk-HJ5MCB3L.js → chunk-MF54ZHWT.js} +20 -3
- package/dist/chunk-MF54ZHWT.js.map +1 -0
- package/dist/{chunk-NRDSGLCQ.js → chunk-N5M2EISA.js} +240 -52
- package/dist/chunk-N5M2EISA.js.map +1 -0
- package/dist/{chunk-OBVJ7RPW.js → chunk-NDF24LYP.js} +3 -3
- package/dist/{chunk-OBVJ7RPW.js.map → chunk-NDF24LYP.js.map} +1 -1
- package/dist/{chunk-ZGQTS3Y4.js → chunk-NGJIVDDD.js} +3 -3
- package/dist/{chunk-ZGQTS3Y4.js.map → chunk-NGJIVDDD.js.map} +1 -1
- package/dist/{chunk-PE36IF2D.js → chunk-NJV5SLEK.js} +159 -44
- package/dist/chunk-NJV5SLEK.js.map +1 -0
- package/dist/{chunk-OOWHXOK6.js → chunk-NJXR5OAM.js} +4 -4
- package/dist/{chunk-OOWHXOK6.js.map → chunk-NJXR5OAM.js.map} +1 -1
- package/dist/{chunk-CGYEHQOX.js → chunk-NOA6EJXE.js} +11 -2
- package/dist/chunk-NOA6EJXE.js.map +1 -0
- package/dist/{chunk-V7PQZOBR.js → chunk-NR7H7ZJP.js} +14 -6
- package/dist/chunk-NR7H7ZJP.js.map +1 -0
- package/dist/{chunk-OBYKJB4U.js → chunk-O2SYFJWP.js} +79 -5
- package/dist/chunk-O2SYFJWP.js.map +1 -0
- package/dist/{chunk-5LKOAX7I.js → chunk-OQ5MKDS3.js} +21 -5
- package/dist/chunk-OQ5MKDS3.js.map +1 -0
- package/dist/{chunk-4P3KTUZH.js → chunk-P23WJCH2.js} +51 -14
- package/dist/chunk-P23WJCH2.js.map +1 -0
- package/dist/{chunk-NWDSLXOX.js → chunk-PHRNUTSG.js} +118 -118
- package/dist/chunk-PHRNUTSG.js.map +1 -0
- package/dist/{chunk-JZCSNEHK.js → chunk-PNOGX36L.js} +141 -39
- package/dist/chunk-PNOGX36L.js.map +1 -0
- package/dist/{chunk-4OV5DSBB.js → chunk-PNTXHTBC.js} +5 -5
- package/dist/chunk-PNTXHTBC.js.map +1 -0
- package/dist/{chunk-TRSQP3JD.js → chunk-POQ6PGNE.js} +20 -4
- package/dist/chunk-POQ6PGNE.js.map +1 -0
- package/dist/{chunk-Y63UQZ7P.js → chunk-QCEKGYHF.js} +3 -3
- package/dist/{chunk-Y63UQZ7P.js.map → chunk-QCEKGYHF.js.map} +1 -1
- package/dist/{chunk-GFCXNFTW.js → chunk-SHQMPGOL.js} +4 -4
- package/dist/{chunk-GFCXNFTW.js.map → chunk-SHQMPGOL.js.map} +1 -1
- package/dist/{chunk-WBYDAL6X.js → chunk-SMT3LNAG.js} +4 -4
- package/dist/{chunk-WBYDAL6X.js.map → chunk-SMT3LNAG.js.map} +1 -1
- package/dist/{chunk-2FMEGSBN.js → chunk-T5TSLSRO.js} +135 -47
- package/dist/chunk-T5TSLSRO.js.map +1 -0
- package/dist/{chunk-2JMLDZLP.js → chunk-TVAR4JHA.js} +903 -138
- package/dist/chunk-TVAR4JHA.js.map +1 -0
- package/dist/{chunk-MVQ3Q2HM.js → chunk-UTKENBB6.js} +5 -5
- package/dist/{chunk-MVQ3Q2HM.js.map → chunk-UTKENBB6.js.map} +1 -1
- package/dist/{chunk-TH4CTXHX.js → chunk-VRLKHL74.js} +6 -6
- package/dist/{chunk-TH4CTXHX.js.map → chunk-VRLKHL74.js.map} +1 -1
- package/dist/{chunk-Z2K6BGUR.js → chunk-WI4T3KIS.js} +51 -16
- package/dist/chunk-WI4T3KIS.js.map +1 -0
- package/dist/{chunk-MGGFBZWA.js → chunk-X3RMRJNR.js} +6 -4
- package/dist/chunk-X3RMRJNR.js.map +1 -0
- package/dist/{chunk-FRPBSUFH.js → chunk-X6LKA3TJ.js} +5 -5
- package/dist/{chunk-FRPBSUFH.js.map → chunk-X6LKA3TJ.js.map} +1 -1
- package/dist/{chunk-3KHYGOEY.js → chunk-XMAJJPA4.js} +3 -3
- package/dist/{chunk-3KHYGOEY.js.map → chunk-XMAJJPA4.js.map} +1 -1
- package/dist/{chunk-Y34MSWEZ.js → chunk-XTVSNWLL.js} +19 -7
- package/dist/chunk-XTVSNWLL.js.map +1 -0
- package/dist/{chunk-VLXDXRRX.js → chunk-XZY6SBGU.js} +3 -3
- package/dist/{chunk-VLXDXRRX.js.map → chunk-XZY6SBGU.js.map} +1 -1
- package/dist/{chunk-5QI2JYJC.js → chunk-YQU2BPQD.js} +7 -5
- package/dist/chunk-YQU2BPQD.js.map +1 -0
- package/dist/cli/index.js +1207 -580
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/agent-checks.d.ts +40 -0
- package/dist/cli/src/agent-checks.d.ts.map +1 -0
- package/dist/cli/src/asset-feeds.d.ts.map +1 -1
- package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/catalog.d.ts +24 -0
- package/dist/cli/src/commands/catalog.d.ts.map +1 -1
- package/dist/cli/src/commands/config.d.ts.map +1 -1
- package/dist/cli/src/commands/diff.d.ts +1 -1
- package/dist/cli/src/commands/diff.d.ts.map +1 -1
- package/dist/cli/src/commands/integration.d.ts.map +1 -1
- package/dist/cli/src/commands/library-cmd.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 -0
- package/dist/cli/src/commands/manage.d.ts.map +1 -1
- package/dist/cli/src/commands/mcp-server.d.ts +1 -1
- package/dist/cli/src/commands/migrate-assets.d.ts +2 -1
- package/dist/cli/src/commands/migrate-assets.d.ts.map +1 -1
- package/dist/cli/src/commands/migrate.d.ts.map +1 -1
- package/dist/cli/src/commands/outdated.d.ts.map +1 -1
- package/dist/cli/src/commands/plugin/claude-code.d.ts +1 -1
- package/dist/cli/src/commands/plugin/claude-code.d.ts.map +1 -1
- package/dist/cli/src/commands/plugin/types.d.ts +1 -1
- package/dist/cli/src/commands/plugin-registry-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/project.d.ts +3 -1
- package/dist/cli/src/commands/project.d.ts.map +1 -1
- package/dist/cli/src/commands/publish-core.d.ts +5 -0
- package/dist/cli/src/commands/publish-core.d.ts.map +1 -1
- package/dist/cli/src/commands/run.d.ts +2 -1
- package/dist/cli/src/commands/run.d.ts.map +1 -1
- package/dist/cli/src/commands/serve-preflight.d.ts +22 -0
- package/dist/cli/src/commands/serve-preflight.d.ts.map +1 -0
- package/dist/cli/src/commands/serve.d.ts.map +1 -1
- package/dist/cli/src/commands/source-manifest-publish.d.ts.map +1 -1
- package/dist/cli/src/commands/source-manifest.d.ts.map +1 -1
- package/dist/cli/src/commands/source.d.ts.map +1 -1
- package/dist/cli/src/commands/store.d.ts.map +1 -1
- package/dist/cli/src/commands/tree.d.ts.map +1 -1
- package/dist/cli/src/commands/update.d.ts.map +1 -1
- package/dist/cli/src/commands/validate.d.ts.map +1 -1
- package/dist/cli/src/commands/why.d.ts +1 -0
- package/dist/cli/src/commands/why.d.ts.map +1 -1
- package/dist/cli/src/curated-manifests.d.ts +21 -0
- package/dist/cli/src/curated-manifests.d.ts.map +1 -0
- package/dist/cli/src/helpers.d.ts +12 -0
- package/dist/cli/src/helpers.d.ts.map +1 -1
- package/dist/cli/src/index-busy.d.ts +8 -0
- package/dist/cli/src/index-busy.d.ts.map +1 -0
- package/dist/cli/src/plugin-store/paths.d.ts +7 -3
- package/dist/cli/src/plugin-store/paths.d.ts.map +1 -1
- package/dist/cli/src/skill-checks.d.ts +29 -8
- package/dist/cli/src/skill-checks.d.ts.map +1 -1
- package/dist/cli/src/store-addable.d.ts +18 -0
- package/dist/cli/src/store-addable.d.ts.map +1 -0
- package/dist/connectors/config.js +5 -5
- package/dist/connectors/index.js +16 -16
- package/dist/{connectors-OXP2JBGI.js → connectors-UNKUKEPG.js} +19 -19
- package/dist/{connectors-OXP2JBGI.js.map → connectors-UNKUKEPG.js.map} +1 -1
- 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 +5 -4
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/core/src/lock.d.ts +19 -8
- package/dist/core/src/lock.d.ts.map +1 -1
- package/dist/core/src/logging/sinks/sqlite-sink.d.ts.map +1 -1
- package/dist/core/src/manifest.d.ts +5 -0
- package/dist/core/src/manifest.d.ts.map +1 -1
- package/dist/core/src/models.d.ts +4 -4
- package/dist/core/src/models.d.ts.map +1 -1
- package/dist/core/src/package-manager.d.ts +19 -0
- package/dist/core/src/package-manager.d.ts.map +1 -0
- package/dist/core/src/publish-manifest.d.ts +11 -1
- package/dist/core/src/publish-manifest.d.ts.map +1 -1
- package/dist/core/src/repo-manager.d.ts +11 -0
- package/dist/core/src/repo-manager.d.ts.map +1 -1
- package/dist/core/src/settings.d.ts +26 -6
- package/dist/core/src/settings.d.ts.map +1 -1
- package/dist/core/src/walker.d.ts +6 -1
- package/dist/core/src/walker.d.ts.map +1 -1
- package/dist/core/src/workspace-config.d.ts +4 -1
- package/dist/core/src/workspace-config.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/source-config.d.ts.map +1 -1
- package/dist/{ensure-sources-5ISVIA4T.js → ensure-sources-POMEQSTM.js} +19 -19
- package/dist/{ensure-sources-5ISVIA4T.js.map → ensure-sources-POMEQSTM.js.map} +1 -1
- package/dist/factory-assets/connectors/box.js +16 -16
- package/dist/factory-assets/connectors/deploy.js +16 -16
- package/dist/factory-assets/connectors/devserver.js +16 -16
- package/dist/factory-assets/connectors/flow/adapter.js +16 -16
- package/dist/factory-assets/connectors/flow/contract/normalize.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/contract.js +1 -1
- package/dist/factory-assets/connectors/flow/engine.js +9 -9
- package/dist/factory-assets/connectors/flow/run-flow.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/run-flow.js +18 -18
- package/dist/factory-assets/connectors/flow.js +16 -16
- package/dist/factory-assets/connectors/git.js +16 -16
- package/dist/factory-assets/connectors/gmail.js +16 -16
- package/dist/factory-assets/connectors/googledrive.js +16 -16
- package/dist/factory-assets/connectors/local.js +16 -16
- package/dist/factory-assets/connectors/mattermost.js +16 -16
- package/dist/factory-assets/connectors/memory.js +16 -16
- package/dist/factory-assets/connectors/minio.js +16 -16
- package/dist/factory-assets/connectors/postgres.js +16 -16
- package/dist/factory-assets/connectors/s3.js +16 -16
- package/dist/factory-assets/connectors/sharepoint.js +16 -16
- package/dist/factory-assets/connectors/sqlite.js +16 -16
- package/dist/factory-assets/connectors/static-server.js +16 -16
- package/dist/factory-assets/connectors/tunnel.js +16 -16
- package/dist/factory-assets/connectors/webdav.js +16 -16
- package/dist/factory-assets/connectors/xstate-store.js +16 -16
- package/dist/factory-assets/connectors/xstate.js +16 -16
- package/dist/factory-assets/skills/authoring-skaile-assets/SKILL.md +10 -8
- package/dist/factory-assets/skills/authoring-skaile-manifests/SKILL.md +15 -11
- package/dist/factory-assets/skills/authoring-skaile-manifests/references/dependency-standard.md +16 -11
- package/dist/factory-assets/skills/skaile-author-asset/SKILL.md +2 -2
- package/dist/{flows-HMSE76PO.js → flows-DVKMZKM4.js} +12 -12
- package/dist/{flows-HMSE76PO.js.map → flows-DVKMZKM4.js.map} +1 -1
- package/dist/{helpers-X6URBGSF.js → helpers-Y4OT7VIS.js} +19 -19
- package/dist/{helpers-X6URBGSF.js.map → helpers-Y4OT7VIS.js.map} +1 -1
- package/dist/library/index.js +12 -12
- package/dist/library/install.js +4 -4
- package/dist/library/src/index.d.ts +3 -3
- package/dist/library/src/index.d.ts.map +1 -1
- package/dist/library/src/install/source-fetch-github.d.ts.map +1 -1
- package/dist/library/src/local/db.d.ts +2 -0
- package/dist/library/src/local/db.d.ts.map +1 -1
- package/dist/library/src/local/library-dir.d.ts +26 -0
- package/dist/library/src/local/library-dir.d.ts.map +1 -1
- package/dist/library/src/local/library-manager.d.ts +5 -0
- package/dist/library/src/local/library-manager.d.ts.map +1 -1
- package/dist/library/src/local/library.d.ts +5 -3
- package/dist/library/src/local/library.d.ts.map +1 -1
- package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
- package/dist/library/src/local/store-paths.d.ts +9 -0
- package/dist/library/src/local/store-paths.d.ts.map +1 -1
- package/dist/library/src/manifest-writer.d.ts.map +1 -1
- package/dist/library/src/remote/index.d.ts +1 -1
- package/dist/library/src/remote/index.d.ts.map +1 -1
- package/dist/library/src/remote/remote-catalog-source.d.ts +17 -0
- package/dist/library/src/remote/remote-catalog-source.d.ts.map +1 -1
- package/dist/library/src/sync/git-driver.d.ts +2 -0
- package/dist/library/src/sync/git-driver.d.ts.map +1 -1
- package/dist/{library-publish-OS3JDW4S.js → library-publish-DI4Q5UOG.js} +73 -38
- package/dist/library-publish-DI4Q5UOG.js.map +1 -0
- package/dist/open-library-N6ESO6IK.js +40 -0
- package/dist/{open-library-4QSUORI6.js.map → open-library-N6ESO6IK.js.map} +1 -1
- package/dist/open-registry-CBZ5MWTT.js +32 -0
- package/dist/{open-registry-VCKS3MP5.js.map → open-registry-CBZ5MWTT.js.map} +1 -1
- package/dist/paths-U6W6MQNQ.js +22 -0
- package/dist/{paths-BVO56A25.js.map → paths-U6W6MQNQ.js.map} +1 -1
- package/dist/{plugin-store-X7GPWGBG.js → plugin-store-XMZSPVBF.js} +48 -12
- package/dist/plugin-store-XMZSPVBF.js.map +1 -0
- package/dist/project-UP52HEHC.js +79 -0
- package/dist/{project-PAXP46RD.js.map → project-UP52HEHC.js.map} +1 -1
- package/dist/resolver/index.js +8 -8
- package/dist/runner/index.js +33 -33
- package/dist/runner/src/agent.d.ts.map +1 -1
- package/dist/runner/src/agents/in-process-host.d.ts.map +1 -1
- package/dist/runner/src/composition/index.d.ts +1 -0
- package/dist/runner/src/composition/index.d.ts.map +1 -1
- package/dist/runner/src/composition/prompt-sections.d.ts +7 -4
- package/dist/runner/src/composition/prompt-sections.d.ts.map +1 -1
- package/dist/runner/src/composition/resolve.d.ts +10 -1
- package/dist/runner/src/composition/resolve.d.ts.map +1 -1
- package/dist/runner/src/composition/verify.d.ts +29 -0
- package/dist/runner/src/composition/verify.d.ts.map +1 -0
- package/dist/runner/src/credential-notice.d.ts +14 -0
- package/dist/runner/src/credential-notice.d.ts.map +1 -0
- package/dist/runner/src/environment.d.ts.map +1 -1
- package/dist/runner/src/final-text.d.ts +17 -0
- package/dist/runner/src/final-text.d.ts.map +1 -0
- package/dist/runner/src/index.d.ts +2 -0
- package/dist/runner/src/index.d.ts.map +1 -1
- package/dist/runner/src/resource-handler.d.ts.map +1 -1
- package/dist/runner/src/serve.d.ts +13 -0
- package/dist/runner/src/serve.d.ts.map +1 -1
- package/dist/runner/src/usage-limit-turn-hold.d.ts +51 -0
- package/dist/runner/src/usage-limit-turn-hold.d.ts.map +1 -0
- package/dist/sdk/asset-manager.js +16 -16
- package/dist/sdk/bridge.js +12 -12
- package/dist/sdk/core.js +7 -7
- package/dist/sdk/flow.js +9 -9
- package/dist/sdk/index.js +36 -34
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/resolver.js +8 -8
- package/dist/sdk/runner.js +33 -33
- package/dist/sdk/src/local-runtime.d.ts.map +1 -1
- package/dist/sdk/transport/ws/client.js +1 -1
- package/dist/sdk/transport/ws/server.js +1 -1
- package/dist/sdk/transport/ws.js +2 -2
- package/dist/sdk/transport.js +2 -2
- package/dist/serve-preflight-6P2JJEJ3.js +47 -0
- package/dist/serve-preflight-6P2JJEJ3.js.map +1 -0
- package/dist/{setup-BV55VHWC.js → setup-5IRUH5OS.js} +24 -24
- package/dist/{setup-BV55VHWC.js.map → setup-5IRUH5OS.js.map} +1 -1
- package/dist/{skills-EDFUCJPX.js → skills-HA36RFNM.js} +13 -13
- package/dist/{skills-EDFUCJPX.js.map → skills-HA36RFNM.js.map} +1 -1
- package/dist/source-DX5SGWEI.js +41 -0
- package/dist/{source-E4VAT5RZ.js.map → source-DX5SGWEI.js.map} +1 -1
- package/dist/source-fetch-github-PIO6EMMF.js +4 -0
- package/dist/{source-fetch-github-QN4LLTL5.js.map → source-fetch-github-PIO6EMMF.js.map} +1 -1
- package/dist/{source-manifest-publish-CLEE6TNH.js → source-manifest-publish-NMRLXWVW.js} +27 -26
- package/dist/source-manifest-publish-NMRLXWVW.js.map +1 -0
- package/dist/transport/index.js +2 -2
- package/dist/transport/src/ws/client.d.ts +6 -0
- package/dist/transport/src/ws/client.d.ts.map +1 -1
- package/dist/transport/src/ws/server.d.ts +4 -0
- package/dist/transport/src/ws/server.d.ts.map +1 -1
- package/dist/transport/ws/client.js +1 -1
- package/dist/transport/ws/server.js +1 -1
- package/dist/transport/ws.js +2 -2
- package/dist/tui/index.js +89 -52
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/src/repl-session.d.ts +1 -1
- package/dist/tui/src/repl-session.d.ts.map +1 -1
- package/dist/tui/src/repl.d.ts +3 -0
- package/dist/tui/src/repl.d.ts.map +1 -1
- package/dist/types/manifests.js +1 -1
- package/dist/types/src/manifests/agent-composition.d.ts +20 -0
- package/dist/types/src/manifests/agent-composition.d.ts.map +1 -1
- package/dist/types/src/manifests/agent.d.ts.map +1 -1
- package/dist/types/src/manifests/cron.d.ts +15 -0
- package/dist/types/src/manifests/cron.d.ts.map +1 -0
- package/dist/types/src/manifests/index.d.ts +3 -2
- package/dist/types/src/manifests/index.d.ts.map +1 -1
- package/dist/types/src/manifests/preset.d.ts +1 -1
- package/dist/workspace-plugin/adapters/mcp.js +23 -23
- package/dist/workspace-plugin/adapters/omp.js +106 -51
- package/dist/workspace-plugin/adapters/omp.js.map +1 -1
- package/dist/workspace-plugin/index.js +2 -2
- package/dist/workspace-plugin/src/adapters/claude-code.d.ts.map +1 -1
- package/dist/workspace-plugin/src/adapters/omp.d.ts +11 -2
- package/dist/workspace-plugin/src/adapters/omp.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/asset-feeds-ELEBTNUS.js.map +0 -1
- package/dist/chunk-2FMEGSBN.js.map +0 -1
- package/dist/chunk-2JMLDZLP.js.map +0 -1
- package/dist/chunk-32XKCNCL.js.map +0 -1
- package/dist/chunk-3BEY4WK3.js.map +0 -1
- package/dist/chunk-4OV5DSBB.js.map +0 -1
- package/dist/chunk-4P3KTUZH.js.map +0 -1
- package/dist/chunk-5LKOAX7I.js.map +0 -1
- package/dist/chunk-5QI2JYJC.js.map +0 -1
- package/dist/chunk-6HHE63CO.js.map +0 -1
- package/dist/chunk-CGYEHQOX.js.map +0 -1
- package/dist/chunk-GEWAIQZ5.js.map +0 -1
- package/dist/chunk-HJ5MCB3L.js.map +0 -1
- package/dist/chunk-IJHH4DSW.js.map +0 -1
- package/dist/chunk-IXWODEED.js.map +0 -1
- package/dist/chunk-JZCSNEHK.js.map +0 -1
- package/dist/chunk-MGGFBZWA.js.map +0 -1
- package/dist/chunk-NRDSGLCQ.js.map +0 -1
- package/dist/chunk-NWDSLXOX.js.map +0 -1
- package/dist/chunk-OBYKJB4U.js.map +0 -1
- package/dist/chunk-PE36IF2D.js.map +0 -1
- package/dist/chunk-R7FOF242.js +0 -59
- package/dist/chunk-R7FOF242.js.map +0 -1
- package/dist/chunk-TRSQP3JD.js.map +0 -1
- package/dist/chunk-V7PQZOBR.js.map +0 -1
- package/dist/chunk-Y34MSWEZ.js.map +0 -1
- package/dist/chunk-YBQONMH2.js.map +0 -1
- package/dist/chunk-Z2K6BGUR.js.map +0 -1
- package/dist/library-publish-OS3JDW4S.js.map +0 -1
- package/dist/open-library-4QSUORI6.js +0 -40
- package/dist/open-registry-VCKS3MP5.js +0 -32
- package/dist/paths-BVO56A25.js +0 -22
- package/dist/plugin-store-X7GPWGBG.js.map +0 -1
- package/dist/project-PAXP46RD.js +0 -41
- package/dist/source-E4VAT5RZ.js +0 -41
- package/dist/source-fetch-github-QN4LLTL5.js +0 -4
- package/dist/source-manifest-publish-CLEE6TNH.js.map +0 -1
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { unregisteredLibraryNames, scanUnlistedAssets, getStoreManifestsDir, missingLibraryDirMessage } from './chunk-
|
|
2
|
-
import { readManifestSourceConfig,
|
|
3
|
-
import { installTargetOf, canonicalEntryRef, deployAll, removeAsset, diffDeployedAgent, createScaffold, installAgent } from './chunk-
|
|
1
|
+
import { unregisteredLibraryNames, renamedLibraryName, resolveConfig, RemoteCatalogSource, OfflineError, describeCatalogError, CatalogHttpError, scanUnlistedAssets, getStoreManifestsDir, missingLibraryDirMessage } from './chunk-C3BMXXTN.js';
|
|
2
|
+
import { readManifestSourceConfig, discoverAssetsInTree, isManifestMode } from './chunk-7CR2OZPA.js';
|
|
3
|
+
import { installTargetOf, canonicalEntryRef, deployAll, removeAsset, diffDeployedAgent, removeExcludedLeftovers, deployedAssetDrift, createScaffold, installAgent } from './chunk-NJV5SLEK.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-7QWQTA5S.js';
|
|
7
|
+
import { resolveConfiguredDriverTarget, GLOBAL_INSTALL_DIR_NAME, resolveLibraryDir, buildLibraryLockEntries, computeHash, buildLockFile, writeLock, readLock, verifyLock, mergeLockFile, extractForPatch, generatePatch, savePatch, applyPatch, LOCK_SCHEMA_VERSION } from './chunk-T5TSLSRO.js';
|
|
8
|
+
import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-SHQMPGOL.js';
|
|
9
9
|
import { deployedBase, deployedDir, isDeployed, deployedPaths } from './chunk-PMECEZK3.js';
|
|
10
|
-
import { resolveSkWorkspaceConfig, effectiveAgentInstances, loadMcpServerDeclarations, resolveGlobalHarnesses, resolveGlobalSkWorkspaceConfig, getGlobalCacheDir, sourceCacheKey, getRepoCommit, matchPin, buildProvenanceIndex, coerceVersion, sourceShortName, resolveAll, ensureRepo, scanRepo, SKAILE_YAML_DEFAULT, checkRepoStatus, resolveAsset,
|
|
10
|
+
import { resolveSkWorkspaceConfig, effectiveAgentInstances, loadMcpServerDeclarations, resolveGlobalHarnesses, resolveGlobalSkWorkspaceConfig, getGlobalCacheDir, sourceCacheKey, getRepoCommit, matchPin, buildProvenanceIndex, coerceVersion, sourceShortName, readLinks, isCommitOnRemote, resolveAll, agentSourceCacheDir, ensureRepo, scanRepo, SKAILE_YAML_DEFAULT, checkRepoStatus, resolveAsset, MAX_PRESET_DEPTH, PresetDepthError, DEFAULT_AGENT_INSTANCE_ID, resolveAgentDefinitionDir, storeManifestSlug } from './chunk-PNOGX36L.js';
|
|
11
11
|
import { globalSkaileDir, globalCacheRoot, migrateLegacyDir } from './chunk-L5VSIPQD.js';
|
|
12
12
|
import { DRIVER_TARGETS } from './chunk-CPSIPIX7.js';
|
|
13
|
-
import { loadSkPublishManifest } from './chunk-
|
|
14
|
-
import { scanDirectory, parseRequires, dedupeRequirements } from './chunk-
|
|
15
|
-
import { parseAssetRef, parseAssetRefLoose, assetRefToStr, slugifyAssetName, depToStr } from './chunk-
|
|
13
|
+
import { loadSkPublishManifest } from './chunk-CTP3XBMF.js';
|
|
14
|
+
import { scanDirectory, parseRequires, dedupeRequirements } from './chunk-XTVSNWLL.js';
|
|
15
|
+
import { parseAssetRef, parseAssetRefLoose, assetRefToStr, slugifyAssetName, depToStr, parseDep } from './chunk-PNTXHTBC.js';
|
|
16
16
|
import { spawnSync } from 'child_process';
|
|
17
17
|
import { existsSync, rmSync, readdirSync, lstatSync, unlinkSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
18
18
|
import path, { resolve, dirname, sep, join, relative, posix } from 'path';
|
|
@@ -40,13 +40,10 @@ function writeLedger(projectDir, ledger) {
|
|
|
40
40
|
function bindInstance(projectDir, id, instance) {
|
|
41
41
|
const errors = [];
|
|
42
42
|
let srcDir;
|
|
43
|
-
const addHint = instance.ref.startsWith("agent:") ? ` \u2014 add the agent first: run skaile add ${instance.ref}` : "";
|
|
44
43
|
try {
|
|
45
44
|
srcDir = resolveAgentDefinitionDir(projectDir, instance.ref);
|
|
46
45
|
} catch (err) {
|
|
47
|
-
errors.push(
|
|
48
|
-
`agent instance "${id}": ${err instanceof Error ? err.message : String(err)}${addHint}`
|
|
49
|
-
);
|
|
46
|
+
errors.push(`agent instance "${id}": ${err instanceof Error ? err.message : String(err)}`);
|
|
50
47
|
}
|
|
51
48
|
if (srcDir !== void 0 && !existsSync(join(srcDir, "agent.yaml"))) {
|
|
52
49
|
errors.push(
|
|
@@ -404,6 +401,19 @@ function filesUnderManifestDir(paths, manifestRel) {
|
|
|
404
401
|
const manifestDir = posix.dirname(manifestRel);
|
|
405
402
|
return paths.map((p) => posix.relative(manifestDir, p)).filter((rel) => rel !== "" && !rel.startsWith(".."));
|
|
406
403
|
}
|
|
404
|
+
function lockedAssetFiles(kind, files) {
|
|
405
|
+
const manifestRel = matchManifestPath(
|
|
406
|
+
kind,
|
|
407
|
+
files.map((f) => f.path)
|
|
408
|
+
) ?? files[0]?.path;
|
|
409
|
+
if (!manifestRel) return [];
|
|
410
|
+
const manifestDir = posix.dirname(manifestRel);
|
|
411
|
+
return files.flatMap((f) => {
|
|
412
|
+
const rel = posix.relative(manifestDir, f.path);
|
|
413
|
+
return rel === "" || rel.startsWith("..") ? [] : [{ rel, sha256: f.sha256 }];
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
var GITHUB_REPO_URL = /github\.com[/:]/i;
|
|
407
417
|
function indexLockByKindName(lock) {
|
|
408
418
|
const lockByKindName = /* @__PURE__ */ new Map();
|
|
409
419
|
for (const [key, entry] of Object.entries(lock?.assets ?? {})) {
|
|
@@ -438,6 +448,28 @@ function commitsBetween(repoDir, from, to, cache) {
|
|
|
438
448
|
return count;
|
|
439
449
|
}
|
|
440
450
|
var COMMIT_ID = /^[0-9a-f]{7,64}$/;
|
|
451
|
+
function commitsTouching(repoDir, from, to, dir, cache) {
|
|
452
|
+
if (!COMMIT_ID.test(from) || !COMMIT_ID.test(to)) return null;
|
|
453
|
+
if (from === to) return 0;
|
|
454
|
+
const key = `${from}..${to} -- ${dir}`;
|
|
455
|
+
const hit = cache.get(key);
|
|
456
|
+
if (hit !== void 0) return hit;
|
|
457
|
+
const r = spawnSync("git", ["-C", repoDir, "rev-list", "--count", `${from}..${to}`, "--", dir], {
|
|
458
|
+
encoding: "utf8",
|
|
459
|
+
stdio: "pipe"
|
|
460
|
+
});
|
|
461
|
+
const n = r.status === 0 ? Number.parseInt(r.stdout.trim(), 10) : Number.NaN;
|
|
462
|
+
if (!Number.isFinite(n) || n < 0) return null;
|
|
463
|
+
cache.set(key, n);
|
|
464
|
+
return n;
|
|
465
|
+
}
|
|
466
|
+
function lockedAssetDir(kind, files) {
|
|
467
|
+
const manifestRel = matchManifestPath(
|
|
468
|
+
kind,
|
|
469
|
+
files.map((f) => f.path)
|
|
470
|
+
) ?? files[0]?.path;
|
|
471
|
+
return manifestRel ? posix.dirname(manifestRel) : ".";
|
|
472
|
+
}
|
|
441
473
|
function libraryDiskHashes(libPath, cache, registry) {
|
|
442
474
|
let hashes = cache.get(libPath);
|
|
443
475
|
if (!hashes) {
|
|
@@ -509,7 +541,7 @@ function newestLibraryDef(snap, libraryName, id) {
|
|
|
509
541
|
}
|
|
510
542
|
return best;
|
|
511
543
|
}
|
|
512
|
-
function libraryPreference(isDefaultLib) {
|
|
544
|
+
function libraryPreference(isDefaultLib, rank) {
|
|
513
545
|
return (a, b) => {
|
|
514
546
|
const va = coerceVersion(a.entry.version ?? "");
|
|
515
547
|
const vb = coerceVersion(b.entry.version ?? "");
|
|
@@ -517,7 +549,9 @@ function libraryPreference(isDefaultLib) {
|
|
|
517
549
|
if (gt(vb, va)) return 1;
|
|
518
550
|
const da = isDefaultLib.get(a.library) ? 0 : 1;
|
|
519
551
|
const db = isDefaultLib.get(b.library) ? 0 : 1;
|
|
520
|
-
return da - db
|
|
552
|
+
if (da !== db) return da - db;
|
|
553
|
+
const byRank = rank ? rank(a) - rank(b) : 0;
|
|
554
|
+
return byRank || a.library.localeCompare(b.library);
|
|
521
555
|
};
|
|
522
556
|
}
|
|
523
557
|
function qualifyDepRef(ref, fallback) {
|
|
@@ -652,8 +686,7 @@ function withKeptLockEntries(lock, kept) {
|
|
|
652
686
|
for (const s of kept.sources) if (!sources.has(s.url)) sources.set(s.url, s);
|
|
653
687
|
return {
|
|
654
688
|
...lock,
|
|
655
|
-
|
|
656
|
-
schema_version: lock.schema_version === 4 || Object.values(kept.assets).some((e) => e.library) ? 4 : 3,
|
|
689
|
+
schema_version: LOCK_SCHEMA_VERSION,
|
|
657
690
|
assets: { ...lock.assets, ...kept.assets },
|
|
658
691
|
sources: [...sources.values()].sort((a, b) => a.url.localeCompare(b.url))
|
|
659
692
|
};
|
|
@@ -674,10 +707,39 @@ function relockedRefs(prev, next) {
|
|
|
674
707
|
}
|
|
675
708
|
return out;
|
|
676
709
|
}
|
|
710
|
+
function libraryMoves(prev, next) {
|
|
711
|
+
if (!prev) return [];
|
|
712
|
+
const out = [];
|
|
713
|
+
for (const [key, entry] of Object.entries(next)) {
|
|
714
|
+
const to = entry.library;
|
|
715
|
+
if (!to || to.installed) continue;
|
|
716
|
+
const id = parseCanonicalLockKey(key);
|
|
717
|
+
for (const [prevKey, before] of Object.entries(prev.assets)) {
|
|
718
|
+
const o = parseCanonicalLockKey(prevKey);
|
|
719
|
+
if (o.kind !== id.kind || o.name !== id.name || o.publisher !== id.publisher) continue;
|
|
720
|
+
const from = before.library;
|
|
721
|
+
if (!from || from.installed || from.name === to.name) continue;
|
|
722
|
+
out.push({ ref: `${id.kind}:@${id.publisher}/${id.name}`, from: from.name, to: to.name });
|
|
723
|
+
break;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
return out;
|
|
727
|
+
}
|
|
677
728
|
function unregisteredLibraryFix(origin, ref) {
|
|
678
729
|
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
730
|
return `register library "${origin.name}" again with ${register}, or drop the dependency with \`skaile remove ${ref}\``;
|
|
680
731
|
}
|
|
732
|
+
function declaredNoHolderReason(ref) {
|
|
733
|
+
return `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 ${ref.split("#")[0]}\``;
|
|
734
|
+
}
|
|
735
|
+
var REGISTER_HOLDER = "register the library that holds it with `skaile library init <name> --path <dir>`";
|
|
736
|
+
function requirementNoHolderFix(asset) {
|
|
737
|
+
return `${REGISTER_HOLDER}, or drop ${asset} with \`skaile remove ${asset}\``;
|
|
738
|
+
}
|
|
739
|
+
function sameAsset(ref, want) {
|
|
740
|
+
const p = parseRefTolerant(ref);
|
|
741
|
+
return p !== null && p.kind === want.kind && p.name === want.name && (!want.publisher || !p.publisher || p.publisher === want.publisher);
|
|
742
|
+
}
|
|
681
743
|
function lockedLibraryProblem(lookup, origin, ref) {
|
|
682
744
|
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
745
|
}
|
|
@@ -767,6 +829,17 @@ var AssetManager = class {
|
|
|
767
829
|
onLibraryCollision;
|
|
768
830
|
/** Store URLs whose failed version lookup was already reported (one warning per URL). */
|
|
769
831
|
warnedStoreVersionLookups = /* @__PURE__ */ new Set();
|
|
832
|
+
/** Stores a lookup could not reach (store URL -> one line why); `add` reports them instead of "not found". */
|
|
833
|
+
storeFailures = /* @__PURE__ */ new Map();
|
|
834
|
+
/** Sources a provenance walk had to skip (source URL → why); one warning per source. */
|
|
835
|
+
skippedSources = /* @__PURE__ */ new Map();
|
|
836
|
+
/** `onSourceError` of every provenance walk: name the source once, leave it out, go on. */
|
|
837
|
+
reportSourceError = (clone, err) => {
|
|
838
|
+
const why = err instanceof Error ? err.message : String(err);
|
|
839
|
+
if (this.skippedSources.has(clone.sourceUrl)) return;
|
|
840
|
+
this.skippedSources.set(clone.sourceUrl, why);
|
|
841
|
+
console.warn(`skaile: source ${clone.sourceUrl} skipped: ${why}`);
|
|
842
|
+
};
|
|
770
843
|
constructor(opts) {
|
|
771
844
|
this.projectDir = resolve(opts.projectDir);
|
|
772
845
|
this.global = opts.global ?? false;
|
|
@@ -801,15 +874,27 @@ var AssetManager = class {
|
|
|
801
874
|
return this.global ? globalSkaileDir() : this.projectDir;
|
|
802
875
|
}
|
|
803
876
|
/**
|
|
804
|
-
* The harnesses a global deploy fans out to: the explicit `harnesses` override
|
|
805
|
-
*
|
|
806
|
-
*
|
|
877
|
+
* The harnesses a global deploy fans out to: the explicit `harnesses` override (a `--harness`
|
|
878
|
+
* filter), else the explicit `global_harnesses:` of `~/.skaile/skaile.yaml`, else every harness
|
|
879
|
+
* whose root dir exists under `~` plus the harness the project is configured for (a project on
|
|
880
|
+
* a harness whose dir does not exist yet still gets its user-scope assets). In project mode
|
|
881
|
+
* this is exactly `[driverTarget]`, so the shared fan-out loop degenerates to the
|
|
807
882
|
* single-target path.
|
|
808
883
|
*/
|
|
809
884
|
targetHarnesses() {
|
|
810
885
|
if (!this.global) return [this.driverTarget];
|
|
811
886
|
if (this.harnessesOverride && this.harnessesOverride.length > 0) return this.harnessesOverride;
|
|
812
|
-
|
|
887
|
+
const resolved = resolveGlobalHarnesses();
|
|
888
|
+
if (resolveGlobalSkWorkspaceConfig().global_harnesses?.length) return resolved;
|
|
889
|
+
const configured = resolveConfiguredDriverTarget(this.projectDir);
|
|
890
|
+
return configured && !resolved.includes(configured) ? [...resolved, configured] : resolved;
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* The harnesses `add` / `install` deploy into: `[driverTarget]` for a project, the global
|
|
894
|
+
* harness set (see {@link AssetManager.targetHarnesses}) for a global manager.
|
|
895
|
+
*/
|
|
896
|
+
deployTargets() {
|
|
897
|
+
return this.targetHarnesses();
|
|
813
898
|
}
|
|
814
899
|
get storeCacheDir() {
|
|
815
900
|
if (this.global) return join(globalCacheRoot(), "store");
|
|
@@ -841,14 +926,15 @@ var AssetManager = class {
|
|
|
841
926
|
}
|
|
842
927
|
/** Deploy options for one harness. In global mode, `driverTarget` is the
|
|
843
928
|
* fan-out target (not the constructor's `driverTarget`, which is project-only). */
|
|
844
|
-
deployOptsFor(target, link, onSkippedSymlink) {
|
|
929
|
+
deployOptsFor(target, link, onSkippedSymlink, onEnvFile) {
|
|
845
930
|
return {
|
|
846
931
|
registry: this.registry,
|
|
847
932
|
driverTarget: target,
|
|
848
933
|
global: this.global,
|
|
849
934
|
cwd: this.projectDir,
|
|
850
935
|
link: link === true,
|
|
851
|
-
...onSkippedSymlink ? { onSkippedSymlink: (entry, p) => onSkippedSymlink(canonicalEntryRef(entry), p) } : {}
|
|
936
|
+
...onSkippedSymlink ? { onSkippedSymlink: (entry, p) => onSkippedSymlink(canonicalEntryRef(entry), p) } : {},
|
|
937
|
+
...onEnvFile ? { onEnvFile: (entry, p) => onEnvFile(canonicalEntryRef(entry), p) } : {}
|
|
852
938
|
};
|
|
853
939
|
}
|
|
854
940
|
/**
|
|
@@ -878,13 +964,18 @@ var AssetManager = class {
|
|
|
878
964
|
* skills resolve. Project scope only. An instance whose `ref` resolves to no agent is
|
|
879
965
|
* reported in `agentInstanceErrors`; any other render error is warned and swallowed.
|
|
880
966
|
*/
|
|
881
|
-
renderAgentInstances() {
|
|
967
|
+
async renderAgentInstances() {
|
|
882
968
|
if (this.global) return {};
|
|
883
969
|
try {
|
|
884
970
|
const result = installAgentInstances({
|
|
885
971
|
projectDir: this.projectDir,
|
|
886
972
|
driverTarget: this.driverTarget
|
|
887
973
|
});
|
|
974
|
+
for (const u of unboundAgentInstances(this.projectDir, this.driverTarget)) {
|
|
975
|
+
if (!u.ref.startsWith("agent:")) continue;
|
|
976
|
+
const at = result.errors.findIndex((e) => e.startsWith(`agent instance "${u.id}":`));
|
|
977
|
+
if (at >= 0) result.errors[at] += ` \u2014 ${(await this.unboundAgentAdvice(u.ref)).advice}`;
|
|
978
|
+
}
|
|
888
979
|
for (const w of [...result.warnings, ...result.errors]) console.warn(`skaile: ${w}`);
|
|
889
980
|
return {
|
|
890
981
|
agentInstances: result.instances,
|
|
@@ -1007,6 +1098,31 @@ var AssetManager = class {
|
|
|
1007
1098
|
if (c.homepage != null) entry.homepage = c.homepage;
|
|
1008
1099
|
return entry;
|
|
1009
1100
|
}
|
|
1101
|
+
/**
|
|
1102
|
+
* The {@link ProvenanceCandidate} a source- or store-origin lock entry stands for: what a
|
|
1103
|
+
* deploy needs to restore the asset from the commit the lock names (`files[]` is the asset's
|
|
1104
|
+
* whole file set). `null` for a library-origin entry or a key that is not a canonical ref.
|
|
1105
|
+
* The source URL is the declared source's own spelling (the bundled factory tree and a
|
|
1106
|
+
* `sources:` entry match their declaration by it).
|
|
1107
|
+
*/
|
|
1108
|
+
lockedCandidate(key, entry, repositories) {
|
|
1109
|
+
if (!entry.source) return null;
|
|
1110
|
+
const { publisher, kind, name, version } = parseCanonicalLockKey(key);
|
|
1111
|
+
if (!publisher || !kind || !name) return null;
|
|
1112
|
+
const url = entry.source.url;
|
|
1113
|
+
const factory = Object.values(repositories).find((d) => d.factory);
|
|
1114
|
+
const declared = factory?.url !== void 0 && normalizeRepoUrl(url) === normalizeRepoUrl(factory.url) ? factory : repositories[sourceCacheKey(url)];
|
|
1115
|
+
return {
|
|
1116
|
+
publisher,
|
|
1117
|
+
kind,
|
|
1118
|
+
name,
|
|
1119
|
+
version: version ?? "",
|
|
1120
|
+
sourceUrl: declared?.url ?? url,
|
|
1121
|
+
commit: entry.source.commit,
|
|
1122
|
+
files: entry.files,
|
|
1123
|
+
sha256: entry.sha256
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1010
1126
|
/**
|
|
1011
1127
|
* Resolve refs the source/store pass could not against the user's registered
|
|
1012
1128
|
* **libraries** (local authoring places). Each library dir is scanned on disk
|
|
@@ -1024,6 +1140,9 @@ var AssetManager = class {
|
|
|
1024
1140
|
* builds an error hint must not warn).
|
|
1025
1141
|
* @param opts.library - Resolve only from this library (the one a lock entry names), not
|
|
1026
1142
|
* from every registered one. Never warns: no choice is made between libraries.
|
|
1143
|
+
* @param opts.lockedLibraries - `kind:publisher/name` → the library its lock entry names
|
|
1144
|
+
* ({@link AssetManager.lockedLibraryNames}). A ref listed here resolves from that library
|
|
1145
|
+
* when it holds a match, whatever the default library is.
|
|
1027
1146
|
* @returns the matched deploy entries, the set of `missing` refs covered, and
|
|
1028
1147
|
* each entry's originating library name.
|
|
1029
1148
|
*/
|
|
@@ -1036,6 +1155,7 @@ var AssetManager = class {
|
|
|
1036
1155
|
const { byKey, isDefaultLib, libraryDir } = scan;
|
|
1037
1156
|
const entries = [];
|
|
1038
1157
|
const fileSets = /* @__PURE__ */ new Map();
|
|
1158
|
+
const diskHashes = /* @__PURE__ */ new Map();
|
|
1039
1159
|
let snap;
|
|
1040
1160
|
const allCandidates = [...byKey.values()].flat();
|
|
1041
1161
|
for (const ref of missing) {
|
|
@@ -1044,12 +1164,53 @@ var AssetManager = class {
|
|
|
1044
1164
|
const hash = ref.indexOf("#");
|
|
1045
1165
|
const pin = parsed.pin ?? (hash >= 0 ? ref.slice(hash + 1) : void 0);
|
|
1046
1166
|
const key = parsed.publisher ? `${parsed.kind}:@${parsed.publisher}/${parsed.name}` : void 0;
|
|
1047
|
-
const
|
|
1167
|
+
const scanned = (key ? byKey.get(key) ?? [] : allCandidates.filter(
|
|
1048
1168
|
(c) => c.entry.kind === parsed.kind && c.entry.name === parsed.name
|
|
1049
1169
|
)).filter((c) => !opts.library || c.library === opts.library);
|
|
1050
|
-
const
|
|
1170
|
+
const pool = [];
|
|
1171
|
+
for (const c of scanned) {
|
|
1172
|
+
if (c.entry.version) {
|
|
1173
|
+
pool.push(c);
|
|
1174
|
+
continue;
|
|
1175
|
+
}
|
|
1176
|
+
if (snap === void 0) snap = await this.loadLibraryIndex();
|
|
1177
|
+
const def = newestLibraryDef(snap, c.library, {
|
|
1178
|
+
kind: c.entry.kind,
|
|
1179
|
+
publisher: c.entry.publisher ?? "",
|
|
1180
|
+
name: c.entry.name
|
|
1181
|
+
});
|
|
1182
|
+
pool.push(def?.version ? { ...c, entry: { ...c.entry, version: def.version } } : c);
|
|
1183
|
+
}
|
|
1184
|
+
let candidates = pool.filter((c) => !pin || matchPin(pin, c.entry.version ?? ""));
|
|
1185
|
+
let lockedLibrary;
|
|
1186
|
+
const lockedMap = opts.preferLocked?.libraries ?? opts.lockedLibraries;
|
|
1187
|
+
if (parsed.publisher) {
|
|
1188
|
+
lockedLibrary = lockedMap?.get(
|
|
1189
|
+
`${parsed.kind}:${parsed.publisher.replace(/^@/, "")}/${parsed.name}`
|
|
1190
|
+
);
|
|
1191
|
+
} else {
|
|
1192
|
+
const same = [...lockedMap ?? []].filter(([k]) => {
|
|
1193
|
+
const slash = k.indexOf("/");
|
|
1194
|
+
return k.startsWith(`${parsed.kind}:`) && k.slice(slash + 1) === parsed.name;
|
|
1195
|
+
});
|
|
1196
|
+
if (same.length === 1) lockedLibrary = same[0][1];
|
|
1197
|
+
}
|
|
1198
|
+
if (lockedLibrary && !opts.preferLocked) {
|
|
1199
|
+
const inLocked = candidates.filter((c) => c.library === lockedLibrary);
|
|
1200
|
+
if (inLocked.length > 0) candidates = inLocked;
|
|
1201
|
+
}
|
|
1051
1202
|
if (candidates.length === 0) continue;
|
|
1052
|
-
|
|
1203
|
+
const prefer = opts.preferLocked ? (c) => {
|
|
1204
|
+
if (lockedLibrary && c.library === lockedLibrary) return 0;
|
|
1205
|
+
const id = `${c.entry.kind}:${(c.entry.publisher ?? "").replace(/^@/, "")}/${c.entry.name}`;
|
|
1206
|
+
const lockedSha = opts.preferLocked?.shas.get(id);
|
|
1207
|
+
const libPath = libraryDir.get(c.library);
|
|
1208
|
+
const onDisk = lockedSha && libPath ? libraryDiskHashes(libPath, diskHashes, this.registry).get(
|
|
1209
|
+
`${c.entry.kind}:${c.entry.name}`
|
|
1210
|
+
) : void 0;
|
|
1211
|
+
return onDisk !== void 0 && onDisk === lockedSha ? 1 : 2;
|
|
1212
|
+
} : void 0;
|
|
1213
|
+
candidates.sort(libraryPreference(isDefaultLib, prefer));
|
|
1053
1214
|
const hit = candidates[0];
|
|
1054
1215
|
if (!opts.quiet && !opts.library) {
|
|
1055
1216
|
this.warnLibraryCollision(
|
|
@@ -1058,16 +1219,7 @@ var AssetManager = class {
|
|
|
1058
1219
|
hit
|
|
1059
1220
|
);
|
|
1060
1221
|
}
|
|
1061
|
-
|
|
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
|
-
}
|
|
1222
|
+
const entry = hit.entry;
|
|
1071
1223
|
withLibraryFiles(entry, libraryDir.get(hit.library), fileSets, this.registry);
|
|
1072
1224
|
entries.push(entry);
|
|
1073
1225
|
libraryOf.set(entry, hit.library);
|
|
@@ -1199,7 +1351,8 @@ var AssetManager = class {
|
|
|
1199
1351
|
const cloneDirs = new Set(clones.map((c) => resolve(c.localPath)));
|
|
1200
1352
|
const index = await buildProvenanceIndex(clones, {
|
|
1201
1353
|
projectDir: this.projectDir,
|
|
1202
|
-
knownKinds: this.knownKinds
|
|
1354
|
+
knownKinds: this.knownKinds,
|
|
1355
|
+
onSourceError: this.reportSourceError
|
|
1203
1356
|
});
|
|
1204
1357
|
const factoryUrl = normalizeRepoUrl(FACTORY_SOURCE_URL);
|
|
1205
1358
|
const hasFactory = Object.values(repositories).some((d) => d.factory);
|
|
@@ -1408,6 +1561,34 @@ var AssetManager = class {
|
|
|
1408
1561
|
publisher: ref?.publisher ?? entry.publisher?.replace(/^@/, "")
|
|
1409
1562
|
};
|
|
1410
1563
|
}
|
|
1564
|
+
/**
|
|
1565
|
+
* Refuse to lock a source commit another machine cannot check out. A commit made in the clone
|
|
1566
|
+
* itself (or one `source sync` could not fast-forward past) is in no remote branch: the lock
|
|
1567
|
+
* would name bytes nobody else has, and `install --locked` there could not restore them.
|
|
1568
|
+
* Linked (dev-override) and user-owned local sources are never checked: their lock is
|
|
1569
|
+
* machine-local by choice.
|
|
1570
|
+
*
|
|
1571
|
+
* @param resolved - Candidates about to be locked.
|
|
1572
|
+
* @param repositories - Source declarations of the project.
|
|
1573
|
+
* @throws With `<url> clone has unpublished commit <sha>` and the way out.
|
|
1574
|
+
*/
|
|
1575
|
+
assertSourceCommitsPublished(resolved, repositories) {
|
|
1576
|
+
const links = readLinks(this.projectDir);
|
|
1577
|
+
const checked = /* @__PURE__ */ new Set();
|
|
1578
|
+
for (const c of resolved) {
|
|
1579
|
+
if (!c.commit || /^0+$/.test(c.commit) || checked.has(`${c.sourceUrl}@${c.commit}`)) continue;
|
|
1580
|
+
checked.add(`${c.sourceUrl}@${c.commit}`);
|
|
1581
|
+
const hit = Object.entries(repositories).find(
|
|
1582
|
+
([, d]) => d.url !== void 0 && !d.factory && d.url === c.sourceUrl
|
|
1583
|
+
);
|
|
1584
|
+
if (!hit || links[hit[0]]) continue;
|
|
1585
|
+
const dir = this.resolveRepoDir(hit[1], hit[0]);
|
|
1586
|
+
if (!dir || isCommitOnRemote(dir, c.commit)) continue;
|
|
1587
|
+
throw new Error(
|
|
1588
|
+
`${c.sourceUrl} clone has unpublished commit ${c.commit.slice(0, 7)} - push it, or reset the clone (git -C ${dir} reset --hard origin/${hit[1].branch ?? "main"}) - nothing was locked`
|
|
1589
|
+
);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1411
1592
|
/**
|
|
1412
1593
|
* Refuse assets of one kind and name from different publishers: they deploy into the
|
|
1413
1594
|
* same folder, so the later one would silently overwrite the earlier. Throws one line
|
|
@@ -1697,6 +1878,11 @@ var AssetManager = class {
|
|
|
1697
1878
|
} catch {
|
|
1698
1879
|
}
|
|
1699
1880
|
}
|
|
1881
|
+
if (byName.state === "unregistered") {
|
|
1882
|
+
const renamed = renamedLibraryName(name);
|
|
1883
|
+
const now = renamed ? snap?.libraries.find((l) => l.name === renamed) : void 0;
|
|
1884
|
+
if (now && existsSync(now.path)) return { state: "ok", path: now.path, name: now.name };
|
|
1885
|
+
}
|
|
1700
1886
|
if (byName.state === "ok" || !origin.url) return byName;
|
|
1701
1887
|
const wanted = normalizeRepoUrl(origin.url);
|
|
1702
1888
|
const byUrl = snap?.libraries.find((l) => {
|
|
@@ -1710,6 +1896,14 @@ var AssetManager = class {
|
|
|
1710
1896
|
const found = this.lockedLibrary(origin, snap);
|
|
1711
1897
|
return found.state === "ok" ? found.path : null;
|
|
1712
1898
|
}
|
|
1899
|
+
/**
|
|
1900
|
+
* The `kind:@publisher/name` identities the lock holds for one `kind` and `name`, whatever
|
|
1901
|
+
* their publisher. `diff` uses it to accept a ref without a publisher only when it names
|
|
1902
|
+
* exactly one locked asset.
|
|
1903
|
+
*/
|
|
1904
|
+
lockedRefsNamed(kind, name) {
|
|
1905
|
+
return Object.keys(this.tryReadLock()?.assets ?? {}).map(parseCanonicalLockKey).filter((id) => id.kind === kind && id.name === name).map((id) => id.publisher ? `${kind}:@${id.publisher}/${name}` : `${kind}:${name}`);
|
|
1906
|
+
}
|
|
1713
1907
|
/**
|
|
1714
1908
|
* Where each library-origin lock entry of this project resolves on this machine: identity
|
|
1715
1909
|
* `kind:publisher/name` (no scope sigil, no version) → the name the locked library is
|
|
@@ -1739,6 +1933,19 @@ var AssetManager = class {
|
|
|
1739
1933
|
}
|
|
1740
1934
|
return out;
|
|
1741
1935
|
}
|
|
1936
|
+
/**
|
|
1937
|
+
* What `update` prefers when libraries tie: the library each lock entry resolves to here
|
|
1938
|
+
* ({@link lockedLibraryNames}, a `library rename` followed) and the sha256 it locked.
|
|
1939
|
+
*/
|
|
1940
|
+
async lockedPreference() {
|
|
1941
|
+
const shas = /* @__PURE__ */ new Map();
|
|
1942
|
+
for (const [key, e] of Object.entries(this.tryReadLock()?.assets ?? {})) {
|
|
1943
|
+
if (!e.library?.sha256 || e.library.installed) continue;
|
|
1944
|
+
const { publisher, kind, name } = parseCanonicalLockKey(key);
|
|
1945
|
+
if (publisher && kind && name) shas.set(`${kind}:${publisher}/${name}`, e.library.sha256);
|
|
1946
|
+
}
|
|
1947
|
+
return { libraries: await this.lockedLibraryNames(), shas };
|
|
1948
|
+
}
|
|
1742
1949
|
// ── Store fetch-then-deploy ────────────────────────────────────────────
|
|
1743
1950
|
/** A candidate's stable identity key (`<publisher>/<kind>:<name>@<version>`). */
|
|
1744
1951
|
candidateKey(c) {
|
|
@@ -1804,6 +2011,7 @@ var AssetManager = class {
|
|
|
1804
2011
|
const resolved = [];
|
|
1805
2012
|
const overridesApplied = /* @__PURE__ */ new Set();
|
|
1806
2013
|
const presets = [];
|
|
2014
|
+
const requiredBy = /* @__PURE__ */ new Map();
|
|
1807
2015
|
const lib = { entries: [], resolved: /* @__PURE__ */ new Set(), libraryOf: /* @__PURE__ */ new Map() };
|
|
1808
2016
|
const missing = /* @__PURE__ */ new Set();
|
|
1809
2017
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1852,6 +2060,13 @@ var AssetManager = class {
|
|
|
1852
2060
|
return depId !== null && declaredById.get(depId) || dep;
|
|
1853
2061
|
})
|
|
1854
2062
|
);
|
|
2063
|
+
if (e.kind !== "preset") {
|
|
2064
|
+
for (const dep of deps2) {
|
|
2065
|
+
const depId = refIdentity(dep);
|
|
2066
|
+
if (depId !== null && declaredById.has(depId)) continue;
|
|
2067
|
+
requiredBy.set(dep, [...requiredBy.get(dep) ?? [], canonicalEntryRef(e)]);
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
1855
2070
|
}
|
|
1856
2071
|
for (const r of hit.resolved) lib.resolved.add(r);
|
|
1857
2072
|
return next;
|
|
@@ -1875,7 +2090,9 @@ var AssetManager = class {
|
|
|
1875
2090
|
})
|
|
1876
2091
|
);
|
|
1877
2092
|
const hit = await this.resolveLibraryEntries([...libraryTried], {
|
|
1878
|
-
quiet: !opts.warnCollisions
|
|
2093
|
+
quiet: !opts.warnCollisions,
|
|
2094
|
+
lockedLibraries: opts.lockedLibraries,
|
|
2095
|
+
preferLocked: opts.preferLocked
|
|
1879
2096
|
});
|
|
1880
2097
|
const next = absorb(hit);
|
|
1881
2098
|
const rest = fresh.filter((ref) => !hit.resolved.has(ref));
|
|
@@ -1892,7 +2109,11 @@ var AssetManager = class {
|
|
|
1892
2109
|
presets.push(...r.presets);
|
|
1893
2110
|
const hit2 = await this.resolveLibraryEntries(
|
|
1894
2111
|
r.missing.filter((m) => !libraryTried.has(m)),
|
|
1895
|
-
{
|
|
2112
|
+
{
|
|
2113
|
+
quiet: !opts.warnCollisions,
|
|
2114
|
+
lockedLibraries: opts.lockedLibraries,
|
|
2115
|
+
preferLocked: opts.preferLocked
|
|
2116
|
+
}
|
|
1896
2117
|
);
|
|
1897
2118
|
next.push(...absorb(hit2));
|
|
1898
2119
|
for (const m of r.missing) if (!hit2.resolved.has(m)) missing.add(m);
|
|
@@ -1903,7 +2124,7 @@ var AssetManager = class {
|
|
|
1903
2124
|
const id = refIdentity(m);
|
|
1904
2125
|
return !lib.resolved.has(m) && !(id !== null && covered.has(id));
|
|
1905
2126
|
});
|
|
1906
|
-
return { resolved, missing: stillMissing, overridesApplied, lib, presets };
|
|
2127
|
+
return { resolved, missing: stillMissing, overridesApplied, lib, presets, requiredBy };
|
|
1907
2128
|
}
|
|
1908
2129
|
/** The catalog fetcher to use: an injected one, else built from `stores`. */
|
|
1909
2130
|
storeFetcherFor(stores) {
|
|
@@ -1918,8 +2139,8 @@ var AssetManager = class {
|
|
|
1918
2139
|
let url = this.catalogUrlOverride;
|
|
1919
2140
|
if (url === void 0) {
|
|
1920
2141
|
try {
|
|
1921
|
-
const { resolveConfig } = await import('./library/index.js');
|
|
1922
|
-
url =
|
|
2142
|
+
const { resolveConfig: resolveConfig2 } = await import('./library/index.js');
|
|
2143
|
+
url = resolveConfig2({ projectDir: this.projectDir }).catalog.url;
|
|
1923
2144
|
} catch {
|
|
1924
2145
|
return [];
|
|
1925
2146
|
}
|
|
@@ -1977,13 +2198,31 @@ var AssetManager = class {
|
|
|
1977
2198
|
// from source.url@commit and ignores it, so "" is inert.
|
|
1978
2199
|
tier: ""
|
|
1979
2200
|
};
|
|
1980
|
-
const
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
2201
|
+
const root = commonDirPrefix(c.files.map((f) => f.path));
|
|
2202
|
+
const intact = c.files.every((f) => {
|
|
2203
|
+
const rel = root && f.path.startsWith(`${root}/`) ? f.path.slice(root.length + 1) : f.path;
|
|
2204
|
+
try {
|
|
2205
|
+
return computeHash(join(targetDir, rel)) === f.sha256;
|
|
2206
|
+
} catch {
|
|
2207
|
+
return false;
|
|
2208
|
+
}
|
|
1985
2209
|
});
|
|
1986
|
-
|
|
2210
|
+
if (intact) {
|
|
2211
|
+
staged.set(this.candidateKey(c), join(targetDir, this.stagedManifestRel(c)));
|
|
2212
|
+
continue;
|
|
2213
|
+
}
|
|
2214
|
+
try {
|
|
2215
|
+
const { installPath } = await installFromManifest({
|
|
2216
|
+
manifest,
|
|
2217
|
+
libraryRoot: this.storeCacheDir,
|
|
2218
|
+
targetDir,
|
|
2219
|
+
fetcher: this.injectedAssetFetcher
|
|
2220
|
+
});
|
|
2221
|
+
staged.set(this.candidateKey(c), join(installPath, this.stagedManifestRel(c)));
|
|
2222
|
+
} catch (err) {
|
|
2223
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
2224
|
+
throw new Error(`${manifest.ref} (${c.sourceUrl} at ${c.commit.slice(0, 7)}): ${reason}`);
|
|
2225
|
+
}
|
|
1987
2226
|
}
|
|
1988
2227
|
return staged;
|
|
1989
2228
|
}
|
|
@@ -2065,6 +2304,9 @@ var AssetManager = class {
|
|
|
2065
2304
|
* @param opts.link - When `true`, symlink local-path assets instead of copying them
|
|
2066
2305
|
* (the author dev-loop). Machine-local / not for committing; a no-op for
|
|
2067
2306
|
* store/factory sources. Defaults to copy.
|
|
2307
|
+
* @param opts.moveLibraries - When `true` (`skaile update`), a locked library asset is
|
|
2308
|
+
* re-resolved from every library and may move to another one; {@link InstallResult.moved}
|
|
2309
|
+
* lists the moves. Without it a locked asset stays on the library its lock entry names.
|
|
2068
2310
|
* @returns {@link InstallResult} summarising what was deployed, what was missing, and any collisions.
|
|
2069
2311
|
*/
|
|
2070
2312
|
async install(opts) {
|
|
@@ -2090,14 +2332,43 @@ var AssetManager = class {
|
|
|
2090
2332
|
if (cloneError) return cloneError;
|
|
2091
2333
|
const provenanceIndex = await buildProvenanceIndex(this.buildClones(repositories), {
|
|
2092
2334
|
projectDir: this.projectDir,
|
|
2093
|
-
knownKinds: this.knownKinds
|
|
2335
|
+
knownKinds: this.knownKinds,
|
|
2336
|
+
onSourceError: this.reportSourceError
|
|
2337
|
+
});
|
|
2338
|
+
const { resolved, missing, overridesApplied, lib, presets, requiredBy } = await this.resolveLibraryFirst(dependencies, {
|
|
2339
|
+
provenanceIndex,
|
|
2340
|
+
overrides,
|
|
2341
|
+
stores,
|
|
2342
|
+
declaredRefs: dependencies,
|
|
2343
|
+
// `install` restores what the lock recorded: a changed default library or a second
|
|
2344
|
+
// library holding the same ref does not move a locked asset. `update` re-resolves.
|
|
2345
|
+
...opts?.moveLibraries ? { preferLocked: await this.lockedPreference() } : { lockedLibraries: await this.lockedLibraryNames() }
|
|
2094
2346
|
});
|
|
2095
|
-
const { resolved, missing, overridesApplied, lib, presets } = await this.resolveLibraryFirst(
|
|
2096
|
-
dependencies,
|
|
2097
|
-
{ provenanceIndex, overrides, stores, declaredRefs: dependencies }
|
|
2098
|
-
);
|
|
2099
2347
|
this.assertNoFolderCollision([...resolved, ...lib.entries.map((e) => this.entryIdentity(e))]);
|
|
2348
|
+
this.assertSourceCommitsPublished(resolved, repositories);
|
|
2100
2349
|
const stillMissing = missing.filter((m) => !lib.resolved.has(m));
|
|
2350
|
+
const lockedKeys = new Set(Object.keys(this.tryReadLock()?.assets ?? {}));
|
|
2351
|
+
const unmetByNew = /* @__PURE__ */ new Map();
|
|
2352
|
+
for (const m of stillMissing) {
|
|
2353
|
+
const newcomers = (requiredBy.get(m) ?? []).filter((parent) => !lockedKeys.has(parent));
|
|
2354
|
+
if (newcomers.length > 0) unmetByNew.set(m, newcomers);
|
|
2355
|
+
}
|
|
2356
|
+
if (unmetByNew.size > 0) {
|
|
2357
|
+
const hints = {};
|
|
2358
|
+
for (const [m, parents] of unmetByNew) {
|
|
2359
|
+
const requirer = parents.map((p) => p.split("#")[0]).join(", ");
|
|
2360
|
+
hints[m] = ` is required by ${requirer} (not found \u2014 ${REGISTER_HOLDER}, or drop ${requirer} with \`skaile remove ${parents[0].split("#")[0]}\`) \u2014 nothing was installed`;
|
|
2361
|
+
}
|
|
2362
|
+
return {
|
|
2363
|
+
deployed: [],
|
|
2364
|
+
removed: [],
|
|
2365
|
+
missing: [...unmetByNew.keys()],
|
|
2366
|
+
missingHints: hints,
|
|
2367
|
+
lockWritten: false,
|
|
2368
|
+
npmInstalled: [],
|
|
2369
|
+
npmFailed: []
|
|
2370
|
+
};
|
|
2371
|
+
}
|
|
2101
2372
|
const missingHints = await this.publisherChangeHints(stillMissing);
|
|
2102
2373
|
const prevLock = this.tryReadLock();
|
|
2103
2374
|
const kept = keptLockEntries(prevLock, stillMissing);
|
|
@@ -2122,6 +2393,7 @@ var AssetManager = class {
|
|
|
2122
2393
|
/* @__PURE__ */ new Set([...Object.keys(libraryLock), ...Object.keys(kept.assets)])
|
|
2123
2394
|
);
|
|
2124
2395
|
const entries = [...await this.buildCatalogEntries(resolved, repositories), ...lib.entries];
|
|
2396
|
+
const copyDrift = await this.lockedCopyDrift();
|
|
2125
2397
|
const deployed = [
|
|
2126
2398
|
...new Set(
|
|
2127
2399
|
this.targetHarnesses().flatMap(
|
|
@@ -2129,25 +2401,32 @@ var AssetManager = class {
|
|
|
2129
2401
|
)
|
|
2130
2402
|
)
|
|
2131
2403
|
];
|
|
2404
|
+
let restored = this.restoredCopies(copyDrift, deployed);
|
|
2132
2405
|
await this.renderDriverMcpConfig();
|
|
2133
|
-
const agentRender = this.renderAgentInstances();
|
|
2406
|
+
const agentRender = await this.renderAgentInstances();
|
|
2134
2407
|
const lockWanted = resolved.length > 0 || lib.entries.length > 0 || existsSync(this.lockPath);
|
|
2135
2408
|
let lockWritten = false;
|
|
2136
2409
|
let relocked = [];
|
|
2410
|
+
let moved = [];
|
|
2137
2411
|
if (lockWanted) {
|
|
2138
2412
|
const lockData = withKeptLockEntries(freshLock, kept);
|
|
2139
2413
|
relocked = relockedRefs(prevLock, lockData);
|
|
2414
|
+
restored = [...restored, ...this.removeExcludedLeftovers(relocked)];
|
|
2415
|
+
moved = libraryMoves(prevLock, libraryLock);
|
|
2140
2416
|
lockWritten = writeLock(this.lockPath, lockData);
|
|
2141
2417
|
}
|
|
2142
2418
|
this.recordInstallHistory(deployed, removed);
|
|
2143
2419
|
const { npmInstalled, npmFailed } = await this.installRuntimeAssetDeps();
|
|
2420
|
+
await this.adviseMissing(stillMissing, missingHints);
|
|
2144
2421
|
return {
|
|
2145
2422
|
deployed,
|
|
2146
2423
|
removed,
|
|
2147
2424
|
missing: stillMissing,
|
|
2148
2425
|
...Object.keys(missingHints).length > 0 ? { missingHints } : {},
|
|
2149
2426
|
...relocked.length > 0 ? { relocked } : {},
|
|
2427
|
+
...moved.length > 0 ? { moved } : {},
|
|
2150
2428
|
...replaced.length > 0 ? { replaced } : {},
|
|
2429
|
+
...restored.length > 0 ? { restored } : {},
|
|
2151
2430
|
lockWritten,
|
|
2152
2431
|
npmInstalled,
|
|
2153
2432
|
npmFailed,
|
|
@@ -2193,7 +2472,8 @@ var AssetManager = class {
|
|
|
2193
2472
|
const { kind, name, publisher } = id;
|
|
2194
2473
|
const component = kind ? this.installTarget(kind) : void 0;
|
|
2195
2474
|
if (!kind || !name || !component) return [];
|
|
2196
|
-
const
|
|
2475
|
+
const keptAgent = kind === "agent" && !this.global ? join(agentSourceCacheDir(this.projectDir), name) : null;
|
|
2476
|
+
const dir = keptAgent && existsSync(keptAgent) ? keptAgent : deployedDir(component, name, this.driverTarget, this.global, this.projectDir);
|
|
2197
2477
|
if (!existsSync(dir)) return [];
|
|
2198
2478
|
try {
|
|
2199
2479
|
const scanned = await scanDirectory(dir, publisher ?? "", { knownKinds: this.knownKinds });
|
|
@@ -2317,13 +2597,33 @@ var AssetManager = class {
|
|
|
2317
2597
|
return null;
|
|
2318
2598
|
}
|
|
2319
2599
|
}
|
|
2600
|
+
/**
|
|
2601
|
+
* A catalog client for `storeUrl` that honours `catalog.cache_ttl` (`0` = air-gapped: no
|
|
2602
|
+
* network, so every lookup that is not cached throws `OfflineError`).
|
|
2603
|
+
*/
|
|
2604
|
+
remoteStore(storeUrl) {
|
|
2605
|
+
let cacheTtlMs;
|
|
2606
|
+
try {
|
|
2607
|
+
cacheTtlMs = resolveConfig({ projectDir: this.projectDir }).catalog.cache_ttl * 1e3;
|
|
2608
|
+
} catch {
|
|
2609
|
+
}
|
|
2610
|
+
return new RemoteCatalogSource({ baseUrl: storeUrl, cacheTtlMs });
|
|
2611
|
+
}
|
|
2612
|
+
/**
|
|
2613
|
+
* Remember why a store could not be asked (store URL → one line without a JS error class
|
|
2614
|
+
* name), so `add` can say `store unreachable` instead of a bare `Asset not found`.
|
|
2615
|
+
*/
|
|
2616
|
+
noteStoreFailure(storeUrl, err) {
|
|
2617
|
+
const text = err instanceof OfflineError ? `${storeUrl}: air-gapped (catalog.cache_ttl: 0), the store was not asked` : describeCatalogError(err, storeUrl);
|
|
2618
|
+
this.storeFailures.set(storeUrl, text);
|
|
2619
|
+
return text;
|
|
2620
|
+
}
|
|
2320
2621
|
/** Build a store fetcher from the configured stores, or undefined when none. */
|
|
2321
2622
|
buildStoreFetcher(stores) {
|
|
2322
2623
|
if (stores.length === 0) return void 0;
|
|
2323
2624
|
return {
|
|
2324
2625
|
getInstallManifest: async (storeUrl, ref) => {
|
|
2325
|
-
const
|
|
2326
|
-
const src = new RemoteCatalogSource({ baseUrl: storeUrl });
|
|
2626
|
+
const src = this.remoteStore(storeUrl);
|
|
2327
2627
|
try {
|
|
2328
2628
|
const m = await src.getInstallManifest(ref);
|
|
2329
2629
|
let deps;
|
|
@@ -2336,7 +2636,7 @@ var AssetManager = class {
|
|
|
2336
2636
|
else if (deps === void 0)
|
|
2337
2637
|
gap = `has a cached catalog row for ${ref} without dependencies`;
|
|
2338
2638
|
} catch (err) {
|
|
2339
|
-
gap = `dependency lookup for ${ref} failed \u2014 ${err}`;
|
|
2639
|
+
gap = `dependency lookup for ${ref} failed \u2014 ${describeCatalogError(err, storeUrl)}`;
|
|
2340
2640
|
}
|
|
2341
2641
|
if (gap) {
|
|
2342
2642
|
console.warn(`skaile: store ${storeUrl} ${gap}; installing without its dependencies`);
|
|
@@ -2350,23 +2650,23 @@ var AssetManager = class {
|
|
|
2350
2650
|
};
|
|
2351
2651
|
} catch (err) {
|
|
2352
2652
|
if (err instanceof CatalogHttpError && err.status === 404) return null;
|
|
2653
|
+
this.noteStoreFailure(storeUrl, err);
|
|
2353
2654
|
throw err;
|
|
2354
2655
|
}
|
|
2355
2656
|
},
|
|
2356
2657
|
getCanonicalDigest: async (storeUrl, ref) => {
|
|
2357
|
-
const
|
|
2358
|
-
const src = new RemoteCatalogSource({ baseUrl: storeUrl });
|
|
2658
|
+
const src = this.remoteStore(storeUrl);
|
|
2359
2659
|
return src.getCanonicalDigest(ref);
|
|
2360
2660
|
},
|
|
2361
2661
|
listVersions: async (storeUrl, ref) => {
|
|
2362
|
-
const
|
|
2363
|
-
const src = new RemoteCatalogSource({ baseUrl: storeUrl });
|
|
2662
|
+
const src = this.remoteStore(storeUrl);
|
|
2364
2663
|
try {
|
|
2365
2664
|
return await src.listVersions(ref);
|
|
2366
2665
|
} catch (err) {
|
|
2666
|
+
const text = this.noteStoreFailure(storeUrl, err);
|
|
2367
2667
|
if (!this.warnedStoreVersionLookups.has(storeUrl)) {
|
|
2368
2668
|
this.warnedStoreVersionLookups.add(storeUrl);
|
|
2369
|
-
console.warn(`skaile: store
|
|
2669
|
+
console.warn(`skaile: store lookup of ${ref} failed: ${text}`);
|
|
2370
2670
|
}
|
|
2371
2671
|
return [];
|
|
2372
2672
|
}
|
|
@@ -2404,28 +2704,84 @@ var AssetManager = class {
|
|
|
2404
2704
|
}
|
|
2405
2705
|
return { npmInstalled, npmFailed };
|
|
2406
2706
|
}
|
|
2707
|
+
/**
|
|
2708
|
+
* Give every ref `install` could not resolve, and that has no hint yet, the fix the shared
|
|
2709
|
+
* {@link AssetManager.projectState} names for it (a declared ref no library or source holds,
|
|
2710
|
+
* a requirement nothing holds). Runs after the deploy, so a requirer is known by then.
|
|
2711
|
+
* Mutates `hints`: ` <reason>` follows the ref in the `Missing:` line.
|
|
2712
|
+
*/
|
|
2713
|
+
async adviseMissing(refs, hints) {
|
|
2714
|
+
const open = refs.filter((r) => !hints[r]);
|
|
2715
|
+
if (open.length === 0) return;
|
|
2716
|
+
const { gaps } = await this.projectState();
|
|
2717
|
+
for (const ref of open) {
|
|
2718
|
+
const want = parseRefTolerant(ref.split(" ")[0] ?? ref);
|
|
2719
|
+
if (!want) continue;
|
|
2720
|
+
const gap = gaps.find(
|
|
2721
|
+
(g) => (g.type === "declared" || g.type === "requires") && g.manualFix && sameAsset(g.ref, want)
|
|
2722
|
+
);
|
|
2723
|
+
if (gap) hints[ref] = ` ${gap.reason}`;
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2407
2726
|
async installLocked(repositories, patches, dependencies) {
|
|
2408
2727
|
const lock = this.tryReadLock();
|
|
2409
2728
|
if (!lock) {
|
|
2729
|
+
const gaps2 = (await this.projectState()).gaps.filter((g) => g.type !== "agent");
|
|
2730
|
+
if (gaps2.some((g) => g.manualFix)) {
|
|
2731
|
+
return {
|
|
2732
|
+
deployed: [],
|
|
2733
|
+
removed: [],
|
|
2734
|
+
missing: gaps2.map((g) => g.message),
|
|
2735
|
+
lockWritten: false,
|
|
2736
|
+
npmInstalled: [],
|
|
2737
|
+
npmFailed: []
|
|
2738
|
+
};
|
|
2739
|
+
}
|
|
2410
2740
|
throw new Error("No lock file found. Run `skaile install` first.");
|
|
2411
2741
|
}
|
|
2412
2742
|
this.assertNoFolderCollision(Object.keys(lock.assets).map(parseCanonicalLockKey));
|
|
2413
2743
|
const declBySlug = new Map(Object.entries(repositories));
|
|
2414
2744
|
const factoryUrl = normalizeRepoUrl(FACTORY_SOURCE_URL);
|
|
2415
|
-
const
|
|
2745
|
+
const factoryDecl = Object.values(repositories).find((d) => d.factory);
|
|
2746
|
+
const factoryDir = factoryDecl?.path ?? null;
|
|
2747
|
+
const isFactoryUrl = (url) => factoryDir !== null && normalizeRepoUrl(url) === factoryUrl;
|
|
2748
|
+
const unavailable = [];
|
|
2416
2749
|
for (const src of lock.sources) {
|
|
2417
|
-
if (
|
|
2750
|
+
if (isFactoryUrl(src.url)) continue;
|
|
2418
2751
|
const slug = sourceCacheKey(src.url);
|
|
2419
|
-
const
|
|
2420
|
-
|
|
2752
|
+
const declared = declBySlug.get(slug);
|
|
2753
|
+
if (!declared && GITHUB_REPO_URL.test(src.url)) continue;
|
|
2754
|
+
try {
|
|
2755
|
+
const dir = ensureRepo(declared ?? { url: src.url }, slug, this.reposDir, {
|
|
2756
|
+
projectDir: this.projectDir,
|
|
2757
|
+
// A lock restore deploys the pinned commit's bytes or fails: never another commit's.
|
|
2758
|
+
.../^0*$/.test(src.commit) ? {} : { pin: src.commit, strictPin: true }
|
|
2759
|
+
});
|
|
2760
|
+
if (!declared) repositories[slug] = { url: src.url, path: dir };
|
|
2761
|
+
} catch (err) {
|
|
2762
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
2763
|
+
unavailable.push(`unavailable: ${src.url} at ${src.commit.slice(0, 7)} (${reason})`);
|
|
2764
|
+
}
|
|
2421
2765
|
}
|
|
2422
|
-
|
|
2423
|
-
|
|
2766
|
+
if (unavailable.length > 0) {
|
|
2767
|
+
throw new Error(`Lock file verification failed:
|
|
2768
|
+
${unavailable.join("\n ")}`);
|
|
2769
|
+
}
|
|
2770
|
+
const candidates = [];
|
|
2771
|
+
const cloneOrigin = {};
|
|
2772
|
+
for (const [key, entry] of Object.entries(lock.assets)) {
|
|
2773
|
+
const candidate = this.lockedCandidate(key, entry, repositories);
|
|
2774
|
+
if (!candidate) continue;
|
|
2775
|
+
candidates.push(candidate);
|
|
2776
|
+
if (isFactoryUrl(candidate.sourceUrl) || this.candidateHasLocalBytes(candidate, repositories)) {
|
|
2777
|
+
cloneOrigin[key] = entry;
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
const verification = verifyLock({ ...lock, assets: cloneOrigin }, (sourceUrl) => {
|
|
2781
|
+
if (isFactoryUrl(sourceUrl)) return factoryDir;
|
|
2424
2782
|
const slug = sourceCacheKey(sourceUrl);
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
};
|
|
2428
|
-
const verification = verifyLock(lock, resolveCloneDir);
|
|
2783
|
+
return this.resolveRepoDir(repositories[slug] ?? { url: sourceUrl }, slug);
|
|
2784
|
+
});
|
|
2429
2785
|
if (!verification.ok) {
|
|
2430
2786
|
const issues = [
|
|
2431
2787
|
...verification.drifted.map((r) => `drifted: ${r}`),
|
|
@@ -2444,30 +2800,16 @@ var AssetManager = class {
|
|
|
2444
2800
|
${lines.join("\n ")}`
|
|
2445
2801
|
);
|
|
2446
2802
|
}
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
const mdRel = entry.files.find((f) => /\.(md|yaml)$/i.test(f.path))?.path ?? entry.files[0]?.path ?? "";
|
|
2455
|
-
resolved.push({
|
|
2456
|
-
name,
|
|
2457
|
-
kind,
|
|
2458
|
-
description: "",
|
|
2459
|
-
source: mdRel ? join(cloneDir, mdRel) : cloneDir,
|
|
2460
|
-
// Keep the publisher label slash-free (repo name), not the full cache key.
|
|
2461
|
-
publisher: sourceShortName(entry.source.url),
|
|
2462
|
-
version: entry.source.commit,
|
|
2463
|
-
// The lock key is the canonical ref; `publisher` above is only a clone label.
|
|
2464
|
-
canonicalRef: ref,
|
|
2465
|
-
requires: [],
|
|
2466
|
-
dependencies: []
|
|
2467
|
-
});
|
|
2468
|
-
if (!repositories[slug]) repositories[slug] = { url: entry.source.url, path: cloneDir };
|
|
2803
|
+
let resolved;
|
|
2804
|
+
try {
|
|
2805
|
+
resolved = await this.buildCatalogEntries(candidates, repositories);
|
|
2806
|
+
} catch (err) {
|
|
2807
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
2808
|
+
throw new Error(`Lock file verification failed:
|
|
2809
|
+
${reason}`);
|
|
2469
2810
|
}
|
|
2470
2811
|
const library = await this.restoreLibraryLockEntries(lock);
|
|
2812
|
+
const copyDrift = await this.lockedCopyDrift();
|
|
2471
2813
|
const deployed = [
|
|
2472
2814
|
...new Set(
|
|
2473
2815
|
this.targetHarnesses().flatMap(
|
|
@@ -2480,8 +2822,9 @@ var AssetManager = class {
|
|
|
2480
2822
|
)
|
|
2481
2823
|
)
|
|
2482
2824
|
];
|
|
2825
|
+
const restored = this.restoredCopies(copyDrift, deployed);
|
|
2483
2826
|
await this.renderDriverMcpConfig();
|
|
2484
|
-
const agentRender = this.renderAgentInstances();
|
|
2827
|
+
const agentRender = await this.renderAgentInstances();
|
|
2485
2828
|
const alreadyMissing = new Set(
|
|
2486
2829
|
library.missing.map((m) => {
|
|
2487
2830
|
const p = parseRefTolerant(m.split(" ")[0] ?? m);
|
|
@@ -2498,6 +2841,7 @@ var AssetManager = class {
|
|
|
2498
2841
|
removed: [],
|
|
2499
2842
|
missing: [...library.missing, ...gaps],
|
|
2500
2843
|
lockWritten: false,
|
|
2844
|
+
...restored.length > 0 ? { restored } : {},
|
|
2501
2845
|
...agentRender
|
|
2502
2846
|
};
|
|
2503
2847
|
}
|
|
@@ -2551,7 +2895,8 @@ var AssetManager = class {
|
|
|
2551
2895
|
this.ensureSourceClonesQuiet(repositories, sources);
|
|
2552
2896
|
const index = await buildProvenanceIndex(this.buildClones(repositories), {
|
|
2553
2897
|
projectDir: this.projectDir,
|
|
2554
|
-
knownKinds: this.knownKinds
|
|
2898
|
+
knownKinds: this.knownKinds,
|
|
2899
|
+
onSourceError: this.reportSourceError
|
|
2555
2900
|
});
|
|
2556
2901
|
for (const candidates of index.values()) for (const c of candidates) note(c);
|
|
2557
2902
|
for (const { entry } of await this.libraryAssets()) note(entry);
|
|
@@ -2572,6 +2917,8 @@ var AssetManager = class {
|
|
|
2572
2917
|
* store/factory sources. Defaults to copy.
|
|
2573
2918
|
* @param opts.onLibraryOrigin - Called once per deployed library-origin asset with its
|
|
2574
2919
|
* canonical ref and the name of the library it was resolved from.
|
|
2920
|
+
* @param opts.onLibraryMoved - Called once per asset whose lock entry named another library
|
|
2921
|
+
* than the one this add resolved it from.
|
|
2575
2922
|
* @param opts.onPresets - Called once with the presets expanded into this add (the
|
|
2576
2923
|
* added preset and any it nests); a library-held preset names its library.
|
|
2577
2924
|
* @returns Array of asset refs that were deployed in this call.
|
|
@@ -2584,11 +2931,19 @@ var AssetManager = class {
|
|
|
2584
2931
|
this.ensureSourceClonesQuiet(repositories, sources);
|
|
2585
2932
|
const provenanceIndex = await buildProvenanceIndex(this.buildClones(repositories), {
|
|
2586
2933
|
projectDir: this.projectDir,
|
|
2587
|
-
knownKinds: this.knownKinds
|
|
2934
|
+
knownKinds: this.knownKinds,
|
|
2935
|
+
onSourceError: this.reportSourceError
|
|
2588
2936
|
});
|
|
2589
2937
|
const { resolved, missing, overridesApplied, lib, presets } = await this.resolveLibraryFirst(
|
|
2590
2938
|
[ref],
|
|
2591
|
-
{
|
|
2939
|
+
{
|
|
2940
|
+
provenanceIndex,
|
|
2941
|
+
overrides,
|
|
2942
|
+
stores,
|
|
2943
|
+
declaredRefs: dependencies,
|
|
2944
|
+
warnCollisions: true,
|
|
2945
|
+
...opts?.preferLockedLibrary ? { preferLocked: await this.lockedPreference() } : {}
|
|
2946
|
+
}
|
|
2592
2947
|
);
|
|
2593
2948
|
if (resolved.length === 0 && lib.entries.length === 0 && presets.length === 0) {
|
|
2594
2949
|
const snap = await this.loadLibraryIndex();
|
|
@@ -2606,6 +2961,12 @@ var AssetManager = class {
|
|
|
2606
2961
|
);
|
|
2607
2962
|
}
|
|
2608
2963
|
}
|
|
2964
|
+
const unreachable = [...this.storeFailures.values()];
|
|
2965
|
+
if (unreachable.length > 0) {
|
|
2966
|
+
throw new Error(
|
|
2967
|
+
`Store unreachable \u2014 ${ref} was not looked up: ${unreachable.join("; ")}. Check the URL with \`skaile catalog test\`; a library or source can still hold the asset.`
|
|
2968
|
+
);
|
|
2969
|
+
}
|
|
2609
2970
|
throw new Error(
|
|
2610
2971
|
`Asset not found: ${ref}${(await this.publisherChangeHints([ref]))[ref] ?? ""}${missing.length ? ` (missing: ${missing.join(", ")})` : ""}`
|
|
2611
2972
|
);
|
|
@@ -2627,6 +2988,7 @@ var AssetManager = class {
|
|
|
2627
2988
|
}
|
|
2628
2989
|
}
|
|
2629
2990
|
}
|
|
2991
|
+
this.assertSourceCommitsPublished(resolved, repositories);
|
|
2630
2992
|
this.assertNoFolderCollision(
|
|
2631
2993
|
[...resolved, ...lib.entries.map((e) => this.entryIdentity(e))],
|
|
2632
2994
|
[
|
|
@@ -2635,8 +2997,8 @@ var AssetManager = class {
|
|
|
2635
2997
|
]
|
|
2636
2998
|
);
|
|
2637
2999
|
if (missing.length > 0) {
|
|
2638
|
-
|
|
2639
|
-
|
|
3000
|
+
throw new Error(
|
|
3001
|
+
`${ref.split("#")[0]} requires ${missing.join(", ")} (not found \u2014 ${REGISTER_HOLDER}, or remove the requirement from the asset's manifest) \u2014 nothing was added`
|
|
2640
3002
|
);
|
|
2641
3003
|
}
|
|
2642
3004
|
const entries = [...await this.buildCatalogEntries(resolved, repositories), ...lib.entries];
|
|
@@ -2647,7 +3009,7 @@ var AssetManager = class {
|
|
|
2647
3009
|
entries,
|
|
2648
3010
|
repositories,
|
|
2649
3011
|
patches,
|
|
2650
|
-
this.deployOptsFor(t, opts?.link, opts?.onSkippedSymlink)
|
|
3012
|
+
this.deployOptsFor(t, opts?.link, opts?.onSkippedSymlink, opts?.onEnvFile)
|
|
2651
3013
|
)
|
|
2652
3014
|
)
|
|
2653
3015
|
)
|
|
@@ -2662,13 +3024,18 @@ var AssetManager = class {
|
|
|
2662
3024
|
if (presets.length > 0) opts?.onPresets?.(presets);
|
|
2663
3025
|
this.addDependencyToConfig(ref);
|
|
2664
3026
|
await this.renderDriverMcpConfig();
|
|
2665
|
-
this.renderAgentInstances();
|
|
3027
|
+
await this.renderAgentInstances();
|
|
2666
3028
|
if (resolved.length > 0 || lib.entries.length > 0) {
|
|
3029
|
+
const libraryLock = await this.libraryLockEntries(lib);
|
|
2667
3030
|
const fresh = {
|
|
2668
|
-
...buildLockFile(resolved, overridesApplied,
|
|
3031
|
+
...buildLockFile(resolved, overridesApplied, libraryLock),
|
|
2669
3032
|
...presetsLockSlice(presets)
|
|
2670
3033
|
};
|
|
2671
|
-
|
|
3034
|
+
const prevLock = this.tryReadLock();
|
|
3035
|
+
if (opts?.onLibraryMoved) {
|
|
3036
|
+
for (const m of libraryMoves(prevLock, libraryLock)) opts.onLibraryMoved(m);
|
|
3037
|
+
}
|
|
3038
|
+
writeLock(this.lockPath, mergeLockFile(prevLock, fresh));
|
|
2672
3039
|
}
|
|
2673
3040
|
for (const d of deployed) {
|
|
2674
3041
|
appendHistory(this.projectDir, {
|
|
@@ -2726,16 +3093,16 @@ var AssetManager = class {
|
|
|
2726
3093
|
const target = memberIdentity(ref);
|
|
2727
3094
|
if (!target || target.kind === "preset") return [];
|
|
2728
3095
|
try {
|
|
2729
|
-
const
|
|
3096
|
+
const sameAsset2 = (id, want) => !!id && id.kind === want.kind && id.name === want.name && (!id.publisher || !want.publisher || id.publisher === want.publisher);
|
|
2730
3097
|
const declared = this.loadConfig().dependencies.map(memberIdentity);
|
|
2731
3098
|
const out = [];
|
|
2732
3099
|
const seen = /* @__PURE__ */ new Set();
|
|
2733
3100
|
for (const p of await this.search(void 0, "preset")) {
|
|
2734
3101
|
const members = [...p.dependencies, ...p.requires.map(depToStr)];
|
|
2735
|
-
if (!members.some((m) =>
|
|
3102
|
+
if (!members.some((m) => sameAsset2(memberIdentity(m), target))) continue;
|
|
2736
3103
|
const publisher = p.publisher?.replace(/^@/, "");
|
|
2737
3104
|
const presetId = { kind: "preset", name: p.name, publisher };
|
|
2738
|
-
if (declared.some((d) =>
|
|
3105
|
+
if (declared.some((d) => sameAsset2(d, presetId))) continue;
|
|
2739
3106
|
const presetRef = publisher ? assetRefToStr({ kind: "preset", name: p.name, publisher }) : `preset:${p.name}`;
|
|
2740
3107
|
if (seen.has(presetRef)) continue;
|
|
2741
3108
|
seen.add(presetRef);
|
|
@@ -3057,11 +3424,35 @@ var AssetManager = class {
|
|
|
3057
3424
|
const requiredBy = [...requires].filter(([node, deps]) => node !== targetKey && deps.includes(targetKey)).map(([node]) => display(node));
|
|
3058
3425
|
return requiredBy.length > 0 ? { ref: display(targetKey), requiredBy } : null;
|
|
3059
3426
|
}
|
|
3427
|
+
/**
|
|
3428
|
+
* Publishers under which the lock or `skaile.yaml` track `kind:name`. A deployed dir carries
|
|
3429
|
+
* no publisher, so this is what says whose copy it is. `undefined` stands for a
|
|
3430
|
+
* publisher-less declaration.
|
|
3431
|
+
*/
|
|
3432
|
+
trackedPublishers(kind, name) {
|
|
3433
|
+
const found = /* @__PURE__ */ new Set();
|
|
3434
|
+
const note = (id) => {
|
|
3435
|
+
if (id?.kind === kind && id.name === name) found.add(id.publisher?.replace(/^@/, ""));
|
|
3436
|
+
};
|
|
3437
|
+
for (const key of Object.keys(this.tryReadLock()?.assets ?? {})) {
|
|
3438
|
+
note(parseCanonicalLockKey(key));
|
|
3439
|
+
}
|
|
3440
|
+
try {
|
|
3441
|
+
for (const dep of this.loadConfig().dependencies) note(memberIdentity(dep));
|
|
3442
|
+
} catch {
|
|
3443
|
+
}
|
|
3444
|
+
return found;
|
|
3445
|
+
}
|
|
3060
3446
|
/** Undeploy `parsed` from every target harness and drop its declaration and lock entry. */
|
|
3061
3447
|
removeResolved(parsed) {
|
|
3448
|
+
const wantPub = parsed.publisher?.replace(/^@/, "");
|
|
3449
|
+
const tracked = this.trackedPublishers(parsed.kind, parsed.name);
|
|
3450
|
+
const someoneElses = wantPub !== void 0 && tracked.size > 0 && !tracked.has(wantPub) && !tracked.has(void 0);
|
|
3062
3451
|
let undeployed = false;
|
|
3063
|
-
|
|
3064
|
-
|
|
3452
|
+
if (!someoneElses) {
|
|
3453
|
+
for (const t of this.targetHarnesses()) {
|
|
3454
|
+
if (removeAsset(parsed.kind, parsed.name, this.deployOptsFor(t))) undeployed = true;
|
|
3455
|
+
}
|
|
3065
3456
|
}
|
|
3066
3457
|
const undeclared = this.removeDependencyFromConfig(parsed);
|
|
3067
3458
|
const unbound = this.removeAgentBindings(parsed);
|
|
@@ -3398,12 +3789,12 @@ var AssetManager = class {
|
|
|
3398
3789
|
return out;
|
|
3399
3790
|
}
|
|
3400
3791
|
/**
|
|
3401
|
-
*
|
|
3402
|
-
*
|
|
3403
|
-
*
|
|
3404
|
-
*
|
|
3405
|
-
* local edit never counts. An asset with no deployed directory is
|
|
3406
|
-
* (`listDeclared` reports it as drift); an agent is rendered, not copied, so it
|
|
3792
|
+
* Locked assets whose deployed directory lacks files the deploy writes — a deleted
|
|
3793
|
+
* `build.py` / `scripts/` helper next to an intact `SKILL.md`. The expected set is the file
|
|
3794
|
+
* set the lock covers: a library entry's files (every file under its manifest `root:`), a
|
|
3795
|
+
* source or store entry's `files[]` (the asset's whole file set at the locked commit). Only
|
|
3796
|
+
* presence is checked, so a local edit never counts. An asset with no deployed directory is
|
|
3797
|
+
* not listed (`listDeclared` reports it as drift); an agent is rendered, not copied, so it
|
|
3407
3798
|
* has no file mirror to compare. `skaile install` restores what is listed.
|
|
3408
3799
|
*
|
|
3409
3800
|
* @returns One {@link IncompleteDeploy} per affected asset; empty when healthy
|
|
@@ -3412,10 +3803,25 @@ var AssetManager = class {
|
|
|
3412
3803
|
async incompleteDeploys() {
|
|
3413
3804
|
const lock = this.tryReadLock();
|
|
3414
3805
|
if (!lock) return [];
|
|
3806
|
+
const out = [];
|
|
3807
|
+
const { patches } = this.loadConfig();
|
|
3808
|
+
for (const [key, entry] of Object.entries(lock.assets)) {
|
|
3809
|
+
if (!entry.source || entry.files.length === 0) continue;
|
|
3810
|
+
const { publisher, kind, name } = parseCanonicalLockKey(key);
|
|
3811
|
+
const component = kind ? this.installTarget(kind) : void 0;
|
|
3812
|
+
if (!publisher || !kind || !name || !component || component === "agent") continue;
|
|
3813
|
+
if (patches[`${kind}:${name}`]) continue;
|
|
3814
|
+
const dest = join(
|
|
3815
|
+
deployedBase(component, this.driverTarget, this.global, this.projectDir),
|
|
3816
|
+
name
|
|
3817
|
+
);
|
|
3818
|
+
if (!existsSync(dest) || lstatSync(dest).isSymbolicLink()) continue;
|
|
3819
|
+
const missing = lockedAssetFiles(kind, entry.files).map((f) => f.rel).filter((rel) => !existsSync(join(dest, rel)));
|
|
3820
|
+
if (missing.length > 0) out.push({ ref: `${kind}:@${publisher}/${name}`, missing });
|
|
3821
|
+
}
|
|
3415
3822
|
const locked = Object.entries(lock.assets).filter(([, e]) => e.library !== void 0 && !e.library.installed).map(([key]) => key);
|
|
3416
|
-
if (locked.length === 0) return
|
|
3823
|
+
if (locked.length === 0) return out;
|
|
3417
3824
|
const lib = await this.resolveLibraryEntries(locked, { quiet: true });
|
|
3418
|
-
const out = [];
|
|
3419
3825
|
for (const entry of lib.entries) {
|
|
3420
3826
|
const component = this.installTarget(entry.kind);
|
|
3421
3827
|
if (!entry.files || !component || component === "agent") continue;
|
|
@@ -3647,7 +4053,7 @@ var AssetManager = class {
|
|
|
3647
4053
|
return locked.kind === asked.kind && locked.name === asked.name;
|
|
3648
4054
|
};
|
|
3649
4055
|
const key = lock.assets[ref] ? ref : Object.keys(lock.assets).find(matchesIdentity);
|
|
3650
|
-
if (!key) return [];
|
|
4056
|
+
if (!key) return asked?.kind === "preset" ? this.whyPreset(lock, asked) : [];
|
|
3651
4057
|
const { requires, roots } = await this.lockedGraph(lock);
|
|
3652
4058
|
if (roots.includes(key)) return [key, "direct (skaile.yaml)"];
|
|
3653
4059
|
const requirers = /* @__PURE__ */ new Map();
|
|
@@ -3672,6 +4078,52 @@ var AssetManager = class {
|
|
|
3672
4078
|
}
|
|
3673
4079
|
return [key, "not required by a declared dependency"];
|
|
3674
4080
|
}
|
|
4081
|
+
/**
|
|
4082
|
+
* The {@link AssetManager.why} chain of a preset. A preset is never a lock asset: its record
|
|
4083
|
+
* is the lock's `presets` slice. Declared in `skaile.yaml` it is `direct`; one only a declared
|
|
4084
|
+
* preset nests is traced through the presets that list it.
|
|
4085
|
+
*
|
|
4086
|
+
* @returns `[]` when the lock does not record the preset.
|
|
4087
|
+
*/
|
|
4088
|
+
async whyPreset(lock, asked) {
|
|
4089
|
+
const wanted = memberIdentity(assetRefToStr(asked));
|
|
4090
|
+
const same = (ref) => {
|
|
4091
|
+
const id = memberIdentity(ref);
|
|
4092
|
+
return id !== null && wanted !== null && id.kind === "preset" && id.name === wanted.name && (!id.publisher || !wanted.publisher || id.publisher === wanted.publisher);
|
|
4093
|
+
};
|
|
4094
|
+
const recorded = (lock.presets ?? []).find(same);
|
|
4095
|
+
if (!recorded) return [];
|
|
4096
|
+
let declared = [];
|
|
4097
|
+
try {
|
|
4098
|
+
declared = this.loadConfig().dependencies;
|
|
4099
|
+
} catch {
|
|
4100
|
+
}
|
|
4101
|
+
const roots = declared.filter((d) => memberIdentity(d)?.kind === "preset");
|
|
4102
|
+
if (roots.some(same)) return [recorded, "direct (skaile.yaml)"];
|
|
4103
|
+
const parent = /* @__PURE__ */ new Map();
|
|
4104
|
+
const seen = new Set(roots);
|
|
4105
|
+
const queue = [...roots];
|
|
4106
|
+
for (let node = queue.shift(); node !== void 0; node = queue.shift()) {
|
|
4107
|
+
let items = [];
|
|
4108
|
+
try {
|
|
4109
|
+
const entry = await this.info(node);
|
|
4110
|
+
items = entry ? libraryEntryDepRefs(entry) : [];
|
|
4111
|
+
} catch {
|
|
4112
|
+
}
|
|
4113
|
+
for (const item of items) {
|
|
4114
|
+
if (memberIdentity(item)?.kind !== "preset" || seen.has(item)) continue;
|
|
4115
|
+
seen.add(item);
|
|
4116
|
+
parent.set(item, node);
|
|
4117
|
+
if (same(item)) {
|
|
4118
|
+
const chain = [];
|
|
4119
|
+
for (let c = item; c !== void 0; c = parent.get(c)) chain.push(c);
|
|
4120
|
+
return [...chain, "direct (skaile.yaml)"];
|
|
4121
|
+
}
|
|
4122
|
+
queue.push(item);
|
|
4123
|
+
}
|
|
4124
|
+
}
|
|
4125
|
+
return [recorded, "not required by a declared dependency"];
|
|
4126
|
+
}
|
|
3675
4127
|
/**
|
|
3676
4128
|
* List installed assets that have a newer upstream available.
|
|
3677
4129
|
*
|
|
@@ -3710,7 +4162,17 @@ var AssetManager = class {
|
|
|
3710
4162
|
if (!kind || !name) continue;
|
|
3711
4163
|
const lockedCommit = entry.source.commit || src.commit;
|
|
3712
4164
|
const moved = lockedCommit && !/^0+$/.test(lockedCommit) && lockedCommit !== status.localHead ? commitsBetween(clone, lockedCommit, status.localHead, commitCounts) : 0;
|
|
3713
|
-
|
|
4165
|
+
let behind = status.behind + moved;
|
|
4166
|
+
if (behind > 0) {
|
|
4167
|
+
const touching = commitsTouching(
|
|
4168
|
+
clone,
|
|
4169
|
+
COMMIT_ID.test(lockedCommit) && !/^0+$/.test(lockedCommit) ? lockedCommit : status.localHead,
|
|
4170
|
+
status.behind > 0 && status.remoteHead ? status.remoteHead : status.localHead,
|
|
4171
|
+
lockedAssetDir(kind, entry.files),
|
|
4172
|
+
commitCounts
|
|
4173
|
+
);
|
|
4174
|
+
if (touching !== null) behind = touching;
|
|
4175
|
+
}
|
|
3714
4176
|
if (behind <= 0) continue;
|
|
3715
4177
|
result.push({
|
|
3716
4178
|
kind,
|
|
@@ -3828,6 +4290,37 @@ var AssetManager = class {
|
|
|
3828
4290
|
}
|
|
3829
4291
|
return null;
|
|
3830
4292
|
}
|
|
4293
|
+
/**
|
|
4294
|
+
* The deploy entry of a source- or store-origin asset, carrying the file set its lock entry
|
|
4295
|
+
* lists (so a missing or edited helper shows in `diff`, not only the manifest). A source asset
|
|
4296
|
+
* reads from its clone; a store asset from the bytes `add`/`install` staged in the project
|
|
4297
|
+
* store cache. `null` when the lock has no such entry or its bytes are not on disk.
|
|
4298
|
+
*
|
|
4299
|
+
* @param want - Kind, name and optional publisher of the asset.
|
|
4300
|
+
*/
|
|
4301
|
+
lockedSourceEntry(want) {
|
|
4302
|
+
const { repositories } = this.loadConfig();
|
|
4303
|
+
for (const [key, e] of Object.entries(this.tryReadLock()?.assets ?? {})) {
|
|
4304
|
+
const id = parseCanonicalLockKey(key);
|
|
4305
|
+
if (!e.source || id.kind !== want.kind || id.name !== want.name) continue;
|
|
4306
|
+
if (want.publisher && id.publisher !== want.publisher) continue;
|
|
4307
|
+
const c = this.lockedCandidate(key, e, repositories);
|
|
4308
|
+
if (!c) continue;
|
|
4309
|
+
if (this.candidateHasLocalBytes(c, repositories)) {
|
|
4310
|
+
return this.candidateToCatalogEntry(c, repositories);
|
|
4311
|
+
}
|
|
4312
|
+
const staged = join(
|
|
4313
|
+
this.storeCacheDir,
|
|
4314
|
+
c.publisher,
|
|
4315
|
+
c.kind,
|
|
4316
|
+
c.name,
|
|
4317
|
+
c.version,
|
|
4318
|
+
this.stagedManifestRel(c)
|
|
4319
|
+
);
|
|
4320
|
+
if (existsSync(staged)) return this.stagedCandidateToEntry(c, staged);
|
|
4321
|
+
}
|
|
4322
|
+
return null;
|
|
4323
|
+
}
|
|
3831
4324
|
/**
|
|
3832
4325
|
* Produce a unified diff from the deployed asset to its catalog source: `-` lines
|
|
3833
4326
|
* are in the deployed copy only (local edits `update` would overwrite), `+` lines
|
|
@@ -3845,9 +4338,17 @@ var AssetManager = class {
|
|
|
3845
4338
|
async diff(ref) {
|
|
3846
4339
|
const parsed = parseRefTolerant(ref);
|
|
3847
4340
|
if (!parsed) return { status: "not-found" };
|
|
3848
|
-
const entry = await this.lockedLibraryEntry(parsed) ?? await this.info(ref);
|
|
4341
|
+
const entry = await this.lockedLibraryEntry(parsed) ?? this.lockedSourceEntry(parsed) ?? await this.info(ref);
|
|
3849
4342
|
if (!entry || !existsSync(entry.source)) return { status: "not-found" };
|
|
4343
|
+
const wantPublisher = parsed.publisher?.replace(/^@/, "");
|
|
4344
|
+
if (wantPublisher) {
|
|
4345
|
+
const lockedHere = Object.keys(this.tryReadLock()?.assets ?? {}).map(parseCanonicalLockKey).filter((id) => id.kind === parsed.kind && id.name === parsed.name);
|
|
4346
|
+
if (lockedHere.length > 0 && !lockedHere.some((id) => id.publisher === wantPublisher)) {
|
|
4347
|
+
return { status: "not-deployed" };
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
3850
4350
|
const component = this.installTarget(parsed.kind);
|
|
4351
|
+
if (parsed.kind === "preset" && this.presetRecorded(parsed)) return { status: "no-files" };
|
|
3851
4352
|
if (!component) return { status: "not-deployed" };
|
|
3852
4353
|
if (component === "agent") {
|
|
3853
4354
|
const diff = diffDeployedAgent(entry, this.deployOptsFor(this.driverTarget));
|
|
@@ -3888,7 +4389,8 @@ var AssetManager = class {
|
|
|
3888
4389
|
this.ensureSourceClonesQuiet(repositories, sources);
|
|
3889
4390
|
const provenanceIndex = await buildProvenanceIndex(this.buildClones(repositories), {
|
|
3890
4391
|
projectDir: this.projectDir,
|
|
3891
|
-
knownKinds: this.knownKinds
|
|
4392
|
+
knownKinds: this.knownKinds,
|
|
4393
|
+
onSourceError: this.reportSourceError
|
|
3892
4394
|
});
|
|
3893
4395
|
const { resolved, overridesApplied, lib } = await this.resolveLibraryFirst(dependencies, {
|
|
3894
4396
|
provenanceIndex,
|
|
@@ -4015,7 +4517,11 @@ var AssetManager = class {
|
|
|
4015
4517
|
const full = await this.info(
|
|
4016
4518
|
publisher ? `${entry.kind}:@${publisher}/${entry.name}` : `${entry.kind}:${entry.name}`
|
|
4017
4519
|
);
|
|
4018
|
-
|
|
4520
|
+
const restorable = !full && publisher !== void 0 && Object.entries(lock?.assets ?? {}).some(([key, e]) => {
|
|
4521
|
+
const id = parseCanonicalLockKey(key);
|
|
4522
|
+
return e.source !== void 0 && id.kind === entry.kind && id.name === entry.name && id.publisher === publisher;
|
|
4523
|
+
});
|
|
4524
|
+
if (!full && !restorable) {
|
|
4019
4525
|
if (publisher) {
|
|
4020
4526
|
const canonical = `${entry.kind}:@${publisher}/${entry.name}`;
|
|
4021
4527
|
const fix = (await this.unresolvedFixes([canonical])).get(canonical);
|
|
@@ -4031,8 +4537,9 @@ var AssetManager = class {
|
|
|
4031
4537
|
}
|
|
4032
4538
|
continue;
|
|
4033
4539
|
}
|
|
4540
|
+
const declaredRequires = full ? full.requires : (await this.deployedRequirementsOf({ ...entry, publisher })).map(parseDep);
|
|
4034
4541
|
const gaps = [];
|
|
4035
|
-
const requirements = dedupeRequirements(
|
|
4542
|
+
const requirements = dedupeRequirements(declaredRequires, publisher).map(
|
|
4036
4543
|
(r) => r.publisher || !publisher ? r : { ...r, publisher }
|
|
4037
4544
|
);
|
|
4038
4545
|
for (const req of requirements) {
|
|
@@ -4113,7 +4620,11 @@ var AssetManager = class {
|
|
|
4113
4620
|
const lock = this.tryReadLock();
|
|
4114
4621
|
const lockedIds = Object.keys(lock?.assets ?? {}).map(parseCanonicalLockKey);
|
|
4115
4622
|
const requirements = await this.doctor();
|
|
4116
|
-
|
|
4623
|
+
let gaps = [];
|
|
4624
|
+
const lockIdentity = (kind, name) => {
|
|
4625
|
+
const publisher = lockedIds.find((id) => id.kind === kind && id.name === name)?.publisher;
|
|
4626
|
+
return publisher ? `${kind}:@${publisher}/${name}` : `${kind}:${name}`;
|
|
4627
|
+
};
|
|
4117
4628
|
for (const i of requirements) {
|
|
4118
4629
|
if (i.unresolved) {
|
|
4119
4630
|
const publisher = lockedIds.find(
|
|
@@ -4130,18 +4641,18 @@ var AssetManager = class {
|
|
|
4130
4641
|
});
|
|
4131
4642
|
continue;
|
|
4132
4643
|
}
|
|
4133
|
-
const asset =
|
|
4644
|
+
const asset = lockIdentity(i.assetKind, i.assetName);
|
|
4134
4645
|
const dep = `${i.depKind}:${i.depName}`;
|
|
4135
4646
|
if (i.inRepos) {
|
|
4136
4647
|
gaps.push({
|
|
4137
4648
|
type: "requires",
|
|
4138
4649
|
ref: dep,
|
|
4139
4650
|
asset,
|
|
4140
|
-
reason: `is required by ${asset} but neither deployed nor locked (
|
|
4141
|
-
message: `${asset} requires ${dep} (
|
|
4651
|
+
reason: `is required by ${asset} but neither deployed nor locked (run skaile install)`,
|
|
4652
|
+
message: `${asset} requires ${dep} (run skaile install)`
|
|
4142
4653
|
});
|
|
4143
4654
|
} else {
|
|
4144
|
-
const fix =
|
|
4655
|
+
const fix = requirementNoHolderFix(asset);
|
|
4145
4656
|
gaps.push({
|
|
4146
4657
|
type: "requires",
|
|
4147
4658
|
ref: dep,
|
|
@@ -4159,17 +4670,51 @@ var AssetManager = class {
|
|
|
4159
4670
|
gaps.push(gap);
|
|
4160
4671
|
named.add(gapIdentity(gap.ref));
|
|
4161
4672
|
}
|
|
4673
|
+
const libraryHeld = (dep) => {
|
|
4674
|
+
const want = parseRefTolerant(dep);
|
|
4675
|
+
return want !== null && gaps.some((g) => g.type === "library" && sameAsset(g.ref, want));
|
|
4676
|
+
};
|
|
4677
|
+
gaps = gaps.filter((g) => !(g.type === "requires" && libraryHeld(g.ref)));
|
|
4162
4678
|
for (const gap of this.undeployedLockGaps(lock, named)) {
|
|
4163
4679
|
gaps.push(gap);
|
|
4164
4680
|
named.add(gapIdentity(gap.ref));
|
|
4165
4681
|
}
|
|
4682
|
+
for (const d of await this.lockedCopyDrift()) {
|
|
4683
|
+
if (named.has(gapIdentity(d.ref))) continue;
|
|
4684
|
+
const parts = [
|
|
4685
|
+
...d.modified.map((f) => `${f} was edited`),
|
|
4686
|
+
...d.extra.map((f) => `${f} is not part of the asset`)
|
|
4687
|
+
];
|
|
4688
|
+
const reason = `is locked, but its deployed copy differs from the lock (${parts.join("; ")}) \u2014 run \`skaile install --locked\` to restore it`;
|
|
4689
|
+
gaps.push({ type: "modified", ref: d.ref, reason, message: `${d.ref} ${reason}` });
|
|
4690
|
+
named.add(gapIdentity(d.ref));
|
|
4691
|
+
}
|
|
4166
4692
|
gaps.push(...await this.declaredGaps(requirements, named));
|
|
4167
4693
|
for (const d of await this.incompleteDeploys()) {
|
|
4168
4694
|
const reason = `is deployed without ${d.missing.join(", ")} \u2014 run \`skaile install\` to restore it`;
|
|
4169
4695
|
gaps.push({ type: "incomplete", ref: d.ref, reason, message: `${d.ref} ${reason}` });
|
|
4170
4696
|
}
|
|
4697
|
+
const skipped = [];
|
|
4698
|
+
await buildProvenanceIndex(this.buildClones(this.loadConfig().repositories), {
|
|
4699
|
+
projectDir: this.projectDir,
|
|
4700
|
+
knownKinds: this.knownKinds,
|
|
4701
|
+
onSourceError: (clone, err) => skipped.push({
|
|
4702
|
+
url: clone.sourceUrl,
|
|
4703
|
+
why: err instanceof Error ? err.message : String(err)
|
|
4704
|
+
})
|
|
4705
|
+
});
|
|
4706
|
+
for (const s of skipped) {
|
|
4707
|
+
const reason = `is skipped: ${s.why.replace(`${s.url}: `, "")} \u2014 fix it or run \`skaile source remove\``;
|
|
4708
|
+
gaps.push({
|
|
4709
|
+
type: "source",
|
|
4710
|
+
ref: s.url,
|
|
4711
|
+
reason,
|
|
4712
|
+
message: `source ${s.url} ${reason}`,
|
|
4713
|
+
manualFix: true
|
|
4714
|
+
});
|
|
4715
|
+
}
|
|
4171
4716
|
for (const u of unboundAgentInstances(this.projectDir, this.driverTarget)) {
|
|
4172
|
-
const reason = u.ref.startsWith("agent:") ?
|
|
4717
|
+
const reason = u.ref.startsWith("agent:") ? await this.unboundAgentReason(u.id, u.ref) : `is bound by agent instance "${u.id}" but resolves to no agent.yaml \u2014 fix the path, or drop the binding from skaile.yaml`;
|
|
4173
4718
|
gaps.push({
|
|
4174
4719
|
type: "agent",
|
|
4175
4720
|
ref: u.ref,
|
|
@@ -4178,7 +4723,65 @@ var AssetManager = class {
|
|
|
4178
4723
|
manualFix: true
|
|
4179
4724
|
});
|
|
4180
4725
|
}
|
|
4181
|
-
return {
|
|
4726
|
+
return {
|
|
4727
|
+
gaps,
|
|
4728
|
+
requirements: requirements.filter(
|
|
4729
|
+
(i) => i.unresolved || !libraryHeld(`${i.depKind}:${i.depName}`)
|
|
4730
|
+
)
|
|
4731
|
+
};
|
|
4732
|
+
}
|
|
4733
|
+
/**
|
|
4734
|
+
* Why the `agent:` ref of agent instance `id` binds to nothing, as the phrase that follows
|
|
4735
|
+
* the ref in a {@link LockGap}; see {@link AssetManager.unboundAgentAdvice}.
|
|
4736
|
+
*/
|
|
4737
|
+
async unboundAgentReason(id, ref) {
|
|
4738
|
+
const { lead, advice } = await this.unboundAgentAdvice(ref);
|
|
4739
|
+
return `is bound by agent instance "${id}" but ${lead} \u2014 ${advice}`;
|
|
4740
|
+
}
|
|
4741
|
+
/**
|
|
4742
|
+
* What is wrong with an `agent:` ref bound by an agent instance and what to do (`lead`, then
|
|
4743
|
+
* `advice`). `skaile add` is named only when a registered library or source holds the agent
|
|
4744
|
+
* and `add` takes the ref (it needs a publisher); otherwise the user registers the library
|
|
4745
|
+
* that holds it, writes the publisher, or drops the binding.
|
|
4746
|
+
*/
|
|
4747
|
+
async unboundAgentAdvice(ref) {
|
|
4748
|
+
const drop = "or drop the binding from skaile.yaml";
|
|
4749
|
+
const parsedRef = parseRefTolerant(ref);
|
|
4750
|
+
const publisher = parsedRef?.publisher;
|
|
4751
|
+
const lockedAgent = Object.keys(this.tryReadLock()?.assets ?? {}).some((key) => {
|
|
4752
|
+
const k = parseCanonicalLockKey(key);
|
|
4753
|
+
return k.kind === "agent" && k.name === parsedRef?.name && (!publisher || !k.publisher || k.publisher === publisher);
|
|
4754
|
+
});
|
|
4755
|
+
if (lockedAgent) {
|
|
4756
|
+
return {
|
|
4757
|
+
lead: "the agent is locked but not restored here",
|
|
4758
|
+
advice: `run \`skaile install --locked\` first, ${drop}`
|
|
4759
|
+
};
|
|
4760
|
+
}
|
|
4761
|
+
if (publisher && await this.info(ref) !== null) {
|
|
4762
|
+
return {
|
|
4763
|
+
lead: "no agent was added for it",
|
|
4764
|
+
advice: `run \`skaile add ${ref}\` first, ${drop}`
|
|
4765
|
+
};
|
|
4766
|
+
}
|
|
4767
|
+
if (!publisher) {
|
|
4768
|
+
return {
|
|
4769
|
+
lead: "names no publisher",
|
|
4770
|
+
advice: `write it as agent:@<publisher>/<name> (\`skaile add\` needs the publisher), ${drop}`
|
|
4771
|
+
};
|
|
4772
|
+
}
|
|
4773
|
+
const fix = (await this.unresolvedFixes([ref])).get(ref);
|
|
4774
|
+
if (fix) {
|
|
4775
|
+
const register = fix.replace(/, or drop the dependency with `skaile remove [^`]*`$/, "");
|
|
4776
|
+
return {
|
|
4777
|
+
lead: "no agent was added for it, and `skaile add` cannot resolve it",
|
|
4778
|
+
advice: `${register}, ${drop}`
|
|
4779
|
+
};
|
|
4780
|
+
}
|
|
4781
|
+
return {
|
|
4782
|
+
lead: "no registered library or source holds it",
|
|
4783
|
+
advice: `register the library that holds it with \`skaile library init <name> --path <dir>\`, ${drop}`
|
|
4784
|
+
};
|
|
4182
4785
|
}
|
|
4183
4786
|
/** @deprecated Use `(await projectState()).gaps`; removed in the next major. */
|
|
4184
4787
|
async lockGaps() {
|
|
@@ -4201,6 +4804,52 @@ var AssetManager = class {
|
|
|
4201
4804
|
(g) => names(g.ref) || g.asset && names(g.asset)
|
|
4202
4805
|
);
|
|
4203
4806
|
}
|
|
4807
|
+
/**
|
|
4808
|
+
* The {@link ProjectState} gaps of everything `ref` requires, transitively: what `check`
|
|
4809
|
+
* says about the requirements of `ref`, so a command that answers for one asset (`diff`)
|
|
4810
|
+
* does not call it fine while a requirement of it is broken. The requirements are read from
|
|
4811
|
+
* the deployed copies (the lock records no edges), the way `remove` and `install` read them
|
|
4812
|
+
* when no library holds the asset any more. The gaps of `ref` itself are not included
|
|
4813
|
+
* ({@link gapsOf}).
|
|
4814
|
+
*
|
|
4815
|
+
* @param ref - Asset ref in `kind:name` or `kind:@publisher/name` form.
|
|
4816
|
+
*/
|
|
4817
|
+
async requirementGapsOf(ref) {
|
|
4818
|
+
const want = parseRefTolerant(ref);
|
|
4819
|
+
if (!want) return [];
|
|
4820
|
+
const gaps = (await this.projectState()).gaps;
|
|
4821
|
+
const lockedIds = Object.keys(this.tryReadLock()?.assets ?? {}).map(parseCanonicalLockKey);
|
|
4822
|
+
const idKey = (id) => `${id.publisher ?? ""}/${id.kind}:${id.name}`;
|
|
4823
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4824
|
+
const queue = [
|
|
4825
|
+
{
|
|
4826
|
+
kind: want.kind,
|
|
4827
|
+
name: want.name,
|
|
4828
|
+
publisher: want.publisher?.replace(/^@/, "") ?? lockedIds.find((l) => l.kind === want.kind && l.name === want.name)?.publisher
|
|
4829
|
+
}
|
|
4830
|
+
];
|
|
4831
|
+
seen.add(idKey(queue[0]));
|
|
4832
|
+
const out = [];
|
|
4833
|
+
for (const asset of queue) {
|
|
4834
|
+
for (const dep of await this.deployedRequirementsOf(asset)) {
|
|
4835
|
+
const id = memberIdentity(dep);
|
|
4836
|
+
if (!id) continue;
|
|
4837
|
+
const publisher = id.publisher ?? lockedIds.find((l) => l.kind === id.kind && l.name === id.name)?.publisher;
|
|
4838
|
+
const next = { kind: id.kind, name: id.name, publisher };
|
|
4839
|
+
if (seen.has(idKey(next))) continue;
|
|
4840
|
+
seen.add(idKey(next));
|
|
4841
|
+
queue.push(next);
|
|
4842
|
+
for (const g of gaps) {
|
|
4843
|
+
if (out.includes(g)) continue;
|
|
4844
|
+
const p = parseRefTolerant(g.ref);
|
|
4845
|
+
if (p !== null && p.kind === next.kind && p.name === next.name && (!publisher || !p.publisher || p.publisher.replace(/^@/, "") === publisher)) {
|
|
4846
|
+
out.push(g);
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4849
|
+
}
|
|
4850
|
+
}
|
|
4851
|
+
return out;
|
|
4852
|
+
}
|
|
4204
4853
|
/**
|
|
4205
4854
|
* Locked library assets whose library cannot supply them: the library is not registered
|
|
4206
4855
|
* (renamed or removed) or no longer holds the asset. Another library holding it makes the
|
|
@@ -4266,6 +4915,121 @@ var AssetManager = class {
|
|
|
4266
4915
|
}
|
|
4267
4916
|
return gaps;
|
|
4268
4917
|
}
|
|
4918
|
+
/**
|
|
4919
|
+
* Remove the files a deploy never writes (`.env`, `.venv/`, `.pytest_cache/`, ...) from the
|
|
4920
|
+
* deployed folders of re-locked assets, as {@link RestoredAsset} rows. The lock covers what
|
|
4921
|
+
* the exclusion list leaves; the extras an older release copied are the owner's to drop, and
|
|
4922
|
+
* this is the one point where they are: the lock was just rewritten.
|
|
4923
|
+
*
|
|
4924
|
+
* @param refs - Lock keys the install re-locked (hash or commit changed).
|
|
4925
|
+
*/
|
|
4926
|
+
removeExcludedLeftovers(refs) {
|
|
4927
|
+
const out = [];
|
|
4928
|
+
for (const key of refs) {
|
|
4929
|
+
const { kind, name } = parseCanonicalLockKey(key);
|
|
4930
|
+
const component = kind ? this.installTarget(kind) : void 0;
|
|
4931
|
+
if (!kind || !name || !component || component === "agent") continue;
|
|
4932
|
+
const dest = deployedDir(component, name, this.driverTarget, this.global, this.projectDir);
|
|
4933
|
+
const removed = removeExcludedLeftovers(dest);
|
|
4934
|
+
if (removed.length === 0) continue;
|
|
4935
|
+
const dir = relative(this.projectDir, dest).split(sep).join("/");
|
|
4936
|
+
out.push({ ref: key, restored: [], removed: removed.map((f) => `${dir}/${f}`) });
|
|
4937
|
+
}
|
|
4938
|
+
return out;
|
|
4939
|
+
}
|
|
4940
|
+
/**
|
|
4941
|
+
* The {@link RestoredAsset} rows for the drifted copies (see {@link lockedCopyDrift}) a
|
|
4942
|
+
* deploy just wrote again: those whose ref is among the `deployed` canonical refs.
|
|
4943
|
+
*/
|
|
4944
|
+
restoredCopies(drifts, deployed) {
|
|
4945
|
+
const rewritten = new Set(deployed.map((d) => d.split("#")[0]));
|
|
4946
|
+
const out = [];
|
|
4947
|
+
for (const d of drifts) {
|
|
4948
|
+
if (!rewritten.has(d.ref)) continue;
|
|
4949
|
+
const { kind, name } = parseCanonicalLockKey(d.key);
|
|
4950
|
+
const component = kind ? this.installTarget(kind) : void 0;
|
|
4951
|
+
if (!kind || !name || !component) continue;
|
|
4952
|
+
const dir = relative(
|
|
4953
|
+
this.projectDir,
|
|
4954
|
+
deployedDir(component, name, this.driverTarget, this.global, this.projectDir)
|
|
4955
|
+
).split(sep).join("/");
|
|
4956
|
+
out.push({
|
|
4957
|
+
ref: d.key,
|
|
4958
|
+
restored: d.modified.map((f) => `${dir}/${f}`),
|
|
4959
|
+
removed: d.extra.map((f) => `${dir}/${f}`)
|
|
4960
|
+
});
|
|
4961
|
+
}
|
|
4962
|
+
return out;
|
|
4963
|
+
}
|
|
4964
|
+
/**
|
|
4965
|
+
* Locked assets whose deployed copy differs from the bytes the lock covers: a file edited by
|
|
4966
|
+
* hand, or a file the asset does not ship. One row per asset, `ref` being `kind:@publisher/name`
|
|
4967
|
+
* and `key` its lock key. The one comparison behind the `modified` gap and the `Restored` lines
|
|
4968
|
+
* of `install`.
|
|
4969
|
+
*
|
|
4970
|
+
* - A library-origin asset is compared with its library's files, but only while those equal the
|
|
4971
|
+
* locked hash (changed library content is the `content` gap's business), both modified and
|
|
4972
|
+
* extra files.
|
|
4973
|
+
* - A source asset is compared with the per-file hashes the lock records (modified files only:
|
|
4974
|
+
* the lock lists what the source covers, not what the deploy copies).
|
|
4975
|
+
*
|
|
4976
|
+
* An agent (rendered, not copied), a `--link` deploy, an asset with a configured patch, and a
|
|
4977
|
+
* copy that is missing are not compared: other gaps cover them. Project mode only.
|
|
4978
|
+
*/
|
|
4979
|
+
async lockedCopyDrift() {
|
|
4980
|
+
if (this.global) return [];
|
|
4981
|
+
const lock = this.tryReadLock();
|
|
4982
|
+
if (!lock) return [];
|
|
4983
|
+
const { patches } = this.loadConfig();
|
|
4984
|
+
const out = [];
|
|
4985
|
+
const deployOpts = {
|
|
4986
|
+
registry: this.registry,
|
|
4987
|
+
driverTarget: this.driverTarget,
|
|
4988
|
+
global: this.global,
|
|
4989
|
+
cwd: this.projectDir
|
|
4990
|
+
};
|
|
4991
|
+
const refOf = (key) => {
|
|
4992
|
+
const { kind, publisher, name } = parseCanonicalLockKey(key);
|
|
4993
|
+
return publisher ? `${kind}:@${publisher}/${name}` : `${kind}:${name}`;
|
|
4994
|
+
};
|
|
4995
|
+
const keyOf = /* @__PURE__ */ new Map();
|
|
4996
|
+
for (const key of Object.keys(lock.assets)) keyOf.set(refOf(key), key);
|
|
4997
|
+
const { entries } = await this.restoreLibraryLockEntries(lock);
|
|
4998
|
+
for (const e of entries) {
|
|
4999
|
+
if (patches[`${e.kind}:${e.name}`]) continue;
|
|
5000
|
+
const drift = deployedAssetDrift(e, deployOpts);
|
|
5001
|
+
if (!drift || drift.modified.length === 0 && drift.extra.length === 0) continue;
|
|
5002
|
+
const ref = `${e.kind}:@${(e.publisher ?? "").replace(/^@/, "")}/${e.name}`;
|
|
5003
|
+
out.push({ ref, key: keyOf.get(ref) ?? ref, ...drift, library: true });
|
|
5004
|
+
}
|
|
5005
|
+
for (const [key, entry] of Object.entries(lock.assets)) {
|
|
5006
|
+
if (!entry.source || entry.files.length === 0) continue;
|
|
5007
|
+
const { kind, name } = parseCanonicalLockKey(key);
|
|
5008
|
+
const component = kind ? this.installTarget(kind) : void 0;
|
|
5009
|
+
if (!kind || !name || !component || component === "agent") continue;
|
|
5010
|
+
if (patches[`${kind}:${name}`]) continue;
|
|
5011
|
+
const dest = deployedDir(component, name, this.driverTarget, this.global, this.projectDir);
|
|
5012
|
+
try {
|
|
5013
|
+
const deployed = lstatSync(dest);
|
|
5014
|
+
if (deployed.isSymbolicLink() || !deployed.isDirectory()) continue;
|
|
5015
|
+
} catch {
|
|
5016
|
+
continue;
|
|
5017
|
+
}
|
|
5018
|
+
const modified = [];
|
|
5019
|
+
for (const f of lockedAssetFiles(kind, entry.files)) {
|
|
5020
|
+
const deployedFile = join(dest, f.rel);
|
|
5021
|
+
if (!existsSync(deployedFile)) continue;
|
|
5022
|
+
try {
|
|
5023
|
+
if (computeHash(deployedFile) !== f.sha256) modified.push(f.rel);
|
|
5024
|
+
} catch {
|
|
5025
|
+
modified.push(f.rel);
|
|
5026
|
+
}
|
|
5027
|
+
}
|
|
5028
|
+
if (modified.length > 0)
|
|
5029
|
+
out.push({ ref: refOf(key), key, modified, extra: [], library: false });
|
|
5030
|
+
}
|
|
5031
|
+
return out;
|
|
5032
|
+
}
|
|
4269
5033
|
/**
|
|
4270
5034
|
* Locked assets (declared or required by one) whose deployed copy is gone: `skaile install`
|
|
4271
5035
|
* restores them. Same deployability rule as {@link AssetManager.listDeclared}'s `drift`.
|
|
@@ -4336,7 +5100,7 @@ var AssetManager = class {
|
|
|
4336
5100
|
} else {
|
|
4337
5101
|
gap = {
|
|
4338
5102
|
type: "declared",
|
|
4339
|
-
reason:
|
|
5103
|
+
reason: declaredNoHolderReason(d.ref),
|
|
4340
5104
|
manualFix: true
|
|
4341
5105
|
};
|
|
4342
5106
|
}
|
|
@@ -4346,7 +5110,7 @@ var AssetManager = class {
|
|
|
4346
5110
|
if (this.presetRecorded(want) || await this.info(d.ref) !== null) continue;
|
|
4347
5111
|
gap = await this.declaredRefResolvable(d.ref) ? { type: "declared", reason: "is declared but not locked \u2014 run `skaile install`" } : {
|
|
4348
5112
|
type: "declared",
|
|
4349
|
-
reason:
|
|
5113
|
+
reason: declaredNoHolderReason(d.ref),
|
|
4350
5114
|
manualFix: true
|
|
4351
5115
|
};
|
|
4352
5116
|
gaps.push({ ...gap, ref: d.ref, message: `${d.ref} ${gap.reason}` });
|
|
@@ -4407,7 +5171,8 @@ var AssetManager = class {
|
|
|
4407
5171
|
const { repositories } = this.loadConfig();
|
|
4408
5172
|
const provenanceIndex = await buildProvenanceIndex(this.buildClones(repositories), {
|
|
4409
5173
|
projectDir: this.projectDir,
|
|
4410
|
-
knownKinds: this.knownKinds
|
|
5174
|
+
knownKinds: this.knownKinds,
|
|
5175
|
+
onSourceError: this.reportSourceError
|
|
4411
5176
|
});
|
|
4412
5177
|
const lockKeys = Object.keys(lock.assets).map(parseCanonicalLockKey);
|
|
4413
5178
|
const sourceCandidate = (ref) => {
|
|
@@ -4715,5 +5480,5 @@ var AssetManager = class {
|
|
|
4715
5480
|
};
|
|
4716
5481
|
|
|
4717
5482
|
export { AssetManager, FACTORY_SOURCE_URL, MissingManifestError, installAgentInstances, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, renderMcpServerConfig, softDepName };
|
|
4718
|
-
//# sourceMappingURL=chunk-
|
|
4719
|
-
//# sourceMappingURL=chunk-
|
|
5483
|
+
//# sourceMappingURL=chunk-TVAR4JHA.js.map
|
|
5484
|
+
//# sourceMappingURL=chunk-TVAR4JHA.js.map
|