@skaile/workspaces 5.10.0 → 5.11.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 +49 -0
- package/README.md +12 -0
- package/dist/{asset-feeds-ELEBTNUS.js → asset-feeds-CXGQIDFR.js} +18 -18
- package/dist/{asset-feeds-ELEBTNUS.js.map → asset-feeds-CXGQIDFR.js.map} +1 -1
- package/dist/asset-manager/catalog-deployer.js +7 -7
- package/dist/asset-manager/index.js +13 -13
- package/dist/asset-manager/installer.js +9 -9
- package/dist/asset-manager/renderers.js +8 -8
- package/dist/asset-manager/src/index.d.ts +103 -2
- package/dist/asset-manager/src/index.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 +23 -3
- package/dist/asset-manager/src/installer.d.ts.map +1 -1
- package/dist/bridge/drivers/claude-sdk.js +10 -10
- package/dist/bridge/drivers/codex.js +9 -9
- package/dist/bridge/drivers/continue.js +9 -9
- package/dist/bridge/drivers/echo.js +1 -1
- package/dist/bridge/drivers/gemini.js +6 -6
- package/dist/bridge/drivers/goose.js +9 -9
- package/dist/bridge/drivers/omp.js +18 -2
- package/dist/bridge/drivers/omp.js.map +1 -1
- package/dist/bridge/drivers/opencode.js +9 -9
- package/dist/bridge/drivers/qwen.js +6 -6
- package/dist/bridge/index.js +11 -11
- package/dist/bridge/src/drivers/omp.d.ts.map +1 -1
- package/dist/{chunk-3BEY4WK3.js → chunk-2F5AWQX5.js} +77 -11
- package/dist/chunk-2F5AWQX5.js.map +1 -0
- package/dist/{chunk-IJHH4DSW.js → chunk-3SM2DL2T.js} +8 -8
- package/dist/{chunk-IJHH4DSW.js.map → chunk-3SM2DL2T.js.map} +1 -1
- package/dist/{chunk-HJ5MCB3L.js → chunk-47U4GZ4M.js} +2 -2
- package/dist/{chunk-HJ5MCB3L.js.map → chunk-47U4GZ4M.js.map} +1 -1
- package/dist/{chunk-7CR6HT2X.js → chunk-4A4OD24G.js} +9 -9
- package/dist/{chunk-7CR6HT2X.js.map → chunk-4A4OD24G.js.map} +1 -1
- package/dist/{chunk-5QI2JYJC.js → chunk-6O2X3GPW.js} +2 -2
- package/dist/{chunk-5QI2JYJC.js.map → chunk-6O2X3GPW.js.map} +1 -1
- package/dist/{chunk-JZCSNEHK.js → chunk-ALEYHUC5.js} +42 -20
- package/dist/chunk-ALEYHUC5.js.map +1 -0
- package/dist/{chunk-4OV5DSBB.js → chunk-BNMZVPYA.js} +5 -5
- package/dist/chunk-BNMZVPYA.js.map +1 -0
- package/dist/{chunk-SBFW3CJH.js → chunk-CAHB6MHA.js} +5 -5
- package/dist/{chunk-SBFW3CJH.js.map → chunk-CAHB6MHA.js.map} +1 -1
- package/dist/{chunk-4P3KTUZH.js → chunk-CJERAGFY.js} +24 -13
- package/dist/chunk-CJERAGFY.js.map +1 -0
- package/dist/{chunk-MVQ3Q2HM.js → chunk-COH6FQAG.js} +4 -4
- package/dist/{chunk-MVQ3Q2HM.js.map → chunk-COH6FQAG.js.map} +1 -1
- package/dist/{chunk-ZGQTS3Y4.js → chunk-CPWLNZGJ.js} +3 -3
- package/dist/{chunk-ZGQTS3Y4.js.map → chunk-CPWLNZGJ.js.map} +1 -1
- package/dist/{chunk-MGGFBZWA.js → chunk-D3B36CYC.js} +4 -3
- package/dist/chunk-D3B36CYC.js.map +1 -0
- package/dist/{chunk-2JMLDZLP.js → chunk-DZMNFCWB.js} +416 -55
- package/dist/chunk-DZMNFCWB.js.map +1 -0
- package/dist/{chunk-GFCXNFTW.js → chunk-EDYHEMJA.js} +4 -4
- package/dist/{chunk-GFCXNFTW.js.map → chunk-EDYHEMJA.js.map} +1 -1
- package/dist/{chunk-PE36IF2D.js → chunk-FH7W6TJ4.js} +65 -31
- package/dist/chunk-FH7W6TJ4.js.map +1 -0
- package/dist/{chunk-G54USEUP.js → chunk-G4FFOV3N.js} +4 -4
- package/dist/{chunk-G54USEUP.js.map → chunk-G4FFOV3N.js.map} +1 -1
- package/dist/{chunk-HOHUEKES.js → chunk-GCHPUTA3.js} +3 -3
- package/dist/{chunk-HOHUEKES.js.map → chunk-GCHPUTA3.js.map} +1 -1
- package/dist/{chunk-TRSQP3JD.js → chunk-GV4DZ6MT.js} +20 -4
- package/dist/chunk-GV4DZ6MT.js.map +1 -0
- package/dist/{chunk-QG3HOJEK.js → chunk-HCEVNYSH.js} +3 -3
- package/dist/{chunk-QG3HOJEK.js.map → chunk-HCEVNYSH.js.map} +1 -1
- package/dist/{chunk-6HHE63CO.js → chunk-HZXUXHIV.js} +4 -4
- package/dist/{chunk-6HHE63CO.js.map → chunk-HZXUXHIV.js.map} +1 -1
- package/dist/{chunk-FRPBSUFH.js → chunk-IER3KIPH.js} +5 -5
- package/dist/{chunk-FRPBSUFH.js.map → chunk-IER3KIPH.js.map} +1 -1
- package/dist/{chunk-GEWAIQZ5.js → chunk-J4RBUFGM.js} +10 -12
- package/dist/chunk-J4RBUFGM.js.map +1 -0
- package/dist/{chunk-OOWHXOK6.js → chunk-M3B6EIJD.js} +4 -4
- package/dist/{chunk-OOWHXOK6.js.map → chunk-M3B6EIJD.js.map} +1 -1
- package/dist/{chunk-VLXDXRRX.js → chunk-MZG34MBZ.js} +3 -3
- package/dist/{chunk-VLXDXRRX.js.map → chunk-MZG34MBZ.js.map} +1 -1
- package/dist/{chunk-2FMEGSBN.js → chunk-PBBPZYVG.js} +31 -9
- package/dist/chunk-PBBPZYVG.js.map +1 -0
- package/dist/{chunk-CLTHEKHR.js → chunk-PQFHMQHQ.js} +4 -4
- package/dist/{chunk-CLTHEKHR.js.map → chunk-PQFHMQHQ.js.map} +1 -1
- package/dist/{chunk-SX5U422E.js → chunk-QVFAS5IO.js} +3 -3
- package/dist/{chunk-SX5U422E.js.map → chunk-QVFAS5IO.js.map} +1 -1
- package/dist/{chunk-JFXQEVLF.js → chunk-QZNJOHN6.js} +3 -3
- package/dist/{chunk-JFXQEVLF.js.map → chunk-QZNJOHN6.js.map} +1 -1
- package/dist/{chunk-V5TZH4GF.js → chunk-R7NHYEJF.js} +4 -4
- package/dist/{chunk-V5TZH4GF.js.map → chunk-R7NHYEJF.js.map} +1 -1
- package/dist/{chunk-V7PQZOBR.js → chunk-RYYLMBA2.js} +5 -5
- package/dist/{chunk-V7PQZOBR.js.map → chunk-RYYLMBA2.js.map} +1 -1
- package/dist/{chunk-WBYDAL6X.js → chunk-S3O3GKB7.js} +4 -4
- package/dist/{chunk-WBYDAL6X.js.map → chunk-S3O3GKB7.js.map} +1 -1
- package/dist/{chunk-Y34MSWEZ.js → chunk-SBSA3IQA.js} +3 -3
- package/dist/{chunk-Y34MSWEZ.js.map → chunk-SBSA3IQA.js.map} +1 -1
- package/dist/{chunk-Y63UQZ7P.js → chunk-T42WRQ4O.js} +3 -3
- package/dist/{chunk-Y63UQZ7P.js.map → chunk-T42WRQ4O.js.map} +1 -1
- package/dist/{chunk-OBVJ7RPW.js → chunk-T7CTHHG7.js} +3 -3
- package/dist/{chunk-OBVJ7RPW.js.map → chunk-T7CTHHG7.js.map} +1 -1
- package/dist/{chunk-7I5VRVDP.js → chunk-TCHRMVTO.js} +4 -4
- package/dist/{chunk-7I5VRVDP.js.map → chunk-TCHRMVTO.js.map} +1 -1
- package/dist/{chunk-NRDSGLCQ.js → chunk-VLTQGE2E.js} +65 -22
- package/dist/chunk-VLTQGE2E.js.map +1 -0
- package/dist/{chunk-Z2K6BGUR.js → chunk-WSBKB4CJ.js} +13 -13
- package/dist/{chunk-Z2K6BGUR.js.map → chunk-WSBKB4CJ.js.map} +1 -1
- package/dist/{chunk-3MKPZZRE.js → chunk-X77SUM4P.js} +3 -3
- package/dist/{chunk-3MKPZZRE.js.map → chunk-X77SUM4P.js.map} +1 -1
- package/dist/{chunk-XCNK4UE5.js → chunk-XDKH7XSA.js} +5 -5
- package/dist/{chunk-XCNK4UE5.js.map → chunk-XDKH7XSA.js.map} +1 -1
- package/dist/{chunk-TH4CTXHX.js → chunk-XUSALIEI.js} +6 -6
- package/dist/{chunk-TH4CTXHX.js.map → chunk-XUSALIEI.js.map} +1 -1
- package/dist/{chunk-3KHYGOEY.js → chunk-Y3HTGHJC.js} +3 -3
- package/dist/{chunk-3KHYGOEY.js.map → chunk-Y3HTGHJC.js.map} +1 -1
- package/dist/{chunk-YBQONMH2.js → chunk-YOH2L76X.js} +90 -50
- package/dist/chunk-YOH2L76X.js.map +1 -0
- package/dist/{chunk-32XKCNCL.js → chunk-ZCAJZ4B2.js} +3 -3
- package/dist/chunk-ZCAJZ4B2.js.map +1 -0
- package/dist/{chunk-IXWODEED.js → chunk-ZPWTOUTK.js} +43 -7
- package/dist/chunk-ZPWTOUTK.js.map +1 -0
- package/dist/cli/index.js +210 -163
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/catalog.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/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/outdated.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/run.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/helpers.d.ts +12 -0
- package/dist/cli/src/helpers.d.ts.map +1 -1
- package/dist/cli/src/skill-checks.d.ts +14 -6
- package/dist/cli/src/skill-checks.d.ts.map +1 -1
- package/dist/connectors/config.js +5 -5
- package/dist/connectors/index.js +15 -15
- package/dist/{connectors-OXP2JBGI.js → connectors-4QWAKPHB.js} +18 -18
- package/dist/{connectors-OXP2JBGI.js.map → connectors-4QWAKPHB.js.map} +1 -1
- package/dist/core/index.js +6 -6
- 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/lock.d.ts +4 -3
- package/dist/core/src/lock.d.ts.map +1 -1
- package/dist/core/src/models.d.ts +1 -1
- package/dist/core/src/models.d.ts.map +1 -1
- 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/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 +6 -6
- 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-2RONZKCU.js} +16 -16
- package/dist/{ensure-sources-5ISVIA4T.js.map → ensure-sources-2RONZKCU.js.map} +1 -1
- package/dist/factory-assets/connectors/box.js +15 -15
- package/dist/factory-assets/connectors/deploy.js +15 -15
- package/dist/factory-assets/connectors/devserver.js +15 -15
- package/dist/factory-assets/connectors/flow/adapter.js +15 -15
- 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 +8 -8
- package/dist/factory-assets/connectors/flow/run-flow.js +17 -17
- package/dist/factory-assets/connectors/flow.js +15 -15
- package/dist/factory-assets/connectors/git.js +15 -15
- package/dist/factory-assets/connectors/gmail.js +15 -15
- package/dist/factory-assets/connectors/googledrive.js +15 -15
- package/dist/factory-assets/connectors/local.js +15 -15
- package/dist/factory-assets/connectors/mattermost.js +15 -15
- package/dist/factory-assets/connectors/memory.js +15 -15
- package/dist/factory-assets/connectors/minio.js +15 -15
- package/dist/factory-assets/connectors/postgres.js +15 -15
- package/dist/factory-assets/connectors/s3.js +15 -15
- package/dist/factory-assets/connectors/sharepoint.js +15 -15
- package/dist/factory-assets/connectors/sqlite.js +15 -15
- package/dist/factory-assets/connectors/static-server.js +15 -15
- package/dist/factory-assets/connectors/tunnel.js +15 -15
- package/dist/factory-assets/connectors/webdav.js +15 -15
- package/dist/factory-assets/connectors/xstate-store.js +15 -15
- package/dist/factory-assets/connectors/xstate.js +15 -15
- package/dist/factory-assets/skills/authoring-skaile-manifests/references/dependency-standard.md +4 -2
- package/dist/{flows-HMSE76PO.js → flows-EQF2CH4U.js} +11 -11
- package/dist/{flows-HMSE76PO.js.map → flows-EQF2CH4U.js.map} +1 -1
- package/dist/{helpers-X6URBGSF.js → helpers-CFK6YP6R.js} +16 -16
- package/dist/{helpers-X6URBGSF.js.map → helpers-CFK6YP6R.js.map} +1 -1
- package/dist/library/index.js +10 -10
- package/dist/library/install.js +3 -3
- package/dist/library/src/index.d.ts +1 -1
- package/dist/library/src/index.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.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-53UTB3MB.js} +51 -24
- package/dist/library-publish-53UTB3MB.js.map +1 -0
- package/dist/open-library-BOSPJVID.js +40 -0
- package/dist/{open-library-4QSUORI6.js.map → open-library-BOSPJVID.js.map} +1 -1
- package/dist/open-registry-4FI7HKET.js +32 -0
- package/dist/{open-registry-VCKS3MP5.js.map → open-registry-4FI7HKET.js.map} +1 -1
- package/dist/{paths-BVO56A25.js → paths-SUS4S4YT.js} +9 -9
- package/dist/{paths-BVO56A25.js.map → paths-SUS4S4YT.js.map} +1 -1
- package/dist/{plugin-store-X7GPWGBG.js → plugin-store-AGQDMING.js} +8 -8
- package/dist/{plugin-store-X7GPWGBG.js.map → plugin-store-AGQDMING.js.map} +1 -1
- package/dist/{project-PAXP46RD.js → project-I55A4O2T.js} +20 -20
- package/dist/{project-PAXP46RD.js.map → project-I55A4O2T.js.map} +1 -1
- package/dist/resolver/index.js +7 -7
- package/dist/runner/index.js +28 -28
- 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 +13 -13
- package/dist/sdk/bridge.js +11 -11
- package/dist/sdk/core.js +6 -6
- package/dist/sdk/flow.js +8 -8
- package/dist/sdk/index.js +28 -28
- package/dist/sdk/resolver.js +7 -7
- package/dist/sdk/runner.js +28 -28
- package/dist/{setup-BV55VHWC.js → setup-7DQJKHUI.js} +21 -21
- package/dist/{setup-BV55VHWC.js.map → setup-7DQJKHUI.js.map} +1 -1
- package/dist/{skills-EDFUCJPX.js → skills-NUEN5NDX.js} +12 -12
- package/dist/{skills-EDFUCJPX.js.map → skills-NUEN5NDX.js.map} +1 -1
- package/dist/{source-E4VAT5RZ.js → source-G2LV5LVD.js} +21 -21
- package/dist/{source-E4VAT5RZ.js.map → source-G2LV5LVD.js.map} +1 -1
- package/dist/{source-manifest-publish-CLEE6TNH.js → source-manifest-publish-6RM7SWLZ.js} +23 -23
- package/dist/{source-manifest-publish-CLEE6TNH.js.map → source-manifest-publish-6RM7SWLZ.js.map} +1 -1
- package/dist/tui/index.js +59 -39
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/src/repl.d.ts.map +1 -1
- package/dist/types/manifests.js +1 -1
- package/dist/types/src/manifests/preset.d.ts +1 -1
- package/dist/workspace-plugin/adapters/mcp.js +22 -22
- package/dist/workspace-plugin/adapters/omp.js +14 -14
- package/dist/workspace-plugin/index.js +1 -1
- package/package.json +1 -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-GEWAIQZ5.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-PE36IF2D.js.map +0 -1
- package/dist/chunk-TRSQP3JD.js.map +0 -1
- package/dist/chunk-YBQONMH2.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
|
@@ -77,9 +77,9 @@ function entryToRaw(e) {
|
|
|
77
77
|
}
|
|
78
78
|
var SHA_RE = /^[0-9a-f]{40}$/i;
|
|
79
79
|
var SCOPED_REF_RE = /^(?:([a-z][a-z0-9-]*):)?@([A-Za-z0-9](?:[A-Za-z0-9]|-(?!-)){0,37}[A-Za-z0-9]|[A-Za-z0-9])\/([^/#\s]+)(?:#(.+))?$/;
|
|
80
|
-
var ASSET_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
80
|
+
var ASSET_NAME_RE = /^(?=.{1,64}$)[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
81
81
|
var SCOPE_PREFIX_RE = /^(?:[a-z][a-z0-9-]*:)?@[^/\s]+\/([^#]+?)(?:#.*)?$/;
|
|
82
|
-
var ASSET_NAME_HINT = 'names must be lowercase kebab-case (a-z, 0-9, single hyphens; e.g. "cli-concept")';
|
|
82
|
+
var ASSET_NAME_HINT = 'names must be lowercase kebab-case (a-z, 0-9, single hyphens; at most 64 characters; e.g. "cli-concept")';
|
|
83
83
|
function isValidAssetName(name) {
|
|
84
84
|
return ASSET_NAME_RE.test(name);
|
|
85
85
|
}
|
|
@@ -89,7 +89,7 @@ function isValidPublisher(publisher) {
|
|
|
89
89
|
return PUBLISHER_RE.test(publisher);
|
|
90
90
|
}
|
|
91
91
|
function slugifyAssetName(raw) {
|
|
92
|
-
const slug = raw.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
92
|
+
const slug = raw.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64).replace(/-+$/, "");
|
|
93
93
|
if (!slug) {
|
|
94
94
|
throw new Error(`cannot derive a canonical asset name from "${raw}" \u2014 ${ASSET_NAME_HINT}.`);
|
|
95
95
|
}
|
|
@@ -174,5 +174,5 @@ function repositoryToRaw(r) {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
export { ASSET_NAME_HINT, PUBLISHER_HINT, assetRefToDep, assetRefToStr, depToStr, entryFromRaw, entryToRaw, isValidAssetName, isValidPublisher, parseAssetRef, parseAssetRefLoose, parseDep, repositoryFromRaw, repositoryToRaw, slugifyAssetName };
|
|
177
|
-
//# sourceMappingURL=chunk-
|
|
178
|
-
//# sourceMappingURL=chunk-
|
|
177
|
+
//# sourceMappingURL=chunk-BNMZVPYA.js.map
|
|
178
|
+
//# sourceMappingURL=chunk-BNMZVPYA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../core/src/models.ts"],"names":[],"mappings":"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","file":"chunk-BNMZVPYA.js","sourcesContent":["/**\n * Pure data models — no I/O, no side effects.\n */\n\nimport semver from \"semver\";\n\n/**\n * Discriminator for catalog entries and asset references.\n * Used in asset ref strings (e.g. `'skill:my-skill'`, `'agent:my-agent'`).\n *\n * Any string: the provider registry (`@skaile/workspaces/discovery`\n * `AssetKindRegistry`) is the only authority on which kinds exist — a kind exists\n * iff a provider is registered for it.\n * @docLink packages/core/concepts#asset-kind\n */\nexport type AssetKind = string;\n\n// ── Dependency ────────────────────────────────────────────────────────────────\n\n/**\n * Declared dependency on another catalog asset.\n * @docLink packages/core/concepts#dependency\n */\nexport interface Dependency {\n /** Asset kind (e.g. \"skill\", \"agent\", \"contract\"). */\n kind: string;\n /** Asset name within that kind. */\n name: string;\n /** Canonical publisher namespace (when known). Absent: the declaring asset's own publisher. */\n publisher?: string;\n /** Version pin (`#<version>` or legacy `@<version>` suffix), when the declaration carried one. */\n pin?: string;\n}\n\n// `[kind:]@<publisher>/<name>[#<pin>]`, with the legacy npm-style `@<version>` suffix on the\n// name. Lenient on the name (the strict grammar runs later, at resolution).\nconst SCOPED_DEP_RE = /^(?:([a-z][a-z0-9-]*):)?@([^/\\s]+)\\/([^#\\s]+?)(?:#(.+))?$/;\n\n/**\n * Parse a dependency string: `\"kind:name\"`, a bare `\"name\"` (kind defaults to `\"skill\"`), or\n * a publisher-qualified `\"kind:@publisher/name[#pin]\"` / `\"@publisher/name[#pin]\"`. The\n * qualified forms fill `publisher` (and `pin`); the other forms leave it absent so the dep\n * resolves under the declaring asset's own publisher.\n *\n * @param s - Dependency string, e.g. `\"skill:use-exa\"`, `\"use-exa\"` or `\"skill:@acme/use-exa#^1.0.0\"`\n * @returns Parsed `{ kind, name, publisher?, pin? }` dependency object\n * @docLink packages/core/concepts#parse-dep\n */\nexport function parseDep(s: string): Dependency {\n const trimmed = s.trim();\n const scoped = SCOPED_DEP_RE.exec(trimmed);\n if (scoped) {\n let name = scoped[3];\n let pin = scoped[4]?.trim() || undefined;\n const at = name.indexOf(\"@\");\n if (at > 0) {\n pin ??= name.slice(at + 1) || undefined;\n name = name.slice(0, at);\n }\n const dep: Dependency = { kind: scoped[1] ?? \"skill\", name, publisher: scoped[2] };\n if (pin) dep.pin = pin;\n return dep;\n }\n const i = trimmed.indexOf(\":\");\n if (i !== -1) {\n const kind = trimmed.slice(0, i).trim();\n const name = trimmed.slice(i + 1).trim();\n return { kind, name };\n }\n return { kind: \"skill\", name: trimmed };\n}\n\n/**\n * Serialize a Dependency back to its string form: `\"kind:name\"`, or\n * `\"kind:@publisher/name[#pin]\"` when it names a publisher.\n *\n * @param d - Dependency to serialize\n * @returns String in `\"kind:name\"` / `\"kind:@publisher/name[#pin]\"` format\n * @docLink packages/core/concepts#dep-to-str\n */\nexport function depToStr(d: Dependency): string {\n const pin = d.pin ? `#${d.pin}` : \"\";\n return d.publisher ? `${d.kind}:@${d.publisher}/${d.name}${pin}` : `${d.kind}:${d.name}${pin}`;\n}\n\n// ── CatalogEntry ──────────────────────────────────────────────────────────────\n\n/**\n * A resolved catalog entry describing an installable asset.\n * Produced by manifest parsers and stored in the catalog YAML.\n * @docLink packages/core/concepts#catalog-entry\n */\nexport interface CatalogEntry {\n /** Unique asset name within its kind. */\n name: string;\n /** Asset kind discriminator. */\n kind: AssetKind;\n /** Short description of what this asset does. */\n description: string;\n /** Absolute path to manifest file */\n source: string;\n /** Canonical publisher namespace this asset belongs to (formerly `repository`). */\n publisher?: string;\n /**\n * Canonical ref (`kind:@publisher/name#version`) the CLI prints for this entry.\n * Set by the asset manager where `publisher` is not the real publisher (a\n * clone-sourced entry carries its clone key there); absent → derived from\n * `publisher` + `version`.\n */\n canonicalRef?: string;\n /**\n * `\"<org>/<repo>\"` coordinate the asset came from. Absent → the asset groups\n * directly under its publisher (local library with no git remote, or a\n * non-GitHub source).\n */\n repo?: string;\n /**\n * Claude plugin (from `.claude-plugin/marketplace.json` / `plugin.json`\n * membership) this asset belongs to, or absent when no plugin lists it.\n * Display-only — groups assets in the manage TUI; never part of identity or\n * the install layout.\n */\n plugin?: string;\n /** Semantic version string (may be empty if not declared in the manifest). */\n version: string;\n /** Skills, agents, or other assets this entry depends on. */\n requires: Dependency[];\n /** Asset refs this entry pulls in (presets: the asset items; flows: `requires`). */\n dependencies: string[];\n /** Presets only: instance items (`library://`, placeholder, connector/mcp) a dependency expansion skips; absent when none. */\n skippedItems?: number;\n /**\n * Kind-specific metadata extracted from the manifest frontmatter.\n * Used by MCP servers to carry default config (transport, command, args, env, url, headers)\n * so that `mcp:name` dependency refs resolve to a runnable declaration without\n * requiring verbose inline config in `skaile.yaml`.\n */\n metadata?: Record<string, unknown>;\n /** Curated facet, surfaced as a badge in the manage TUI (not a tree axis). */\n category?: string;\n /** Store-listing keywords (manifest `assets[].keywords`, else frontmatter). */\n keywords?: string[];\n /** Store-listing license (manifest `assets[].license`, else repo-level default). */\n license?: string;\n /** Store-listing homepage (manifest `assets[].homepage`, else repo-level default). */\n homepage?: string;\n}\n\n/**\n * Construct a CatalogEntry from a raw deserialized record (e.g. from catalog.yaml).\n *\n * @param d - Raw object with loosely typed fields\n * @returns Normalized CatalogEntry\n * @docLink packages/core/concepts#entry-from-raw\n */\nexport function entryFromRaw(d: Record<string, unknown>): CatalogEntry {\n const rawDeps = d.dependencies;\n const deps = Array.isArray(rawDeps) ? (rawDeps as string[]).filter(Boolean) : [];\n const entry: CatalogEntry = {\n name: String(d.name ?? \"\"),\n kind: String(d.kind ?? \"skill\") as AssetKind,\n description: String(d.description ?? \"\"),\n source: String(d.source ?? \"\"),\n publisher: d.publisher != null ? String(d.publisher) : undefined,\n repo: d.repo != null ? String(d.repo) : undefined,\n plugin: d.plugin != null ? String(d.plugin) : undefined,\n version: String(d.version ?? \"\"),\n requires: Array.isArray(d.requires)\n ? (d.requires as string[]).filter(Boolean).map(parseDep)\n : [],\n dependencies: deps,\n };\n if (d.metadata != null && typeof d.metadata === \"object\" && !Array.isArray(d.metadata)) {\n entry.metadata = d.metadata as Record<string, unknown>;\n }\n if (d.category != null) entry.category = String(d.category);\n if (Array.isArray(d.keywords)) {\n entry.keywords = (d.keywords as unknown[]).filter((k): k is string => typeof k === \"string\");\n }\n if (d.license != null) entry.license = String(d.license);\n if (d.homepage != null) entry.homepage = String(d.homepage);\n return entry;\n}\n\n/**\n * Serialize a CatalogEntry to a plain record suitable for YAML/JSON persistence.\n *\n * @param e - CatalogEntry to serialize\n * @returns Plain object with string-serialized requires and dependencies\n * @docLink packages/core/concepts#entry-to-raw\n */\nexport function entryToRaw(e: CatalogEntry): Record<string, unknown> {\n const raw: Record<string, unknown> = {\n name: e.name,\n kind: e.kind,\n description: e.description,\n source: e.source,\n publisher: e.publisher,\n repo: e.repo,\n version: e.version,\n ...(e.plugin != null ? { plugin: e.plugin } : {}),\n requires: e.requires.map(depToStr),\n dependencies: e.dependencies,\n };\n if (e.metadata) raw.metadata = e.metadata;\n if (e.category != null) raw.category = e.category;\n if (e.keywords && e.keywords.length > 0) raw.keywords = e.keywords;\n if (e.license != null) raw.license = e.license;\n if (e.homepage != null) raw.homepage = e.homepage;\n return raw;\n}\n\n// ── AssetRef ─────────────────────────────────────────────────────────────────\n\n/**\n * A parsed asset reference: `kind:@<publisher>/name[#pin]`.\n *\n * `publisher` is the canonical, GitHub-shaped publisher namespace (≤39 chars,\n * alphanumeric+hyphen). `pin` is a SemVer constraint, exact SHA, or absent.\n * Floating refs (`main`, `latest`, `HEAD`) are rejected at parse time.\n *\n * Produced by `parseAssetRef`; consumed by `resolveAsset` and `resolveAll`.\n * @docLink packages/core/concepts#asset-ref\n */\nexport interface AssetRef {\n kind: string;\n name: string;\n /** Canonical publisher namespace. Optional only for ambiguity-resolution\n * during migration; new manifests require it. */\n publisher?: string;\n /** SemVer constraint (^1.4.0, ~1.4, 1.x, exact 1.4.0), 40-char SHA, or undefined. */\n pin?: string;\n}\n\nconst SHA_RE = /^[0-9a-f]{40}$/i;\n\n// Scoped grammar: `kind:@publisher/name[#version]`. The publisher sub-pattern is\n// GitHub-shaped (1-39 chars, alphanumeric + single hyphens, no leading/trailing or\n// double hyphen); `@` is the scope sigil and `#` the version sigil. `name` is\n// intentionally permissive (`[^/#\\s]+` — only the structural separators are\n// forbidden); floating-ref rejection stays in `isValidPin`, so `#main`/`#latest`\n// match here and fail there with a clear message.\nconst SCOPED_REF_RE =\n /^(?:([a-z][a-z0-9-]*):)?@([A-Za-z0-9](?:[A-Za-z0-9]|-(?!-)){0,37}[A-Za-z0-9]|[A-Za-z0-9])\\/([^/#\\s]+)(?:#(.+))?$/;\n\n// Canonical asset-name grammar: lowercase kebab-case (npm-style, scope-free) —\n// `a-z` / `0-9` segments joined by single hyphens, 1-64 characters, no leading/trailing hyphen,\n// no uppercase, spaces, dots, or underscores. Names become directory names,\n// lock keys, and CLI args, so the constraint is intentionally narrow.\nconst ASSET_NAME_RE = /^(?=.{1,64}$)[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\n// Diagnostic-only matcher: a ref carrying a `kind:@publisher/` scope prefix,\n// capturing whatever follows (sans `#pin`) as the candidate name. Used solely\n// to tell \"missing publisher\" apart from \"malformed name\" when the strict\n// grammar above fails (e.g. a space in the name).\nconst SCOPE_PREFIX_RE = /^(?:[a-z][a-z0-9-]*:)?@[^/\\s]+\\/([^#]+?)(?:#.*)?$/;\n\n/** Human-readable statement of the canonical asset-name rule. */\nexport const ASSET_NAME_HINT =\n 'names must be lowercase kebab-case (a-z, 0-9, single hyphens; at most 64 characters; e.g. \"cli-concept\")';\n\n/**\n * True when `name` is a canonical asset name: lowercase kebab-case, scope-free.\n *\n * This is the single source of truth for asset-name validity — `parseAssetRef`\n * enforces it, and `skaile validate` reports violations across a repo tree.\n * @docLink packages/core/concepts#is-valid-asset-name\n */\nexport function isValidAssetName(name: string): boolean {\n return ASSET_NAME_RE.test(name);\n}\n\n// The one publisher slug: 1-39 chars, lowercase letters and digits, single `-`\n// inside, no leading/trailing hyphen. The lowercase form of the publisher grammar of\n// `SCOPED_REF_RE`, so every publisher accepted here also parses in a\n// `kind:@<publisher>/name` ref.\nconst PUBLISHER_RE = /^[a-z0-9](?:[a-z0-9]|-(?!-)){0,37}[a-z0-9]$|^[a-z0-9]$/;\n\n/** Human-readable statement of the publisher rule, shared by every command that checks one. */\nexport const PUBLISHER_HINT =\n 'publishers must be a bare name of 1-39 characters: lowercase letters, digits and single hyphens inside (like \"acme\" or \"my-lib\"), with no @, /, #, dots, underscores or spaces and no leading or trailing hyphen';\n\n/**\n * True when `publisher` is a valid bare publisher slug (see {@link PUBLISHER_HINT}).\n * The one rule behind `library create --publisher`, `library set <lib> publisher=`,\n * `asset import --publisher`, `library index`, `validate` and the publish plan; the\n * caller strips a leading `@` first.\n */\nexport function isValidPublisher(publisher: string): boolean {\n return PUBLISHER_RE.test(publisher);\n}\n\n/**\n * Coerce an arbitrary string into a canonical asset name (lowercase kebab-case).\n *\n * For **third-party sources we don't control**, an upstream asset may carry a\n * human-styled identity (`\"Complex App\"`, `\"CLI_Concept\"`). The canonical grammar\n * (`isValidAssetName`) rejects those, so the ingestion boundary slugifies them to\n * a valid identity rather than crashing: Unicode is folded to ASCII, the result is\n * lowercased, every run of non-`[a-z0-9]` becomes a single hyphen, and\n * leading/trailing hyphens are trimmed. The transform is idempotent and a no-op on\n * already-canonical names.\n *\n * This is intentionally **lossy** — the pretty original is not part of identity.\n * Callers that want to preserve it for display must stash it themselves (e.g. on\n * `CatalogEntry.metadata.displayName`). Authoring-time validation (`skaile validate`)\n * still uses `isValidAssetName` on raw frontmatter, so first-party typos surface there.\n *\n * @throws When `raw` contains no `[a-z0-9]` character (nothing to slugify).\n * @docLink packages/core/concepts#slugify-asset-name\n */\nexport function slugifyAssetName(raw: string): string {\n const slug = raw\n .normalize(\"NFKD\")\n .replace(/[\\u0300-\\u036f]/g, \"\") // strip combining accents\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64)\n .replace(/-+$/, \"\");\n if (!slug) {\n throw new Error(`cannot derive a canonical asset name from \"${raw}\" — ${ASSET_NAME_HINT}.`);\n }\n return slug;\n}\n\n/** True when `pin` is a SemVer constraint, exact SemVer, or 40-char SHA. */\nfunction isValidPin(pin: string): boolean {\n if (SHA_RE.test(pin)) return true;\n if (semver.valid(pin)) return true;\n if (semver.validRange(pin)) return true;\n return false;\n}\n\n/** Throw the canonical non-canonical-pin error for a ref `s` carrying `pin`. */\nfunction rejectFloatingPin(s: string, pin: string): never {\n throw new Error(\n `non-canonical pin \"${pin}\" in \"${s}\" — pin must be a SemVer ` +\n \"constraint (1.4.0, ^1.4, ~1.4, 1.x), a 40-char SHA, or absent. \" +\n \"Floating refs (main/latest/HEAD) are not allowed.\",\n );\n}\n\n/** Throw the canonical malformed-name error for a ref `s` carrying `name`. */\nfunction rejectInvalidName(s: string, name: string): never {\n throw new Error(\n `invalid asset name \"${name}\" in ref \"${s}\" — ${ASSET_NAME_HINT}. ` +\n \"Run the `migrate-skaile-manifest` skill on legacy manifests.\",\n );\n}\n\n/**\n * Parse a canonical asset reference string into an `AssetRef` object.\n *\n * Grammar: `kind:@<publisher>/name[#version]`\n * \"skill:@skaile-ai/audit\" → { kind: \"skill\", name: \"audit\", publisher: \"skaile-ai\" }\n * \"skill:@skaile-ai/audit#^1.4.0\" → { …, pin: \"^1.4.0\" }\n * \"skill:@skaile-ai/audit#<40-sha>\" → { …, pin: \"<40-sha>\" }\n *\n * `@` is the scope sigil and `#` the version sigil. `<publisher>` is GitHub-shaped\n * (≤39 chars, alphanumeric+hyphen, no leading/trailing or double hyphen). `pin`\n * accepts a SemVer constraint (`^`, `~`, `x`, exact), a 40-char SHA, or is absent.\n * Floating refs (`main`/`latest`/`HEAD`/anything non-canonical) are parse-time errors.\n *\n * The shorthand `mcp:` is normalized to `mcp-server:`. `kind` defaults to `\"skill\"`.\n *\n * @param s - Asset reference string\n * @returns Parsed `AssetRef`\n * @throws When the ref matches no grammar, the publisher is malformed, or the pin\n * is a floating ref.\n * @docLink packages/core/concepts#parse-asset-ref\n */\nexport function parseAssetRef(s: string): AssetRef {\n const trimmed = s.trim();\n const m = SCOPED_REF_RE.exec(trimmed);\n if (m) {\n const kindRaw = m[1] ?? \"skill\";\n const kind = kindRaw === \"mcp\" ? \"mcp-server\" : kindRaw;\n const publisher = m[2];\n const name = m[3];\n const pin = m[4]?.trim() || undefined;\n if (!isValidAssetName(name)) rejectInvalidName(s, name);\n if (pin !== undefined && !isValidPin(pin)) rejectFloatingPin(s, pin);\n return { kind, name, publisher, pin };\n }\n\n // The strict grammar failed. If the ref nonetheless carries a `@publisher/`\n // scope and the fault is the name (e.g. an embedded space), surface a\n // name-specific error rather than the misleading \"publisher required\" — the\n // publisher is plainly present. A *valid* captured name means the publisher\n // itself is malformed, so fall through to the publisher error below.\n const scoped = SCOPE_PREFIX_RE.exec(trimmed);\n if (scoped) {\n const candidate = scoped[1].trim();\n if (!isValidAssetName(candidate)) rejectInvalidName(s, candidate);\n }\n\n throw new Error(\n `publisher required in asset ref \"${s}\" — use \\`kind:@<publisher>/name\\`. ` +\n \"Run the `migrate-skaile-manifest` skill on legacy manifests.\",\n );\n}\n\n/**\n * Parse a ref for identity matching, tolerating a non-canonical pin. A lock key\n * can pin a content-sha pseudo-version (`#0.0.0-sha.<hash>`) that\n * {@link parseAssetRef} rejects; matchers only need the version-agnostic\n * `kind/publisher/name`, so drop the pin and retry before giving up.\n *\n * @returns The parsed ref (its `pin` empty when the pin was dropped), or `null`.\n */\nexport function parseAssetRefLoose(ref: string): AssetRef | null {\n try {\n return parseAssetRef(ref);\n } catch {\n const hash = ref.indexOf(\"#\");\n if (hash < 0) return null;\n try {\n return parseAssetRef(ref.slice(0, hash));\n } catch {\n return null;\n }\n }\n}\n\n/**\n * Serialize an AssetRef back to its canonical string form.\n *\n * Emits the scope form `kind:@publisher/name[#pin]` when `publisher` is present,\n * and the bare `kind:name[#pin]` form for transitive refs that inherit it.\n *\n * @param ref - AssetRef to serialize\n * @returns String in `\"kind:@publisher/name[#pin]\"` (or bare `\"kind:name[#pin]\"`) format\n * @docLink packages/core/concepts#asset-ref-to-str\n */\nexport function assetRefToStr(ref: AssetRef): string {\n const scope = ref.publisher ? `@${ref.publisher}/${ref.name}` : ref.name;\n return `${ref.kind}:${scope}${ref.pin ? `#${ref.pin}` : \"\"}`;\n}\n\n/**\n * Convert an AssetRef to a simple Dependency, dropping the repository and pin qualifiers.\n *\n * @param ref - Full asset reference (may include repository and pin)\n * @returns Dependency with only kind and name\n * @docLink packages/core/concepts#asset-ref-to-dep\n */\nexport function assetRefToDep(ref: AssetRef): Dependency {\n // Grammar-agnostic — drops publisher/pin, so the scope-sigil change doesn't touch it.\n return { kind: ref.kind, name: ref.name };\n}\n\n// ── Lock File ────────────────────────────────────────────────────────────────\n\n/** A path/sha256 pair recorded for one file inside a locked asset. */\nexport interface LockFileEntry {\n path: string;\n sha256: string;\n}\n\n/**\n * Library-origin marker on a {@link LockEntry}: the asset was resolved from a\n * registered library (a local authoring place) rather than a git source/store.\n */\nexport interface LockLibraryOrigin {\n /** Name of the library the asset was resolved from. */\n name: string;\n /** Library version of the asset at lock time. */\n version: string;\n /** Content hash recorded in the library index at lock time; absent when the library was never indexed. */\n sha256?: string;\n /**\n * Remote URL of the library at lock time, recorded for a git-backed library only. The name is\n * machine-local; when it is not registered on another machine, `install --locked` and `check`\n * match a registered library by this URL instead. Optional: locks without it resolve by name\n * as before.\n */\n url?: string;\n /**\n * Set by `skaile asset install`: the files were copied or linked straight into\n * the project, not deployed from a `skaile.yaml` dependency. `skaile install`\n * leaves such an entry and its files alone instead of reconciling them away.\n */\n installed?: \"copy\" | \"link\";\n}\n\n/**\n * Per-asset entry in the lock file (v3 schema).\n * Keyed in `LockFile.assets` by canonical ref (`<kind>:@<publisher>/<name>#<version>`).\n * Source-origin entries carry `source` + `files`; library-origin entries carry\n * `library` instead (no `source`, empty `files`). Both fields are additive, so\n * lock files written before library origin existed still load unchanged.\n * @docLink packages/core/api-reference#lock-entry\n */\nexport interface LockEntry {\n /** Composite sha256 over sorted `<path>:<sha256>\\n` rows (library-origin: the library's hash, `\"\"` when unknown). */\n sha256: string;\n /** Resolved upstream source + commit. Absent for library-origin entries. */\n source?: { url: string; commit: string };\n /** Files that constitute the asset. Empty for library-origin entries. */\n files: LockFileEntry[];\n /** True when an `overrides[]` entry pinned this resolution. */\n override_applied: boolean;\n /** Set when the asset was resolved from a registered library. */\n library?: LockLibraryOrigin;\n}\n\n/** Per-source-URL entry in `LockFile.sources`. */\nexport interface LockSourceEntry {\n url: string;\n commit: string;\n}\n\n/**\n * Full skaile.lock.yaml structure (v3 schema).\n * @docLink packages/core/api-reference#lock-file\n */\nexport interface LockFile {\n /**\n * Lock file schema version: 3, or 4 when the lock holds a library-origin\n * entry (no `source`), so CLIs that predate library origin reject it cleanly.\n */\n schema_version: 3 | 4;\n /** ISO timestamp of when the lock was generated. */\n locked_at: string;\n /** Resolved assets keyed by canonical ref `<kind>:@<publisher>/<name>#<version>`. */\n assets: Record<string, LockEntry>;\n /** Every source URL that contributed at least one resolved asset. */\n sources: LockSourceEntry[];\n /**\n * Resolved plugin packages (from `skaile.yaml` `plugins:`), keyed by package\n * name. The plugin-store reconciler reads this slice into its reconcile-hash\n * so a lock change reinstalls even when the manifest list is unchanged.\n */\n plugins?: Record<string, LockPluginEntry>;\n /**\n * Canonical refs of the `preset:` dependencies that `install` / `add` expanded into the\n * assets above (`preset:@publisher/name#version`, nested presets included). A preset is\n * never locked as an asset, so this is the only offline trace that a declared preset\n * resolved: `check` reports a declared preset that is neither listed here nor held by a\n * local library or source. Absent when no preset was expanded.\n */\n presets?: string[];\n}\n\n/** One pinned plugin package in the lock file's `plugins` slice. */\nexport interface LockPluginEntry {\n /** Resolved exact version (e.g. \"0.1.3\"). */\n version: string;\n /** Package integrity hash (e.g. \"sha512-...\"); may be empty until populated from bun's output. */\n integrity: string;\n}\n\n// ── Repository ───────────────────────────────────────────────────────────────\n\ntype RepositoryKind = \"local\" | \"github\";\n\n/**\n * A registered asset repository (local path or cloned GitHub repo).\n * Stored in the catalog; consumed by `repo-manager` for cloning and scanning.\n * @docLink packages/core/concepts#repository\n */\nexport interface Repository {\n /** Logical repository name. */\n name: string;\n /** Storage kind: \"local\" for paths, \"github\" for remote URLs. */\n kind: RepositoryKind;\n /** Absolute path (local) or remote URL (github). */\n path: string;\n /** Active branch. */\n branch: string;\n /** Upstream fork URL (for fork-based workflows). */\n upstream?: string;\n}\n\n/**\n * Construct a `Repository` from a raw deserialized record.\n *\n * @param d - Raw object from YAML/JSON\n * @returns Normalized `Repository`\n * @docLink packages/core/concepts#repository-from-raw\n */\nexport function repositoryFromRaw(d: Record<string, unknown>): Repository {\n return {\n name: String(d.name ?? \"\"),\n kind: String(d.kind ?? \"local\") as RepositoryKind,\n path: String(d.path ?? \"\"),\n branch: String(d.branch ?? \"main\"),\n upstream: d.upstream != null ? String(d.upstream) : undefined,\n };\n}\n\n/**\n * Serialize a `Repository` to a plain record for YAML/JSON persistence.\n * Omits the `branch` field when it equals `\"main\"` to keep serialized output clean.\n *\n * @param r - Repository to serialize\n * @returns Plain object suitable for YAML/JSON\n * @docLink packages/core/concepts#repository-to-raw\n */\nexport function repositoryToRaw(r: Repository): Record<string, unknown> {\n const d: Record<string, unknown> = {\n name: r.name,\n kind: r.kind,\n path: r.path,\n };\n if (r.branch !== \"main\") d.branch = r.branch;\n if (r.upstream != null) d.upstream = r.upstream;\n return d;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { flowKindProvider } from './chunk-
|
|
2
|
-
import { knowledgeKindProvider } from './chunk-
|
|
3
|
-
import { createDefaultKindRegistry } from './chunk-
|
|
1
|
+
import { flowKindProvider } from './chunk-TCHRMVTO.js';
|
|
2
|
+
import { knowledgeKindProvider } from './chunk-2F5AWQX5.js';
|
|
3
|
+
import { createDefaultKindRegistry } from './chunk-J4RBUFGM.js';
|
|
4
4
|
|
|
5
5
|
// cli/src/open-registry.ts
|
|
6
6
|
var registry;
|
|
@@ -13,5 +13,5 @@ function getKnownKinds() {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export { getKindRegistry, getKnownKinds };
|
|
16
|
-
//# sourceMappingURL=chunk-
|
|
17
|
-
//# sourceMappingURL=chunk-
|
|
16
|
+
//# sourceMappingURL=chunk-CAHB6MHA.js.map
|
|
17
|
+
//# sourceMappingURL=chunk-CAHB6MHA.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../cli/src/open-registry.ts"],"names":[],"mappings":";;;;;AAgBA,IAAI,QAAA;AAQG,SAAS,eAAA,GAAqC;AACnD,EAAA,QAAA,KAAa,yBAAA,CAA0B,CAAC,gBAAA,EAAkB,qBAAqB,CAAC,CAAA;AAChF,EAAA,OAAO,QAAA;AACT;AAGO,SAAS,aAAA,GAAqC;AACnD,EAAA,OAAO,IAAI,GAAA,CAAI,eAAA,EAAgB,CAAE,aAAa,CAAA;AAChD","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../cli/src/open-registry.ts"],"names":[],"mappings":";;;;;AAgBA,IAAI,QAAA;AAQG,SAAS,eAAA,GAAqC;AACnD,EAAA,QAAA,KAAa,yBAAA,CAA0B,CAAC,gBAAA,EAAkB,qBAAqB,CAAC,CAAA;AAChF,EAAA,OAAO,QAAA;AACT;AAGO,SAAS,aAAA,GAAqC;AACnD,EAAA,OAAO,IAAI,GAAA,CAAI,eAAA,EAAgB,CAAE,aAAa,CAAA;AAChD","file":"chunk-CAHB6MHA.js","sourcesContent":["/**\n * open-registry.ts — the CLI's one AssetKindRegistry.\n *\n * The provider registry is the only authority on asset kinds. The CLI builds it\n * once per process with all built-in providers (from @skaile/workspaces/discovery)\n * plus the extension kinds (flow from\n * @skaile/workspaces/factory-assets/connectors/flow/engine, knowledge from\n * @skaile/workspaces/library) and hands the same instance to every consumer\n * (catalog sources, the installer, validation, composition).\n */\n\nimport type { AssetKindRegistry } from \"@skaile/workspaces/discovery\";\nimport { createDefaultKindRegistry } from \"@skaile/workspaces/discovery\";\nimport { flowKindProvider } from \"@skaile/workspaces/factory-assets/connectors/flow/engine\";\nimport { knowledgeKindProvider } from \"@skaile/workspaces/library\";\n\nlet registry: AssetKindRegistry | undefined;\n\n/**\n * The process-wide, fully-configured AssetKindRegistry.\n *\n * Registers every built-in kind plus flow and knowledge. Built lazily on first\n * call; every later call returns the same instance.\n */\nexport function getKindRegistry(): AssetKindRegistry {\n registry ??= createDefaultKindRegistry([flowKindProvider, knowledgeKindProvider]);\n return registry;\n}\n\n/** Registered kind names as a set — the `knownKinds` argument of the manifest scanners. */\nexport function getKnownKinds(): ReadonlySet<string> {\n return new Set(getKindRegistry().getAllKinds());\n}\n"]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createSpinner } from './chunk-NESV47MF.js';
|
|
2
|
-
import { logInfo, logWarn, TARGET_DEFAULT_HINT, logErr, logOk, colorRef, S, warnLegacyClaudeCopies, formatSoftDepHint } from './chunk-
|
|
3
|
-
import { getKindRegistry } from './chunk-
|
|
4
|
-
import { AssetManager } from './chunk-
|
|
5
|
-
import { readLock } from './chunk-
|
|
6
|
-
import { SourceEntryError } from './chunk-
|
|
2
|
+
import { logInfo, logWarn, TARGET_DEFAULT_HINT, logErr, logOk, colorRef, S, requireProjectConfig, warnLegacyClaudeCopies, formatSoftDepHint } from './chunk-GV4DZ6MT.js';
|
|
3
|
+
import { getKindRegistry } from './chunk-CAHB6MHA.js';
|
|
4
|
+
import { AssetManager } from './chunk-DZMNFCWB.js';
|
|
5
|
+
import { readLock } from './chunk-PBBPZYVG.js';
|
|
6
|
+
import { SourceEntryError } from './chunk-ALEYHUC5.js';
|
|
7
7
|
import { userConfigPath } from './chunk-L5VSIPQD.js';
|
|
8
8
|
import { SUPPORTED_DRIVER_TARGETS } from './chunk-CPSIPIX7.js';
|
|
9
|
-
import { parseAssetRef } from './chunk-
|
|
9
|
+
import { parseAssetRef } from './chunk-BNMZVPYA.js';
|
|
10
10
|
import path from 'path';
|
|
11
11
|
import * as p from '@clack/prompts';
|
|
12
12
|
import { Command } from 'commander';
|
|
@@ -62,6 +62,9 @@ function reportAgentInstances(instances, removedFiles, onLine = logInfo, onRemov
|
|
|
62
62
|
function reportRelocked(relocked, onLine = logInfo) {
|
|
63
63
|
for (const ref of relocked ?? []) onLine(`Re-locked ${ref}`);
|
|
64
64
|
}
|
|
65
|
+
function reportMoved(moved, onLine = logWarn) {
|
|
66
|
+
for (const m of moved ?? []) onLine(`${m.ref} moved from ${m.from} to ${m.to}`);
|
|
67
|
+
}
|
|
65
68
|
function reportReplaced(replaced, onLine = logInfo) {
|
|
66
69
|
for (const r of replaced ?? []) onLine(`${r.ref} replaced ${r.from} \u2192 ${r.to}`);
|
|
67
70
|
}
|
|
@@ -105,7 +108,7 @@ async function runRefInstall(ref, opts) {
|
|
|
105
108
|
const spinner = createSpinner();
|
|
106
109
|
spinner.start(`Installing ${ref}`);
|
|
107
110
|
try {
|
|
108
|
-
const { openCatalogSource, openLibrary } = await import('./open-library-
|
|
111
|
+
const { openCatalogSource, openLibrary } = await import('./open-library-BOSPJVID.js');
|
|
109
112
|
const catalog = await openCatalogSource({ projectDir: path.resolve(opts.projectDir) });
|
|
110
113
|
if (!supportsInstallManifest(catalog)) {
|
|
111
114
|
throw new Error(
|
|
@@ -146,8 +149,9 @@ async function runYamlInstall(opts) {
|
|
|
146
149
|
await runGlobalInstall(opts, harnesses);
|
|
147
150
|
return;
|
|
148
151
|
}
|
|
152
|
+
requireProjectConfig(projectDir);
|
|
149
153
|
try {
|
|
150
|
-
const { ensureSourcesCloned } = await import('./ensure-sources-
|
|
154
|
+
const { ensureSourcesCloned } = await import('./ensure-sources-2RONZKCU.js');
|
|
151
155
|
const hydrate = ensureSourcesCloned(projectDir, { quiet: true });
|
|
152
156
|
if (hydrate.cloned.length > 0) {
|
|
153
157
|
logOk(`Cloned source(s): ${hydrate.cloned.join(", ")}`);
|
|
@@ -173,6 +177,10 @@ async function runYamlInstall(opts) {
|
|
|
173
177
|
if (result.deployed.length > 0) {
|
|
174
178
|
for (const d of result.deployed) logOk(d);
|
|
175
179
|
}
|
|
180
|
+
for (const r of result.restored ?? []) {
|
|
181
|
+
for (const f of r.restored) logInfo(`Restored ${f}`);
|
|
182
|
+
for (const f of r.removed) logInfo(`Removed ${f} (not part of ${r.ref})`);
|
|
183
|
+
}
|
|
176
184
|
reportPresetExpansions(result.presets);
|
|
177
185
|
reportAgentInstances(result.agentInstances, result.agentFilesRemoved);
|
|
178
186
|
if (result.removed.length > 0) {
|
|
@@ -180,7 +188,8 @@ async function runYamlInstall(opts) {
|
|
|
180
188
|
}
|
|
181
189
|
reportReplaced(result.replaced);
|
|
182
190
|
reportRelocked(result.relocked);
|
|
183
|
-
|
|
191
|
+
reportMoved(result.moved);
|
|
192
|
+
if (result.deployed.length === 0 && result.removed.length === 0 && !result.replaced?.length && result.missing.length === 0 && !result.relocked?.length && !result.moved?.length && !result.agentInstanceErrors?.length) {
|
|
184
193
|
logInfo("Nothing to install (already up to date).");
|
|
185
194
|
}
|
|
186
195
|
if (result.agentInstanceErrors?.length) {
|
|
@@ -230,7 +239,8 @@ async function runGlobalInstall(opts, harnesses) {
|
|
|
230
239
|
if (result.removed.length > 0) for (const r of result.removed) logWarn(`Removed: ${r}`);
|
|
231
240
|
reportReplaced(result.replaced);
|
|
232
241
|
reportRelocked(result.relocked);
|
|
233
|
-
|
|
242
|
+
reportMoved(result.moved);
|
|
243
|
+
if (result.deployed.length === 0 && result.removed.length === 0 && !result.replaced?.length && result.missing.length === 0 && !result.relocked?.length && !result.moved?.length)
|
|
234
244
|
logInfo("Nothing to install (already up to date).");
|
|
235
245
|
if (result.missing.length > 0) {
|
|
236
246
|
for (const m of result.missing) logErr(`Missing: ${m}${result.missingHints?.[m] ?? ""}`);
|
|
@@ -250,6 +260,7 @@ async function runGlobalInstall(opts, harnesses) {
|
|
|
250
260
|
}
|
|
251
261
|
function makeCheckCommand() {
|
|
252
262
|
return new Command("check").description("Check for unmet requirements").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
|
|
263
|
+
requireProjectConfig(opts.projectDir);
|
|
253
264
|
const am = new AssetManager({
|
|
254
265
|
registry: getKindRegistry(),
|
|
255
266
|
projectDir: path.resolve(opts.projectDir)
|
|
@@ -322,6 +333,6 @@ function makeCleanCommand() {
|
|
|
322
333
|
});
|
|
323
334
|
}
|
|
324
335
|
|
|
325
|
-
export { REF_HINT, makeCheckCommand, makeCleanCommand, makeInstallCommand, reportAgentInstances, reportInstalledSoftDeps, reportPresetExpansions, reportRelocked, reportReplaced, runPointerOnlyInstall, supportsInstallManifest };
|
|
326
|
-
//# sourceMappingURL=chunk-
|
|
327
|
-
//# sourceMappingURL=chunk-
|
|
336
|
+
export { REF_HINT, makeCheckCommand, makeCleanCommand, makeInstallCommand, reportAgentInstances, reportInstalledSoftDeps, reportMoved, reportPresetExpansions, reportRelocked, reportReplaced, runPointerOnlyInstall, supportsInstallManifest };
|
|
337
|
+
//# sourceMappingURL=chunk-CJERAGFY.js.map
|
|
338
|
+
//# sourceMappingURL=chunk-CJERAGFY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../cli/src/commands/project.ts"],"names":["confirm"],"mappings":"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","file":"chunk-CJERAGFY.js","sourcesContent":["import path from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport {\n AssetManager,\n type InstalledAgentInstance,\n type LibraryMove,\n type ReplacedAsset,\n} from \"@skaile/workspaces/asset-manager\";\nimport {\n type DriverTarget,\n type PresetExpansion,\n parseAssetRef,\n readLock,\n SUPPORTED_DRIVER_TARGETS,\n SourceEntryError,\n userConfigPath,\n} from \"@skaile/workspaces/core\";\nimport type { InstallManifest } from \"@skaile/workspaces/types\";\nimport { Command } from \"commander\";\nimport {\n colorRef,\n requireProjectConfig,\n formatSoftDepHint,\n logErr,\n logInfo,\n logOk,\n logWarn,\n S,\n TARGET_DEFAULT_HINT,\n warnLegacyClaudeCopies,\n} from \"../helpers.ts\";\nimport { createSpinner } from \"../spinner.ts\";\nimport { getKindRegistry } from \"../open-registry.ts\";\n\n/**\n * Canonical asset-ref shape accepted by `skaile install <ref>`:\n * `kind:@<publisher>/<name>#<version>` (the `#` version sigil). Validated via\n * `parseAssetRef` so the CLI shares the single canonical grammar; the legacy\n * trailing-`@version` shape is rejected.\n */\nexport const REF_HINT = \"kind:@<publisher>/<name>#<version> (e.g. skill:@skaile/use-exa#1.0.0)\";\n\n/** True when `ref` parses as a canonical asset ref. */\nfunction isValidAssetRef(ref: string): boolean {\n try {\n parseAssetRef(ref);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Minimal catalog-source surface the pointer-only install path needs.\n * `RemoteCatalogSource` satisfies this — narrowing keeps {@link runPointerOnlyInstall}\n * testable with a hand-rolled stub.\n */\nexport interface InstallManifestSource {\n getInstallManifest(ref: string): Promise<InstallManifest>;\n}\n\n/**\n * Capability check: is this catalog source able to serve install manifests?\n *\n * `openCatalogSource` returns a `RemoteCatalogSource | RestCatalogSource`.\n * Only the tRPC-framed `RemoteCatalogSource` implements `getInstallManifest`;\n * the REST-framed `RestCatalogSource` (the default for any catalog URL other\n * than `https://skaile.store`) does not. Calling it unconditionally would be a\n * runtime `TypeError`, so the pointer-only install path must capability-detect\n * first and fail with a clear, actionable message.\n */\nexport function supportsInstallManifest(source: unknown): source is InstallManifestSource {\n return (\n typeof (source as { getInstallManifest?: unknown } | null | undefined)?.getInstallManifest ===\n \"function\"\n );\n}\n\n/**\n * Minimal library surface the pointer-only install path needs.\n * `LocalIndex` satisfies this.\n */\nexport interface InstallLibrary {\n install(manifest: InstallManifest): Promise<{ installPath: string }>;\n}\n\n/**\n * Result of a pointer-only catalog install.\n */\nexport interface PointerOnlyInstallResult {\n /** Absolute path the verified asset bytes were written to. */\n installPath: string;\n /** The pinned upstream commit SHA the asset was fetched at. */\n commitSha: string;\n /** Number of files in the install manifest. */\n fileCount: number;\n}\n\n/**\n * Pointer-only catalog install — the `skaile install <ref>` code path.\n *\n * 1. Resolves the pointer-only {@link InstallManifest} from the Catalog.\n * 2. Hands it to the library, which fetches each file's bytes directly from\n * the upstream repo at the pinned commit, verifies every per-file SHA256\n * plus the composite SHA256, and only then writes the verified files.\n *\n * Both dependencies are injected so the function is unit-testable without a\n * network round-trip. In production the CLI passes a `RemoteCatalogSource`\n * and a `LocalIndex`.\n *\n * @param ref - Canonical asset ref (`kind:@<publisher>/<name>#<version>`).\n * @param deps - Injected catalog source + library.\n * @returns The install path, pinned commit SHA, and file count.\n * @throws When the ref is malformed, the manifest cannot be resolved, or any\n * hash verification fails. The underlying error message is surfaced as-is.\n */\nexport async function runPointerOnlyInstall(\n ref: string,\n deps: { catalog: InstallManifestSource; library: InstallLibrary },\n): Promise<PointerOnlyInstallResult> {\n let requested: ReturnType<typeof parseAssetRef>;\n try {\n requested = parseAssetRef(ref);\n } catch (e) {\n throw new Error(\n `malformed asset ref '${ref}' — expected ${REF_HINT}: ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n const manifest = await deps.catalog.getInstallManifest(ref);\n // [M1] Identity check: the catalog must not install a different asset than\n // requested. Compare the PARSED refs (kind/publisher/name/pin) so equivalent\n // spellings (optional `kind:`, default `skill`) are treated as the same ref.\n const got = parseAssetRef(manifest.ref);\n if (\n got.kind !== requested.kind ||\n got.publisher !== requested.publisher ||\n got.name !== requested.name ||\n got.pin !== requested.pin\n ) {\n throw new Error(\n `catalog identity mismatch: requested '${ref}' but the catalog returned a manifest for '${manifest.ref}'`,\n );\n }\n const { installPath } = await deps.library.install(manifest);\n return {\n installPath,\n commitSha: manifest.source.commitSha,\n fileCount: manifest.files.length,\n };\n}\n\n/**\n * Print one summary line per `preset:` dependency `skaile install` expanded: how many\n * asset items joined the install set and how many instance items (`library://`,\n * placeholders) were skipped, which only `skaile preset apply` materialises.\n */\nexport function reportPresetExpansions(\n presets: readonly PresetExpansion[] | undefined,\n onLine: (line: string) => void = logInfo,\n): void {\n for (const preset of presets ?? []) {\n onLine(\n `preset ${preset.ref}: ${preset.assets} assets, ${preset.skipped} instance items skipped (apply with skaile preset apply)`,\n );\n }\n}\n\n/**\n * Print one line per agent instance `skaile install` rendered (with the files\n * written) and one per native agent file removed because its instance left `skaile.yaml`.\n */\nexport function reportAgentInstances(\n instances: readonly InstalledAgentInstance[] | undefined,\n removedFiles: readonly string[] | undefined,\n onLine: (line: string) => void = logInfo,\n onRemoved: (line: string) => void = logWarn,\n): void {\n for (const instance of instances ?? []) {\n onLine(`agent ${instance.id}: ${instance.files.join(\", \")}`);\n }\n for (const file of removedFiles ?? []) onRemoved(`Removed: ${file}`);\n}\n\n/** One `Re-locked` line per lock entry `install`/`update` rewrote for an already-locked asset. */\nexport function reportRelocked(\n relocked: string[] | undefined,\n onLine: (line: string) => void = logInfo,\n): void {\n for (const ref of relocked ?? []) onLine(`Re-locked ${ref}`);\n}\n\n/** One `! <ref> moved from <a> to <b>` line per locked asset that now resolves from another library. */\nexport function reportMoved(\n moved: readonly LibraryMove[] | undefined,\n onLine: (line: string) => void = logWarn,\n): void {\n for (const m of moved ?? []) onLine(`${m.ref} moved from ${m.from} to ${m.to}`);\n}\n\n/** One `replaced <old> → <new>` line per asset `install`/`update` moved to another locked version. */\nexport function reportReplaced(\n replaced: readonly ReplacedAsset[] | undefined,\n onLine: (line: string) => void = logInfo,\n): void {\n for (const r of replaced ?? []) onLine(`${r.ref} replaced ${r.from} → ${r.to}`);\n}\n\n/**\n * Creates the `skaile install` command.\n *\n * Two modes, selected by argument shape:\n *\n * - `skaile install` (no positional arg) — reads `skaile.yaml` and deploys all\n * declared assets (and their transitive dependencies) to the configured\n * driver target directory. Supports `--locked` for CI-mode install from a\n * lock file.\n * - `skaile install kind:@<publisher>/<name>#<version>` — pointer-only catalog\n * install: resolves the pointer-only install manifest from the configured\n * Catalog, fetches each file's bytes directly from the upstream repo at the\n * pinned commit, verifies every per-file + the composite SHA256, then writes\n * the verified files into the local Library.\n *\n * @returns Configured {@link Command} ready for `program.addCommand()`.\n * @docLink cli/commands/project#make-install-command\n */\nexport function makeInstallCommand(): Command {\n return new Command(\"install\")\n .description(`Install dependencies from skaile.yaml, or a single asset by ref (${REF_HINT})`)\n .argument(\"[ref]\", `Asset ref to install from the Catalog (${REF_HINT})`)\n .option(\"--locked\", \"Install from lock file (CI mode — fails on drift)\")\n .option(\"--project-dir <path>\", \"Project directory\", process.cwd())\n .option(\"--target <agent>\", `Agent framework (${TARGET_DEFAULT_HINT})`)\n .option(\n \"--global\",\n \"Install the global SSOT (~/.skaile/skaile.yaml), fanning out to every global harness\",\n )\n .option(\n \"--harness <ids>\",\n \"Comma-separated global harnesses to install into (default: all resolved); implies --global\",\n )\n .option(\n \"--link\",\n \"symlink local-path assets instead of copying (dev loop; machine-local, not for committing)\",\n )\n .action(runInstallCommand);\n}\n\n/** Options shape accepted by the `skaile install` command action. */\ninterface InstallCommandOptions {\n locked?: boolean;\n projectDir: string;\n target?: string;\n global?: boolean;\n harness?: string;\n link?: boolean;\n}\n\n/**\n * Parse a `--harness a,b` value into validated {@link DriverTarget}s, exiting on\n * an unknown id. Returns `undefined` when the flag is absent (resolve the full\n * global set instead).\n */\nfunction parseHarnessFilter(raw: string | undefined): DriverTarget[] | undefined {\n if (!raw) return undefined;\n const ids = raw\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n const out: DriverTarget[] = [];\n for (const id of ids) {\n if (!(SUPPORTED_DRIVER_TARGETS as string[]).includes(id)) {\n logErr(`unknown harness '${id}' — expected one of: ${SUPPORTED_DRIVER_TARGETS.join(\", \")}`);\n process.exit(1);\n }\n out.push(id as DriverTarget);\n }\n return out.length > 0 ? out : undefined;\n}\n\n/**\n * `skaile install` action body. Dispatches by argument shape:\n * a positional `ref` selects pointer-only catalog install, otherwise the\n * legacy `skaile.yaml` install path runs.\n */\nasync function runInstallCommand(\n ref: string | undefined,\n opts: InstallCommandOptions,\n): Promise<void> {\n // ── Pointer-only catalog install: `skaile install <ref>` ──────────────\n if (ref !== undefined) {\n await runRefInstall(ref, opts);\n return;\n }\n\n // ── Legacy install: `skaile install` reads skaile.yaml ────────────────\n await runYamlInstall(opts);\n}\n\n/** Pointer-only catalog install path for `skaile install <ref>`. */\nasync function runRefInstall(ref: string, opts: InstallCommandOptions): Promise<void> {\n if (!isValidAssetRef(ref)) {\n logErr(`malformed asset ref '${ref}' — expected ${REF_HINT}`);\n process.exit(1);\n }\n const spinner = createSpinner();\n spinner.start(`Installing ${ref}`);\n try {\n const { openCatalogSource, openLibrary } = await import(\"../open-library.ts\");\n const catalog = await openCatalogSource({ projectDir: path.resolve(opts.projectDir) });\n // [H2] REST-framed catalogs (the default for any catalog URL other\n // than https://skaile.store) cannot serve install manifests. Detect\n // and fail clearly rather than throwing a runtime TypeError.\n if (!supportsInstallManifest(catalog)) {\n throw new Error(\n \"pointer-only install (skaile install <ref>) requires a tRPC-framed Catalog. \" +\n \"The configured catalog uses REST framing, which does not serve install \" +\n \"manifests. Set catalog.url to https://skaile.store, or catalog.framing: trpc, \" +\n `in ${userConfigPath()}.`,\n );\n }\n const library = await openLibrary();\n try {\n const result = await runPointerOnlyInstall(ref, { catalog, library });\n spinner.stop(\"Done\");\n logOk(`Installed ${colorRef(ref)}`);\n logInfo(`Path: ${S.dim(result.installPath)}`);\n logInfo(`Commit: ${S.dim(result.commitSha)}`);\n logInfo(`Files: ${S.dim(String(result.fileCount))}`);\n logInfo(\n S.dim(\n `Installed globally (see Path above) — use \\`skaile add ${ref}\\` to deploy into this project.`,\n ),\n );\n } finally {\n library.close();\n }\n } catch (err) {\n spinner.stop(\"Failed\");\n const msg = err instanceof Error ? err.message : String(err);\n if (/unreachable/i.test(msg)) {\n logErr(`asset uninstallable — source commit no longer available (${msg})`);\n } else {\n logErr(msg);\n }\n process.exit(1);\n }\n}\n\n/** Legacy install path for bare `skaile install` (reads skaile.yaml). */\nasync function runYamlInstall(opts: InstallCommandOptions): Promise<void> {\n const projectDir = path.resolve(opts.projectDir);\n\n const harnesses = parseHarnessFilter(opts.harness);\n // `--harness` implies `--global`.\n if (opts.global || harnesses) {\n await runGlobalInstall(opts, harnesses);\n return;\n }\n\n // A project without a readable skaile.yaml stops here, before sources are cloned, assets\n // are deployed or undeployed, or the lock is written.\n requireProjectConfig(projectDir);\n\n // Hydrate sources declared in skaile.yaml before resolving assets, so\n // freshly checked-out projects pull their source clones automatically.\n try {\n const { ensureSourcesCloned } = await import(\"../ensure-sources.ts\");\n const hydrate = ensureSourcesCloned(projectDir, { quiet: true });\n if (hydrate.cloned.length > 0) {\n logOk(`Cloned source(s): ${hydrate.cloned.join(\", \")}`);\n }\n if (hydrate.failed.length > 0) {\n logErr(`Failed to clone source(s): ${hydrate.failed.join(\", \")}`);\n }\n } catch (err) {\n logWarn(`source hydration skipped: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n const am = new AssetManager({\n registry: getKindRegistry(),\n projectDir,\n driverTarget: opts.target as DriverTarget,\n });\n const spinner = createSpinner();\n spinner.start(opts.locked ? \"Installing from lock file\" : \"Installing dependencies\");\n try {\n const result = await am.install({ locked: opts.locked, link: opts.link });\n spinner.stop(\n result.agentInstanceErrors?.length || result.missing.length > 0 ? \"Failed\" : \"Done\",\n );\n if (result.deployed.length > 0) {\n for (const d of result.deployed) logOk(d);\n }\n for (const r of result.restored ?? []) {\n for (const f of r.restored) logInfo(`Restored ${f}`);\n for (const f of r.removed) logInfo(`Removed ${f} (not part of ${r.ref})`);\n }\n reportPresetExpansions(result.presets);\n reportAgentInstances(result.agentInstances, result.agentFilesRemoved);\n if (result.removed.length > 0) {\n for (const r of result.removed) logWarn(`Removed: ${r}`);\n }\n reportReplaced(result.replaced);\n reportRelocked(result.relocked);\n reportMoved(result.moved);\n if (\n result.deployed.length === 0 &&\n result.removed.length === 0 &&\n !result.replaced?.length &&\n result.missing.length === 0 &&\n !result.relocked?.length &&\n !result.moved?.length &&\n !result.agentInstanceErrors?.length\n ) {\n logInfo(\"Nothing to install (already up to date).\");\n }\n if (result.agentInstanceErrors?.length) {\n logErr(\n `${result.agentInstanceErrors.length} agent instance(s) could not be rendered (see above)`,\n );\n process.exitCode = 1;\n }\n if (result.missing.length > 0) {\n for (const m of result.missing) logErr(`Missing: ${m}${result.missingHints?.[m] ?? \"\"}`);\n // Partial-miss must fail the process — CI can't otherwise distinguish a\n // clean install from \"half the assets never resolved\".\n process.exitCode = 1;\n }\n if (result.lockWritten) {\n logInfo(`Lock file written: ${S.dim(\"skaile.lock.yaml\")}`);\n }\n warnLegacyClaudeCopies(am);\n // Report-only: surface soft deps the declared assets reference but aren't\n // present. Never a prompt — install is a batch/CI path. Skipped under\n // --locked: that mode is \"restore exactly\", so an `add` nudge would jar.\n if (!opts.locked) await reportInstalledSoftDeps(am);\n } catch (err) {\n spinner.stop(\"Failed\");\n logErr(err instanceof SourceEntryError ? err.message : String(err));\n process.exit(1);\n }\n}\n\n/**\n * Report (never prompt) the body-link soft deps that the declared assets\n * reference but that aren't in the project — the `install` counterpart to the\n * `add`-time soft-dep surface. `install` is a batch/CI path (often non-TTY), so\n * it only ever prints a hint: pulling stays an explicit `skaile add`. Best-effort\n * — `reportSoftDeps` swallows any index failure and returns `[]`.\n */\nexport async function reportInstalledSoftDeps(\n am: Pick<AssetManager, \"listDeclared\" | \"reportSoftDeps\">,\n onHint: (line: string) => void = (l) => logInfo(S.dim(l)),\n): Promise<void> {\n try {\n const declared = (await am.listDeclared()).map((d) => d.ref);\n if (declared.length === 0) return;\n const edges = await am.reportSoftDeps(declared);\n for (const edge of edges) onHint(formatSoftDepHint(edge));\n } catch {\n // Best-effort: a soft-dep report must never fail an install that succeeded.\n }\n}\n\n/**\n * Global cross-harness install: deploy every dep declared in the global SSOT\n * (`~/.skaile/skaile.yaml`) into each resolved global harness's dir under `~`,\n * write the global lock (`~/.skaile/skaile.lock.yaml`), then print per-harness\n * state. `harnesses` is the `--harness` filter (omit for the full resolved set).\n */\nasync function runGlobalInstall(\n opts: InstallCommandOptions,\n harnesses: DriverTarget[] | undefined,\n): Promise<void> {\n const am = new AssetManager({\n registry: getKindRegistry(),\n projectDir: path.resolve(opts.projectDir),\n global: true,\n harnesses,\n });\n const spinner = createSpinner();\n spinner.start(\"Installing global dependencies\");\n try {\n const result = await am.install({ locked: opts.locked, link: opts.link });\n spinner.stop(result.missing.length > 0 ? \"Failed\" : \"Done\");\n if (result.deployed.length > 0) for (const d of result.deployed) logOk(d);\n reportPresetExpansions(result.presets);\n if (result.removed.length > 0) for (const r of result.removed) logWarn(`Removed: ${r}`);\n reportReplaced(result.replaced);\n reportRelocked(result.relocked);\n reportMoved(result.moved);\n if (\n result.deployed.length === 0 &&\n result.removed.length === 0 &&\n !result.replaced?.length &&\n result.missing.length === 0 &&\n !result.relocked?.length &&\n !result.moved?.length\n )\n logInfo(\"Nothing to install (already up to date).\");\n if (result.missing.length > 0) {\n for (const m of result.missing) logErr(`Missing: ${m}${result.missingHints?.[m] ?? \"\"}`);\n process.exitCode = 1;\n }\n if (result.lockWritten) logInfo(`Global lock written: ${S.dim(\"~/.skaile/skaile.lock.yaml\")}`);\n\n // Per-harness reconciliation summary so a partial fan-out is visible.\n const state = am.globalState({});\n const byHarness = new Map<string, number>();\n for (const s of state)\n if (s.state === \"installed\") byHarness.set(s.harness, (byHarness.get(s.harness) ?? 0) + 1);\n for (const [harness, n] of byHarness) logInfo(`${harness}: ${n} installed`);\n } catch (err) {\n spinner.stop(\"Failed\");\n logErr(String(err));\n process.exit(1);\n }\n}\n\n/**\n * Creates the `skaile check` command.\n *\n * Fails (exit 1) on every problem {@link AssetManager.projectState} reports: unmet\n * requirements of deployed assets, a declared dep that never resolved into the lock (its\n * library or source is gone, like `skaile list` showing it as `declared`) or never\n * materialized (e.g. a store-sourced `mcp-server`, #462), a locked asset whose library is\n * gone or whose deployed copy or files are missing, a locked library asset whose files\n * changed since the lock (or whose lock hash predates the shared asset hash), and an\n * `agents.<id>.ref` that binds to no agent. `doctor`, `outdated`, `diff` and\n * `install --locked` take their verdict from the same state.\n *\n * @returns Configured {@link Command} ready for `program.addCommand()`.\n * @docLink cli/commands/project#make-check-command\n */\nexport function makeCheckCommand(): Command {\n return new Command(\"check\")\n .description(\"Check for unmet requirements\")\n .option(\"--project-dir <path>\", \"Project directory\", process.cwd())\n .action(async (opts) => {\n requireProjectConfig(opts.projectDir);\n const am = new AssetManager({\n registry: getKindRegistry(),\n projectDir: path.resolve(opts.projectDir),\n });\n const { gaps } = await am.projectState();\n if (gaps.length === 0) {\n logOk(\"All dependencies satisfied.\");\n } else {\n for (const g of gaps) logErr(g.message);\n process.exit(1);\n }\n });\n}\n\n/**\n * Creates the `skaile clean` command.\n *\n * Removes all skaile-managed assets tracked in `skaile.lock.yaml` from the\n * workspace. With `--all` also removes history, patches, repos, and the lock\n * file itself. Preserves unmanaged (manually placed) assets.\n *\n * @returns Configured {@link Command} ready for `program.addCommand()`.\n * @docLink cli/commands/project#make-clean-command\n */\nexport function makeCleanCommand(): Command {\n return new Command(\"clean\")\n .description(\"Remove all skaile-managed assets from the workspace\")\n .option(\"--all\", \"Full reset: also remove history, patches, repos, and lock file\")\n .option(\"--dry-run\", \"Show what would be removed without doing it\")\n .option(\"-y, --yes\", \"Skip confirmation prompt\")\n .option(\"--project-dir <path>\", \"Project directory\", process.cwd())\n .option(\"--target <agent>\", `Agent framework (${TARGET_DEFAULT_HINT})`)\n .action(async (opts) => {\n const am = new AssetManager({\n registry: getKindRegistry(),\n projectDir: path.resolve(opts.projectDir),\n driverTarget: opts.target as DriverTarget,\n });\n\n // Preview: load lock file to show what will be cleaned\n const lock = readLock(path.resolve(opts.projectDir, \"skaile.lock.yaml\"));\n\n if (!lock || Object.keys(lock.assets).length === 0) {\n logInfo(\"Nothing to clean (no skaile-managed assets found).\");\n return;\n }\n\n const assetRefs = Object.keys(lock.assets);\n console.log();\n console.log(` ${S.heading(\"Assets to remove:\")} ${S.dim(`(${assetRefs.length})`)}`);\n for (const ref of assetRefs) {\n console.log(` ${colorRef(ref)}`);\n }\n\n if (opts.all) {\n console.log();\n console.log(` ${S.heading(\"Also removing:\")}`);\n console.log(` ${S.dim(\".skaile/history.yaml\")}`);\n console.log(` ${S.dim(\".skaile/patches/\")}`);\n console.log(` ${S.dim(\"skaile.lock.yaml\")}`);\n }\n\n if (opts.dryRun) {\n console.log();\n logInfo(\"Dry run — no changes made.\");\n return;\n }\n\n if (!opts.yes) {\n const confirm = await p.confirm({ message: \"Proceed?\" });\n if (p.isCancel(confirm) || !confirm) {\n logInfo(\"Cancelled.\");\n return;\n }\n }\n\n const result = am.clean({ all: opts.all });\n\n console.log();\n for (const r of result.removed) {\n logOk(`Removed ${r}`);\n }\n for (const s of result.skipped) {\n logWarn(`Skipped ${s.ref}: ${s.reason}`);\n }\n if (result.unmanaged.length > 0) {\n console.log();\n logInfo(`Kept ${result.unmanaged.length} unmanaged asset(s):`);\n for (const u of result.unmanaged) {\n console.log(` ${S.dim(u)}`);\n }\n }\n if (opts.all) {\n console.log();\n logOk(\"Full reset complete.\");\n }\n });\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { compositeSha256 } from './chunk-
|
|
2
|
-
import { parseAssetRef } from './chunk-
|
|
1
|
+
import { compositeSha256 } from './chunk-ZPWTOUTK.js';
|
|
2
|
+
import { parseAssetRef } from './chunk-BNMZVPYA.js';
|
|
3
3
|
import { createHash } from 'crypto';
|
|
4
4
|
import { rm, mkdir, writeFile } from 'fs/promises';
|
|
5
5
|
import { isAbsolute, resolve, sep, join, dirname } from 'path';
|
|
@@ -123,5 +123,5 @@ async function installFlat(manifest, targetDir, fetcher) {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
export { assertSafeManifestPath, installFromManifest, longestCommonDirPrefix };
|
|
126
|
-
//# sourceMappingURL=chunk-
|
|
127
|
-
//# sourceMappingURL=chunk-
|
|
126
|
+
//# sourceMappingURL=chunk-COH6FQAG.js.map
|
|
127
|
+
//# sourceMappingURL=chunk-COH6FQAG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../library/src/install/install-from-manifest.ts"],"names":[],"mappings":"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","file":"chunk-MVQ3Q2HM.js","sourcesContent":["/**\n * Pointer-only install path.\n *\n * Given an {@link InstallManifest} (the Pointer Triple the Catalog hands\n * clients), this:\n *\n * 1. fetches the asset bytes directly from the upstream repo at the pinned\n * commit (via an injectable fetcher, default {@link fetchAssetFilesFromGitHub});\n * 2. verifies EVERY per-file SHA256 against `manifest.files[].sha256`;\n * 3. verifies the composite SHA256 rollup over the sorted\n * `<path>:<sha256>\\n` lines against `manifest.sha256`;\n * 4. writes the verified bytes under `<libraryRoot>/@<publisher>/<name>/<version>`.\n *\n * Any hash mismatch is a hard failure — bytes are not written if per-file\n * verification fails, and the composite check is the second gate.\n *\n * @docLink packages/library/concepts#install\n */\n\nimport { createHash } from \"node:crypto\";\nimport { mkdir, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, resolve, sep } from \"node:path\";\nimport type { InstallManifest } from \"@skaile/workspaces/types\";\n// Narrow module, not the `core` barrel: the barrel's chunks carry `import.meta`,\n// which breaks consumers that transpile this entry to CommonJS.\nimport { parseAssetRef } from \"../../../core/src/models.js\";\nimport { compositeSha256 } from \"../../../core/src/publish-manifest.js\";\n\n/**\n * Validate a single manifest-supplied file path against path traversal.\n *\n * `manifest.files[].path` comes off the network — the attacker controls the\n * entire manifest (and therefore every hash in it), so hash verification can\n * NEVER mitigate a malicious *destination*. A path like\n * `../../../../home/user/.bashrc` or an absolute path would escape\n * `installPath` and yield an arbitrary file write. Every path is checked\n * BEFORE any fetch or write happens; the first bad path aborts the entire\n * install with a hard throw.\n *\n * A path is rejected if ANY of:\n * - it is empty;\n * - it is absolute (`path.isAbsolute`) or has a leading slash;\n * - it contains a `..` segment;\n * - `path.resolve(installPath, p)` is not `installPath` itself and does not\n * start with `installPath + path.sep` (escapes the install dir).\n *\n * @throws An error matching `/unsafe path in manifest/` on the first bad path.\n */\nexport function assertSafeManifestPath(installPath: string, p: string): void {\n const bad = (): never => {\n throw new Error(`unsafe path in manifest: ${p}`);\n };\n if (!p || p.length === 0) bad();\n if (isAbsolute(p) || p.startsWith(\"/\") || p.startsWith(\"\\\\\")) bad();\n const segments = p.split(/[/\\\\]/);\n if (segments.some((s) => s === \"..\")) bad();\n const resolved = resolve(installPath, p);\n if (resolved !== installPath && !resolved.startsWith(installPath + sep)) bad();\n}\n\n/**\n * Validate one component (publisher / name / version) of the attacker-controlled\n * `manifest.ref`.\n *\n * `installPath` is built by joining these components onto `libraryRoot`. A\n * component containing a path separator or a `..` / leading-dot segment would\n * let `installPath` itself escape `libraryRoot` — yielding an arbitrary file\n * write AND, via the pre-write `rm(installPath, { recursive })`, an arbitrary\n * recursive delete. The per-file `assertSafeManifestPath` guard cannot catch\n * this: it only validates each `f.path` *relative to* `installPath`, never\n * `installPath` itself. Components must be plain identifier-like strings.\n *\n * @throws An error matching `/unsafe ref/` on a bad component.\n */\nfunction assertSafeRefComponent(kind: string, value: string): void {\n // Reject empty, leading-dot (covers `.` and `..`), path separators, and\n // ASCII control characters (NUL et al.) — fails a malformed segment fast\n // with a domain-specific error rather than a raw EINVAL deeper in.\n const hasControlChar = [...value].some((c) => c.charCodeAt(0) < 0x20);\n if (!value || value.startsWith(\".\") || /[/\\\\]/.test(value) || hasControlChar) {\n throw new Error(`unsafe ref ${kind} component in manifest: '${value}'`);\n }\n}\n\n/**\n * Longest common **directory** prefix across manifest paths, compared by whole\n * slash-delimited segments (never raw-string — so `app/` and `app-data/` never\n * collide). Each path's basename is excluded, so the result is always a\n * directory prefix and every path keeps a non-empty remainder after stripping.\n *\n * Used by flat mode to reproduce the platform pointer-installer's asset-rooting:\n * the store persists repo-root-relative paths (e.g. `skaile-platform/mcpo/xls/MCP.md`)\n * but the runner scans `.skaile/assets/<kind>/<name>/` for immediate-child files,\n * so this prefix is stripped from the WRITE path while the fetch keeps the full\n * repo path. Returns `''` when there is no common directory (a no-op strip).\n */\nexport function longestCommonDirPrefix(paths: readonly string[]): string {\n if (paths.length === 0) return \"\";\n const dirSegments = paths.map((p) => p.split(\"/\").slice(0, -1));\n let common = dirSegments[0]!;\n for (let i = 1; i < dirSegments.length && common.length > 0; i++) {\n const segs = dirSegments[i]!;\n let n = 0;\n while (n < common.length && n < segs.length && common[n] === segs[n]) n++;\n common = common.slice(0, n);\n }\n return common.join(\"/\");\n}\n\n/**\n * Fetcher signature — fetches `{ path → Buffer }` for the requested paths at\n * a pinned upstream commit. {@link fetchAssetFilesFromGitHub} is the default\n * production implementation; tests inject a mock.\n */\nexport type AssetFetcher = (opts: {\n url: string;\n commitSha: string;\n paths: string[];\n}) => Promise<Record<string, Buffer>>;\n\n/**\n * Options for {@link installFromManifest}.\n */\nexport interface InstallOpts {\n /** The pointer-only install manifest from the Catalog. */\n manifest: InstallManifest;\n /** Filesystem root the asset is installed under (ref-derived mode). */\n libraryRoot: string;\n /**\n * Pluggable fetcher so tests can inject mock data. Defaults to\n * {@link fetchAssetFilesFromGitHub} in production.\n */\n fetcher?: AssetFetcher;\n /**\n * Flat-layout mode. When set, install-core reproduces the platform\n * pointer-installer's behavior: it ignores `libraryRoot`/ref-derivation, does\n * NOT parse `manifest.ref` and does NOT verify the composite sha256, strips\n * the longest-common-dir prefix from each path, per-file sha256-verifies, and\n * writes the stripped paths as immediate children of `targetDir` (what the\n * runner's `.skaile/assets/<kind>/<name>/` scan requires). `installPath` is\n * `targetDir`. Absent → unchanged ref-derived `@<pub>/name/version/<path>`\n * layout with composite verify.\n */\n targetDir?: string;\n}\n\n/**\n * Result of a successful {@link installFromManifest} call.\n */\nexport interface InstallResult {\n /** Absolute path the asset files were written to. */\n installPath: string;\n}\n\n/**\n * Fetch, verify, and write an asset's files per its {@link InstallManifest}.\n *\n * @throws An error matching `/hash mismatch/i` if any per-file SHA256 differs.\n * @throws An error matching `/composite hash mismatch/i` if the rollup differs.\n * @throws An error if the ref is malformed or the fetcher omits a file.\n */\nexport async function installFromManifest(opts: InstallOpts): Promise<InstallResult> {\n const { manifest, libraryRoot } = opts;\n const fetcher =\n opts.fetcher ?? (await import(\"./source-fetch-github.js\")).fetchAssetFilesFromGitHub;\n\n // Flat mode: reproduce the platform pointer-installer's asset-rooted layout.\n // No ref parse, no composite verify — the platform store may not satisfy a\n // ref-grammar or composite, and the runner only needs immediate-child files.\n if (opts.targetDir !== undefined) {\n return installFlat(manifest, opts.targetDir, fetcher);\n }\n\n // 1. Parse ref into install path: `skill:@x/git#1.0.0` → `<root>/@x/git/1.0.0`.\n // Done first so the C1 path-traversal guard can resolve against installPath\n // BEFORE any network fetch happens. The ref is attacker-controlled, so each\n // segment is further validated as a safe path component (H1) after parsing.\n // `parseAssetRef` is the single canonical grammar (`kind:@publisher/name#version`);\n // the legacy trailing-`@version` shape was removed in core and is rejected here.\n let parsed: ReturnType<typeof parseAssetRef>;\n try {\n parsed = parseAssetRef(manifest.ref);\n } catch (e) {\n throw new Error(`invalid ref: ${manifest.ref}: ${e instanceof Error ? e.message : String(e)}`);\n }\n const publisher = parsed.publisher;\n const name = parsed.name;\n const version = parsed.pin;\n if (!publisher) throw new Error(`invalid ref: ${manifest.ref} (missing publisher)`);\n if (!version) throw new Error(`invalid ref: ${manifest.ref} (missing version pin)`);\n assertSafeRefComponent(\"publisher\", publisher);\n assertSafeRefComponent(\"name\", name);\n assertSafeRefComponent(\"version\", version);\n const root = resolve(libraryRoot);\n const installPath = resolve(join(root, `@${publisher}`, name, version));\n // Defense in depth: even with the segment guards above, assert the built\n // installPath stays strictly inside libraryRoot before any write or `rm`.\n if (installPath !== root && !installPath.startsWith(root + sep)) {\n throw new Error(`unsafe install path: ref '${manifest.ref}' resolves outside the library root`);\n }\n\n // 2. [C1] Validate EVERY manifest path against traversal BEFORE fetching.\n // The attacker controls the manifest (and thus all hashes) — hashes verify\n // content, never destination. Reject the whole install on the first bad path.\n for (const f of manifest.files) {\n assertSafeManifestPath(installPath, f.path);\n }\n\n // 3. Fetch all files at the pinned commit.\n const paths = manifest.files.map((f) => f.path);\n const bytes = await fetcher({\n url: manifest.source.url,\n commitSha: manifest.source.commitSha,\n paths,\n });\n\n // 4. Verify per-file SHA256 — hard fail before writing anything. The path\n // key used to read from the fetcher result is re-guarded as defense in depth.\n for (const f of manifest.files) {\n assertSafeManifestPath(installPath, f.path);\n const buf = bytes[f.path];\n if (!buf) throw new Error(`fetcher returned no bytes for ${f.path}`);\n const actual = createHash(\"sha256\").update(buf).digest(\"hex\");\n if (actual !== f.sha256) {\n throw new Error(`hash mismatch for ${f.path}: expected ${f.sha256}, got ${actual}`);\n }\n }\n\n // 5. Verify composite SHA256 over the sorted `<path>:<sha256>\\n` lines.\n const actualComposite = compositeSha256(manifest.files);\n if (actualComposite !== manifest.sha256) {\n throw new Error(`composite hash mismatch: expected ${manifest.sha256}, got ${actualComposite}`);\n }\n\n // 6. [M1] Write all verified files. A failed install must leave NO partial\n // directory: any prior `installPath` is removed first (clean overwrite), and\n // a mid-loop write failure removes the partially-written tree before\n // rethrowing.\n await rm(installPath, { recursive: true, force: true });\n try {\n for (const f of manifest.files) {\n const target = join(installPath, f.path);\n await mkdir(dirname(target), { recursive: true });\n await writeFile(target, bytes[f.path]!);\n }\n } catch (e) {\n await rm(installPath, { recursive: true, force: true }).catch(() => {});\n throw e;\n }\n\n return { installPath };\n}\n\n/**\n * Flat-layout install — the platform pointer-installer's behavior, made canonical\n * in install-core. Validates every path, fetches with the FULL repo paths, per-file\n * sha256-verifies, then strips the longest-common-dir prefix and writes each file\n * as `join(targetDir, path.slice(assetRoot.length + 1))` — immediate children of\n * `targetDir`. No ref parse, no composite check.\n */\nasync function installFlat(\n manifest: InstallManifest,\n targetDir: string,\n fetcher: AssetFetcher,\n): Promise<InstallResult> {\n const target = resolve(targetDir);\n\n // Gate every path before any fetch — the attacker controls the whole manifest.\n for (const f of manifest.files) {\n assertSafeManifestPath(target, f.path);\n }\n\n // Fetch keys off the FULL repo path (matches the upstream tree).\n const paths = manifest.files.map((f) => f.path);\n const bytes = await fetcher({\n url: manifest.source.url,\n commitSha: manifest.source.commitSha,\n paths,\n });\n\n // Strip the asset-root dir prefix from the WRITE path only — the fetch above\n // still keyed off the full repo path. Stripping removes leading whole segments\n // (never the basename), so a non-empty remainder always survives.\n const assetRoot = longestCommonDirPrefix(paths);\n\n for (const f of manifest.files) {\n const buf = bytes[f.path];\n if (!buf) throw new Error(`fetcher returned no bytes for ${f.path}`);\n const actual = createHash(\"sha256\").update(buf).digest(\"hex\");\n if (actual !== f.sha256) {\n throw new Error(`hash mismatch for ${f.path}: expected ${f.sha256}, got ${actual}`);\n }\n const relPath = assetRoot ? f.path.slice(assetRoot.length + 1) : f.path;\n // Re-guard the post-strip destination — it is what we actually write.\n assertSafeManifestPath(target, relPath);\n const dest = join(target, relPath);\n await mkdir(dirname(dest), { recursive: true });\n await writeFile(dest, buf);\n }\n\n return { installPath: target };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../library/src/install/install-from-manifest.ts"],"names":[],"mappings":"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","file":"chunk-COH6FQAG.js","sourcesContent":["/**\n * Pointer-only install path.\n *\n * Given an {@link InstallManifest} (the Pointer Triple the Catalog hands\n * clients), this:\n *\n * 1. fetches the asset bytes directly from the upstream repo at the pinned\n * commit (via an injectable fetcher, default {@link fetchAssetFilesFromGitHub});\n * 2. verifies EVERY per-file SHA256 against `manifest.files[].sha256`;\n * 3. verifies the composite SHA256 rollup over the sorted\n * `<path>:<sha256>\\n` lines against `manifest.sha256`;\n * 4. writes the verified bytes under `<libraryRoot>/@<publisher>/<name>/<version>`.\n *\n * Any hash mismatch is a hard failure — bytes are not written if per-file\n * verification fails, and the composite check is the second gate.\n *\n * @docLink packages/library/concepts#install\n */\n\nimport { createHash } from \"node:crypto\";\nimport { mkdir, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, resolve, sep } from \"node:path\";\nimport type { InstallManifest } from \"@skaile/workspaces/types\";\n// Narrow module, not the `core` barrel: the barrel's chunks carry `import.meta`,\n// which breaks consumers that transpile this entry to CommonJS.\nimport { parseAssetRef } from \"../../../core/src/models.js\";\nimport { compositeSha256 } from \"../../../core/src/publish-manifest.js\";\n\n/**\n * Validate a single manifest-supplied file path against path traversal.\n *\n * `manifest.files[].path` comes off the network — the attacker controls the\n * entire manifest (and therefore every hash in it), so hash verification can\n * NEVER mitigate a malicious *destination*. A path like\n * `../../../../home/user/.bashrc` or an absolute path would escape\n * `installPath` and yield an arbitrary file write. Every path is checked\n * BEFORE any fetch or write happens; the first bad path aborts the entire\n * install with a hard throw.\n *\n * A path is rejected if ANY of:\n * - it is empty;\n * - it is absolute (`path.isAbsolute`) or has a leading slash;\n * - it contains a `..` segment;\n * - `path.resolve(installPath, p)` is not `installPath` itself and does not\n * start with `installPath + path.sep` (escapes the install dir).\n *\n * @throws An error matching `/unsafe path in manifest/` on the first bad path.\n */\nexport function assertSafeManifestPath(installPath: string, p: string): void {\n const bad = (): never => {\n throw new Error(`unsafe path in manifest: ${p}`);\n };\n if (!p || p.length === 0) bad();\n if (isAbsolute(p) || p.startsWith(\"/\") || p.startsWith(\"\\\\\")) bad();\n const segments = p.split(/[/\\\\]/);\n if (segments.some((s) => s === \"..\")) bad();\n const resolved = resolve(installPath, p);\n if (resolved !== installPath && !resolved.startsWith(installPath + sep)) bad();\n}\n\n/**\n * Validate one component (publisher / name / version) of the attacker-controlled\n * `manifest.ref`.\n *\n * `installPath` is built by joining these components onto `libraryRoot`. A\n * component containing a path separator or a `..` / leading-dot segment would\n * let `installPath` itself escape `libraryRoot` — yielding an arbitrary file\n * write AND, via the pre-write `rm(installPath, { recursive })`, an arbitrary\n * recursive delete. The per-file `assertSafeManifestPath` guard cannot catch\n * this: it only validates each `f.path` *relative to* `installPath`, never\n * `installPath` itself. Components must be plain identifier-like strings.\n *\n * @throws An error matching `/unsafe ref/` on a bad component.\n */\nfunction assertSafeRefComponent(kind: string, value: string): void {\n // Reject empty, leading-dot (covers `.` and `..`), path separators, and\n // ASCII control characters (NUL et al.) — fails a malformed segment fast\n // with a domain-specific error rather than a raw EINVAL deeper in.\n const hasControlChar = [...value].some((c) => c.charCodeAt(0) < 0x20);\n if (!value || value.startsWith(\".\") || /[/\\\\]/.test(value) || hasControlChar) {\n throw new Error(`unsafe ref ${kind} component in manifest: '${value}'`);\n }\n}\n\n/**\n * Longest common **directory** prefix across manifest paths, compared by whole\n * slash-delimited segments (never raw-string — so `app/` and `app-data/` never\n * collide). Each path's basename is excluded, so the result is always a\n * directory prefix and every path keeps a non-empty remainder after stripping.\n *\n * Used by flat mode to reproduce the platform pointer-installer's asset-rooting:\n * the store persists repo-root-relative paths (e.g. `skaile-platform/mcpo/xls/MCP.md`)\n * but the runner scans `.skaile/assets/<kind>/<name>/` for immediate-child files,\n * so this prefix is stripped from the WRITE path while the fetch keeps the full\n * repo path. Returns `''` when there is no common directory (a no-op strip).\n */\nexport function longestCommonDirPrefix(paths: readonly string[]): string {\n if (paths.length === 0) return \"\";\n const dirSegments = paths.map((p) => p.split(\"/\").slice(0, -1));\n let common = dirSegments[0]!;\n for (let i = 1; i < dirSegments.length && common.length > 0; i++) {\n const segs = dirSegments[i]!;\n let n = 0;\n while (n < common.length && n < segs.length && common[n] === segs[n]) n++;\n common = common.slice(0, n);\n }\n return common.join(\"/\");\n}\n\n/**\n * Fetcher signature — fetches `{ path → Buffer }` for the requested paths at\n * a pinned upstream commit. {@link fetchAssetFilesFromGitHub} is the default\n * production implementation; tests inject a mock.\n */\nexport type AssetFetcher = (opts: {\n url: string;\n commitSha: string;\n paths: string[];\n}) => Promise<Record<string, Buffer>>;\n\n/**\n * Options for {@link installFromManifest}.\n */\nexport interface InstallOpts {\n /** The pointer-only install manifest from the Catalog. */\n manifest: InstallManifest;\n /** Filesystem root the asset is installed under (ref-derived mode). */\n libraryRoot: string;\n /**\n * Pluggable fetcher so tests can inject mock data. Defaults to\n * {@link fetchAssetFilesFromGitHub} in production.\n */\n fetcher?: AssetFetcher;\n /**\n * Flat-layout mode. When set, install-core reproduces the platform\n * pointer-installer's behavior: it ignores `libraryRoot`/ref-derivation, does\n * NOT parse `manifest.ref` and does NOT verify the composite sha256, strips\n * the longest-common-dir prefix from each path, per-file sha256-verifies, and\n * writes the stripped paths as immediate children of `targetDir` (what the\n * runner's `.skaile/assets/<kind>/<name>/` scan requires). `installPath` is\n * `targetDir`. Absent → unchanged ref-derived `@<pub>/name/version/<path>`\n * layout with composite verify.\n */\n targetDir?: string;\n}\n\n/**\n * Result of a successful {@link installFromManifest} call.\n */\nexport interface InstallResult {\n /** Absolute path the asset files were written to. */\n installPath: string;\n}\n\n/**\n * Fetch, verify, and write an asset's files per its {@link InstallManifest}.\n *\n * @throws An error matching `/hash mismatch/i` if any per-file SHA256 differs.\n * @throws An error matching `/composite hash mismatch/i` if the rollup differs.\n * @throws An error if the ref is malformed or the fetcher omits a file.\n */\nexport async function installFromManifest(opts: InstallOpts): Promise<InstallResult> {\n const { manifest, libraryRoot } = opts;\n const fetcher =\n opts.fetcher ?? (await import(\"./source-fetch-github.js\")).fetchAssetFilesFromGitHub;\n\n // Flat mode: reproduce the platform pointer-installer's asset-rooted layout.\n // No ref parse, no composite verify — the platform store may not satisfy a\n // ref-grammar or composite, and the runner only needs immediate-child files.\n if (opts.targetDir !== undefined) {\n return installFlat(manifest, opts.targetDir, fetcher);\n }\n\n // 1. Parse ref into install path: `skill:@x/git#1.0.0` → `<root>/@x/git/1.0.0`.\n // Done first so the C1 path-traversal guard can resolve against installPath\n // BEFORE any network fetch happens. The ref is attacker-controlled, so each\n // segment is further validated as a safe path component (H1) after parsing.\n // `parseAssetRef` is the single canonical grammar (`kind:@publisher/name#version`);\n // the legacy trailing-`@version` shape was removed in core and is rejected here.\n let parsed: ReturnType<typeof parseAssetRef>;\n try {\n parsed = parseAssetRef(manifest.ref);\n } catch (e) {\n throw new Error(`invalid ref: ${manifest.ref}: ${e instanceof Error ? e.message : String(e)}`);\n }\n const publisher = parsed.publisher;\n const name = parsed.name;\n const version = parsed.pin;\n if (!publisher) throw new Error(`invalid ref: ${manifest.ref} (missing publisher)`);\n if (!version) throw new Error(`invalid ref: ${manifest.ref} (missing version pin)`);\n assertSafeRefComponent(\"publisher\", publisher);\n assertSafeRefComponent(\"name\", name);\n assertSafeRefComponent(\"version\", version);\n const root = resolve(libraryRoot);\n const installPath = resolve(join(root, `@${publisher}`, name, version));\n // Defense in depth: even with the segment guards above, assert the built\n // installPath stays strictly inside libraryRoot before any write or `rm`.\n if (installPath !== root && !installPath.startsWith(root + sep)) {\n throw new Error(`unsafe install path: ref '${manifest.ref}' resolves outside the library root`);\n }\n\n // 2. [C1] Validate EVERY manifest path against traversal BEFORE fetching.\n // The attacker controls the manifest (and thus all hashes) — hashes verify\n // content, never destination. Reject the whole install on the first bad path.\n for (const f of manifest.files) {\n assertSafeManifestPath(installPath, f.path);\n }\n\n // 3. Fetch all files at the pinned commit.\n const paths = manifest.files.map((f) => f.path);\n const bytes = await fetcher({\n url: manifest.source.url,\n commitSha: manifest.source.commitSha,\n paths,\n });\n\n // 4. Verify per-file SHA256 — hard fail before writing anything. The path\n // key used to read from the fetcher result is re-guarded as defense in depth.\n for (const f of manifest.files) {\n assertSafeManifestPath(installPath, f.path);\n const buf = bytes[f.path];\n if (!buf) throw new Error(`fetcher returned no bytes for ${f.path}`);\n const actual = createHash(\"sha256\").update(buf).digest(\"hex\");\n if (actual !== f.sha256) {\n throw new Error(`hash mismatch for ${f.path}: expected ${f.sha256}, got ${actual}`);\n }\n }\n\n // 5. Verify composite SHA256 over the sorted `<path>:<sha256>\\n` lines.\n const actualComposite = compositeSha256(manifest.files);\n if (actualComposite !== manifest.sha256) {\n throw new Error(`composite hash mismatch: expected ${manifest.sha256}, got ${actualComposite}`);\n }\n\n // 6. [M1] Write all verified files. A failed install must leave NO partial\n // directory: any prior `installPath` is removed first (clean overwrite), and\n // a mid-loop write failure removes the partially-written tree before\n // rethrowing.\n await rm(installPath, { recursive: true, force: true });\n try {\n for (const f of manifest.files) {\n const target = join(installPath, f.path);\n await mkdir(dirname(target), { recursive: true });\n await writeFile(target, bytes[f.path]!);\n }\n } catch (e) {\n await rm(installPath, { recursive: true, force: true }).catch(() => {});\n throw e;\n }\n\n return { installPath };\n}\n\n/**\n * Flat-layout install — the platform pointer-installer's behavior, made canonical\n * in install-core. Validates every path, fetches with the FULL repo paths, per-file\n * sha256-verifies, then strips the longest-common-dir prefix and writes each file\n * as `join(targetDir, path.slice(assetRoot.length + 1))` — immediate children of\n * `targetDir`. No ref parse, no composite check.\n */\nasync function installFlat(\n manifest: InstallManifest,\n targetDir: string,\n fetcher: AssetFetcher,\n): Promise<InstallResult> {\n const target = resolve(targetDir);\n\n // Gate every path before any fetch — the attacker controls the whole manifest.\n for (const f of manifest.files) {\n assertSafeManifestPath(target, f.path);\n }\n\n // Fetch keys off the FULL repo path (matches the upstream tree).\n const paths = manifest.files.map((f) => f.path);\n const bytes = await fetcher({\n url: manifest.source.url,\n commitSha: manifest.source.commitSha,\n paths,\n });\n\n // Strip the asset-root dir prefix from the WRITE path only — the fetch above\n // still keyed off the full repo path. Stripping removes leading whole segments\n // (never the basename), so a non-empty remainder always survives.\n const assetRoot = longestCommonDirPrefix(paths);\n\n for (const f of manifest.files) {\n const buf = bytes[f.path];\n if (!buf) throw new Error(`fetcher returned no bytes for ${f.path}`);\n const actual = createHash(\"sha256\").update(buf).digest(\"hex\");\n if (actual !== f.sha256) {\n throw new Error(`hash mismatch for ${f.path}: expected ${f.sha256}, got ${actual}`);\n }\n const relPath = assetRoot ? f.path.slice(assetRoot.length + 1) : f.path;\n // Re-guard the post-strip destination — it is what we actually write.\n assertSafeManifestPath(target, relPath);\n const dest = join(target, relPath);\n await mkdir(dirname(dest), { recursive: true });\n await writeFile(dest, buf);\n }\n\n return { installPath: target };\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getProviderPreset, registryCredentialEnv, providerCredentialEnvName, BUILTIN_DRIVER_CATALOG } from './chunk-
|
|
1
|
+
import { getProviderPreset, registryCredentialEnv, providerCredentialEnvName, BUILTIN_DRIVER_CATALOG } from './chunk-47U4GZ4M.js';
|
|
2
2
|
import { mergeRegistries, resolveEntryBaseUrl, normalizeEntryBaseUrl, registryEntries, isEntryEnabled, parseModelRef } from './chunk-MJHSLODD.js';
|
|
3
3
|
|
|
4
4
|
// bridge/src/provider-materialize/env-drivers.ts
|
|
@@ -137,5 +137,5 @@ function continueRoleBinding(session) {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
export { bindSingleProviderEntry, continueRoleBinding, credentialsForEveryProvider, entryBaseUrl, entryModelIds, entrySurface, harnessModelSelector, harnessProviderName, isStockCatalogEndpoint, registryModelEntries, resolveEnvDriverSession, resolveRegistryBinding, selectableEntries, versionedAnthropicBaseUrl };
|
|
140
|
-
//# sourceMappingURL=chunk-
|
|
141
|
-
//# sourceMappingURL=chunk-
|
|
140
|
+
//# sourceMappingURL=chunk-CPWLNZGJ.js.map
|
|
141
|
+
//# sourceMappingURL=chunk-CPWLNZGJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../bridge/src/provider-materialize/env-drivers.ts"],"names":[],"mappings":"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","file":"chunk-ZGQTS3Y4.js","sourcesContent":["/**\n * Registry adapter for the **env-shaped CLI drivers** — Gemini, Qwen, OpenCode,\n * Goose and Continue (§2.3).\n *\n * These harnesses take their endpoint from the environment rather than from a\n * config file, so the adapter's job is three things: resolve which registry\n * entry the session's model selector names, refuse at start when that entry\n * speaks a wire surface the harness cannot, and hand the driver the\n * provider-side model id it must put on the command line.\n *\n * Two pluralities meet here (`BUILTIN_DRIVER_CATALOG.providerPlurality`):\n *\n * - `single` — Gemini and Qwen address exactly one endpoint. The bound entry\n * supplies the credential *and* the base URL, and a surface mismatch is\n * fatal: a Gemini CLI pointed at an `openai-completions` endpoint cannot\n * work, and failing at start names the surface instead of leaving the user\n * with an opaque error mid-turn.\n * - `credentials-n` — OpenCode, Goose and Continue accept every enabled\n * entry's credential at once and select one active model. The credential\n * fan-out is `registryCredentialEnv`; the active model is this module's\n * `<provider>/<model>` binding.\n *\n * Writing the per-endpoint config files those three need for *custom*\n * endpoints (`opencode.json`, Goose `custom_providers/*.json`, Continue\n * `config.yaml`) is the file half, and is deliberately not here.\n *\n * @see PROVIDER-CONFIG-PLAN.md §2.3\n */\n\nimport {\n type AIProviderLlmEntry,\n type AIProviderSurface,\n isEntryEnabled,\n type MergedAIProviderRegistry,\n mergeRegistries,\n normalizeEntryBaseUrl,\n parseModelRef,\n registryEntries,\n resolveEntryBaseUrl,\n} from \"@skaile/workspaces/core/provider-registry\";\nimport type { ModelEntry } from \"../models.js\";\nimport { getProviderPreset } from \"../provider-catalog.js\";\nimport { BUILTIN_DRIVER_CATALOG } from \"../registry.js\";\nimport type { AgentConfig } from \"../types.js\";\nimport { providerCredentialEnvName, registryCredentialEnv } from \"./credential-env.js\";\n\n/**\n * Everything a CLI driver needs to know about this session's AI providers,\n * resolved once from its {@link AgentConfig}.\n */\nexport interface EnvDriverSession {\n /** The merged registry this session may address. Empty when none was configured. */\n registry: MergedAIProviderRegistry;\n /**\n * Environment `credential.ref` lookups resolve against — the process\n * environment widened with `config.env`, which is where the session\n * boundary delivered every resolved `SKAILE_AIP_<ID>_KEY`.\n */\n lookupEnv: Record<string, string | undefined>;\n /** Model selector: `<providerId>/<modelId>`, a bare id, or `@role`. */\n modelRef?: string;\n /** Roles table an `@role` selector resolves through. */\n roles?: Record<string, string>;\n}\n\n/**\n * Resolve the session's providers once, from its {@link AgentConfig}.\n *\n * `config.env` is folded into `lookupEnv` rather than kept apart: it is part\n * of the session's environment, not an extra, and a credential or\n * `*_BASE_URL` delivered there must be visible exactly as the child will see\n * it.\n */\nexport function resolveEnvDriverSession(\n config: AgentConfig,\n processEnv: Record<string, string | undefined> = process.env,\n): EnvDriverSession {\n return {\n registry: config.registry ?? mergeRegistries([]),\n lookupEnv: { ...processEnv, ...config.env },\n ...(config.modelRef ? { modelRef: config.modelRef } : {}),\n ...(config.roles ? { roles: config.roles } : {}),\n };\n}\n\n/** One resolved endpoint + model — everything a driver needs to spawn. */\nexport interface RegistryModelBinding {\n /** Registry id of the selected entry. */\n providerId: string;\n /** The selected entry itself. */\n entry: AIProviderLlmEntry;\n /** Logical model id, after `@role` expansion and before `model_map`. */\n modelId?: string;\n /** Provider-side model id — what goes on the wire / command line. */\n providerModelId?: string;\n /** Wire protocol, from the entry or its preset. */\n surface?: AIProviderSurface;\n /** Resolved endpoint, from the entry, its transport params, or its preset. */\n baseUrl?: string;\n /**\n * The provider name the *harness* knows this endpoint by — a catalog preset\n * id for a stock endpoint, the registry id for anything custom. See\n * {@link harnessProviderName}.\n */\n harnessProviderId: string;\n /** Non-fatal notes from `parseModelRef` (dangling role, disabled provider). */\n warnings: string[];\n}\n\n/** The entry's wire surface: its own, else its preset's. */\nexport function entrySurface(entry: AIProviderLlmEntry): AIProviderSurface | undefined {\n if (entry.surface) return entry.surface;\n return entry.preset ? getProviderPreset(entry.preset)?.surface : undefined;\n}\n\n/**\n * The entry's endpoint: its literal or transport-derived URL, else its\n * preset's literal, in the canonical spelling for its surface\n * (`normalizeEntryBaseUrl`: an `anthropic-messages` endpoint is its host root,\n * so `https://api.anthropic.com/v1` reads as `https://api.anthropic.com`).\n * Transport templates that still carry `{param}` placeholders never come\n * back — `resolveEntryBaseUrl` withholds those, and a preset's template is not\n * a URL.\n *\n * Every adapter reads the endpoint here and only re-spells it for a client\n * that wants something else ({@link versionedAnthropicBaseUrl}).\n */\nexport function entryBaseUrl(entry: AIProviderLlmEntry): string | undefined {\n const resolved =\n resolveEntryBaseUrl(entry) ??\n (entry.preset ? getProviderPreset(entry.preset)?.base_url : undefined);\n return normalizeEntryBaseUrl(resolved, entrySurface(entry));\n}\n\n/**\n * An `anthropic-messages` endpoint spelled for a client that appends only\n * `/messages` — `@ai-sdk/anthropic` (OpenCode) and Continue — rather than\n * `/v1/messages` like the Claude CLI, the Anthropic SDK and Goose. `baseUrl`\n * must already be canonical ({@link entryBaseUrl}); every other surface passes\n * through unchanged.\n */\nexport function versionedAnthropicBaseUrl(\n baseUrl: string,\n surface: AIProviderSurface | undefined,\n): string {\n if (surface !== \"anthropic-messages\") return baseUrl;\n // Append to the path, not the string: a query or fragment stays at the end.\n try {\n const url = new URL(baseUrl);\n url.pathname = `${url.pathname.replace(/\\/+$/, \"\")}/v1`;\n return url.toString();\n } catch {\n return `${baseUrl}/v1`;\n }\n}\n\n/**\n * True when a `credentials-n` harness already knows this endpoint under its\n * own catalog name — the entry names a preset and did not move it somewhere\n * else. Both sides are compared canonically, so `https://api.anthropic.com/v1`\n * is still the `anthropic` preset's endpoint.\n *\n * The one rule both halves of §2.3 read: it decides the name the env half\n * puts on the command line ({@link harnessProviderName}) *and* whether the\n * file half has to describe the endpoint at all. Reading it twice is what\n * keeps `-m <name>/<model>` and the generated provider file talking about the\n * same thing.\n */\nexport function isStockCatalogEndpoint(entry: AIProviderLlmEntry): boolean {\n const preset = entry.preset ? getProviderPreset(entry.preset) : undefined;\n if (!preset) return false;\n return entryBaseUrl(entry) === normalizeEntryBaseUrl(preset.base_url, entrySurface(entry));\n}\n\n/**\n * The provider name to give a `credentials-n` harness (`-m <name>/<model>`,\n * `GOOSE_PROVIDER`).\n *\n * A stock catalog endpoint is named by its preset, because that is the name\n * OpenCode's models.dev list and Goose's built-in provider table already use —\n * `prod-claude: {preset: anthropic}` is still Anthropic to them. An entry with\n * an endpoint of its own is named by its registry id: no built-in table knows\n * it, so the id is what its generated provider file is keyed by (the file half\n * of §2.3).\n */\nexport function harnessProviderName(providerId: string, entry: AIProviderLlmEntry): string {\n const preset = entry.preset ? getProviderPreset(entry.preset) : undefined;\n if (!preset || !isStockCatalogEndpoint(entry)) return providerId;\n return preset.id;\n}\n\n/**\n * Enabled `llm`/`embed` entries, in registry order. Also the set the file\n * adapters render (`opencode-config.ts`, `goose-custom-providers.ts`,\n * `continue-config-yaml.ts`): the env half and the file half must agree on\n * which entries exist before they can agree on what to call them.\n */\nexport function selectableEntries(\n registry: MergedAIProviderRegistry,\n): Array<[string, AIProviderLlmEntry]> {\n return registryEntries(registry).filter(\n (pair): pair is [string, AIProviderLlmEntry] =>\n (pair[1].kind === \"llm\" || pair[1].kind === \"embed\") && isEntryEnabled(pair[1]),\n );\n}\n\n/**\n * The provider-side model ids an entry declares, as `[logicalId, providerId]`\n * pairs in declaration order: every `model_map` entry, plus every\n * `capabilities` key the map does not rename.\n */\nexport function entryModelIds(entry: AIProviderLlmEntry): Array<[string, string]> {\n const logicalIds = [\n ...Object.keys(entry.model_map ?? {}),\n ...Object.keys(entry.capabilities ?? {}).filter((id) => !(id in (entry.model_map ?? {}))),\n ];\n return logicalIds.map((id) => [id, entry.model_map?.[id] ?? id]);\n}\n\nfunction describeBinding(\n providerId: string,\n entry: AIProviderLlmEntry,\n modelId: string | undefined,\n providerModelId: string | undefined,\n warnings: string[],\n): RegistryModelBinding {\n const surface = entrySurface(entry);\n const baseUrl = entryBaseUrl(entry);\n return {\n providerId,\n entry,\n ...(modelId === undefined ? {} : { modelId }),\n ...(providerModelId === undefined ? {} : { providerModelId }),\n ...(surface ? { surface } : {}),\n ...(baseUrl ? { baseUrl } : {}),\n harnessProviderId: harnessProviderName(providerId, entry),\n warnings,\n };\n}\n\n/**\n * Resolve the session's endpoint + model.\n *\n * With no selector the first entry in registry order wins and the harness\n * keeps its own default model — exactly what an absent `model` meant before\n * the registry existed. Returns `undefined` when no entry can serve a model\n * (an empty, fully-disabled or voice-only registry).\n */\nexport function resolveRegistryBinding(\n session: EnvDriverSession,\n): RegistryModelBinding | undefined {\n const entries = selectableEntries(session.registry);\n if (entries.length === 0) return undefined;\n\n const selector = session.modelRef?.trim();\n if (!selector) {\n const [providerId, entry] = entries[0];\n return describeBinding(providerId, entry, undefined, undefined, []);\n }\n\n // A selector that is exactly an entry id names the endpoint and nothing\n // else: the harness keeps its own default model. `parseModelRef` would read\n // it as a bare *model* id and fall back to registry order.\n const named = entries.find(([id]) => id === selector);\n if (named) return describeBinding(named[0], named[1], undefined, undefined, []);\n\n const resolved = parseModelRef(selector, session.registry, session.roles);\n if (!resolved) return undefined;\n const match = entries.find(([id]) => id === resolved.providerId);\n if (!match) return undefined;\n return describeBinding(\n match[0],\n match[1],\n resolved.modelId,\n resolved.providerModelId,\n resolved.warnings,\n );\n}\n\n/**\n * Every credential a `credentials-n` harness may use: one variable per\n * enabled registry entry. OpenCode, Goose and Continue have always received\n * *all* of them, not just the selected endpoint's, because they route across\n * providers inside a single session.\n */\nexport function credentialsForEveryProvider(session: EnvDriverSession): Record<string, string> {\n return registryCredentialEnv(session.registry, { env: session.lookupEnv });\n}\n\n/**\n * Throw when the bound entry speaks a wire surface this driver cannot.\n *\n * The message names the offending surface and lists the ones the harness does\n * speak (`BUILTIN_DRIVER_CATALOG[driverId].surfaces`). An entry that declares\n * no surface and names no preset is not judged — there is nothing to compare.\n */\nexport function assertDriverSpeaksSurface(\n driverId: string,\n productName: string,\n binding: RegistryModelBinding,\n): void {\n const supported = BUILTIN_DRIVER_CATALOG[driverId]?.surfaces;\n if (!supported || supported.length === 0) return;\n const surface = binding.surface;\n if (!surface || supported.includes(surface)) return;\n throw new Error(\n `${productName} cannot speak the '${surface}' surface of AI provider entry ` +\n `'${binding.providerId}'. ${productName} speaks: ${supported.join(\", \")}. ` +\n `Point this session's model at an entry with one of those surfaces, ` +\n `or run it on a driver that speaks '${surface}'.`,\n );\n}\n\n/**\n * The models a `credentials-n` harness can be pointed at, straight from the\n * registry: every enabled entry's mapped ids, namespaced the way the harness\n * takes them (`-m <provider>/<model>`).\n *\n * These harnesses have no model-list endpoint of their own — OpenCode reads\n * models.dev, Goose and Continue read their config — so the registry is the\n * only list that describes *this* session's reachable models, and it needs no\n * network call to produce.\n */\nexport function registryModelEntries(session: EnvDriverSession): ModelEntry[] {\n const out: ModelEntry[] = [];\n const seen = new Set<string>();\n for (const [providerId, entry] of selectableEntries(session.registry)) {\n const harnessId = harnessProviderName(providerId, entry);\n const label = entry.label ?? providerId;\n for (const [logicalId, providerModelId] of entryModelIds(entry)) {\n const id = `${harnessId}/${providerModelId}`;\n if (seen.has(id)) continue;\n seen.add(id);\n out.push({ id, name: `${label} ${logicalId}` });\n }\n }\n return out;\n}\n\n/**\n * Resolve the binding and enforce the surface — what a `single`-plurality\n * driver does at start.\n *\n * The registry is authoritative: pointing the driver at an entry it cannot\n * speak throws rather than silently running somewhere else. `undefined` when\n * the session configured no endpoint at all, which leaves the driver on its\n * own native auth.\n */\nexport function bindSingleProviderEntry(\n driverId: string,\n productName: string,\n session: EnvDriverSession,\n): RegistryModelBinding | undefined {\n const binding = resolveRegistryBinding(session);\n if (!binding) return undefined;\n assertDriverSpeaksSurface(driverId, productName, binding);\n return binding;\n}\n\n/**\n * The `<provider>/<model>` selector a `credentials-n` harness takes on its\n * command line (`opencode -m`). `undefined` when no model was selected — the\n * harness then uses its own default rather than being handed a bare provider.\n */\nexport function harnessModelSelector(binding: RegistryModelBinding): string | undefined {\n if (!binding.providerModelId) return undefined;\n return `${binding.harnessProviderId}/${binding.providerModelId}`;\n}\n\n/**\n * Continue's model selection is a **role binding**, not a flag: `cn` has no\n * `--model` option (only `--config <slug>`), and its `config.yaml` binds each\n * model to roles (`chat`, `edit`, `apply`, …). This is the binding for the\n * role a headless `cn -p` turn runs as, and the shape its generated\n * `config.yaml` is rendered from.\n *\n * `apiKeyEnv` is a variable *name*: the secret travels in the child\n * environment, never in a rendered config.\n */\nexport interface ContinueRoleBinding {\n /** Continue role this model serves. A headless prompt is a `chat` turn. */\n role: \"chat\";\n /** Registry id of the entry. */\n providerId: string;\n /** Provider name Continue knows the endpoint by. */\n provider: string;\n /** Provider-side model id. */\n model?: string;\n /** Endpoint, when the entry states one, spelled the way Continue's `apiBase` wants it. */\n apiBase?: string;\n /** Env var holding the credential — the name, never the value. */\n apiKeyEnv: string;\n}\n\n/**\n * Map the session's chosen endpoint onto the Continue role a headless turn\n * runs as. `undefined` when the session configured no endpoint — `cn` then\n * runs against whatever its own `config.yaml` / Hub login provides.\n */\nexport function continueRoleBinding(session: EnvDriverSession): ContinueRoleBinding | undefined {\n const binding = resolveRegistryBinding(session);\n if (!binding) return undefined;\n return {\n role: \"chat\",\n providerId: binding.providerId,\n provider: binding.harnessProviderId,\n ...(binding.providerModelId ? { model: binding.providerModelId } : {}),\n ...(binding.baseUrl\n ? { apiBase: versionedAnthropicBaseUrl(binding.baseUrl, binding.surface) }\n : {}),\n apiKeyEnv: providerCredentialEnvName(binding.providerId),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../bridge/src/provider-materialize/env-drivers.ts"],"names":[],"mappings":";;;;AAyEO,SAAS,uBAAA,CACd,MAAA,EACA,UAAA,GAAiD,OAAA,CAAQ,GAAA,EACvC;AAClB,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,MAAA,CAAO,QAAA,IAAY,eAAA,CAAgB,EAAE,CAAA;AAAA,IAC/C,WAAW,EAAE,GAAG,UAAA,EAAY,GAAG,OAAO,GAAA,EAAI;AAAA,IAC1C,GAAI,OAAO,QAAA,GAAW,EAAE,UAAU,MAAA,CAAO,QAAA,KAAa,EAAC;AAAA,IACvD,GAAI,OAAO,KAAA,GAAQ,EAAE,OAAO,MAAA,CAAO,KAAA,KAAU;AAAC,GAChD;AACF;AA2BO,SAAS,aAAa,KAAA,EAA0D;AACrF,EAAA,IAAI,KAAA,CAAM,OAAA,EAAS,OAAO,KAAA,CAAM,OAAA;AAChC,EAAA,OAAO,MAAM,MAAA,GAAS,iBAAA,CAAkB,KAAA,CAAM,MAAM,GAAG,OAAA,GAAU,MAAA;AACnE;AAcO,SAAS,aAAa,KAAA,EAA+C;AAC1E,EAAA,MAAM,QAAA,GACJ,mBAAA,CAAoB,KAAK,CAAA,KACxB,KAAA,CAAM,SAAS,iBAAA,CAAkB,KAAA,CAAM,MAAM,CAAA,EAAG,QAAA,GAAW,MAAA,CAAA;AAC9D,EAAA,OAAO,qBAAA,CAAsB,QAAA,EAAU,YAAA,CAAa,KAAK,CAAC,CAAA;AAC5D;AASO,SAAS,yBAAA,CACd,SACA,OAAA,EACQ;AACR,EAAA,IAAI,OAAA,KAAY,sBAAsB,OAAO,OAAA;AAE7C,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAO,CAAA;AAC3B,IAAA,GAAA,CAAI,WAAW,CAAA,EAAG,GAAA,CAAI,SAAS,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAC,CAAA,GAAA,CAAA;AAClD,IAAA,OAAO,IAAI,QAAA,EAAS;AAAA,EACtB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,GAAG,OAAO,CAAA,GAAA,CAAA;AAAA,EACnB;AACF;AAcO,SAAS,uBAAuB,KAAA,EAAoC;AACzE,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA,GAAS,iBAAA,CAAkB,KAAA,CAAM,MAAM,CAAA,GAAI,MAAA;AAChE,EAAA,IAAI,CAAC,QAAQ,OAAO,KAAA;AACpB,EAAA,OAAO,YAAA,CAAa,KAAK,CAAA,KAAM,qBAAA,CAAsB,OAAO,QAAA,EAAU,YAAA,CAAa,KAAK,CAAC,CAAA;AAC3F;AAaO,SAAS,mBAAA,CAAoB,YAAoB,KAAA,EAAmC;AACzF,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA,GAAS,iBAAA,CAAkB,KAAA,CAAM,MAAM,CAAA,GAAI,MAAA;AAChE,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,sBAAA,CAAuB,KAAK,GAAG,OAAO,UAAA;AACtD,EAAA,OAAO,MAAA,CAAO,EAAA;AAChB;AAQO,SAAS,kBACd,QAAA,EACqC;AACrC,EAAA,OAAO,eAAA,CAAgB,QAAQ,CAAA,CAAE,MAAA;AAAA,IAC/B,CAAC,IAAA,KAAA,CACE,IAAA,CAAK,CAAC,EAAE,IAAA,KAAS,KAAA,IAAS,IAAA,CAAK,CAAC,EAAE,IAAA,KAAS,OAAA,KAAY,cAAA,CAAe,IAAA,CAAK,CAAC,CAAC;AAAA,GAClF;AACF;AAOO,SAAS,cAAc,KAAA,EAAoD;AAChF,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,GAAG,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,SAAA,IAAa,EAAE,CAAA;AAAA,IACpC,GAAG,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,YAAA,IAAgB,EAAE,CAAA,CAAE,MAAA,CAAO,CAAC,OAAO,EAAE,EAAA,KAAO,KAAA,CAAM,SAAA,IAAa,EAAC,CAAA,CAAG;AAAA,GAC1F;AACA,EAAA,OAAO,UAAA,CAAW,GAAA,CAAI,CAAC,EAAA,KAAO,CAAC,EAAA,EAAI,KAAA,CAAM,SAAA,GAAY,EAAE,CAAA,IAAK,EAAE,CAAC,CAAA;AACjE;AAEA,SAAS,eAAA,CACP,UAAA,EACA,KAAA,EACA,OAAA,EACA,iBACA,QAAA,EACsB;AACtB,EAAA,MAAM,OAAA,GAAU,aAAa,KAAK,CAAA;AAClC,EAAA,MAAM,OAAA,GAAU,aAAa,KAAK,CAAA;AAClC,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA,KAAA;AAAA,IACA,GAAI,OAAA,KAAY,MAAA,GAAY,EAAC,GAAI,EAAE,OAAA,EAAQ;AAAA,IAC3C,GAAI,eAAA,KAAoB,MAAA,GAAY,EAAC,GAAI,EAAE,eAAA,EAAgB;AAAA,IAC3D,GAAI,OAAA,GAAU,EAAE,OAAA,KAAY,EAAC;AAAA,IAC7B,GAAI,OAAA,GAAU,EAAE,OAAA,KAAY,EAAC;AAAA,IAC7B,iBAAA,EAAmB,mBAAA,CAAoB,UAAA,EAAY,KAAK,CAAA;AAAA,IACxD;AAAA,GACF;AACF;AAUO,SAAS,uBACd,OAAA,EACkC;AAClC,EAAA,MAAM,OAAA,GAAU,iBAAA,CAAkB,OAAA,CAAQ,QAAQ,CAAA;AAClD,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAEjC,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,QAAA,EAAU,IAAA,EAAK;AACxC,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,CAAC,UAAA,EAAY,KAAK,CAAA,GAAI,QAAQ,CAAC,CAAA;AACrC,IAAA,OAAO,gBAAgB,UAAA,EAAY,KAAA,EAAO,MAAA,EAAW,MAAA,EAAW,EAAE,CAAA;AAAA,EACpE;AAKA,EAAA,MAAM,KAAA,GAAQ,QAAQ,IAAA,CAAK,CAAC,CAAC,EAAE,CAAA,KAAM,OAAO,QAAQ,CAAA;AACpD,EAAA,IAAI,KAAA,EAAO,OAAO,eAAA,CAAgB,KAAA,CAAM,CAAC,CAAA,EAAG,KAAA,CAAM,CAAC,CAAA,EAAG,MAAA,EAAW,MAAA,EAAW,EAAE,CAAA;AAE9E,EAAA,MAAM,WAAW,aAAA,CAAc,QAAA,EAAU,OAAA,CAAQ,QAAA,EAAU,QAAQ,KAAK,CAAA;AACxE,EAAA,IAAI,CAAC,UAAU,OAAO,MAAA;AACtB,EAAA,MAAM,KAAA,GAAQ,QAAQ,IAAA,CAAK,CAAC,CAAC,EAAE,CAAA,KAAM,EAAA,KAAO,QAAA,CAAS,UAAU,CAAA;AAC/D,EAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AACnB,EAAA,OAAO,eAAA;AAAA,IACL,MAAM,CAAC,CAAA;AAAA,IACP,MAAM,CAAC,CAAA;AAAA,IACP,QAAA,CAAS,OAAA;AAAA,IACT,QAAA,CAAS,eAAA;AAAA,IACT,QAAA,CAAS;AAAA,GACX;AACF;AAQO,SAAS,4BAA4B,OAAA,EAAmD;AAC7F,EAAA,OAAO,sBAAsB,OAAA,CAAQ,QAAA,EAAU,EAAE,GAAA,EAAK,OAAA,CAAQ,WAAW,CAAA;AAC3E;AASO,SAAS,yBAAA,CACd,QAAA,EACA,WAAA,EACA,OAAA,EACM;AACN,EAAA,MAAM,SAAA,GAAY,sBAAA,CAAuB,QAAQ,CAAA,EAAG,QAAA;AACpD,EAAA,IAAI,CAAC,SAAA,IAAa,SAAA,CAAU,MAAA,KAAW,CAAA,EAAG;AAC1C,EAAA,MAAM,UAAU,OAAA,CAAQ,OAAA;AACxB,EAAA,IAAI,CAAC,OAAA,IAAW,SAAA,CAAU,QAAA,CAAS,OAAO,CAAA,EAAG;AAC7C,EAAA,MAAM,IAAI,KAAA;AAAA,IACR,CAAA,EAAG,WAAW,CAAA,mBAAA,EAAsB,OAAO,mCACrC,OAAA,CAAQ,UAAU,CAAA,GAAA,EAAM,WAAW,YAAY,SAAA,CAAU,IAAA,CAAK,IAAI,CAAC,2GAEjC,OAAO,CAAA,EAAA;AAAA,GACjD;AACF;AAYO,SAAS,qBAAqB,OAAA,EAAyC;AAC5E,EAAA,MAAM,MAAoB,EAAC;AAC3B,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,KAAA,MAAW,CAAC,UAAA,EAAY,KAAK,KAAK,iBAAA,CAAkB,OAAA,CAAQ,QAAQ,CAAA,EAAG;AACrE,IAAA,MAAM,SAAA,GAAY,mBAAA,CAAoB,UAAA,EAAY,KAAK,CAAA;AACvD,IAAA,MAAM,KAAA,GAAQ,MAAM,KAAA,IAAS,UAAA;AAC7B,IAAA,KAAA,MAAW,CAAC,SAAA,EAAW,eAAe,CAAA,IAAK,aAAA,CAAc,KAAK,CAAA,EAAG;AAC/D,MAAA,MAAM,EAAA,GAAK,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,eAAe,CAAA,CAAA;AAC1C,MAAA,IAAI,IAAA,CAAK,GAAA,CAAI,EAAE,CAAA,EAAG;AAClB,MAAA,IAAA,CAAK,IAAI,EAAE,CAAA;AACX,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,IAAA,EAAM,GAAG,KAAK,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAAI,CAAA;AAAA,IAChD;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;AAWO,SAAS,uBAAA,CACd,QAAA,EACA,WAAA,EACA,OAAA,EACkC;AAClC,EAAA,MAAM,OAAA,GAAU,uBAAuB,OAAO,CAAA;AAC9C,EAAA,IAAI,CAAC,SAAS,OAAO,MAAA;AACrB,EAAA,yBAAA,CAA0B,QAAA,EAAU,aAAa,OAAO,CAAA;AACxD,EAAA,OAAO,OAAA;AACT;AAOO,SAAS,qBAAqB,OAAA,EAAmD;AACtF,EAAA,IAAI,CAAC,OAAA,CAAQ,eAAA,EAAiB,OAAO,MAAA;AACrC,EAAA,OAAO,CAAA,EAAG,OAAA,CAAQ,iBAAiB,CAAA,CAAA,EAAI,QAAQ,eAAe,CAAA,CAAA;AAChE;AAgCO,SAAS,oBAAoB,OAAA,EAA4D;AAC9F,EAAA,MAAM,OAAA,GAAU,uBAAuB,OAAO,CAAA;AAC9C,EAAA,IAAI,CAAC,SAAS,OAAO,MAAA;AACrB,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,MAAA;AAAA,IACN,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,UAAU,OAAA,CAAQ,iBAAA;AAAA,IAClB,GAAI,QAAQ,eAAA,GAAkB,EAAE,OAAO,OAAA,CAAQ,eAAA,KAAoB,EAAC;AAAA,IACpE,GAAI,OAAA,CAAQ,OAAA,GACR,EAAE,OAAA,EAAS,yBAAA,CAA0B,OAAA,CAAQ,OAAA,EAAS,OAAA,CAAQ,OAAO,CAAA,EAAE,GACvE,EAAC;AAAA,IACL,SAAA,EAAW,yBAAA,CAA0B,OAAA,CAAQ,UAAU;AAAA,GACzD;AACF","file":"chunk-CPWLNZGJ.js","sourcesContent":["/**\n * Registry adapter for the **env-shaped CLI drivers** — Gemini, Qwen, OpenCode,\n * Goose and Continue (§2.3).\n *\n * These harnesses take their endpoint from the environment rather than from a\n * config file, so the adapter's job is three things: resolve which registry\n * entry the session's model selector names, refuse at start when that entry\n * speaks a wire surface the harness cannot, and hand the driver the\n * provider-side model id it must put on the command line.\n *\n * Two pluralities meet here (`BUILTIN_DRIVER_CATALOG.providerPlurality`):\n *\n * - `single` — Gemini and Qwen address exactly one endpoint. The bound entry\n * supplies the credential *and* the base URL, and a surface mismatch is\n * fatal: a Gemini CLI pointed at an `openai-completions` endpoint cannot\n * work, and failing at start names the surface instead of leaving the user\n * with an opaque error mid-turn.\n * - `credentials-n` — OpenCode, Goose and Continue accept every enabled\n * entry's credential at once and select one active model. The credential\n * fan-out is `registryCredentialEnv`; the active model is this module's\n * `<provider>/<model>` binding.\n *\n * Writing the per-endpoint config files those three need for *custom*\n * endpoints (`opencode.json`, Goose `custom_providers/*.json`, Continue\n * `config.yaml`) is the file half, and is deliberately not here.\n *\n * @see PROVIDER-CONFIG-PLAN.md §2.3\n */\n\nimport {\n type AIProviderLlmEntry,\n type AIProviderSurface,\n isEntryEnabled,\n type MergedAIProviderRegistry,\n mergeRegistries,\n normalizeEntryBaseUrl,\n parseModelRef,\n registryEntries,\n resolveEntryBaseUrl,\n} from \"@skaile/workspaces/core/provider-registry\";\nimport type { ModelEntry } from \"../models.js\";\nimport { getProviderPreset } from \"../provider-catalog.js\";\nimport { BUILTIN_DRIVER_CATALOG } from \"../registry.js\";\nimport type { AgentConfig } from \"../types.js\";\nimport { providerCredentialEnvName, registryCredentialEnv } from \"./credential-env.js\";\n\n/**\n * Everything a CLI driver needs to know about this session's AI providers,\n * resolved once from its {@link AgentConfig}.\n */\nexport interface EnvDriverSession {\n /** The merged registry this session may address. Empty when none was configured. */\n registry: MergedAIProviderRegistry;\n /**\n * Environment `credential.ref` lookups resolve against — the process\n * environment widened with `config.env`, which is where the session\n * boundary delivered every resolved `SKAILE_AIP_<ID>_KEY`.\n */\n lookupEnv: Record<string, string | undefined>;\n /** Model selector: `<providerId>/<modelId>`, a bare id, or `@role`. */\n modelRef?: string;\n /** Roles table an `@role` selector resolves through. */\n roles?: Record<string, string>;\n}\n\n/**\n * Resolve the session's providers once, from its {@link AgentConfig}.\n *\n * `config.env` is folded into `lookupEnv` rather than kept apart: it is part\n * of the session's environment, not an extra, and a credential or\n * `*_BASE_URL` delivered there must be visible exactly as the child will see\n * it.\n */\nexport function resolveEnvDriverSession(\n config: AgentConfig,\n processEnv: Record<string, string | undefined> = process.env,\n): EnvDriverSession {\n return {\n registry: config.registry ?? mergeRegistries([]),\n lookupEnv: { ...processEnv, ...config.env },\n ...(config.modelRef ? { modelRef: config.modelRef } : {}),\n ...(config.roles ? { roles: config.roles } : {}),\n };\n}\n\n/** One resolved endpoint + model — everything a driver needs to spawn. */\nexport interface RegistryModelBinding {\n /** Registry id of the selected entry. */\n providerId: string;\n /** The selected entry itself. */\n entry: AIProviderLlmEntry;\n /** Logical model id, after `@role` expansion and before `model_map`. */\n modelId?: string;\n /** Provider-side model id — what goes on the wire / command line. */\n providerModelId?: string;\n /** Wire protocol, from the entry or its preset. */\n surface?: AIProviderSurface;\n /** Resolved endpoint, from the entry, its transport params, or its preset. */\n baseUrl?: string;\n /**\n * The provider name the *harness* knows this endpoint by — a catalog preset\n * id for a stock endpoint, the registry id for anything custom. See\n * {@link harnessProviderName}.\n */\n harnessProviderId: string;\n /** Non-fatal notes from `parseModelRef` (dangling role, disabled provider). */\n warnings: string[];\n}\n\n/** The entry's wire surface: its own, else its preset's. */\nexport function entrySurface(entry: AIProviderLlmEntry): AIProviderSurface | undefined {\n if (entry.surface) return entry.surface;\n return entry.preset ? getProviderPreset(entry.preset)?.surface : undefined;\n}\n\n/**\n * The entry's endpoint: its literal or transport-derived URL, else its\n * preset's literal, in the canonical spelling for its surface\n * (`normalizeEntryBaseUrl`: an `anthropic-messages` endpoint is its host root,\n * so `https://api.anthropic.com/v1` reads as `https://api.anthropic.com`).\n * Transport templates that still carry `{param}` placeholders never come\n * back — `resolveEntryBaseUrl` withholds those, and a preset's template is not\n * a URL.\n *\n * Every adapter reads the endpoint here and only re-spells it for a client\n * that wants something else ({@link versionedAnthropicBaseUrl}).\n */\nexport function entryBaseUrl(entry: AIProviderLlmEntry): string | undefined {\n const resolved =\n resolveEntryBaseUrl(entry) ??\n (entry.preset ? getProviderPreset(entry.preset)?.base_url : undefined);\n return normalizeEntryBaseUrl(resolved, entrySurface(entry));\n}\n\n/**\n * An `anthropic-messages` endpoint spelled for a client that appends only\n * `/messages` — `@ai-sdk/anthropic` (OpenCode) and Continue — rather than\n * `/v1/messages` like the Claude CLI, the Anthropic SDK and Goose. `baseUrl`\n * must already be canonical ({@link entryBaseUrl}); every other surface passes\n * through unchanged.\n */\nexport function versionedAnthropicBaseUrl(\n baseUrl: string,\n surface: AIProviderSurface | undefined,\n): string {\n if (surface !== \"anthropic-messages\") return baseUrl;\n // Append to the path, not the string: a query or fragment stays at the end.\n try {\n const url = new URL(baseUrl);\n url.pathname = `${url.pathname.replace(/\\/+$/, \"\")}/v1`;\n return url.toString();\n } catch {\n return `${baseUrl}/v1`;\n }\n}\n\n/**\n * True when a `credentials-n` harness already knows this endpoint under its\n * own catalog name — the entry names a preset and did not move it somewhere\n * else. Both sides are compared canonically, so `https://api.anthropic.com/v1`\n * is still the `anthropic` preset's endpoint.\n *\n * The one rule both halves of §2.3 read: it decides the name the env half\n * puts on the command line ({@link harnessProviderName}) *and* whether the\n * file half has to describe the endpoint at all. Reading it twice is what\n * keeps `-m <name>/<model>` and the generated provider file talking about the\n * same thing.\n */\nexport function isStockCatalogEndpoint(entry: AIProviderLlmEntry): boolean {\n const preset = entry.preset ? getProviderPreset(entry.preset) : undefined;\n if (!preset) return false;\n return entryBaseUrl(entry) === normalizeEntryBaseUrl(preset.base_url, entrySurface(entry));\n}\n\n/**\n * The provider name to give a `credentials-n` harness (`-m <name>/<model>`,\n * `GOOSE_PROVIDER`).\n *\n * A stock catalog endpoint is named by its preset, because that is the name\n * OpenCode's models.dev list and Goose's built-in provider table already use —\n * `prod-claude: {preset: anthropic}` is still Anthropic to them. An entry with\n * an endpoint of its own is named by its registry id: no built-in table knows\n * it, so the id is what its generated provider file is keyed by (the file half\n * of §2.3).\n */\nexport function harnessProviderName(providerId: string, entry: AIProviderLlmEntry): string {\n const preset = entry.preset ? getProviderPreset(entry.preset) : undefined;\n if (!preset || !isStockCatalogEndpoint(entry)) return providerId;\n return preset.id;\n}\n\n/**\n * Enabled `llm`/`embed` entries, in registry order. Also the set the file\n * adapters render (`opencode-config.ts`, `goose-custom-providers.ts`,\n * `continue-config-yaml.ts`): the env half and the file half must agree on\n * which entries exist before they can agree on what to call them.\n */\nexport function selectableEntries(\n registry: MergedAIProviderRegistry,\n): Array<[string, AIProviderLlmEntry]> {\n return registryEntries(registry).filter(\n (pair): pair is [string, AIProviderLlmEntry] =>\n (pair[1].kind === \"llm\" || pair[1].kind === \"embed\") && isEntryEnabled(pair[1]),\n );\n}\n\n/**\n * The provider-side model ids an entry declares, as `[logicalId, providerId]`\n * pairs in declaration order: every `model_map` entry, plus every\n * `capabilities` key the map does not rename.\n */\nexport function entryModelIds(entry: AIProviderLlmEntry): Array<[string, string]> {\n const logicalIds = [\n ...Object.keys(entry.model_map ?? {}),\n ...Object.keys(entry.capabilities ?? {}).filter((id) => !(id in (entry.model_map ?? {}))),\n ];\n return logicalIds.map((id) => [id, entry.model_map?.[id] ?? id]);\n}\n\nfunction describeBinding(\n providerId: string,\n entry: AIProviderLlmEntry,\n modelId: string | undefined,\n providerModelId: string | undefined,\n warnings: string[],\n): RegistryModelBinding {\n const surface = entrySurface(entry);\n const baseUrl = entryBaseUrl(entry);\n return {\n providerId,\n entry,\n ...(modelId === undefined ? {} : { modelId }),\n ...(providerModelId === undefined ? {} : { providerModelId }),\n ...(surface ? { surface } : {}),\n ...(baseUrl ? { baseUrl } : {}),\n harnessProviderId: harnessProviderName(providerId, entry),\n warnings,\n };\n}\n\n/**\n * Resolve the session's endpoint + model.\n *\n * With no selector the first entry in registry order wins and the harness\n * keeps its own default model — exactly what an absent `model` meant before\n * the registry existed. Returns `undefined` when no entry can serve a model\n * (an empty, fully-disabled or voice-only registry).\n */\nexport function resolveRegistryBinding(\n session: EnvDriverSession,\n): RegistryModelBinding | undefined {\n const entries = selectableEntries(session.registry);\n if (entries.length === 0) return undefined;\n\n const selector = session.modelRef?.trim();\n if (!selector) {\n const [providerId, entry] = entries[0];\n return describeBinding(providerId, entry, undefined, undefined, []);\n }\n\n // A selector that is exactly an entry id names the endpoint and nothing\n // else: the harness keeps its own default model. `parseModelRef` would read\n // it as a bare *model* id and fall back to registry order.\n const named = entries.find(([id]) => id === selector);\n if (named) return describeBinding(named[0], named[1], undefined, undefined, []);\n\n const resolved = parseModelRef(selector, session.registry, session.roles);\n if (!resolved) return undefined;\n const match = entries.find(([id]) => id === resolved.providerId);\n if (!match) return undefined;\n return describeBinding(\n match[0],\n match[1],\n resolved.modelId,\n resolved.providerModelId,\n resolved.warnings,\n );\n}\n\n/**\n * Every credential a `credentials-n` harness may use: one variable per\n * enabled registry entry. OpenCode, Goose and Continue have always received\n * *all* of them, not just the selected endpoint's, because they route across\n * providers inside a single session.\n */\nexport function credentialsForEveryProvider(session: EnvDriverSession): Record<string, string> {\n return registryCredentialEnv(session.registry, { env: session.lookupEnv });\n}\n\n/**\n * Throw when the bound entry speaks a wire surface this driver cannot.\n *\n * The message names the offending surface and lists the ones the harness does\n * speak (`BUILTIN_DRIVER_CATALOG[driverId].surfaces`). An entry that declares\n * no surface and names no preset is not judged — there is nothing to compare.\n */\nexport function assertDriverSpeaksSurface(\n driverId: string,\n productName: string,\n binding: RegistryModelBinding,\n): void {\n const supported = BUILTIN_DRIVER_CATALOG[driverId]?.surfaces;\n if (!supported || supported.length === 0) return;\n const surface = binding.surface;\n if (!surface || supported.includes(surface)) return;\n throw new Error(\n `${productName} cannot speak the '${surface}' surface of AI provider entry ` +\n `'${binding.providerId}'. ${productName} speaks: ${supported.join(\", \")}. ` +\n `Point this session's model at an entry with one of those surfaces, ` +\n `or run it on a driver that speaks '${surface}'.`,\n );\n}\n\n/**\n * The models a `credentials-n` harness can be pointed at, straight from the\n * registry: every enabled entry's mapped ids, namespaced the way the harness\n * takes them (`-m <provider>/<model>`).\n *\n * These harnesses have no model-list endpoint of their own — OpenCode reads\n * models.dev, Goose and Continue read their config — so the registry is the\n * only list that describes *this* session's reachable models, and it needs no\n * network call to produce.\n */\nexport function registryModelEntries(session: EnvDriverSession): ModelEntry[] {\n const out: ModelEntry[] = [];\n const seen = new Set<string>();\n for (const [providerId, entry] of selectableEntries(session.registry)) {\n const harnessId = harnessProviderName(providerId, entry);\n const label = entry.label ?? providerId;\n for (const [logicalId, providerModelId] of entryModelIds(entry)) {\n const id = `${harnessId}/${providerModelId}`;\n if (seen.has(id)) continue;\n seen.add(id);\n out.push({ id, name: `${label} ${logicalId}` });\n }\n }\n return out;\n}\n\n/**\n * Resolve the binding and enforce the surface — what a `single`-plurality\n * driver does at start.\n *\n * The registry is authoritative: pointing the driver at an entry it cannot\n * speak throws rather than silently running somewhere else. `undefined` when\n * the session configured no endpoint at all, which leaves the driver on its\n * own native auth.\n */\nexport function bindSingleProviderEntry(\n driverId: string,\n productName: string,\n session: EnvDriverSession,\n): RegistryModelBinding | undefined {\n const binding = resolveRegistryBinding(session);\n if (!binding) return undefined;\n assertDriverSpeaksSurface(driverId, productName, binding);\n return binding;\n}\n\n/**\n * The `<provider>/<model>` selector a `credentials-n` harness takes on its\n * command line (`opencode -m`). `undefined` when no model was selected — the\n * harness then uses its own default rather than being handed a bare provider.\n */\nexport function harnessModelSelector(binding: RegistryModelBinding): string | undefined {\n if (!binding.providerModelId) return undefined;\n return `${binding.harnessProviderId}/${binding.providerModelId}`;\n}\n\n/**\n * Continue's model selection is a **role binding**, not a flag: `cn` has no\n * `--model` option (only `--config <slug>`), and its `config.yaml` binds each\n * model to roles (`chat`, `edit`, `apply`, …). This is the binding for the\n * role a headless `cn -p` turn runs as, and the shape its generated\n * `config.yaml` is rendered from.\n *\n * `apiKeyEnv` is a variable *name*: the secret travels in the child\n * environment, never in a rendered config.\n */\nexport interface ContinueRoleBinding {\n /** Continue role this model serves. A headless prompt is a `chat` turn. */\n role: \"chat\";\n /** Registry id of the entry. */\n providerId: string;\n /** Provider name Continue knows the endpoint by. */\n provider: string;\n /** Provider-side model id. */\n model?: string;\n /** Endpoint, when the entry states one, spelled the way Continue's `apiBase` wants it. */\n apiBase?: string;\n /** Env var holding the credential — the name, never the value. */\n apiKeyEnv: string;\n}\n\n/**\n * Map the session's chosen endpoint onto the Continue role a headless turn\n * runs as. `undefined` when the session configured no endpoint — `cn` then\n * runs against whatever its own `config.yaml` / Hub login provides.\n */\nexport function continueRoleBinding(session: EnvDriverSession): ContinueRoleBinding | undefined {\n const binding = resolveRegistryBinding(session);\n if (!binding) return undefined;\n return {\n role: \"chat\",\n providerId: binding.providerId,\n provider: binding.harnessProviderId,\n ...(binding.providerModelId ? { model: binding.providerModelId } : {}),\n ...(binding.baseUrl\n ? { apiBase: versionedAnthropicBaseUrl(binding.baseUrl, binding.surface) }\n : {}),\n apiKeyEnv: providerCredentialEnvName(binding.providerId),\n };\n}\n"]}
|
|
@@ -354,12 +354,13 @@ function parseFlowDefinition(data) {
|
|
|
354
354
|
}
|
|
355
355
|
}
|
|
356
356
|
if (typeof data === "object" && data !== null && Object.hasOwn(data, "schemaVersion")) {
|
|
357
|
-
const
|
|
357
|
+
const authored = Object.hasOwn(data, "version") ? data : { ...data, version: "0.1.0" };
|
|
358
|
+
const result = FlowDefinitionSchema.safeParse(authored);
|
|
358
359
|
return result.success ? success(result.data) : failure(result.error);
|
|
359
360
|
}
|
|
360
361
|
return normalizeV1(data);
|
|
361
362
|
}
|
|
362
363
|
|
|
363
364
|
export { normalizeV1, parseFlowDefinition };
|
|
364
|
-
//# sourceMappingURL=chunk-
|
|
365
|
-
//# sourceMappingURL=chunk-
|
|
365
|
+
//# sourceMappingURL=chunk-D3B36CYC.js.map
|
|
366
|
+
//# sourceMappingURL=chunk-D3B36CYC.js.map
|