@skaile/workspaces 0.8.5
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 +135 -0
- package/LICENSE +201 -0
- package/README.md +82 -0
- package/dist/asset-manager/catalog-deployer.js +4 -0
- package/dist/asset-manager/catalog-deployer.js.map +1 -0
- package/dist/asset-manager/contrib.js +4 -0
- package/dist/asset-manager/contrib.js.map +1 -0
- package/dist/asset-manager/fragments.js +4 -0
- package/dist/asset-manager/fragments.js.map +1 -0
- package/dist/asset-manager/history.js +4 -0
- package/dist/asset-manager/history.js.map +1 -0
- package/dist/asset-manager/index.js +22 -0
- package/dist/asset-manager/index.js.map +1 -0
- package/dist/asset-manager/installer.js +18 -0
- package/dist/asset-manager/installer.js.map +1 -0
- package/dist/asset-manager/renderers.js +5 -0
- package/dist/asset-manager/renderers.js.map +1 -0
- package/dist/asset-manager/scaffold.js +18 -0
- package/dist/asset-manager/scaffold.js.map +1 -0
- package/dist/asset-manager/src/catalog-deployer.d.ts +144 -0
- package/dist/asset-manager/src/catalog-deployer.d.ts.map +1 -0
- package/dist/asset-manager/src/contrib.d.ts +133 -0
- package/dist/asset-manager/src/contrib.d.ts.map +1 -0
- package/dist/asset-manager/src/fragments.d.ts +111 -0
- package/dist/asset-manager/src/fragments.d.ts.map +1 -0
- package/dist/asset-manager/src/history.d.ts +52 -0
- package/dist/asset-manager/src/history.d.ts.map +1 -0
- package/dist/asset-manager/src/index.d.ts +459 -0
- package/dist/asset-manager/src/index.d.ts.map +1 -0
- package/dist/asset-manager/src/installer.d.ts +85 -0
- package/dist/asset-manager/src/installer.d.ts.map +1 -0
- package/dist/asset-manager/src/renderers.d.ts +125 -0
- package/dist/asset-manager/src/renderers.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/index.d.ts +19 -0
- package/dist/asset-manager/src/scaffold/index.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/agents.d.ts +67 -0
- package/dist/asset-manager/src/scaffold/layers/agents.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/base.d.ts +17 -0
- package/dist/asset-manager/src/scaffold/layers/base.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/connectors.d.ts +18 -0
- package/dist/asset-manager/src/scaffold/layers/connectors.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/container.d.ts +16 -0
- package/dist/asset-manager/src/scaffold/layers/container.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/driver-target.d.ts +17 -0
- package/dist/asset-manager/src/scaffold/layers/driver-target.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/hooks.d.ts +22 -0
- package/dist/asset-manager/src/scaffold/layers/hooks.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/skills.d.ts +31 -0
- package/dist/asset-manager/src/scaffold/layers/skills.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/template.d.ts +16 -0
- package/dist/asset-manager/src/scaffold/layers/template.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/scaffolder.d.ts +77 -0
- package/dist/asset-manager/src/scaffold/scaffolder.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/types.d.ts +241 -0
- package/dist/asset-manager/src/scaffold/types.d.ts.map +1 -0
- package/dist/base-assets/connectors/deploy/adapter.d.ts +37 -0
- package/dist/base-assets/connectors/deploy/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/deploy.js +20 -0
- package/dist/base-assets/connectors/deploy.js.map +1 -0
- package/dist/base-assets/connectors/devserver/adapter.d.ts +43 -0
- package/dist/base-assets/connectors/devserver/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/devserver.js +20 -0
- package/dist/base-assets/connectors/devserver.js.map +1 -0
- package/dist/base-assets/connectors/flow/adapter.d.ts +200 -0
- package/dist/base-assets/connectors/flow/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/adapter.js +20 -0
- package/dist/base-assets/connectors/flow/adapter.js.map +1 -0
- package/dist/base-assets/connectors/flow/engine/engine.d.ts +107 -0
- package/dist/base-assets/connectors/flow/engine/engine.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine/flow-kind-provider.d.ts +16 -0
- package/dist/base-assets/connectors/flow/engine/flow-kind-provider.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine/flow-manifest.d.ts +215 -0
- package/dist/base-assets/connectors/flow/engine/flow-manifest.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine/index.d.ts +7 -0
- package/dist/base-assets/connectors/flow/engine/index.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine/loader.d.ts +43 -0
- package/dist/base-assets/connectors/flow/engine/loader.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine/types.d.ts +298 -0
- package/dist/base-assets/connectors/flow/engine/types.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine.js +4 -0
- package/dist/base-assets/connectors/flow/engine.js.map +1 -0
- package/dist/base-assets/connectors/flow/index.d.ts +3 -0
- package/dist/base-assets/connectors/flow/index.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/prompt-fragments.d.ts +90 -0
- package/dist/base-assets/connectors/flow/prompt-fragments.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/prompt-fragments.js +4 -0
- package/dist/base-assets/connectors/flow/prompt-fragments.js.map +1 -0
- package/dist/base-assets/connectors/flow/run-flow.d.ts +159 -0
- package/dist/base-assets/connectors/flow/run-flow.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/run-flow.js +23 -0
- package/dist/base-assets/connectors/flow/run-flow.js.map +1 -0
- package/dist/base-assets/connectors/flow/stimulus-driver.d.ts +42 -0
- package/dist/base-assets/connectors/flow/stimulus-driver.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/stimulus-driver.js +4 -0
- package/dist/base-assets/connectors/flow/stimulus-driver.js.map +1 -0
- package/dist/base-assets/connectors/flow.js +20 -0
- package/dist/base-assets/connectors/flow.js.map +1 -0
- package/dist/base-assets/connectors/gmail/adapter.d.ts +31 -0
- package/dist/base-assets/connectors/gmail/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/gmail.js +20 -0
- package/dist/base-assets/connectors/gmail.js.map +1 -0
- package/dist/base-assets/connectors/mattermost/adapter.d.ts +38 -0
- package/dist/base-assets/connectors/mattermost/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/mattermost.js +20 -0
- package/dist/base-assets/connectors/mattermost.js.map +1 -0
- package/dist/base-assets/connectors/memory/adapter.d.ts +32 -0
- package/dist/base-assets/connectors/memory/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/memory.js +20 -0
- package/dist/base-assets/connectors/memory.js.map +1 -0
- package/dist/base-assets/connectors/minio/adapter.d.ts +32 -0
- package/dist/base-assets/connectors/minio/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/minio.js +20 -0
- package/dist/base-assets/connectors/minio.js.map +1 -0
- package/dist/base-assets/connectors/postgres/adapter.d.ts +40 -0
- package/dist/base-assets/connectors/postgres/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/postgres.js +20 -0
- package/dist/base-assets/connectors/postgres.js.map +1 -0
- package/dist/base-assets/connectors/redis/adapter.d.ts +39 -0
- package/dist/base-assets/connectors/redis/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/redis.js +20 -0
- package/dist/base-assets/connectors/redis.js.map +1 -0
- package/dist/base-assets/connectors/sqlite/adapter.d.ts +42 -0
- package/dist/base-assets/connectors/sqlite/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/sqlite.js +20 -0
- package/dist/base-assets/connectors/sqlite.js.map +1 -0
- package/dist/base-assets/connectors/static-server/adapter.d.ts +28 -0
- package/dist/base-assets/connectors/static-server/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/static-server.js +20 -0
- package/dist/base-assets/connectors/static-server.js.map +1 -0
- package/dist/base-assets/connectors/tunnel/adapter.d.ts +28 -0
- package/dist/base-assets/connectors/tunnel/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/tunnel.js +20 -0
- package/dist/base-assets/connectors/tunnel.js.map +1 -0
- package/dist/base-assets/connectors/xstate/adapter.d.ts +51 -0
- package/dist/base-assets/connectors/xstate/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/xstate-store/adapter.d.ts +40 -0
- package/dist/base-assets/connectors/xstate-store/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/xstate-store.js +20 -0
- package/dist/base-assets/connectors/xstate-store.js.map +1 -0
- package/dist/base-assets/connectors/xstate.js +20 -0
- package/dist/base-assets/connectors/xstate.js.map +1 -0
- package/dist/base-assets/connectors/yjs/adapter.d.ts +49 -0
- package/dist/base-assets/connectors/yjs/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/yjs.js +20 -0
- package/dist/base-assets/connectors/yjs.js.map +1 -0
- package/dist/base-assets/index.d.ts +8 -0
- package/dist/base-assets/index.d.ts.map +1 -0
- package/dist/base-assets/index.js +9 -0
- package/dist/base-assets/index.js.map +1 -0
- package/dist/base-assets/mounts/git/driver.d.ts +183 -0
- package/dist/base-assets/mounts/git/driver.d.ts.map +1 -0
- package/dist/base-assets/mounts/git.js +20 -0
- package/dist/base-assets/mounts/git.js.map +1 -0
- package/dist/base-assets/mounts/local/driver.d.ts +27 -0
- package/dist/base-assets/mounts/local/driver.d.ts.map +1 -0
- package/dist/base-assets/mounts/local.js +20 -0
- package/dist/base-assets/mounts/local.js.map +1 -0
- package/dist/base-assets/mounts/s3/driver.d.ts +27 -0
- package/dist/base-assets/mounts/s3/driver.d.ts.map +1 -0
- package/dist/base-assets/mounts/s3.js +20 -0
- package/dist/base-assets/mounts/s3.js.map +1 -0
- package/dist/base-assets/mounts/sharepoint/driver.d.ts +31 -0
- package/dist/base-assets/mounts/sharepoint/driver.d.ts.map +1 -0
- package/dist/base-assets/mounts/sharepoint.js +20 -0
- package/dist/base-assets/mounts/sharepoint.js.map +1 -0
- package/dist/base-assets/mounts/webdav/driver.d.ts +32 -0
- package/dist/base-assets/mounts/webdav/driver.d.ts.map +1 -0
- package/dist/base-assets/mounts/webdav.js +20 -0
- package/dist/base-assets/mounts/webdav.js.map +1 -0
- package/dist/bridge/drivers/claude-sdk.js +836 -0
- package/dist/bridge/drivers/claude-sdk.js.map +1 -0
- package/dist/bridge/drivers/codex.js +478 -0
- package/dist/bridge/drivers/codex.js.map +1 -0
- package/dist/bridge/drivers/echo.js +219 -0
- package/dist/bridge/drivers/echo.js.map +1 -0
- package/dist/bridge/drivers/omp.js +431 -0
- package/dist/bridge/drivers/omp.js.map +1 -0
- package/dist/bridge/index.js +9 -0
- package/dist/bridge/index.js.map +1 -0
- package/dist/bridge/src/capability-dispatch.d.ts +94 -0
- package/dist/bridge/src/capability-dispatch.d.ts.map +1 -0
- package/dist/bridge/src/drivers/claude-sdk.d.ts +224 -0
- package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -0
- package/dist/bridge/src/drivers/codex.d.ts +66 -0
- package/dist/bridge/src/drivers/codex.d.ts.map +1 -0
- package/dist/bridge/src/drivers/echo.d.ts +59 -0
- package/dist/bridge/src/drivers/echo.d.ts.map +1 -0
- package/dist/bridge/src/drivers/omp.d.ts +101 -0
- package/dist/bridge/src/drivers/omp.d.ts.map +1 -0
- package/dist/bridge/src/error-classifier.d.ts +90 -0
- package/dist/bridge/src/error-classifier.d.ts.map +1 -0
- package/dist/bridge/src/index.d.ts +10 -0
- package/dist/bridge/src/index.d.ts.map +1 -0
- package/dist/bridge/src/logger.d.ts +22 -0
- package/dist/bridge/src/logger.d.ts.map +1 -0
- package/dist/bridge/src/models.d.ts +90 -0
- package/dist/bridge/src/models.d.ts.map +1 -0
- package/dist/bridge/src/normalizer.d.ts +91 -0
- package/dist/bridge/src/normalizer.d.ts.map +1 -0
- package/dist/bridge/src/registry.d.ts +90 -0
- package/dist/bridge/src/registry.d.ts.map +1 -0
- package/dist/bridge/src/runtime.d.ts +42 -0
- package/dist/bridge/src/runtime.d.ts.map +1 -0
- package/dist/bridge/src/types.d.ts +564 -0
- package/dist/bridge/src/types.d.ts.map +1 -0
- package/dist/bridge/src/validation.d.ts +27 -0
- package/dist/bridge/src/validation.d.ts.map +1 -0
- package/dist/chunk-2M3XTMOL.js +23 -0
- package/dist/chunk-2M3XTMOL.js.map +1 -0
- package/dist/chunk-3W7Z74ZP.js +7678 -0
- package/dist/chunk-3W7Z74ZP.js.map +1 -0
- package/dist/chunk-44ZICIN4.js +418 -0
- package/dist/chunk-44ZICIN4.js.map +1 -0
- package/dist/chunk-46T37EBP.js +1517 -0
- package/dist/chunk-46T37EBP.js.map +1 -0
- package/dist/chunk-4NDWKA64.js +71 -0
- package/dist/chunk-4NDWKA64.js.map +1 -0
- package/dist/chunk-5CSE3QL2.js +546 -0
- package/dist/chunk-5CSE3QL2.js.map +1 -0
- package/dist/chunk-65CYXYUW.js +537 -0
- package/dist/chunk-65CYXYUW.js.map +1 -0
- package/dist/chunk-6UQ66R46.js +72 -0
- package/dist/chunk-6UQ66R46.js.map +1 -0
- package/dist/chunk-77CUYYO3.js +101 -0
- package/dist/chunk-77CUYYO3.js.map +1 -0
- package/dist/chunk-7H7EOIRH.js +393 -0
- package/dist/chunk-7H7EOIRH.js.map +1 -0
- package/dist/chunk-7HCGI2GW.js +385 -0
- package/dist/chunk-7HCGI2GW.js.map +1 -0
- package/dist/chunk-7HLNUSNE.js +212 -0
- package/dist/chunk-7HLNUSNE.js.map +1 -0
- package/dist/chunk-7PTP3SQJ.js +151 -0
- package/dist/chunk-7PTP3SQJ.js.map +1 -0
- package/dist/chunk-AIGWF3TJ.js +73 -0
- package/dist/chunk-AIGWF3TJ.js.map +1 -0
- package/dist/chunk-BVHFSUFM.js +343 -0
- package/dist/chunk-BVHFSUFM.js.map +1 -0
- package/dist/chunk-CCKGX5AS.js +481 -0
- package/dist/chunk-CCKGX5AS.js.map +1 -0
- package/dist/chunk-CGYEHQOX.js +117 -0
- package/dist/chunk-CGYEHQOX.js.map +1 -0
- package/dist/chunk-CSUBFKAN.js +747 -0
- package/dist/chunk-CSUBFKAN.js.map +1 -0
- package/dist/chunk-D5IH3QMH.js +112 -0
- package/dist/chunk-D5IH3QMH.js.map +1 -0
- package/dist/chunk-DOMCYP7D.js +3229 -0
- package/dist/chunk-DOMCYP7D.js.map +1 -0
- package/dist/chunk-EE3XTJ62.js +840 -0
- package/dist/chunk-EE3XTJ62.js.map +1 -0
- package/dist/chunk-EWP5HZBV.js +226 -0
- package/dist/chunk-EWP5HZBV.js.map +1 -0
- package/dist/chunk-FQHHCICT.js +591 -0
- package/dist/chunk-FQHHCICT.js.map +1 -0
- package/dist/chunk-FVTV7M76.js +30 -0
- package/dist/chunk-FVTV7M76.js.map +1 -0
- package/dist/chunk-GCRKAFH7.js +40 -0
- package/dist/chunk-GCRKAFH7.js.map +1 -0
- package/dist/chunk-GVOLEJG5.js +93 -0
- package/dist/chunk-GVOLEJG5.js.map +1 -0
- package/dist/chunk-GZWJGNNN.js +122 -0
- package/dist/chunk-GZWJGNNN.js.map +1 -0
- package/dist/chunk-HK5FRWG6.js +44 -0
- package/dist/chunk-HK5FRWG6.js.map +1 -0
- package/dist/chunk-IPUYL6TD.js +279 -0
- package/dist/chunk-IPUYL6TD.js.map +1 -0
- package/dist/chunk-JDX54X4Y.js +535 -0
- package/dist/chunk-JDX54X4Y.js.map +1 -0
- package/dist/chunk-JKNWJ64A.js +31 -0
- package/dist/chunk-JKNWJ64A.js.map +1 -0
- package/dist/chunk-JLPC4YWT.js +124 -0
- package/dist/chunk-JLPC4YWT.js.map +1 -0
- package/dist/chunk-K5GBV4SA.js +31 -0
- package/dist/chunk-K5GBV4SA.js.map +1 -0
- package/dist/chunk-KLNL7QHN.js +56 -0
- package/dist/chunk-KLNL7QHN.js.map +1 -0
- package/dist/chunk-KOVLSBXK.js +227 -0
- package/dist/chunk-KOVLSBXK.js.map +1 -0
- package/dist/chunk-KTBKW2FI.js +46 -0
- package/dist/chunk-KTBKW2FI.js.map +1 -0
- package/dist/chunk-LSGAYQ2E.js +166 -0
- package/dist/chunk-LSGAYQ2E.js.map +1 -0
- package/dist/chunk-LV2HPH3C.js +73 -0
- package/dist/chunk-LV2HPH3C.js.map +1 -0
- package/dist/chunk-MBBTBKAS.js +201 -0
- package/dist/chunk-MBBTBKAS.js.map +1 -0
- package/dist/chunk-MJHLQRJJ.js +325 -0
- package/dist/chunk-MJHLQRJJ.js.map +1 -0
- package/dist/chunk-NSBPE2FW.js +15 -0
- package/dist/chunk-NSBPE2FW.js.map +1 -0
- package/dist/chunk-NYJKXVG6.js +4166 -0
- package/dist/chunk-NYJKXVG6.js.map +1 -0
- package/dist/chunk-O4JH3KUE.js +56 -0
- package/dist/chunk-O4JH3KUE.js.map +1 -0
- package/dist/chunk-O5AE4QDX.js +67 -0
- package/dist/chunk-O5AE4QDX.js.map +1 -0
- package/dist/chunk-O7SG5PC2.js +3 -0
- package/dist/chunk-O7SG5PC2.js.map +1 -0
- package/dist/chunk-OKRUTSG7.js +87 -0
- package/dist/chunk-OKRUTSG7.js.map +1 -0
- package/dist/chunk-Q5URN24L.js +310 -0
- package/dist/chunk-Q5URN24L.js.map +1 -0
- package/dist/chunk-QT2KQHDT.js +49 -0
- package/dist/chunk-QT2KQHDT.js.map +1 -0
- package/dist/chunk-RRVQAE5D.js +51 -0
- package/dist/chunk-RRVQAE5D.js.map +1 -0
- package/dist/chunk-SZ3SIVZQ.js +78 -0
- package/dist/chunk-SZ3SIVZQ.js.map +1 -0
- package/dist/chunk-TS6VCR4W.js +195 -0
- package/dist/chunk-TS6VCR4W.js.map +1 -0
- package/dist/chunk-UMMBL7SW.js +210 -0
- package/dist/chunk-UMMBL7SW.js.map +1 -0
- package/dist/chunk-UQ6LFBPZ.js +122 -0
- package/dist/chunk-UQ6LFBPZ.js.map +1 -0
- package/dist/chunk-V37HONL7.js +526 -0
- package/dist/chunk-V37HONL7.js.map +1 -0
- package/dist/chunk-W2O5LWYU.js +3 -0
- package/dist/chunk-W2O5LWYU.js.map +1 -0
- package/dist/chunk-X5YPJV4N.js +14 -0
- package/dist/chunk-X5YPJV4N.js.map +1 -0
- package/dist/chunk-XCBG2KDC.js +23 -0
- package/dist/chunk-XCBG2KDC.js.map +1 -0
- package/dist/chunk-XEGHWFAX.js +174 -0
- package/dist/chunk-XEGHWFAX.js.map +1 -0
- package/dist/chunk-XOSBNBB6.js +155 -0
- package/dist/chunk-XOSBNBB6.js.map +1 -0
- package/dist/chunk-Y46TBPLI.js +97 -0
- package/dist/chunk-Y46TBPLI.js.map +1 -0
- package/dist/chunk-Z3RER6YZ.js +343 -0
- package/dist/chunk-Z3RER6YZ.js.map +1 -0
- package/dist/chunk-ZUQIXLRJ.js +284 -0
- package/dist/chunk-ZUQIXLRJ.js.map +1 -0
- package/dist/cli/index.js +5685 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/src/commands/asset-cmd.d.ts +15 -0
- package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -0
- package/dist/cli/src/commands/auth.d.ts +16 -0
- package/dist/cli/src/commands/auth.d.ts.map +1 -0
- package/dist/cli/src/commands/catalog-cmd.d.ts +23 -0
- package/dist/cli/src/commands/catalog-cmd.d.ts.map +1 -0
- package/dist/cli/src/commands/catalog.d.ts +92 -0
- package/dist/cli/src/commands/catalog.d.ts.map +1 -0
- package/dist/cli/src/commands/complete-resolvers.d.ts +35 -0
- package/dist/cli/src/commands/complete-resolvers.d.ts.map +1 -0
- package/dist/cli/src/commands/complete.d.ts +14 -0
- package/dist/cli/src/commands/complete.d.ts.map +1 -0
- package/dist/cli/src/commands/config.d.ts +17 -0
- package/dist/cli/src/commands/config.d.ts.map +1 -0
- package/dist/cli/src/commands/connect.d.ts +13 -0
- package/dist/cli/src/commands/connect.d.ts.map +1 -0
- package/dist/cli/src/commands/connector.d.ts +30 -0
- package/dist/cli/src/commands/connector.d.ts.map +1 -0
- package/dist/cli/src/commands/debug.d.ts +13 -0
- package/dist/cli/src/commands/debug.d.ts.map +1 -0
- package/dist/cli/src/commands/diff.d.ts +12 -0
- package/dist/cli/src/commands/diff.d.ts.map +1 -0
- package/dist/cli/src/commands/flow.d.ts +14 -0
- package/dist/cli/src/commands/flow.d.ts.map +1 -0
- package/dist/cli/src/commands/history.d.ts +12 -0
- package/dist/cli/src/commands/history.d.ts.map +1 -0
- package/dist/cli/src/commands/library-cmd.d.ts +12 -0
- package/dist/cli/src/commands/library-cmd.d.ts.map +1 -0
- package/dist/cli/src/commands/library-status.d.ts +19 -0
- package/dist/cli/src/commands/library-status.d.ts.map +1 -0
- package/dist/cli/src/commands/logs.d.ts +13 -0
- package/dist/cli/src/commands/logs.d.ts.map +1 -0
- package/dist/cli/src/commands/manage.d.ts +62 -0
- package/dist/cli/src/commands/manage.d.ts.map +1 -0
- package/dist/cli/src/commands/mcp-server.d.ts +15 -0
- package/dist/cli/src/commands/mcp-server.d.ts.map +1 -0
- package/dist/cli/src/commands/mount.d.ts +22 -0
- package/dist/cli/src/commands/mount.d.ts.map +1 -0
- package/dist/cli/src/commands/npx.d.ts +14 -0
- package/dist/cli/src/commands/npx.d.ts.map +1 -0
- package/dist/cli/src/commands/outdated.d.ts +12 -0
- package/dist/cli/src/commands/outdated.d.ts.map +1 -0
- package/dist/cli/src/commands/patch.d.ts +14 -0
- package/dist/cli/src/commands/patch.d.ts.map +1 -0
- package/dist/cli/src/commands/plugin/claude-code.d.ts +17 -0
- package/dist/cli/src/commands/plugin/claude-code.d.ts.map +1 -0
- package/dist/cli/src/commands/plugin/codex.d.ts +5 -0
- package/dist/cli/src/commands/plugin/codex.d.ts.map +1 -0
- package/dist/cli/src/commands/plugin/omp.d.ts +12 -0
- package/dist/cli/src/commands/plugin/omp.d.ts.map +1 -0
- package/dist/cli/src/commands/plugin/types.d.ts +65 -0
- package/dist/cli/src/commands/plugin/types.d.ts.map +1 -0
- package/dist/cli/src/commands/plugin.d.ts +14 -0
- package/dist/cli/src/commands/plugin.d.ts.map +1 -0
- package/dist/cli/src/commands/preset-cmd.d.ts +19 -0
- package/dist/cli/src/commands/preset-cmd.d.ts.map +1 -0
- package/dist/cli/src/commands/project.d.ts +34 -0
- package/dist/cli/src/commands/project.d.ts.map +1 -0
- package/dist/cli/src/commands/rebuild.d.ts +21 -0
- package/dist/cli/src/commands/rebuild.d.ts.map +1 -0
- package/dist/cli/src/commands/run.d.ts +68 -0
- package/dist/cli/src/commands/run.d.ts.map +1 -0
- package/dist/cli/src/commands/serve.d.ts +13 -0
- package/dist/cli/src/commands/serve.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/format.d.ts +21 -0
- package/dist/cli/src/commands/session-logs/format.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/index.d.ts +18 -0
- package/dist/cli/src/commands/session-logs/index.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/local-query.d.ts +19 -0
- package/dist/cli/src/commands/session-logs/local-query.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/local-tail.d.ts +29 -0
- package/dist/cli/src/commands/session-logs/local-tail.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/parse-time.d.ts +11 -0
- package/dist/cli/src/commands/session-logs/parse-time.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/remote-query.d.ts +26 -0
- package/dist/cli/src/commands/session-logs/remote-query.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/remote-tail.d.ts +22 -0
- package/dist/cli/src/commands/session-logs/remote-tail.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/resolve-mode.d.ts +27 -0
- package/dist/cli/src/commands/session-logs/resolve-mode.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/sqlite-row.d.ts +51 -0
- package/dist/cli/src/commands/session-logs/sqlite-row.d.ts.map +1 -0
- package/dist/cli/src/commands/session.d.ts +15 -0
- package/dist/cli/src/commands/session.d.ts.map +1 -0
- package/dist/cli/src/commands/show.d.ts +13 -0
- package/dist/cli/src/commands/show.d.ts.map +1 -0
- package/dist/cli/src/commands/source-sidecar.d.ts +6 -0
- package/dist/cli/src/commands/source-sidecar.d.ts.map +1 -0
- package/dist/cli/src/commands/source.d.ts +8 -0
- package/dist/cli/src/commands/source.d.ts.map +1 -0
- package/dist/cli/src/commands/store.d.ts +13 -0
- package/dist/cli/src/commands/store.d.ts.map +1 -0
- package/dist/cli/src/commands/tree.d.ts +12 -0
- package/dist/cli/src/commands/tree.d.ts.map +1 -0
- package/dist/cli/src/commands/update.d.ts +22 -0
- package/dist/cli/src/commands/update.d.ts.map +1 -0
- package/dist/cli/src/commands/validate.d.ts +17 -0
- package/dist/cli/src/commands/validate.d.ts.map +1 -0
- package/dist/cli/src/commands/verify.d.ts +13 -0
- package/dist/cli/src/commands/verify.d.ts.map +1 -0
- package/dist/cli/src/commands/why.d.ts +12 -0
- package/dist/cli/src/commands/why.d.ts.map +1 -0
- package/dist/cli/src/completion.d.ts +19 -0
- package/dist/cli/src/completion.d.ts.map +1 -0
- package/dist/cli/src/helpers.d.ts +54 -0
- package/dist/cli/src/helpers.d.ts.map +1 -0
- package/dist/cli/src/hooks/pre-commit-version.d.ts +10 -0
- package/dist/cli/src/hooks/pre-commit-version.d.ts.map +1 -0
- package/dist/cli/src/index.d.ts +8 -0
- package/dist/cli/src/index.d.ts.map +1 -0
- package/dist/cli/src/open-library.d.ts +101 -0
- package/dist/cli/src/open-library.d.ts.map +1 -0
- package/dist/cli/src/open-registry.d.ts +24 -0
- package/dist/cli/src/open-registry.d.ts.map +1 -0
- package/dist/cli/src/paths.d.ts +27 -0
- package/dist/cli/src/paths.d.ts.map +1 -0
- package/dist/cli/src/setup.d.ts +19 -0
- package/dist/cli/src/setup.d.ts.map +1 -0
- package/dist/cli/src/skill-walker.d.ts +31 -0
- package/dist/cli/src/skill-walker.d.ts.map +1 -0
- package/dist/cli/src/store-client.d.ts +55 -0
- package/dist/cli/src/store-client.d.ts.map +1 -0
- package/dist/client/index.js +4 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/src/client.d.ts +67 -0
- package/dist/client/src/client.d.ts.map +1 -0
- package/dist/client/src/index.d.ts +2 -0
- package/dist/client/src/index.d.ts.map +1 -0
- package/dist/connectors/config.js +14 -0
- package/dist/connectors/config.js.map +1 -0
- package/dist/connectors/index.js +20 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/rclone-config.js +4 -0
- package/dist/connectors/rclone-config.js.map +1 -0
- package/dist/connectors/rclone.js +4 -0
- package/dist/connectors/rclone.js.map +1 -0
- package/dist/connectors/src/adapters/base.d.ts +66 -0
- package/dist/connectors/src/adapters/base.d.ts.map +1 -0
- package/dist/connectors/src/cli.d.ts +16 -0
- package/dist/connectors/src/cli.d.ts.map +1 -0
- package/dist/connectors/src/config.d.ts +125 -0
- package/dist/connectors/src/config.d.ts.map +1 -0
- package/dist/connectors/src/connector-manager.d.ts +147 -0
- package/dist/connectors/src/connector-manager.d.ts.map +1 -0
- package/dist/connectors/src/connector-registry.d.ts +59 -0
- package/dist/connectors/src/connector-registry.d.ts.map +1 -0
- package/dist/connectors/src/connector-tools.d.ts +61 -0
- package/dist/connectors/src/connector-tools.d.ts.map +1 -0
- package/dist/connectors/src/connector-types.d.ts +220 -0
- package/dist/connectors/src/connector-types.d.ts.map +1 -0
- package/dist/connectors/src/credential-helper-script.d.ts +87 -0
- package/dist/connectors/src/credential-helper-script.d.ts.map +1 -0
- package/dist/connectors/src/drivers/base.d.ts +44 -0
- package/dist/connectors/src/drivers/base.d.ts.map +1 -0
- package/dist/connectors/src/index.d.ts +51 -0
- package/dist/connectors/src/index.d.ts.map +1 -0
- package/dist/connectors/src/log-buffer.d.ts +21 -0
- package/dist/connectors/src/log-buffer.d.ts.map +1 -0
- package/dist/connectors/src/managed-gitconfig.d.ts +122 -0
- package/dist/connectors/src/managed-gitconfig.d.ts.map +1 -0
- package/dist/connectors/src/mount-manager.d.ts +147 -0
- package/dist/connectors/src/mount-manager.d.ts.map +1 -0
- package/dist/connectors/src/mount-prompt.d.ts +13 -0
- package/dist/connectors/src/mount-prompt.d.ts.map +1 -0
- package/dist/connectors/src/mount-registry.d.ts +61 -0
- package/dist/connectors/src/mount-registry.d.ts.map +1 -0
- package/dist/connectors/src/mount-types.d.ts +222 -0
- package/dist/connectors/src/mount-types.d.ts.map +1 -0
- package/dist/connectors/src/npm-installer.d.ts +69 -0
- package/dist/connectors/src/npm-installer.d.ts.map +1 -0
- package/dist/connectors/src/port-pool.d.ts +25 -0
- package/dist/connectors/src/port-pool.d.ts.map +1 -0
- package/dist/connectors/src/rclone-config/index.d.ts +8 -0
- package/dist/connectors/src/rclone-config/index.d.ts.map +1 -0
- package/dist/connectors/src/rclone-config/onedrive.d.ts +47 -0
- package/dist/connectors/src/rclone-config/onedrive.d.ts.map +1 -0
- package/dist/connectors/src/rclone-config/webdav.d.ts +49 -0
- package/dist/connectors/src/rclone-config/webdav.d.ts.map +1 -0
- package/dist/connectors/src/rclone-process-manager.d.ts +104 -0
- package/dist/connectors/src/rclone-process-manager.d.ts.map +1 -0
- package/dist/connectors/src/secrets.d.ts +264 -0
- package/dist/connectors/src/secrets.d.ts.map +1 -0
- package/dist/connectors/src/shared-types.d.ts +171 -0
- package/dist/connectors/src/shared-types.d.ts.map +1 -0
- package/dist/connectors/src/watcher.d.ts +23 -0
- package/dist/connectors/src/watcher.d.ts.map +1 -0
- package/dist/connectors/src/worktree.d.ts +78 -0
- package/dist/connectors/src/worktree.d.ts.map +1 -0
- package/dist/connectors-7WS2KOSZ.js +5 -0
- package/dist/connectors-7WS2KOSZ.js.map +1 -0
- package/dist/core/discovery.js +4 -0
- package/dist/core/discovery.js.map +1 -0
- package/dist/core/driver-targets.js +4 -0
- package/dist/core/driver-targets.js.map +1 -0
- package/dist/core/framework.js +4 -0
- package/dist/core/framework.js.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logging.js +4 -0
- package/dist/core/logging.js.map +1 -0
- package/dist/core/manifest.js +5 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/core/models.js +4 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/runtime-assets.js +7 -0
- package/dist/core/runtime-assets.js.map +1 -0
- package/dist/core/src/discovery.d.ts +40 -0
- package/dist/core/src/discovery.d.ts.map +1 -0
- package/dist/core/src/driver-targets.d.ts +54 -0
- package/dist/core/src/driver-targets.d.ts.map +1 -0
- package/dist/core/src/framework.d.ts +46 -0
- package/dist/core/src/framework.d.ts.map +1 -0
- package/dist/core/src/index.d.ts +36 -0
- package/dist/core/src/index.d.ts.map +1 -0
- package/dist/core/src/lock.d.ts +69 -0
- package/dist/core/src/lock.d.ts.map +1 -0
- package/dist/core/src/logging/config.d.ts +17 -0
- package/dist/core/src/logging/config.d.ts.map +1 -0
- package/dist/core/src/logging/create-logger.d.ts +32 -0
- package/dist/core/src/logging/create-logger.d.ts.map +1 -0
- package/dist/core/src/logging/index.d.ts +16 -0
- package/dist/core/src/logging/index.d.ts.map +1 -0
- package/dist/core/src/logging/log-store.d.ts +74 -0
- package/dist/core/src/logging/log-store.d.ts.map +1 -0
- package/dist/core/src/logging/sanitize.d.ts +4 -0
- package/dist/core/src/logging/sanitize.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/no-op-sink.d.ts +9 -0
- package/dist/core/src/logging/sinks/no-op-sink.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/on-log-bridge-sink.d.ts +16 -0
- package/dist/core/src/logging/sinks/on-log-bridge-sink.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/sqlite-sink.d.ts +18 -0
- package/dist/core/src/logging/sinks/sqlite-sink.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/stdout-sink.d.ts +24 -0
- package/dist/core/src/logging/sinks/stdout-sink.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/types.d.ts +5 -0
- package/dist/core/src/logging/sinks/types.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/ws-log-sink.d.ts +24 -0
- package/dist/core/src/logging/sinks/ws-log-sink.d.ts.map +1 -0
- package/dist/core/src/manifest.d.ts +228 -0
- package/dist/core/src/manifest.d.ts.map +1 -0
- package/dist/core/src/models.d.ts +304 -0
- package/dist/core/src/models.d.ts.map +1 -0
- package/dist/core/src/patch.d.ts +59 -0
- package/dist/core/src/patch.d.ts.map +1 -0
- package/dist/core/src/repo-manager.d.ts +232 -0
- package/dist/core/src/repo-manager.d.ts.map +1 -0
- package/dist/core/src/runtime-assets.d.ts +125 -0
- package/dist/core/src/runtime-assets.d.ts.map +1 -0
- package/dist/core/src/settings.d.ts +188 -0
- package/dist/core/src/settings.d.ts.map +1 -0
- package/dist/core/src/store.d.ts +48 -0
- package/dist/core/src/store.d.ts.map +1 -0
- package/dist/core/src/workspace-config.d.ts +744 -0
- package/dist/core/src/workspace-config.d.ts.map +1 -0
- package/dist/core/src/workspace-yaml-editor.d.ts +74 -0
- package/dist/core/src/workspace-yaml-editor.d.ts.map +1 -0
- package/dist/core/store.js +5 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/workspace-config.js +6 -0
- package/dist/core/workspace-config.js.map +1 -0
- package/dist/discovery/index.js +8 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/src/asset-kind-registry.d.ts +35 -0
- package/dist/discovery/src/asset-kind-registry.d.ts.map +1 -0
- package/dist/discovery/src/builtin-providers.d.ts +37 -0
- package/dist/discovery/src/builtin-providers.d.ts.map +1 -0
- package/dist/discovery/src/discover-manifest.d.ts +41 -0
- package/dist/discovery/src/discover-manifest.d.ts.map +1 -0
- package/dist/discovery/src/discover.d.ts +92 -0
- package/dist/discovery/src/discover.d.ts.map +1 -0
- package/dist/discovery/src/hash.d.ts +45 -0
- package/dist/discovery/src/hash.d.ts.map +1 -0
- package/dist/discovery/src/index.d.ts +19 -0
- package/dist/discovery/src/index.d.ts.map +1 -0
- package/dist/discovery/src/requires-graph.d.ts +70 -0
- package/dist/discovery/src/requires-graph.d.ts.map +1 -0
- package/dist/discovery/src/source-config.d.ts +456 -0
- package/dist/discovery/src/source-config.d.ts.map +1 -0
- package/dist/discovery/src/tree-entries.d.ts +98 -0
- package/dist/discovery/src/tree-entries.d.ts.map +1 -0
- package/dist/flows-ZULSVHX5.js +7 -0
- package/dist/flows-ZULSVHX5.js.map +1 -0
- package/dist/helpers-I3SREIC3.js +4 -0
- package/dist/helpers-I3SREIC3.js.map +1 -0
- package/dist/library/index.js +9 -0
- package/dist/library/index.js.map +1 -0
- package/dist/library/src/config.d.ts +238 -0
- package/dist/library/src/config.d.ts.map +1 -0
- package/dist/library/src/index.d.ts +32 -0
- package/dist/library/src/index.d.ts.map +1 -0
- package/dist/library/src/knowledge/index.d.ts +9 -0
- package/dist/library/src/knowledge/index.d.ts.map +1 -0
- package/dist/library/src/knowledge/knowledge-kind-provider.d.ts +16 -0
- package/dist/library/src/knowledge/knowledge-kind-provider.d.ts.map +1 -0
- package/dist/library/src/knowledge/knowledge-manifest.d.ts +52 -0
- package/dist/library/src/knowledge/knowledge-manifest.d.ts.map +1 -0
- package/dist/library/src/library.d.ts +344 -0
- package/dist/library/src/library.d.ts.map +1 -0
- package/dist/library/src/local/db.d.ts +29 -0
- package/dist/library/src/local/db.d.ts.map +1 -0
- package/dist/library/src/local/library.d.ts +85 -0
- package/dist/library/src/local/library.d.ts.map +1 -0
- package/dist/library/src/local/local-catalog-source.d.ts +66 -0
- package/dist/library/src/local/local-catalog-source.d.ts.map +1 -0
- package/dist/library/src/local/schema.d.ts +783 -0
- package/dist/library/src/local/schema.d.ts.map +1 -0
- package/dist/library/src/local/sidecar-git.d.ts +104 -0
- package/dist/library/src/local/sidecar-git.d.ts.map +1 -0
- package/dist/library/src/local/sidecar-paths.d.ts +87 -0
- package/dist/library/src/local/sidecar-paths.d.ts.map +1 -0
- package/dist/library/src/local/user-library-manager.d.ts +41 -0
- package/dist/library/src/local/user-library-manager.d.ts.map +1 -0
- package/dist/library/src/migration.d.ts +38 -0
- package/dist/library/src/migration.d.ts.map +1 -0
- package/dist/library/src/pin-resolver.d.ts +45 -0
- package/dist/library/src/pin-resolver.d.ts.map +1 -0
- package/dist/library/src/preset/apply.d.ts +105 -0
- package/dist/library/src/preset/apply.d.ts.map +1 -0
- package/dist/library/src/preset/index.d.ts +13 -0
- package/dist/library/src/preset/index.d.ts.map +1 -0
- package/dist/library/src/preset/interpolate.d.ts +109 -0
- package/dist/library/src/preset/interpolate.d.ts.map +1 -0
- package/dist/library/src/preset/parse.d.ts +65 -0
- package/dist/library/src/preset/parse.d.ts.map +1 -0
- package/dist/library/src/preset/placeholders.d.ts +103 -0
- package/dist/library/src/preset/placeholders.d.ts.map +1 -0
- package/dist/library/src/preset/resolve-item.d.ts +119 -0
- package/dist/library/src/preset/resolve-item.d.ts.map +1 -0
- package/dist/library/src/preset/upgrade.d.ts +96 -0
- package/dist/library/src/preset/upgrade.d.ts.map +1 -0
- package/dist/library/src/remote/cache.d.ts +150 -0
- package/dist/library/src/remote/cache.d.ts.map +1 -0
- package/dist/library/src/remote/index.d.ts +13 -0
- package/dist/library/src/remote/index.d.ts.map +1 -0
- package/dist/library/src/remote/remote-catalog-source.d.ts +199 -0
- package/dist/library/src/remote/remote-catalog-source.d.ts.map +1 -0
- package/dist/library/src/remote/rest-catalog-source.d.ts +135 -0
- package/dist/library/src/remote/rest-catalog-source.d.ts.map +1 -0
- package/dist/library/src/sync/driver.d.ts +19 -0
- package/dist/library/src/sync/driver.d.ts.map +1 -0
- package/dist/library/src/sync/git-driver.d.ts +21 -0
- package/dist/library/src/sync/git-driver.d.ts.map +1 -0
- package/dist/library/src/sync/local-driver.d.ts +19 -0
- package/dist/library/src/sync/local-driver.d.ts.map +1 -0
- package/dist/library/src/sync/manifest-writeback.d.ts +23 -0
- package/dist/library/src/sync/manifest-writeback.d.ts.map +1 -0
- package/dist/library/src/sync/store-driver.d.ts +21 -0
- package/dist/library/src/sync/store-driver.d.ts.map +1 -0
- package/dist/library/src/user-library.d.ts +149 -0
- package/dist/library/src/user-library.d.ts.map +1 -0
- package/dist/library/src/workspace-config.d.ts +451 -0
- package/dist/library/src/workspace-config.d.ts.map +1 -0
- package/dist/mounts-PQLFYD2C.js +5 -0
- package/dist/mounts-PQLFYD2C.js.map +1 -0
- package/dist/open-library-N5T5HRTS.js +12 -0
- package/dist/open-library-N5T5HRTS.js.map +1 -0
- package/dist/paths-FKKGS6BA.js +4 -0
- package/dist/paths-FKKGS6BA.js.map +1 -0
- package/dist/plugins/index.js +4 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/src/asset-kind-provider.d.ts +99 -0
- package/dist/plugins/src/asset-kind-provider.d.ts.map +1 -0
- package/dist/plugins/src/asset-kind-registry.d.ts +106 -0
- package/dist/plugins/src/asset-kind-registry.d.ts.map +1 -0
- package/dist/plugins/src/catalog-source.d.ts +87 -0
- package/dist/plugins/src/catalog-source.d.ts.map +1 -0
- package/dist/plugins/src/index.d.ts +8 -0
- package/dist/plugins/src/index.d.ts.map +1 -0
- package/dist/plugins/src/secrets-provider.d.ts +143 -0
- package/dist/plugins/src/secrets-provider.d.ts.map +1 -0
- package/dist/provider-QXKEDXWJ.js +174 -0
- package/dist/provider-QXKEDXWJ.js.map +1 -0
- package/dist/resolver/index.js +4 -0
- package/dist/resolver/index.js.map +1 -0
- package/dist/resolver/src/index.d.ts +6 -0
- package/dist/resolver/src/index.d.ts.map +1 -0
- package/dist/resolver/src/parser.d.ts +47 -0
- package/dist/resolver/src/parser.d.ts.map +1 -0
- package/dist/resolver/src/preamble.d.ts +32 -0
- package/dist/resolver/src/preamble.d.ts.map +1 -0
- package/dist/resolver/src/types.d.ts +279 -0
- package/dist/resolver/src/types.d.ts.map +1 -0
- package/dist/resolver/src/validator.d.ts +55 -0
- package/dist/resolver/src/validator.d.ts.map +1 -0
- package/dist/resolver/src/version.d.ts +50 -0
- package/dist/resolver/src/version.d.ts.map +1 -0
- package/dist/runner/index.js +34 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/runner/src/agent.d.ts +52 -0
- package/dist/runner/src/agent.d.ts.map +1 -0
- package/dist/runner/src/builtin-capabilities.d.ts +23 -0
- package/dist/runner/src/builtin-capabilities.d.ts.map +1 -0
- package/dist/runner/src/capability-registry.d.ts +212 -0
- package/dist/runner/src/capability-registry.d.ts.map +1 -0
- package/dist/runner/src/capability-roundtrip.d.ts +90 -0
- package/dist/runner/src/capability-roundtrip.d.ts.map +1 -0
- package/dist/runner/src/compaction/index.d.ts +6 -0
- package/dist/runner/src/compaction/index.d.ts.map +1 -0
- package/dist/runner/src/compaction/orchestrator.d.ts +99 -0
- package/dist/runner/src/compaction/orchestrator.d.ts.map +1 -0
- package/dist/runner/src/compaction/prompt.d.ts +15 -0
- package/dist/runner/src/compaction/prompt.d.ts.map +1 -0
- package/dist/runner/src/compaction/strategy.d.ts +41 -0
- package/dist/runner/src/compaction/strategy.d.ts.map +1 -0
- package/dist/runner/src/composition/bootstrap.d.ts +73 -0
- package/dist/runner/src/composition/bootstrap.d.ts.map +1 -0
- package/dist/runner/src/composition/compile.d.ts +84 -0
- package/dist/runner/src/composition/compile.d.ts.map +1 -0
- package/dist/runner/src/composition/index.d.ts +14 -0
- package/dist/runner/src/composition/index.d.ts.map +1 -0
- package/dist/runner/src/composition/resolve.d.ts +53 -0
- package/dist/runner/src/composition/resolve.d.ts.map +1 -0
- package/dist/runner/src/composition/types.d.ts +103 -0
- package/dist/runner/src/composition/types.d.ts.map +1 -0
- package/dist/runner/src/config.d.ts +11 -0
- package/dist/runner/src/config.d.ts.map +1 -0
- package/dist/runner/src/context.d.ts +16 -0
- package/dist/runner/src/context.d.ts.map +1 -0
- package/dist/runner/src/define-capability.d.ts +153 -0
- package/dist/runner/src/define-capability.d.ts.map +1 -0
- package/dist/runner/src/environment.d.ts +21 -0
- package/dist/runner/src/environment.d.ts.map +1 -0
- package/dist/runner/src/file-changed-rewriter.d.ts +35 -0
- package/dist/runner/src/file-changed-rewriter.d.ts.map +1 -0
- package/dist/runner/src/index.d.ts +22 -0
- package/dist/runner/src/index.d.ts.map +1 -0
- package/dist/runner/src/logging-bootstrap.d.ts +92 -0
- package/dist/runner/src/logging-bootstrap.d.ts.map +1 -0
- package/dist/runner/src/manifest.d.ts +33 -0
- package/dist/runner/src/manifest.d.ts.map +1 -0
- package/dist/runner/src/markdown-stream.d.ts +22 -0
- package/dist/runner/src/markdown-stream.d.ts.map +1 -0
- package/dist/runner/src/mixin-resolver.d.ts +61 -0
- package/dist/runner/src/mixin-resolver.d.ts.map +1 -0
- package/dist/runner/src/prompt-assembly.d.ts +42 -0
- package/dist/runner/src/prompt-assembly.d.ts.map +1 -0
- package/dist/runner/src/recipe-resolver.d.ts +18 -0
- package/dist/runner/src/recipe-resolver.d.ts.map +1 -0
- package/dist/runner/src/recipe-templating.d.ts +20 -0
- package/dist/runner/src/recipe-templating.d.ts.map +1 -0
- package/dist/runner/src/refresh-flag-dispatcher.d.ts +54 -0
- package/dist/runner/src/refresh-flag-dispatcher.d.ts.map +1 -0
- package/dist/runner/src/resource-handler.d.ts +22 -0
- package/dist/runner/src/resource-handler.d.ts.map +1 -0
- package/dist/runner/src/resources.d.ts +102 -0
- package/dist/runner/src/resources.d.ts.map +1 -0
- package/dist/runner/src/runner-capabilities.d.ts +120 -0
- package/dist/runner/src/runner-capabilities.d.ts.map +1 -0
- package/dist/runner/src/serve-credentials.d.ts +50 -0
- package/dist/runner/src/serve-credentials.d.ts.map +1 -0
- package/dist/runner/src/serve.d.ts +154 -0
- package/dist/runner/src/serve.d.ts.map +1 -0
- package/dist/runner/src/session-builder.d.ts +213 -0
- package/dist/runner/src/session-builder.d.ts.map +1 -0
- package/dist/runner/src/session-stimulus.d.ts +79 -0
- package/dist/runner/src/session-stimulus.d.ts.map +1 -0
- package/dist/runner/src/session.d.ts +139 -0
- package/dist/runner/src/session.d.ts.map +1 -0
- package/dist/runner/src/workspace-migration.d.ts +54 -0
- package/dist/runner/src/workspace-migration.d.ts.map +1 -0
- package/dist/sdk/asset-manager.js +22 -0
- package/dist/sdk/asset-manager.js.map +1 -0
- package/dist/sdk/bridge.js +9 -0
- package/dist/sdk/bridge.js.map +1 -0
- package/dist/sdk/client.js +4 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/core.js +13 -0
- package/dist/sdk/core.js.map +1 -0
- package/dist/sdk/flow.js +4 -0
- package/dist/sdk/flow.js.map +1 -0
- package/dist/sdk/index.js +339 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/resolver.js +4 -0
- package/dist/sdk/resolver.js.map +1 -0
- package/dist/sdk/runner.js +34 -0
- package/dist/sdk/runner.js.map +1 -0
- package/dist/sdk/session.js +5 -0
- package/dist/sdk/session.js.map +1 -0
- package/dist/sdk/src/agent-session.d.ts +67 -0
- package/dist/sdk/src/agent-session.d.ts.map +1 -0
- package/dist/sdk/src/asset-manager/index.d.ts +2 -0
- package/dist/sdk/src/asset-manager/index.d.ts.map +1 -0
- package/dist/sdk/src/bridge/index.d.ts +2 -0
- package/dist/sdk/src/bridge/index.d.ts.map +1 -0
- package/dist/sdk/src/client/index.d.ts +2 -0
- package/dist/sdk/src/client/index.d.ts.map +1 -0
- package/dist/sdk/src/core/index.d.ts +2 -0
- package/dist/sdk/src/core/index.d.ts.map +1 -0
- package/dist/sdk/src/factory.d.ts +19 -0
- package/dist/sdk/src/factory.d.ts.map +1 -0
- package/dist/sdk/src/flow/index.d.ts +2 -0
- package/dist/sdk/src/flow/index.d.ts.map +1 -0
- package/dist/sdk/src/index.d.ts +7 -0
- package/dist/sdk/src/index.d.ts.map +1 -0
- package/dist/sdk/src/local-runtime.d.ts +51 -0
- package/dist/sdk/src/local-runtime.d.ts.map +1 -0
- package/dist/sdk/src/resolver/index.d.ts +2 -0
- package/dist/sdk/src/resolver/index.d.ts.map +1 -0
- package/dist/sdk/src/runner/index.d.ts +2 -0
- package/dist/sdk/src/runner/index.d.ts.map +1 -0
- package/dist/sdk/src/session/index.d.ts +2 -0
- package/dist/sdk/src/session/index.d.ts.map +1 -0
- package/dist/sdk/src/store/index.d.ts +2 -0
- package/dist/sdk/src/store/index.d.ts.map +1 -0
- package/dist/sdk/src/telemetry/index.d.ts +2 -0
- package/dist/sdk/src/telemetry/index.d.ts.map +1 -0
- package/dist/sdk/src/transport/index.d.ts +2 -0
- package/dist/sdk/src/transport/index.d.ts.map +1 -0
- package/dist/sdk/src/transport/ws/client.d.ts +2 -0
- package/dist/sdk/src/transport/ws/client.d.ts.map +1 -0
- package/dist/sdk/src/transport/ws/index.d.ts +2 -0
- package/dist/sdk/src/transport/ws/index.d.ts.map +1 -0
- package/dist/sdk/src/transport/ws/server.d.ts +2 -0
- package/dist/sdk/src/transport/ws/server.d.ts.map +1 -0
- package/dist/sdk/src/transport.d.ts +31 -0
- package/dist/sdk/src/transport.d.ts.map +1 -0
- package/dist/sdk/src/types/index.d.ts +2 -0
- package/dist/sdk/src/types/index.d.ts.map +1 -0
- package/dist/sdk/src/types.d.ts +140 -0
- package/dist/sdk/src/types.d.ts.map +1 -0
- package/dist/sdk/src/workspace.d.ts +32 -0
- package/dist/sdk/src/workspace.d.ts.map +1 -0
- package/dist/sdk/store.js +4 -0
- package/dist/sdk/store.js.map +1 -0
- package/dist/sdk/telemetry.js +4 -0
- package/dist/sdk/telemetry.js.map +1 -0
- package/dist/sdk/transport/ws/client.js +4 -0
- package/dist/sdk/transport/ws/client.js.map +1 -0
- package/dist/sdk/transport/ws/server.js +4 -0
- package/dist/sdk/transport/ws/server.js.map +1 -0
- package/dist/sdk/transport/ws.js +6 -0
- package/dist/sdk/transport/ws.js.map +1 -0
- package/dist/sdk/transport.js +7 -0
- package/dist/sdk/transport.js.map +1 -0
- package/dist/sdk/types.js +4 -0
- package/dist/sdk/types.js.map +1 -0
- package/dist/secrets/index.js +5 -0
- package/dist/secrets/index.js.map +1 -0
- package/dist/secrets/src/index.d.ts +12 -0
- package/dist/secrets/src/index.d.ts.map +1 -0
- package/dist/secrets/src/lifecycle.d.ts +51 -0
- package/dist/secrets/src/lifecycle.d.ts.map +1 -0
- package/dist/secrets/src/providers/env.d.ts +26 -0
- package/dist/secrets/src/providers/env.d.ts.map +1 -0
- package/dist/secrets/src/providers/local.d.ts +63 -0
- package/dist/secrets/src/providers/local.d.ts.map +1 -0
- package/dist/secrets/src/router.d.ts +91 -0
- package/dist/secrets/src/router.d.ts.map +1 -0
- package/dist/session/index.js +5 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/src/dispatcher.d.ts +246 -0
- package/dist/session/src/dispatcher.d.ts.map +1 -0
- package/dist/session/src/index.d.ts +6 -0
- package/dist/session/src/index.d.ts.map +1 -0
- package/dist/session/src/mentions.d.ts +80 -0
- package/dist/session/src/mentions.d.ts.map +1 -0
- package/dist/session/src/types.d.ts +109 -0
- package/dist/session/src/types.d.ts.map +1 -0
- package/dist/sessions-2IUX4P3P.js +5 -0
- package/dist/sessions-2IUX4P3P.js.map +1 -0
- package/dist/setup-BMTC562F.js +488 -0
- package/dist/setup-BMTC562F.js.map +1 -0
- package/dist/skills-CRL3VJNN.js +7 -0
- package/dist/skills-CRL3VJNN.js.map +1 -0
- package/dist/store/index.js +4 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/react.js +40 -0
- package/dist/store/react.js.map +1 -0
- package/dist/store/src/index.d.ts +4 -0
- package/dist/store/src/index.d.ts.map +1 -0
- package/dist/store/src/react.d.ts +75 -0
- package/dist/store/src/react.d.ts.map +1 -0
- package/dist/store/src/resource-client.d.ts +128 -0
- package/dist/store/src/resource-client.d.ts.map +1 -0
- package/dist/store/src/store.d.ts +172 -0
- package/dist/store/src/store.d.ts.map +1 -0
- package/dist/store/src/types.d.ts +248 -0
- package/dist/store/src/types.d.ts.map +1 -0
- package/dist/store/src/vue.d.ts +52 -0
- package/dist/store/src/vue.d.ts.map +1 -0
- package/dist/store/vue.js +23 -0
- package/dist/store/vue.js.map +1 -0
- package/dist/store-client-X7Y7D5QX.js +14 -0
- package/dist/store-client-X7Y7D5QX.js.map +1 -0
- package/dist/telemetry/index.js +4 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/src/config.d.ts +28 -0
- package/dist/telemetry/src/config.d.ts.map +1 -0
- package/dist/telemetry/src/context.d.ts +36 -0
- package/dist/telemetry/src/context.d.ts.map +1 -0
- package/dist/telemetry/src/index.d.ts +5 -0
- package/dist/telemetry/src/index.d.ts.map +1 -0
- package/dist/telemetry/src/noop.d.ts +25 -0
- package/dist/telemetry/src/noop.d.ts.map +1 -0
- package/dist/telemetry/src/otel/exporter.d.ts +17 -0
- package/dist/telemetry/src/otel/exporter.d.ts.map +1 -0
- package/dist/telemetry/src/otel/gen-ai.d.ts +17 -0
- package/dist/telemetry/src/otel/gen-ai.d.ts.map +1 -0
- package/dist/telemetry/src/otel/provider.d.ts +34 -0
- package/dist/telemetry/src/otel/provider.d.ts.map +1 -0
- package/dist/telemetry/src/types.d.ts +182 -0
- package/dist/telemetry/src/types.d.ts.map +1 -0
- package/dist/transport/index.js +7 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/src/index.d.ts +2 -0
- package/dist/transport/src/index.d.ts.map +1 -0
- package/dist/transport/src/ws/client.d.ts +72 -0
- package/dist/transport/src/ws/client.d.ts.map +1 -0
- package/dist/transport/src/ws/index.d.ts +3 -0
- package/dist/transport/src/ws/index.d.ts.map +1 -0
- package/dist/transport/src/ws/server.d.ts +67 -0
- package/dist/transport/src/ws/server.d.ts.map +1 -0
- package/dist/transport/ws/client.js +4 -0
- package/dist/transport/ws/client.js.map +1 -0
- package/dist/transport/ws/server.js +4 -0
- package/dist/transport/ws/server.js.map +1 -0
- package/dist/transport/ws.js +6 -0
- package/dist/transport/ws.js.map +1 -0
- package/dist/tui/index.js +471 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/src/index.d.ts +4 -0
- package/dist/tui/src/index.d.ts.map +1 -0
- package/dist/tui/src/repl-renderer.d.ts +31 -0
- package/dist/tui/src/repl-renderer.d.ts.map +1 -0
- package/dist/tui/src/repl-session.d.ts +69 -0
- package/dist/tui/src/repl-session.d.ts.map +1 -0
- package/dist/tui/src/repl.d.ts +49 -0
- package/dist/tui/src/repl.d.ts.map +1 -0
- package/dist/tui/src/telemetry.d.ts +88 -0
- package/dist/tui/src/telemetry.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/manifests.js +4 -0
- package/dist/types/manifests.js.map +1 -0
- package/dist/types/src/capabilities.d.ts +398 -0
- package/dist/types/src/capabilities.d.ts.map +1 -0
- package/dist/types/src/envelope.d.ts +120 -0
- package/dist/types/src/envelope.d.ts.map +1 -0
- package/dist/types/src/events.d.ts +1075 -0
- package/dist/types/src/events.d.ts.map +1 -0
- package/dist/types/src/flow.d.ts +312 -0
- package/dist/types/src/flow.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +57 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/lifecycle.d.ts +269 -0
- package/dist/types/src/lifecycle.d.ts.map +1 -0
- package/dist/types/src/logging.d.ts +161 -0
- package/dist/types/src/logging.d.ts.map +1 -0
- package/dist/types/src/manifests/_shared.d.ts +162 -0
- package/dist/types/src/manifests/_shared.d.ts.map +1 -0
- package/dist/types/src/manifests/agent.d.ts +343 -0
- package/dist/types/src/manifests/agent.d.ts.map +1 -0
- package/dist/types/src/manifests/connector.d.ts +126 -0
- package/dist/types/src/manifests/connector.d.ts.map +1 -0
- package/dist/types/src/manifests/contract.d.ts +90 -0
- package/dist/types/src/manifests/contract.d.ts.map +1 -0
- package/dist/types/src/manifests/index.d.ts +40 -0
- package/dist/types/src/manifests/index.d.ts.map +1 -0
- package/dist/types/src/manifests/mcp-server.d.ts +42 -0
- package/dist/types/src/manifests/mcp-server.d.ts.map +1 -0
- package/dist/types/src/manifests/mount.d.ts +93 -0
- package/dist/types/src/manifests/mount.d.ts.map +1 -0
- package/dist/types/src/manifests/persona.d.ts +90 -0
- package/dist/types/src/manifests/persona.d.ts.map +1 -0
- package/dist/types/src/manifests/preset.d.ts +704 -0
- package/dist/types/src/manifests/preset.d.ts.map +1 -0
- package/dist/types/src/manifests/prompt.d.ts +90 -0
- package/dist/types/src/manifests/prompt.d.ts.map +1 -0
- package/dist/types/src/manifests/ruleset.d.ts +90 -0
- package/dist/types/src/manifests/ruleset.d.ts.map +1 -0
- package/dist/types/src/manifests/skill.d.ts +2391 -0
- package/dist/types/src/manifests/skill.d.ts.map +1 -0
- package/dist/types/src/mentions.d.ts +49 -0
- package/dist/types/src/mentions.d.ts.map +1 -0
- package/dist/types/src/messaging.d.ts +105 -0
- package/dist/types/src/messaging.d.ts.map +1 -0
- package/dist/types/src/protocol.d.ts +201 -0
- package/dist/types/src/protocol.d.ts.map +1 -0
- package/dist/types/src/reactions.d.ts +34 -0
- package/dist/types/src/reactions.d.ts.map +1 -0
- package/dist/types/src/runtime.d.ts +219 -0
- package/dist/types/src/runtime.d.ts.map +1 -0
- package/dist/types/src/transport.d.ts +64 -0
- package/dist/types/src/transport.d.ts.map +1 -0
- package/dist/types/src/version.d.ts +129 -0
- package/dist/types/src/version.d.ts.map +1 -0
- package/dist/validator-764EQNM3.js +5 -0
- package/dist/validator-764EQNM3.js.map +1 -0
- package/dist/workspace-plugin/adapters/mcp.js +259 -0
- package/dist/workspace-plugin/adapters/mcp.js.map +1 -0
- package/dist/workspace-plugin/adapters/omp.js +251 -0
- package/dist/workspace-plugin/adapters/omp.js.map +1 -0
- package/dist/workspace-plugin/index.js +6 -0
- package/dist/workspace-plugin/index.js.map +1 -0
- package/dist/workspace-plugin/src/adapters/claude-code.d.ts +17 -0
- package/dist/workspace-plugin/src/adapters/claude-code.d.ts.map +1 -0
- package/dist/workspace-plugin/src/adapters/mcp.d.ts +78 -0
- package/dist/workspace-plugin/src/adapters/mcp.d.ts.map +1 -0
- package/dist/workspace-plugin/src/adapters/omp.d.ts +60 -0
- package/dist/workspace-plugin/src/adapters/omp.d.ts.map +1 -0
- package/dist/workspace-plugin/src/index.d.ts +8 -0
- package/dist/workspace-plugin/src/index.d.ts.map +1 -0
- package/dist/workspace-plugin/src/plugin.d.ts +83 -0
- package/dist/workspace-plugin/src/plugin.d.ts.map +1 -0
- package/dist/workspace-plugin/src/store.d.ts +36 -0
- package/dist/workspace-plugin/src/store.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/connectors.d.ts +94 -0
- package/dist/workspace-plugin/src/tools/connectors.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/flows.d.ts +54 -0
- package/dist/workspace-plugin/src/tools/flows.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/mounts.d.ts +51 -0
- package/dist/workspace-plugin/src/tools/mounts.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/sessions.d.ts +35 -0
- package/dist/workspace-plugin/src/tools/sessions.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/skills.d.ts +75 -0
- package/dist/workspace-plugin/src/tools/skills.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/validator.d.ts +64 -0
- package/dist/workspace-plugin/src/tools/validator.d.ts.map +1 -0
- package/dist/workspace-plugin/src/types.d.ts +73 -0
- package/dist/workspace-plugin/src/types.d.ts.map +1 -0
- package/dist/workspace-plugin/src/utils/ai-assets.d.ts +16 -0
- package/dist/workspace-plugin/src/utils/ai-assets.d.ts.map +1 -0
- package/dist/workspace-plugin/src/utils/project-dir.d.ts +23 -0
- package/dist/workspace-plugin/src/utils/project-dir.d.ts.map +1 -0
- package/package.json +646 -0
|
@@ -0,0 +1,3229 @@
|
|
|
1
|
+
import { discoverAssetsInTree, loadSourceConfig } from './chunk-46T37EBP.js';
|
|
2
|
+
import { PresetManifestSchema } from './chunk-Z3RER6YZ.js';
|
|
3
|
+
import { __export, __require } from './chunk-NSBPE2FW.js';
|
|
4
|
+
import * as crypto from 'crypto';
|
|
5
|
+
import * as fs10 from 'fs';
|
|
6
|
+
import * as path5 from 'path';
|
|
7
|
+
import { eq, like, and } from 'drizzle-orm';
|
|
8
|
+
import * as z2 from 'zod';
|
|
9
|
+
import * as os from 'os';
|
|
10
|
+
import { stringify, parse, parseDocument } from 'yaml';
|
|
11
|
+
import { createClient } from '@libsql/client';
|
|
12
|
+
import { drizzle } from 'drizzle-orm/libsql';
|
|
13
|
+
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
|
|
14
|
+
import { spawnSync } from 'child_process';
|
|
15
|
+
|
|
16
|
+
// library/src/library.ts
|
|
17
|
+
var KNOWN_ASSET_KINDS = [
|
|
18
|
+
"skill",
|
|
19
|
+
"agent",
|
|
20
|
+
"connector",
|
|
21
|
+
"mount",
|
|
22
|
+
"flow",
|
|
23
|
+
"contract",
|
|
24
|
+
"prompt",
|
|
25
|
+
"mcp-server",
|
|
26
|
+
"knowledge",
|
|
27
|
+
"persona",
|
|
28
|
+
"ruleset"
|
|
29
|
+
];
|
|
30
|
+
var PIN_POLICIES = ["exact", "minor-track", "latest"];
|
|
31
|
+
var LibraryError = class extends Error {
|
|
32
|
+
constructor(message, code) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.code = code;
|
|
35
|
+
this.name = "LibraryError";
|
|
36
|
+
}
|
|
37
|
+
code;
|
|
38
|
+
};
|
|
39
|
+
var SourceNotFoundError = class extends LibraryError {
|
|
40
|
+
constructor(id) {
|
|
41
|
+
super(`Source not found: ${id}`, "SOURCE_NOT_FOUND");
|
|
42
|
+
this.name = "SourceNotFoundError";
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var InstanceNotFoundError = class extends LibraryError {
|
|
46
|
+
constructor(id) {
|
|
47
|
+
super(`Instance not found: ${id}`, "INSTANCE_NOT_FOUND");
|
|
48
|
+
this.name = "InstanceNotFoundError";
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var SubscriptionNotFoundError = class extends LibraryError {
|
|
52
|
+
constructor(id) {
|
|
53
|
+
super(`Subscription not found: ${id}`, "SUBSCRIPTION_NOT_FOUND");
|
|
54
|
+
this.name = "SubscriptionNotFoundError";
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
var DuplicateSubscriptionError = class extends LibraryError {
|
|
58
|
+
constructor(workspaceId, instanceId) {
|
|
59
|
+
super(
|
|
60
|
+
`Workspace "${workspaceId}" already subscribes to instance "${instanceId}"`,
|
|
61
|
+
"DUPLICATE_SUBSCRIPTION"
|
|
62
|
+
);
|
|
63
|
+
this.name = "DuplicateSubscriptionError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var InstanceHasConsumersError = class extends LibraryError {
|
|
67
|
+
constructor(instanceId, count) {
|
|
68
|
+
super(
|
|
69
|
+
`Instance "${instanceId}" has ${count} active subscription(s). Use { cascade: true } to force delete.`,
|
|
70
|
+
"INSTANCE_HAS_CONSUMERS"
|
|
71
|
+
);
|
|
72
|
+
this.name = "InstanceHasConsumersError";
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var LOCAL_CATALOG_URL = "local";
|
|
76
|
+
function isLocalCatalogUrl(url) {
|
|
77
|
+
return typeof url === "string" && url.trim().toLowerCase() === LOCAL_CATALOG_URL;
|
|
78
|
+
}
|
|
79
|
+
var CatalogConfigSchema = z2.object({
|
|
80
|
+
/** Catalog base URL, or `"local"` (case-insensitive) to disable the remote catalog. Default: https://skaile.store */
|
|
81
|
+
url: z2.union([
|
|
82
|
+
z2.string().url(),
|
|
83
|
+
// Accept any casing/whitespace variant of "local", normalise to canonical.
|
|
84
|
+
z2.string().refine((s) => s.trim().toLowerCase() === LOCAL_CATALOG_URL, {
|
|
85
|
+
message: `Expected a valid URL or "${LOCAL_CATALOG_URL}"`
|
|
86
|
+
}).transform(() => LOCAL_CATALOG_URL)
|
|
87
|
+
]).optional(),
|
|
88
|
+
/** Cache TTL in seconds. 0 = air-gapped (manual `skaile update` only). */
|
|
89
|
+
cache_ttl: z2.number().int().min(0).optional(),
|
|
90
|
+
/**
|
|
91
|
+
* Wire framing to use when talking to a remote catalog.
|
|
92
|
+
* `"trpc"` — skaile.store tRPC backend (default for `https://skaile.store`).
|
|
93
|
+
* `"rest"` — forge-store REST backend (default for any other URL).
|
|
94
|
+
*/
|
|
95
|
+
framing: z2.enum(["trpc", "rest"]).optional()
|
|
96
|
+
});
|
|
97
|
+
var LibraryConfigSchema = z2.object({
|
|
98
|
+
/** Library storage directory. Default: ~/.skaile/libraries */
|
|
99
|
+
dir: z2.string().optional(),
|
|
100
|
+
/** Default pin policy for new instances/subscriptions. */
|
|
101
|
+
pin_policy: z2.enum(PIN_POLICIES).optional()
|
|
102
|
+
});
|
|
103
|
+
var SkaileConfigSchema = z2.object({
|
|
104
|
+
catalog: CatalogConfigSchema.optional(),
|
|
105
|
+
library: LibraryConfigSchema.optional()
|
|
106
|
+
});
|
|
107
|
+
function defaultLibraryDir() {
|
|
108
|
+
return path5.join(os.homedir(), ".skaile", "libraries");
|
|
109
|
+
}
|
|
110
|
+
function resolveLibraryDir() {
|
|
111
|
+
if (process.env.SKAILE_LIBRARIES_DIR) return process.env.SKAILE_LIBRARIES_DIR;
|
|
112
|
+
if (process.env.SKAILE_LIBRARY_DIR) {
|
|
113
|
+
process.stderr.write(
|
|
114
|
+
"[skaile/library] SKAILE_LIBRARY_DIR is deprecated \u2014 use SKAILE_LIBRARIES_DIR.\n"
|
|
115
|
+
);
|
|
116
|
+
return process.env.SKAILE_LIBRARY_DIR;
|
|
117
|
+
}
|
|
118
|
+
return defaultLibraryDir();
|
|
119
|
+
}
|
|
120
|
+
function getConfigDefaults() {
|
|
121
|
+
return {
|
|
122
|
+
catalog: { url: "https://skaile.store", cache_ttl: 86400, framing: "trpc" },
|
|
123
|
+
library: { dir: defaultLibraryDir(), pin_policy: "minor-track" }
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
var CONFIG_FILENAME = "config.yaml";
|
|
127
|
+
function userConfigPath() {
|
|
128
|
+
return path5.join(os.homedir(), ".skaile", CONFIG_FILENAME);
|
|
129
|
+
}
|
|
130
|
+
function projectConfigPath(projectDir) {
|
|
131
|
+
return path5.join(projectDir, ".skaile", CONFIG_FILENAME);
|
|
132
|
+
}
|
|
133
|
+
function loadConfigFile(filePath) {
|
|
134
|
+
if (!fs10.existsSync(filePath)) return null;
|
|
135
|
+
try {
|
|
136
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
137
|
+
const raw = parse(content);
|
|
138
|
+
if (!raw || typeof raw !== "object") return null;
|
|
139
|
+
return SkaileConfigSchema.partial().parse(raw);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
process.stderr.write(
|
|
142
|
+
`[skaile/config] Warning: ignoring invalid config at ${filePath}: ${err instanceof Error ? err.message : String(err)}
|
|
143
|
+
`
|
|
144
|
+
);
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function deepMerge(base, overlay) {
|
|
149
|
+
const result = { ...base };
|
|
150
|
+
for (const key of Object.keys(overlay)) {
|
|
151
|
+
const val = overlay[key];
|
|
152
|
+
if (val === void 0) continue;
|
|
153
|
+
if (typeof val === "object" && val !== null && !Array.isArray(val) && typeof result[key] === "object" && result[key] !== null) {
|
|
154
|
+
result[key] = deepMerge(
|
|
155
|
+
result[key],
|
|
156
|
+
val
|
|
157
|
+
);
|
|
158
|
+
} else {
|
|
159
|
+
result[key] = val;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
function resolveConfig(opts) {
|
|
165
|
+
const defaults = getConfigDefaults();
|
|
166
|
+
let config = { ...defaults };
|
|
167
|
+
const userPath = opts?.userConfigFile ?? userConfigPath();
|
|
168
|
+
const userCfg = loadConfigFile(userPath);
|
|
169
|
+
if (userCfg) config = deepMerge(config, userCfg);
|
|
170
|
+
let projCfg = null;
|
|
171
|
+
if (opts?.projectDir) {
|
|
172
|
+
projCfg = loadConfigFile(projectConfigPath(opts.projectDir));
|
|
173
|
+
if (projCfg) config = deepMerge(config, projCfg);
|
|
174
|
+
}
|
|
175
|
+
if (opts?.overrides) config = deepMerge(config, opts.overrides);
|
|
176
|
+
const resolved = config;
|
|
177
|
+
const explicitFraming = userCfg?.catalog?.framing !== void 0 || projCfg?.catalog?.framing !== void 0 || opts?.overrides?.catalog?.framing !== void 0;
|
|
178
|
+
if (!explicitFraming && resolved.catalog.url !== "https://skaile.store") {
|
|
179
|
+
resolved.catalog.framing = "rest";
|
|
180
|
+
}
|
|
181
|
+
return resolved;
|
|
182
|
+
}
|
|
183
|
+
function saveConfig(filePath, config) {
|
|
184
|
+
const dir = path5.dirname(filePath);
|
|
185
|
+
if (!fs10.existsSync(dir)) {
|
|
186
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
187
|
+
}
|
|
188
|
+
fs10.writeFileSync(filePath, stringify(config, { indent: 2 }), "utf-8");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// library/src/local/schema.ts
|
|
192
|
+
var schema_exports = {};
|
|
193
|
+
__export(schema_exports, {
|
|
194
|
+
assetDefinitions: () => assetDefinitions,
|
|
195
|
+
instances: () => instances,
|
|
196
|
+
libraries: () => libraries,
|
|
197
|
+
subscriptions: () => subscriptions
|
|
198
|
+
});
|
|
199
|
+
var libraries = sqliteTable("libraries", {
|
|
200
|
+
/** UUID primary key. */
|
|
201
|
+
id: text("id").primaryKey(),
|
|
202
|
+
/** User-visible handle; unique. */
|
|
203
|
+
name: text("name").notNull(),
|
|
204
|
+
/** Absolute on-disk root. */
|
|
205
|
+
path: text("path").notNull(),
|
|
206
|
+
/** Backend kind: `local | git | store`. */
|
|
207
|
+
backend: text("backend").notNull(),
|
|
208
|
+
/** Backend-specific JSON config; stored as text, parsed on read. */
|
|
209
|
+
backendConfig: text("backend_config").notNull().default("{}"),
|
|
210
|
+
/** Ownership: `owner | contributor | reader`. */
|
|
211
|
+
ownership: text("ownership").notNull(),
|
|
212
|
+
/** Layout: `flat | domain` or null when not yet detected. */
|
|
213
|
+
structure: text("structure"),
|
|
214
|
+
/** Boolean (0/1) — true iff this is the auto-target for `asset migrate`. */
|
|
215
|
+
isDefault: integer("is_default", { mode: "boolean" }).notNull().default(false),
|
|
216
|
+
/** Boolean (0/1) — true iff the CLI generated the on-disk manifest. */
|
|
217
|
+
manifestGenerated: integer("manifest_generated", { mode: "boolean" }).notNull().default(false),
|
|
218
|
+
/** Last sync ISO timestamp. */
|
|
219
|
+
lastSyncAt: text("last_sync_at"),
|
|
220
|
+
/** Creation ISO timestamp. */
|
|
221
|
+
createdAt: text("created_at").notNull(),
|
|
222
|
+
/** Last-update ISO timestamp. */
|
|
223
|
+
updatedAt: text("updated_at").notNull()
|
|
224
|
+
});
|
|
225
|
+
var assetDefinitions = sqliteTable("asset_definitions", {
|
|
226
|
+
id: text("id").primaryKey(),
|
|
227
|
+
kind: text("kind").notNull(),
|
|
228
|
+
publisher: text("publisher").notNull(),
|
|
229
|
+
name: text("name").notNull(),
|
|
230
|
+
version: text("version").notNull(),
|
|
231
|
+
sha256: text("sha256"),
|
|
232
|
+
description: text("description"),
|
|
233
|
+
license: text("license"),
|
|
234
|
+
category: text("category"),
|
|
235
|
+
manifest: text("manifest").notNull(),
|
|
236
|
+
/** FK to the library that provided this definition. */
|
|
237
|
+
libraryId: text("library_id"),
|
|
238
|
+
kindProviderVersion: text("kind_provider_version"),
|
|
239
|
+
cachedAt: text("cached_at").notNull(),
|
|
240
|
+
updatedAt: text("updated_at").notNull()
|
|
241
|
+
});
|
|
242
|
+
var instances = sqliteTable("instances", {
|
|
243
|
+
id: text("id").primaryKey(),
|
|
244
|
+
defRef: text("def_ref").notNull(),
|
|
245
|
+
defPin: text("def_pin").notNull(),
|
|
246
|
+
config: text("config").notNull().default("{}"),
|
|
247
|
+
credentialRef: text("credential_ref"),
|
|
248
|
+
createdAt: text("created_at").notNull(),
|
|
249
|
+
updatedAt: text("updated_at").notNull(),
|
|
250
|
+
createdBy: text("created_by")
|
|
251
|
+
});
|
|
252
|
+
var subscriptions = sqliteTable("subscriptions", {
|
|
253
|
+
id: text("id").primaryKey(),
|
|
254
|
+
workspaceId: text("workspace_id").notNull(),
|
|
255
|
+
instanceId: text("instance_id").notNull(),
|
|
256
|
+
pinPolicy: text("pin_policy").notNull(),
|
|
257
|
+
subscribedAt: text("subscribed_at").notNull()
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// library/src/local/db.ts
|
|
261
|
+
var DDL = `
|
|
262
|
+
CREATE TABLE IF NOT EXISTS libraries (
|
|
263
|
+
id TEXT PRIMARY KEY,
|
|
264
|
+
name TEXT NOT NULL,
|
|
265
|
+
path TEXT NOT NULL,
|
|
266
|
+
backend TEXT NOT NULL,
|
|
267
|
+
backend_config TEXT NOT NULL DEFAULT '{}',
|
|
268
|
+
ownership TEXT NOT NULL,
|
|
269
|
+
structure TEXT,
|
|
270
|
+
is_default INTEGER NOT NULL DEFAULT 0,
|
|
271
|
+
manifest_generated INTEGER NOT NULL DEFAULT 0,
|
|
272
|
+
last_sync_at TEXT,
|
|
273
|
+
created_at TEXT NOT NULL,
|
|
274
|
+
updated_at TEXT NOT NULL
|
|
275
|
+
);
|
|
276
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_libraries_name ON libraries(name);
|
|
277
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_libraries_default
|
|
278
|
+
ON libraries(is_default) WHERE is_default = 1;
|
|
279
|
+
|
|
280
|
+
CREATE TABLE IF NOT EXISTS asset_definitions (
|
|
281
|
+
id TEXT PRIMARY KEY,
|
|
282
|
+
kind TEXT NOT NULL,
|
|
283
|
+
publisher TEXT NOT NULL,
|
|
284
|
+
name TEXT NOT NULL,
|
|
285
|
+
version TEXT NOT NULL,
|
|
286
|
+
sha256 TEXT,
|
|
287
|
+
description TEXT,
|
|
288
|
+
license TEXT,
|
|
289
|
+
category TEXT,
|
|
290
|
+
manifest TEXT NOT NULL,
|
|
291
|
+
library_id TEXT REFERENCES libraries(id) ON DELETE SET NULL,
|
|
292
|
+
kind_provider_version TEXT,
|
|
293
|
+
cached_at TEXT NOT NULL,
|
|
294
|
+
updated_at TEXT NOT NULL
|
|
295
|
+
);
|
|
296
|
+
CREATE INDEX IF NOT EXISTS idx_asset_defs_kind ON asset_definitions(kind);
|
|
297
|
+
CREATE INDEX IF NOT EXISTS idx_asset_defs_publisher ON asset_definitions(publisher);
|
|
298
|
+
CREATE INDEX IF NOT EXISTS idx_asset_defs_library_id ON asset_definitions(library_id);
|
|
299
|
+
|
|
300
|
+
CREATE TABLE IF NOT EXISTS instances (
|
|
301
|
+
id TEXT PRIMARY KEY,
|
|
302
|
+
def_ref TEXT NOT NULL,
|
|
303
|
+
def_pin TEXT NOT NULL,
|
|
304
|
+
config TEXT NOT NULL DEFAULT '{}',
|
|
305
|
+
credential_ref TEXT,
|
|
306
|
+
created_at TEXT NOT NULL,
|
|
307
|
+
updated_at TEXT NOT NULL,
|
|
308
|
+
created_by TEXT
|
|
309
|
+
);
|
|
310
|
+
CREATE INDEX IF NOT EXISTS idx_instances_def_ref ON instances(def_ref);
|
|
311
|
+
|
|
312
|
+
CREATE TABLE IF NOT EXISTS subscriptions (
|
|
313
|
+
id TEXT PRIMARY KEY,
|
|
314
|
+
workspace_id TEXT NOT NULL,
|
|
315
|
+
instance_id TEXT NOT NULL REFERENCES instances(id) ON DELETE CASCADE,
|
|
316
|
+
pin_policy TEXT NOT NULL,
|
|
317
|
+
subscribed_at TEXT NOT NULL
|
|
318
|
+
);
|
|
319
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_subs_ws_instance
|
|
320
|
+
ON subscriptions(workspace_id, instance_id);
|
|
321
|
+
CREATE INDEX IF NOT EXISTS idx_subs_instance_id ON subscriptions(instance_id);
|
|
322
|
+
`;
|
|
323
|
+
async function legacySourcesPresent(client) {
|
|
324
|
+
const rs = await client.execute(
|
|
325
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name='sources'"
|
|
326
|
+
);
|
|
327
|
+
return rs.rows.length > 0;
|
|
328
|
+
}
|
|
329
|
+
async function librariesPresent(client) {
|
|
330
|
+
const rs = await client.execute(
|
|
331
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name='libraries'"
|
|
332
|
+
);
|
|
333
|
+
return rs.rows.length > 0;
|
|
334
|
+
}
|
|
335
|
+
function slugify(p) {
|
|
336
|
+
const base = path5.basename(p) || "lib";
|
|
337
|
+
return base.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-|-$/g, "") || "lib";
|
|
338
|
+
}
|
|
339
|
+
async function runLibrariesMigration(client) {
|
|
340
|
+
const oldRows = (await client.execute("SELECT id, type, url, path, ref, last_synced_at, created_at FROM sources")).rows;
|
|
341
|
+
const stmts = [];
|
|
342
|
+
stmts.push({
|
|
343
|
+
sql: `
|
|
344
|
+
CREATE TABLE libraries (
|
|
345
|
+
id TEXT PRIMARY KEY,
|
|
346
|
+
name TEXT NOT NULL,
|
|
347
|
+
path TEXT NOT NULL,
|
|
348
|
+
backend TEXT NOT NULL,
|
|
349
|
+
backend_config TEXT NOT NULL DEFAULT '{}',
|
|
350
|
+
ownership TEXT NOT NULL,
|
|
351
|
+
structure TEXT,
|
|
352
|
+
is_default INTEGER NOT NULL DEFAULT 0,
|
|
353
|
+
manifest_generated INTEGER NOT NULL DEFAULT 0,
|
|
354
|
+
last_sync_at TEXT,
|
|
355
|
+
created_at TEXT NOT NULL,
|
|
356
|
+
updated_at TEXT NOT NULL
|
|
357
|
+
);
|
|
358
|
+
`
|
|
359
|
+
});
|
|
360
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
361
|
+
for (const row of oldRows) {
|
|
362
|
+
const backend = row.type === "github" ? "git" : row.type === "catalog" ? "store" : "local";
|
|
363
|
+
const ownership = backend === "local" ? "owner" : "reader";
|
|
364
|
+
const baseSlug = slugify(row.path ?? row.url);
|
|
365
|
+
let name = baseSlug;
|
|
366
|
+
let i = 2;
|
|
367
|
+
while (usedNames.has(name)) name = `${baseSlug}-${i++}`;
|
|
368
|
+
usedNames.add(name);
|
|
369
|
+
const cfg = backend === "git" ? { url: row.url, branch: row.ref ?? "main", authHint: "ssh" } : backend === "store" ? { url: row.url, publisher: "", tokenRef: "" } : {};
|
|
370
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
371
|
+
stmts.push({
|
|
372
|
+
sql: `INSERT INTO libraries
|
|
373
|
+
(id, name, path, backend, backend_config, ownership, last_sync_at, created_at, updated_at)
|
|
374
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
375
|
+
args: [
|
|
376
|
+
row.id,
|
|
377
|
+
name,
|
|
378
|
+
row.path ?? row.url,
|
|
379
|
+
backend,
|
|
380
|
+
JSON.stringify(cfg),
|
|
381
|
+
ownership,
|
|
382
|
+
row.last_synced_at,
|
|
383
|
+
row.created_at,
|
|
384
|
+
now
|
|
385
|
+
]
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
stmts.push({ sql: `CREATE UNIQUE INDEX idx_libraries_name ON libraries(name);` });
|
|
389
|
+
stmts.push({
|
|
390
|
+
sql: `CREATE UNIQUE INDEX idx_libraries_default
|
|
391
|
+
ON libraries(is_default) WHERE is_default = 1;`
|
|
392
|
+
});
|
|
393
|
+
stmts.push({ sql: `ALTER TABLE asset_definitions RENAME COLUMN source_id TO library_id;` });
|
|
394
|
+
stmts.push({
|
|
395
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_asset_defs_library_id
|
|
396
|
+
ON asset_definitions(library_id);`
|
|
397
|
+
});
|
|
398
|
+
stmts.push({ sql: `DROP TABLE sources;` });
|
|
399
|
+
await client.batch(stmts);
|
|
400
|
+
}
|
|
401
|
+
function relocateLegacyFileIfPresent(newDbPath) {
|
|
402
|
+
const fs12 = __require("fs");
|
|
403
|
+
const parent = path5.dirname(newDbPath);
|
|
404
|
+
if (path5.basename(parent) !== "libraries") return;
|
|
405
|
+
const legacy = path5.join(path5.dirname(parent), "library", "lib.db");
|
|
406
|
+
if (!fs12.existsSync(legacy) || fs12.existsSync(newDbPath)) return;
|
|
407
|
+
fs12.mkdirSync(parent, { recursive: true });
|
|
408
|
+
fs12.renameSync(legacy, newDbPath);
|
|
409
|
+
for (const ext of ["-wal", "-shm"]) {
|
|
410
|
+
const src = legacy + ext;
|
|
411
|
+
if (fs12.existsSync(src)) fs12.renameSync(src, newDbPath + ext);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
async function createLibraryDb(dbPath) {
|
|
415
|
+
relocateLegacyFileIfPresent(dbPath);
|
|
416
|
+
const client = createClient({ url: `file:${dbPath}` });
|
|
417
|
+
await client.execute("PRAGMA journal_mode = WAL");
|
|
418
|
+
await client.execute("PRAGMA foreign_keys = ON");
|
|
419
|
+
if (await legacySourcesPresent(client) && !await librariesPresent(client)) {
|
|
420
|
+
await runLibrariesMigration(client);
|
|
421
|
+
}
|
|
422
|
+
await client.executeMultiple(DDL);
|
|
423
|
+
const db = drizzle(client, { schema: schema_exports });
|
|
424
|
+
return { db, close: () => client.close() };
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// library/src/local/library.ts
|
|
428
|
+
function escapeLikePrefix(prefix) {
|
|
429
|
+
return prefix.replace(/[%_]/g, "\\$&");
|
|
430
|
+
}
|
|
431
|
+
function rowToSource(row) {
|
|
432
|
+
const cfg = (() => {
|
|
433
|
+
try {
|
|
434
|
+
return JSON.parse(row.backendConfig);
|
|
435
|
+
} catch {
|
|
436
|
+
return {};
|
|
437
|
+
}
|
|
438
|
+
})();
|
|
439
|
+
return {
|
|
440
|
+
id: row.id,
|
|
441
|
+
type: row.backend,
|
|
442
|
+
name: row.name,
|
|
443
|
+
path: row.path,
|
|
444
|
+
ownership: row.ownership,
|
|
445
|
+
isDefault: row.isDefault,
|
|
446
|
+
backendConfig: cfg,
|
|
447
|
+
structure: row.structure ?? void 0,
|
|
448
|
+
manifestGenerated: row.manifestGenerated,
|
|
449
|
+
lastSyncedAt: row.lastSyncAt ? new Date(row.lastSyncAt) : void 0,
|
|
450
|
+
createdAt: new Date(row.createdAt),
|
|
451
|
+
updatedAt: new Date(row.updatedAt),
|
|
452
|
+
url: typeof cfg.url === "string" ? cfg.url : void 0,
|
|
453
|
+
ref: typeof cfg.branch === "string" ? cfg.branch : void 0
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
function rowToAssetDef(row) {
|
|
457
|
+
return {
|
|
458
|
+
id: row.id,
|
|
459
|
+
kind: row.kind,
|
|
460
|
+
publisher: row.publisher,
|
|
461
|
+
name: row.name,
|
|
462
|
+
version: row.version,
|
|
463
|
+
sha256: row.sha256 ?? void 0,
|
|
464
|
+
description: row.description ?? void 0,
|
|
465
|
+
license: row.license ?? void 0,
|
|
466
|
+
category: row.category ?? void 0,
|
|
467
|
+
manifest: JSON.parse(row.manifest),
|
|
468
|
+
sourceId: row.libraryId ?? void 0,
|
|
469
|
+
kindProviderVersion: row.kindProviderVersion ?? void 0,
|
|
470
|
+
cachedAt: new Date(row.cachedAt),
|
|
471
|
+
updatedAt: new Date(row.updatedAt)
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
function rowToInstance(row) {
|
|
475
|
+
return {
|
|
476
|
+
id: row.id,
|
|
477
|
+
defRef: row.defRef,
|
|
478
|
+
defPin: row.defPin,
|
|
479
|
+
config: JSON.parse(row.config),
|
|
480
|
+
credentialRef: row.credentialRef ?? void 0,
|
|
481
|
+
createdAt: new Date(row.createdAt),
|
|
482
|
+
updatedAt: new Date(row.updatedAt),
|
|
483
|
+
createdBy: row.createdBy ?? void 0
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
function rowToSubscription(row) {
|
|
487
|
+
return {
|
|
488
|
+
id: row.id,
|
|
489
|
+
workspaceId: row.workspaceId,
|
|
490
|
+
instanceId: row.instanceId,
|
|
491
|
+
pinPolicy: row.pinPolicy,
|
|
492
|
+
subscribedAt: new Date(row.subscribedAt)
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
var LocalLibrary = class {
|
|
496
|
+
dbPath;
|
|
497
|
+
dbHandleRef = null;
|
|
498
|
+
dbPromise = null;
|
|
499
|
+
_kindRegistry;
|
|
500
|
+
/**
|
|
501
|
+
* Construct a LocalLibrary. Synchronous — does not open the DB.
|
|
502
|
+
*
|
|
503
|
+
* @param optionsOrDir - Either a `LocalLibraryOptions` object or a string
|
|
504
|
+
* path (legacy signature, kept for backward compat).
|
|
505
|
+
*/
|
|
506
|
+
constructor(optionsOrDir) {
|
|
507
|
+
let dir;
|
|
508
|
+
if (typeof optionsOrDir === "string") {
|
|
509
|
+
dir = optionsOrDir;
|
|
510
|
+
} else {
|
|
511
|
+
dir = optionsOrDir?.libraryDir ?? resolveLibraryDir();
|
|
512
|
+
this._kindRegistry = optionsOrDir?.kindRegistry;
|
|
513
|
+
}
|
|
514
|
+
if (!fs10.existsSync(dir)) {
|
|
515
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
516
|
+
}
|
|
517
|
+
this.dbPath = path5.join(dir, "lib.db");
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Lazily open the SQLite DB on first use. The `??=` dedupes concurrent
|
|
521
|
+
* first calls so the DB is opened exactly once, with no race.
|
|
522
|
+
*/
|
|
523
|
+
async ensureDb() {
|
|
524
|
+
if (this.dbHandleRef) return this.dbHandleRef.db;
|
|
525
|
+
this.dbPromise ??= createLibraryDb(this.dbPath);
|
|
526
|
+
this.dbHandleRef = await this.dbPromise;
|
|
527
|
+
return this.dbHandleRef.db;
|
|
528
|
+
}
|
|
529
|
+
/** The kind registry bound to this library (if any). */
|
|
530
|
+
get kinds() {
|
|
531
|
+
return this._kindRegistry;
|
|
532
|
+
}
|
|
533
|
+
/** Close the underlying SQLite connection. Call in tests / cleanup. */
|
|
534
|
+
close() {
|
|
535
|
+
if (this.dbHandleRef) this.dbHandleRef.close();
|
|
536
|
+
this.dbHandleRef = null;
|
|
537
|
+
this.dbPromise = null;
|
|
538
|
+
}
|
|
539
|
+
/** Internal access for UserLibraryManager. Do not call from user code. */
|
|
540
|
+
async dbHandle() {
|
|
541
|
+
return this.ensureDb();
|
|
542
|
+
}
|
|
543
|
+
// -- Sources -------------------------------------------------------------
|
|
544
|
+
async listSources() {
|
|
545
|
+
const db = await this.ensureDb();
|
|
546
|
+
const rows = await db.select().from(libraries).all();
|
|
547
|
+
return rows.map(rowToSource);
|
|
548
|
+
}
|
|
549
|
+
async addSource(input) {
|
|
550
|
+
const db = await this.ensureDb();
|
|
551
|
+
const id = crypto.randomUUID();
|
|
552
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
553
|
+
await db.insert(libraries).values({
|
|
554
|
+
id,
|
|
555
|
+
name: input.name,
|
|
556
|
+
path: input.path,
|
|
557
|
+
backend: input.type,
|
|
558
|
+
backendConfig: JSON.stringify(input.backendConfig ?? {}),
|
|
559
|
+
ownership: input.ownership ?? (input.type === "local" ? "owner" : "reader"),
|
|
560
|
+
isDefault: input.isDefault ?? false,
|
|
561
|
+
manifestGenerated: false,
|
|
562
|
+
createdAt: now,
|
|
563
|
+
updatedAt: now
|
|
564
|
+
}).run();
|
|
565
|
+
const row = await db.select().from(libraries).where(eq(libraries.id, id)).get();
|
|
566
|
+
return rowToSource(row);
|
|
567
|
+
}
|
|
568
|
+
async removeSource(id) {
|
|
569
|
+
const db = await this.ensureDb();
|
|
570
|
+
const existing = await db.select().from(libraries).where(eq(libraries.id, id)).get();
|
|
571
|
+
if (!existing) throw new SourceNotFoundError(id);
|
|
572
|
+
await db.delete(libraries).where(eq(libraries.id, id)).run();
|
|
573
|
+
}
|
|
574
|
+
async syncSource(id) {
|
|
575
|
+
const db = await this.ensureDb();
|
|
576
|
+
const existing = await db.select().from(libraries).where(eq(libraries.id, id)).get();
|
|
577
|
+
if (!existing) throw new SourceNotFoundError(id);
|
|
578
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
579
|
+
await db.update(libraries).set({ lastSyncAt: now, updatedAt: now }).where(eq(libraries.id, id)).run();
|
|
580
|
+
return { sourceId: id, assetsFound: 0, assetsUpdated: 0, errors: [] };
|
|
581
|
+
}
|
|
582
|
+
// -- Asset definitions ---------------------------------------------------
|
|
583
|
+
/**
|
|
584
|
+
* Insert or update a cached asset definition.
|
|
585
|
+
*
|
|
586
|
+
* Not on the IAssetIndex interface -- used by catalog sources (Task 1.5)
|
|
587
|
+
* and tests. INSERT OR REPLACE semantics.
|
|
588
|
+
*/
|
|
589
|
+
async upsertAssetDef(def) {
|
|
590
|
+
const db = await this.ensureDb();
|
|
591
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
592
|
+
let providerVersion = def.kindProviderVersion ?? null;
|
|
593
|
+
if (!providerVersion && this._kindRegistry) {
|
|
594
|
+
const provider = this._kindRegistry.getProvider(def.kind);
|
|
595
|
+
if (provider) {
|
|
596
|
+
providerVersion = provider.providerVersion;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
await db.insert(assetDefinitions).values({
|
|
600
|
+
id: def.id,
|
|
601
|
+
kind: def.kind,
|
|
602
|
+
publisher: def.publisher,
|
|
603
|
+
name: def.name,
|
|
604
|
+
version: def.version,
|
|
605
|
+
sha256: def.sha256 ?? null,
|
|
606
|
+
description: def.description ?? null,
|
|
607
|
+
license: def.license ?? null,
|
|
608
|
+
category: def.category ?? null,
|
|
609
|
+
manifest: JSON.stringify(def.manifest),
|
|
610
|
+
libraryId: def.sourceId ?? null,
|
|
611
|
+
kindProviderVersion: providerVersion,
|
|
612
|
+
cachedAt: def.cachedAt?.toISOString() ?? now,
|
|
613
|
+
updatedAt: now
|
|
614
|
+
}).onConflictDoUpdate({
|
|
615
|
+
target: assetDefinitions.id,
|
|
616
|
+
set: {
|
|
617
|
+
kind: def.kind,
|
|
618
|
+
publisher: def.publisher,
|
|
619
|
+
name: def.name,
|
|
620
|
+
version: def.version,
|
|
621
|
+
sha256: def.sha256 ?? null,
|
|
622
|
+
description: def.description ?? null,
|
|
623
|
+
license: def.license ?? null,
|
|
624
|
+
category: def.category ?? null,
|
|
625
|
+
manifest: JSON.stringify(def.manifest),
|
|
626
|
+
libraryId: def.sourceId ?? null,
|
|
627
|
+
kindProviderVersion: providerVersion,
|
|
628
|
+
updatedAt: now
|
|
629
|
+
}
|
|
630
|
+
}).run();
|
|
631
|
+
}
|
|
632
|
+
async getAssetDef(ref) {
|
|
633
|
+
const db = await this.ensureDb();
|
|
634
|
+
const row = await db.select().from(assetDefinitions).where(eq(assetDefinitions.id, ref)).get();
|
|
635
|
+
return row ? rowToAssetDef(row) : null;
|
|
636
|
+
}
|
|
637
|
+
async listAssetDefs(filter) {
|
|
638
|
+
const db = await this.ensureDb();
|
|
639
|
+
if (!filter) {
|
|
640
|
+
return (await db.select().from(assetDefinitions).all()).map(rowToAssetDef);
|
|
641
|
+
}
|
|
642
|
+
const conditions = [];
|
|
643
|
+
if (filter.kind) conditions.push(eq(assetDefinitions.kind, filter.kind));
|
|
644
|
+
if (filter.publisher) conditions.push(eq(assetDefinitions.publisher, filter.publisher));
|
|
645
|
+
if (filter.prefix)
|
|
646
|
+
conditions.push(like(assetDefinitions.id, `${escapeLikePrefix(filter.prefix)}%`));
|
|
647
|
+
if (filter.sourceId) conditions.push(eq(assetDefinitions.libraryId, filter.sourceId));
|
|
648
|
+
const where = conditions.length > 0 ? and(...conditions) : void 0;
|
|
649
|
+
let rows = where ? await db.select().from(assetDefinitions).where(where).all() : await db.select().from(assetDefinitions).all();
|
|
650
|
+
if (filter.offset) rows = rows.slice(filter.offset);
|
|
651
|
+
if (filter.limit) rows = rows.slice(0, filter.limit);
|
|
652
|
+
return rows.map(rowToAssetDef);
|
|
653
|
+
}
|
|
654
|
+
// -- Instances -----------------------------------------------------------
|
|
655
|
+
async createInstance(input) {
|
|
656
|
+
const db = await this.ensureDb();
|
|
657
|
+
const id = crypto.randomUUID();
|
|
658
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
659
|
+
const pin = input.defPin ?? "minor-track";
|
|
660
|
+
const config = input.config ?? {};
|
|
661
|
+
await db.insert(instances).values({
|
|
662
|
+
id,
|
|
663
|
+
defRef: input.defRef,
|
|
664
|
+
defPin: pin,
|
|
665
|
+
config: JSON.stringify(config),
|
|
666
|
+
credentialRef: input.credentialRef ?? null,
|
|
667
|
+
createdAt: now,
|
|
668
|
+
updatedAt: now,
|
|
669
|
+
createdBy: input.createdBy ?? null
|
|
670
|
+
}).run();
|
|
671
|
+
return {
|
|
672
|
+
id,
|
|
673
|
+
defRef: input.defRef,
|
|
674
|
+
defPin: pin,
|
|
675
|
+
config,
|
|
676
|
+
credentialRef: input.credentialRef,
|
|
677
|
+
createdAt: new Date(now),
|
|
678
|
+
updatedAt: new Date(now),
|
|
679
|
+
createdBy: input.createdBy
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
async getInstance(id) {
|
|
683
|
+
const db = await this.ensureDb();
|
|
684
|
+
const row = await db.select().from(instances).where(eq(instances.id, id)).get();
|
|
685
|
+
return row ? rowToInstance(row) : null;
|
|
686
|
+
}
|
|
687
|
+
async listInstances(filter) {
|
|
688
|
+
const db = await this.ensureDb();
|
|
689
|
+
if (!filter) {
|
|
690
|
+
return (await db.select().from(instances).all()).map(rowToInstance);
|
|
691
|
+
}
|
|
692
|
+
const conditions = [];
|
|
693
|
+
if (filter.defRef) conditions.push(eq(instances.defRef, filter.defRef));
|
|
694
|
+
if (filter.defPin) conditions.push(eq(instances.defPin, filter.defPin));
|
|
695
|
+
const where = conditions.length > 0 ? and(...conditions) : void 0;
|
|
696
|
+
let rows = where ? await db.select().from(instances).where(where).all() : await db.select().from(instances).all();
|
|
697
|
+
if (filter.offset) rows = rows.slice(filter.offset);
|
|
698
|
+
if (filter.limit) rows = rows.slice(0, filter.limit);
|
|
699
|
+
return rows.map(rowToInstance);
|
|
700
|
+
}
|
|
701
|
+
async updateInstance(id, patch) {
|
|
702
|
+
const db = await this.ensureDb();
|
|
703
|
+
const existing = await db.select().from(instances).where(eq(instances.id, id)).get();
|
|
704
|
+
if (!existing) throw new InstanceNotFoundError(id);
|
|
705
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
706
|
+
const updates = { updatedAt: now };
|
|
707
|
+
if (patch.config !== void 0) updates.config = JSON.stringify(patch.config);
|
|
708
|
+
if (patch.credentialRef !== void 0) updates.credentialRef = patch.credentialRef;
|
|
709
|
+
if (patch.defPin !== void 0) updates.defPin = patch.defPin;
|
|
710
|
+
await db.update(instances).set(updates).where(eq(instances.id, id)).run();
|
|
711
|
+
const updated = await db.select().from(instances).where(eq(instances.id, id)).get();
|
|
712
|
+
return rowToInstance(updated);
|
|
713
|
+
}
|
|
714
|
+
async deleteInstance(id, opts) {
|
|
715
|
+
const db = await this.ensureDb();
|
|
716
|
+
const existing = await db.select().from(instances).where(eq(instances.id, id)).get();
|
|
717
|
+
if (!existing) throw new InstanceNotFoundError(id);
|
|
718
|
+
const consumers = await db.select().from(subscriptions).where(eq(subscriptions.instanceId, id)).all();
|
|
719
|
+
if (consumers.length > 0 && !opts?.cascade) {
|
|
720
|
+
throw new InstanceHasConsumersError(id, consumers.length);
|
|
721
|
+
}
|
|
722
|
+
await db.delete(instances).where(eq(instances.id, id)).run();
|
|
723
|
+
}
|
|
724
|
+
// -- Subscriptions -------------------------------------------------------
|
|
725
|
+
async subscribe(workspaceId, instanceId, pin) {
|
|
726
|
+
const db = await this.ensureDb();
|
|
727
|
+
const instance = await db.select().from(instances).where(eq(instances.id, instanceId)).get();
|
|
728
|
+
if (!instance) throw new InstanceNotFoundError(instanceId);
|
|
729
|
+
const existing = await db.select().from(subscriptions).where(
|
|
730
|
+
and(
|
|
731
|
+
eq(subscriptions.workspaceId, workspaceId),
|
|
732
|
+
eq(subscriptions.instanceId, instanceId)
|
|
733
|
+
)
|
|
734
|
+
).get();
|
|
735
|
+
if (existing) throw new DuplicateSubscriptionError(workspaceId, instanceId);
|
|
736
|
+
const id = crypto.randomUUID();
|
|
737
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
738
|
+
await db.insert(subscriptions).values({ id, workspaceId, instanceId, pinPolicy: pin, subscribedAt: now }).run();
|
|
739
|
+
return { id, workspaceId, instanceId, pinPolicy: pin, subscribedAt: new Date(now) };
|
|
740
|
+
}
|
|
741
|
+
async unsubscribe(subscriptionId) {
|
|
742
|
+
const db = await this.ensureDb();
|
|
743
|
+
const existing = await db.select().from(subscriptions).where(eq(subscriptions.id, subscriptionId)).get();
|
|
744
|
+
if (!existing) throw new SubscriptionNotFoundError(subscriptionId);
|
|
745
|
+
await db.delete(subscriptions).where(eq(subscriptions.id, subscriptionId)).run();
|
|
746
|
+
}
|
|
747
|
+
async listSubscriptions(workspaceId) {
|
|
748
|
+
const db = await this.ensureDb();
|
|
749
|
+
return (await db.select().from(subscriptions).where(eq(subscriptions.workspaceId, workspaceId)).all()).map(rowToSubscription);
|
|
750
|
+
}
|
|
751
|
+
async getConsumptionGraph(instanceId) {
|
|
752
|
+
const db = await this.ensureDb();
|
|
753
|
+
return (await db.select().from(subscriptions).where(eq(subscriptions.instanceId, instanceId)).all()).map(rowToSubscription);
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
// library/src/user-library.ts
|
|
758
|
+
var LIBRARY_BACKENDS = ["local", "git", "store"];
|
|
759
|
+
var LIBRARY_OWNERSHIPS = ["owner", "contributor", "reader"];
|
|
760
|
+
var LIBRARY_STRUCTURES = ["flat", "domain"];
|
|
761
|
+
var LibrarySyncError = class extends Error {
|
|
762
|
+
constructor(message, code) {
|
|
763
|
+
super(message);
|
|
764
|
+
this.code = code;
|
|
765
|
+
this.name = "LibrarySyncError";
|
|
766
|
+
}
|
|
767
|
+
code;
|
|
768
|
+
};
|
|
769
|
+
var OperationNotPermittedError = class extends LibrarySyncError {
|
|
770
|
+
constructor(verb, reason) {
|
|
771
|
+
super(`Operation not permitted: ${verb} \u2014 ${reason}`, "operation_not_permitted");
|
|
772
|
+
this.name = "OperationNotPermittedError";
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
var DuplicateLibraryNameError = class extends LibrarySyncError {
|
|
776
|
+
constructor(name) {
|
|
777
|
+
super(`A library named "${name}" already exists.`, "duplicate_name");
|
|
778
|
+
this.name = "DuplicateLibraryNameError";
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
var UserLibraryNotFoundError = class extends LibrarySyncError {
|
|
782
|
+
constructor(ident) {
|
|
783
|
+
super(`Library not found: ${ident}`, "library_not_found");
|
|
784
|
+
this.name = "UserLibraryNotFoundError";
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
// library/src/sync/git-driver.ts
|
|
789
|
+
function git(cwd, args) {
|
|
790
|
+
return spawnSync("git", args, { cwd, encoding: "utf-8" });
|
|
791
|
+
}
|
|
792
|
+
function ok(r, action) {
|
|
793
|
+
if (r.status !== 0) {
|
|
794
|
+
throw new LibrarySyncError(
|
|
795
|
+
`git ${action} failed: ${r.stderr.trim() || r.stdout.trim()}`,
|
|
796
|
+
"remote_error"
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
return r.stdout.trim();
|
|
800
|
+
}
|
|
801
|
+
function gitCfg(lib) {
|
|
802
|
+
return lib.backendConfig;
|
|
803
|
+
}
|
|
804
|
+
var GitSyncDriver = class {
|
|
805
|
+
backend = "git";
|
|
806
|
+
async status(lib) {
|
|
807
|
+
const cfg = gitCfg(lib);
|
|
808
|
+
const porcelain = git(lib.path, ["status", "--porcelain"]);
|
|
809
|
+
if (porcelain.status !== 0) {
|
|
810
|
+
return {
|
|
811
|
+
reachable: false,
|
|
812
|
+
localChanges: { added: [], modified: [], deleted: [] },
|
|
813
|
+
notes: [`git not initialised at ${lib.path}`]
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
const added = [];
|
|
817
|
+
const modified = [];
|
|
818
|
+
const deleted = [];
|
|
819
|
+
for (const line of porcelain.stdout.split("\n").filter(Boolean)) {
|
|
820
|
+
const xy = line.slice(0, 2);
|
|
821
|
+
const file = line.slice(3);
|
|
822
|
+
if (xy.includes("A") || xy.startsWith("??")) added.push(file);
|
|
823
|
+
else if (xy.includes("D")) deleted.push(file);
|
|
824
|
+
else if (xy.includes("M") || xy.includes("R")) modified.push(file);
|
|
825
|
+
}
|
|
826
|
+
let remoteChanges;
|
|
827
|
+
const fetch2 = git(lib.path, ["fetch", "--quiet"]);
|
|
828
|
+
const reachable = fetch2.status === 0;
|
|
829
|
+
if (reachable) {
|
|
830
|
+
const counts = git(lib.path, [
|
|
831
|
+
"rev-list",
|
|
832
|
+
"--left-right",
|
|
833
|
+
"--count",
|
|
834
|
+
`${cfg.branch}...origin/${cfg.branch}`
|
|
835
|
+
]);
|
|
836
|
+
if (counts.status === 0) {
|
|
837
|
+
const [ahead, behind] = counts.stdout.trim().split(/\s+/).map(Number);
|
|
838
|
+
remoteChanges = { ahead: ahead || 0, behind: behind || 0 };
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
return {
|
|
842
|
+
reachable,
|
|
843
|
+
localChanges: { added, modified, deleted },
|
|
844
|
+
remoteChanges,
|
|
845
|
+
notes: reachable ? [] : ["unable to reach origin"]
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
async pull(lib, opts) {
|
|
849
|
+
const cfg = gitCfg(lib);
|
|
850
|
+
const args = ["pull", "--ff-only", "origin", cfg.branch];
|
|
851
|
+
if (opts?.rebase) args.splice(1, 1, "--rebase");
|
|
852
|
+
const r = git(lib.path, args);
|
|
853
|
+
if (r.status !== 0) {
|
|
854
|
+
if (/non-fast-forward|diverged|conflict/i.test(r.stderr)) {
|
|
855
|
+
return { applied: 0, conflicts: [{ path: "(branch)", reason: r.stderr.trim() }] };
|
|
856
|
+
}
|
|
857
|
+
throw new LibrarySyncError(`git pull failed: ${r.stderr.trim()}`, "remote_error");
|
|
858
|
+
}
|
|
859
|
+
return { applied: 1, conflicts: [] };
|
|
860
|
+
}
|
|
861
|
+
async push(lib, opts) {
|
|
862
|
+
if (lib.ownership !== "owner") {
|
|
863
|
+
throw new OperationNotPermittedError(
|
|
864
|
+
"push",
|
|
865
|
+
`library "${lib.name}" has ownership=${lib.ownership}; use \`propose\` instead`
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
const cfg = gitCfg(lib);
|
|
869
|
+
const args = ["push", "origin", cfg.branch];
|
|
870
|
+
if (opts?.force) args.push("--force-with-lease");
|
|
871
|
+
ok(git(lib.path, args), "push");
|
|
872
|
+
return { pushed: 1 };
|
|
873
|
+
}
|
|
874
|
+
async propose(lib, opts) {
|
|
875
|
+
if (lib.ownership !== "contributor") {
|
|
876
|
+
throw new OperationNotPermittedError(
|
|
877
|
+
"propose",
|
|
878
|
+
`propose requires ownership=contributor; got ${lib.ownership}`
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
const cfg = gitCfg(lib);
|
|
882
|
+
const branch = opts.branch ?? `skaile/${(/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}`;
|
|
883
|
+
const remotes = ok(git(lib.path, ["remote"]), "remote-list").split("\n");
|
|
884
|
+
if (!remotes.includes("fork")) {
|
|
885
|
+
if (!cfg.forkUrl) {
|
|
886
|
+
const fork = spawnSync(
|
|
887
|
+
"gh",
|
|
888
|
+
["repo", "fork", cfg.url, "--remote", "--remote-name", "fork"],
|
|
889
|
+
{
|
|
890
|
+
cwd: lib.path,
|
|
891
|
+
encoding: "utf-8"
|
|
892
|
+
}
|
|
893
|
+
);
|
|
894
|
+
if (fork.status !== 0) {
|
|
895
|
+
throw new LibrarySyncError(
|
|
896
|
+
`gh repo fork failed: ${fork.stderr.trim()}. Manual fallback: fork ${cfg.url} on github.com and run \`skaile library set ${lib.name} backendConfig.forkUrl=<url>\`.`,
|
|
897
|
+
"auth_required"
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
} else {
|
|
901
|
+
ok(git(lib.path, ["remote", "add", "fork", cfg.forkUrl]), "remote-add");
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
ok(git(lib.path, ["checkout", "-B", branch]), "checkout");
|
|
905
|
+
ok(git(lib.path, ["push", "fork", branch]), "push-fork");
|
|
906
|
+
const ghArgs = ["pr", "create", "--base", cfg.branch, "--head", `fork:${branch}`];
|
|
907
|
+
if (opts.title) ghArgs.push("--title", opts.title);
|
|
908
|
+
if (opts.body) ghArgs.push("--body", opts.body);
|
|
909
|
+
const pr = spawnSync("gh", ghArgs, { cwd: lib.path, encoding: "utf-8" });
|
|
910
|
+
if (pr.status !== 0) {
|
|
911
|
+
const manualUrl = `${cfg.url.replace(/\.git$/, "")}/compare/${cfg.branch}...${branch}`;
|
|
912
|
+
throw new LibrarySyncError(
|
|
913
|
+
`gh pr create failed: ${pr.stderr.trim()}. Open manually: ${manualUrl}`,
|
|
914
|
+
"remote_error"
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
const prUrl = pr.stdout.trim().split("\n").pop() ?? "(unknown)";
|
|
918
|
+
return { prUrl, branch };
|
|
919
|
+
}
|
|
920
|
+
async publish(_lib, _refs, _opts) {
|
|
921
|
+
throw new OperationNotPermittedError("publish", "git libraries cannot publish; use store");
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
|
|
925
|
+
// library/src/sync/local-driver.ts
|
|
926
|
+
var LocalSyncDriver = class {
|
|
927
|
+
backend = "local";
|
|
928
|
+
async status(_lib) {
|
|
929
|
+
return {
|
|
930
|
+
reachable: true,
|
|
931
|
+
localChanges: { added: [], modified: [], deleted: [] },
|
|
932
|
+
notes: ["local library \u2014 no remote sync needed"]
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
async pull(_lib, _opts) {
|
|
936
|
+
return { applied: 0, conflicts: [] };
|
|
937
|
+
}
|
|
938
|
+
async push(_lib, _opts) {
|
|
939
|
+
return { pushed: 0 };
|
|
940
|
+
}
|
|
941
|
+
async propose(_lib, _opts) {
|
|
942
|
+
throw new OperationNotPermittedError(
|
|
943
|
+
"propose",
|
|
944
|
+
"local libraries have no remote; convert to git first"
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
async publish(_lib, _refs, _opts) {
|
|
948
|
+
throw new OperationNotPermittedError("publish", "local libraries cannot publish");
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
|
|
952
|
+
// library/src/sync/store-driver.ts
|
|
953
|
+
var StoreSyncDriver = class {
|
|
954
|
+
backend = "store";
|
|
955
|
+
async status(_lib) {
|
|
956
|
+
return {
|
|
957
|
+
reachable: true,
|
|
958
|
+
localChanges: { added: [], modified: [], deleted: [] },
|
|
959
|
+
notes: ["catalog refresh only \u2014 store write path is a stub in MVP"]
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
async pull(_lib, _opts) {
|
|
963
|
+
return { applied: 0, conflicts: [] };
|
|
964
|
+
}
|
|
965
|
+
async push(_lib, _opts) {
|
|
966
|
+
throw new OperationNotPermittedError("push", "store libraries publish via `publish`");
|
|
967
|
+
}
|
|
968
|
+
async propose(_lib, _opts) {
|
|
969
|
+
throw new OperationNotPermittedError("propose", "store libraries publish via `publish`");
|
|
970
|
+
}
|
|
971
|
+
async publish(_lib, _refs, _opts) {
|
|
972
|
+
throw new LibrarySyncError(
|
|
973
|
+
"store backend write path is not yet wired (MVP stub)",
|
|
974
|
+
"remote_error"
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
|
|
979
|
+
// library/src/local/user-library-manager.ts
|
|
980
|
+
function rowToUserLibrary(row) {
|
|
981
|
+
const cfg = (() => {
|
|
982
|
+
try {
|
|
983
|
+
return JSON.parse(row.backendConfig);
|
|
984
|
+
} catch {
|
|
985
|
+
return {};
|
|
986
|
+
}
|
|
987
|
+
})();
|
|
988
|
+
return {
|
|
989
|
+
id: row.id,
|
|
990
|
+
name: row.name,
|
|
991
|
+
path: row.path,
|
|
992
|
+
backend: row.backend,
|
|
993
|
+
backendConfig: cfg,
|
|
994
|
+
ownership: row.ownership,
|
|
995
|
+
structure: row.structure ?? void 0,
|
|
996
|
+
isDefault: row.isDefault,
|
|
997
|
+
manifestGenerated: row.manifestGenerated,
|
|
998
|
+
lastSyncAt: row.lastSyncAt ? new Date(row.lastSyncAt) : void 0,
|
|
999
|
+
createdAt: new Date(row.createdAt),
|
|
1000
|
+
updatedAt: new Date(row.updatedAt)
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
var UserLibraryManager = class {
|
|
1004
|
+
constructor(lib) {
|
|
1005
|
+
this.lib = lib;
|
|
1006
|
+
}
|
|
1007
|
+
lib;
|
|
1008
|
+
localDrv = new LocalSyncDriver();
|
|
1009
|
+
gitDrv = new GitSyncDriver();
|
|
1010
|
+
storeDrv = new StoreSyncDriver();
|
|
1011
|
+
/** Resolve the sync driver for a given backend. */
|
|
1012
|
+
driverFor(backend) {
|
|
1013
|
+
switch (backend) {
|
|
1014
|
+
case "local":
|
|
1015
|
+
return this.localDrv;
|
|
1016
|
+
case "git":
|
|
1017
|
+
return this.gitDrv;
|
|
1018
|
+
case "store":
|
|
1019
|
+
return this.storeDrv;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
async addLibrary(input) {
|
|
1023
|
+
const db = await this.lib.dbHandle();
|
|
1024
|
+
const existing = await db.select().from(libraries).where(eq(libraries.name, input.name)).get();
|
|
1025
|
+
if (existing) throw new DuplicateLibraryNameError(input.name);
|
|
1026
|
+
const id = crypto.randomUUID();
|
|
1027
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1028
|
+
if (input.isDefault) {
|
|
1029
|
+
await db.update(libraries).set({ isDefault: false }).run();
|
|
1030
|
+
}
|
|
1031
|
+
await db.insert(libraries).values({
|
|
1032
|
+
id,
|
|
1033
|
+
name: input.name,
|
|
1034
|
+
path: input.path,
|
|
1035
|
+
backend: input.backend,
|
|
1036
|
+
backendConfig: JSON.stringify(input.backendConfig ?? {}),
|
|
1037
|
+
ownership: input.ownership,
|
|
1038
|
+
structure: input.structure ?? null,
|
|
1039
|
+
isDefault: input.isDefault ?? false,
|
|
1040
|
+
manifestGenerated: input.manifestGenerated ?? false,
|
|
1041
|
+
createdAt: now,
|
|
1042
|
+
updatedAt: now
|
|
1043
|
+
}).run();
|
|
1044
|
+
return this.requireLibrary(id);
|
|
1045
|
+
}
|
|
1046
|
+
async listLibraries() {
|
|
1047
|
+
const db = await this.lib.dbHandle();
|
|
1048
|
+
const rows = await db.select().from(libraries).all();
|
|
1049
|
+
return rows.map(rowToUserLibrary).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
1050
|
+
}
|
|
1051
|
+
async getLibrary(nameOrId) {
|
|
1052
|
+
const db = await this.lib.dbHandle();
|
|
1053
|
+
let row = await db.select().from(libraries).where(eq(libraries.name, nameOrId)).get();
|
|
1054
|
+
if (!row) {
|
|
1055
|
+
row = await db.select().from(libraries).where(eq(libraries.id, nameOrId)).get();
|
|
1056
|
+
}
|
|
1057
|
+
return row ? rowToUserLibrary(row) : null;
|
|
1058
|
+
}
|
|
1059
|
+
async requireLibrary(nameOrId) {
|
|
1060
|
+
const lib = await this.getLibrary(nameOrId);
|
|
1061
|
+
if (!lib) throw new UserLibraryNotFoundError(nameOrId);
|
|
1062
|
+
return lib;
|
|
1063
|
+
}
|
|
1064
|
+
async updateLibrary(nameOrId, patch) {
|
|
1065
|
+
const lib = await this.requireLibrary(nameOrId);
|
|
1066
|
+
const db = await this.lib.dbHandle();
|
|
1067
|
+
const updates = {
|
|
1068
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1069
|
+
};
|
|
1070
|
+
if (patch.name !== void 0) updates.name = patch.name;
|
|
1071
|
+
if (patch.path !== void 0) updates.path = patch.path;
|
|
1072
|
+
if (patch.backendConfig !== void 0)
|
|
1073
|
+
updates.backendConfig = JSON.stringify(patch.backendConfig);
|
|
1074
|
+
if (patch.ownership !== void 0) updates.ownership = patch.ownership;
|
|
1075
|
+
if (patch.structure !== void 0) updates.structure = patch.structure;
|
|
1076
|
+
if (patch.manifestGenerated !== void 0) updates.manifestGenerated = patch.manifestGenerated;
|
|
1077
|
+
if (patch.isDefault !== void 0) updates.isDefault = patch.isDefault;
|
|
1078
|
+
if (patch.lastSyncAt !== void 0) updates.lastSyncAt = patch.lastSyncAt.toISOString();
|
|
1079
|
+
await db.update(libraries).set(updates).where(eq(libraries.id, lib.id)).run();
|
|
1080
|
+
return this.requireLibrary(lib.id);
|
|
1081
|
+
}
|
|
1082
|
+
async setDefault(nameOrId) {
|
|
1083
|
+
const lib = await this.requireLibrary(nameOrId);
|
|
1084
|
+
const db = await this.lib.dbHandle();
|
|
1085
|
+
await db.update(libraries).set({ isDefault: false }).run();
|
|
1086
|
+
await db.update(libraries).set({ isDefault: true, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq(libraries.id, lib.id)).run();
|
|
1087
|
+
return this.requireLibrary(lib.id);
|
|
1088
|
+
}
|
|
1089
|
+
async removeLibrary(nameOrId, opts = {}) {
|
|
1090
|
+
const lib = await this.requireLibrary(nameOrId);
|
|
1091
|
+
const db = await this.lib.dbHandle();
|
|
1092
|
+
await db.delete(libraries).where(eq(libraries.id, lib.id)).run();
|
|
1093
|
+
if (opts.purge && fs10.existsSync(lib.path)) {
|
|
1094
|
+
fs10.rmSync(lib.path, { recursive: true, force: true });
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Idempotently ensure a `personal` library exists at `<librariesDir>/personal`.
|
|
1099
|
+
* Created silently — one stderr line — on first call when no writable default
|
|
1100
|
+
* exists. Returns the library row and a `created` flag.
|
|
1101
|
+
*/
|
|
1102
|
+
async ensurePersonalLibrary(librariesDir) {
|
|
1103
|
+
const existing = await this.getLibrary("personal");
|
|
1104
|
+
if (existing) return { library: existing, created: false };
|
|
1105
|
+
const all = await this.listLibraries();
|
|
1106
|
+
const writableDefault = all.find(
|
|
1107
|
+
(l) => l.isDefault && (l.ownership === "owner" || l.ownership === "contributor")
|
|
1108
|
+
);
|
|
1109
|
+
if (writableDefault) return { library: writableDefault, created: false };
|
|
1110
|
+
const personalPath = path5.join(librariesDir, "personal");
|
|
1111
|
+
fs10.mkdirSync(personalPath, { recursive: true });
|
|
1112
|
+
const lib = await this.addLibrary({
|
|
1113
|
+
name: "personal",
|
|
1114
|
+
path: personalPath,
|
|
1115
|
+
backend: "local",
|
|
1116
|
+
backendConfig: {},
|
|
1117
|
+
ownership: "owner",
|
|
1118
|
+
structure: "domain",
|
|
1119
|
+
isDefault: true,
|
|
1120
|
+
manifestGenerated: false
|
|
1121
|
+
});
|
|
1122
|
+
process.stderr.write(
|
|
1123
|
+
`[skaile/library] Created personal library at ${personalPath} (default).
|
|
1124
|
+
`
|
|
1125
|
+
);
|
|
1126
|
+
return { library: lib, created: true };
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
var SKAILE_HOME_ENV = "SKAILE_HOME";
|
|
1130
|
+
function getSidecarRoot() {
|
|
1131
|
+
const home = process.env[SKAILE_HOME_ENV] ?? path5.join(os.homedir(), ".skaile");
|
|
1132
|
+
return path5.join(home, "sources");
|
|
1133
|
+
}
|
|
1134
|
+
function resolveSidecarPaths(slug) {
|
|
1135
|
+
const rootDir = getSidecarRoot();
|
|
1136
|
+
const sidecarDir = path5.join(rootDir, slug);
|
|
1137
|
+
return {
|
|
1138
|
+
rootDir,
|
|
1139
|
+
sidecarDir,
|
|
1140
|
+
manifestFile: path5.join(sidecarDir, ".skaile-source.yaml"),
|
|
1141
|
+
readmeFile: path5.join(sidecarDir, "README.md"),
|
|
1142
|
+
lockFile: path5.join(sidecarDir, ".skaile-source.lock.json")
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
function deriveSlug(sourceConfig, sourcePath, existingSlugs) {
|
|
1146
|
+
const fromConfig = sourceConfig && typeof sourceConfig.name === "string" ? sourceConfig.name : void 0;
|
|
1147
|
+
const base = fromConfig && fromConfig.length > 0 ? slugify2(fromConfig) : slugify2(path5.basename(sourcePath || "")) || "unnamed-source";
|
|
1148
|
+
const taken = new Set(existingSlugs);
|
|
1149
|
+
if (!taken.has(base)) return base;
|
|
1150
|
+
for (let i = 2; i < 1e3; i++) {
|
|
1151
|
+
const candidate = `${base}-${i}`;
|
|
1152
|
+
if (!taken.has(candidate)) return candidate;
|
|
1153
|
+
}
|
|
1154
|
+
return `${base}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1155
|
+
}
|
|
1156
|
+
function listSidecarSlugsOnDisk() {
|
|
1157
|
+
const root = getSidecarRoot();
|
|
1158
|
+
if (!fs10.existsSync(root)) return [];
|
|
1159
|
+
const out = [];
|
|
1160
|
+
for (const entry of fs10.readdirSync(root, { withFileTypes: true })) {
|
|
1161
|
+
if (!entry.isDirectory()) continue;
|
|
1162
|
+
if (entry.name.startsWith(".")) continue;
|
|
1163
|
+
out.push(entry.name);
|
|
1164
|
+
}
|
|
1165
|
+
return out.sort();
|
|
1166
|
+
}
|
|
1167
|
+
function slugify2(input) {
|
|
1168
|
+
return input.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^[-.]+|[-.]+$/g, "");
|
|
1169
|
+
}
|
|
1170
|
+
var FALLBACK_USER_NAME = "Skaile CLI";
|
|
1171
|
+
var FALLBACK_USER_EMAIL = "skaile-cli@local";
|
|
1172
|
+
var ROOT_README = `# Skaile Sidecar Manifests
|
|
1173
|
+
|
|
1174
|
+
This directory is managed by \`skaile source sidecar\` commands. Each
|
|
1175
|
+
subdirectory is a curated local-overlay manifest for an asset source
|
|
1176
|
+
registered in your LocalLibrary at \`~/.skaile/library/lib.db\`.
|
|
1177
|
+
|
|
1178
|
+
You can push this repo to your own remote (e.g. a private dotfiles repo)
|
|
1179
|
+
to share or back up your sidecars across machines:
|
|
1180
|
+
|
|
1181
|
+
\`\`\`bash
|
|
1182
|
+
skaile source sidecar git -- remote add origin git@example.com:you/sidecars.git
|
|
1183
|
+
skaile source sidecar git -- push -u origin main
|
|
1184
|
+
\`\`\`
|
|
1185
|
+
|
|
1186
|
+
See the agent-framework docs (\`library/docs/source-sidecars.md\`) for the
|
|
1187
|
+
full workflow.
|
|
1188
|
+
`;
|
|
1189
|
+
var GITATTRIBUTES = "* text=auto eol=lf\n";
|
|
1190
|
+
var SidecarGit = class {
|
|
1191
|
+
constructor(rootDir) {
|
|
1192
|
+
this.rootDir = rootDir;
|
|
1193
|
+
}
|
|
1194
|
+
rootDir;
|
|
1195
|
+
/**
|
|
1196
|
+
* Initialize the sidecar root if it doesn't yet exist.
|
|
1197
|
+
*
|
|
1198
|
+
* Steps (idempotent — each is a no-op when already present):
|
|
1199
|
+
* 1. `mkdir -p <rootDir>`
|
|
1200
|
+
* 2. `git init -b main <rootDir>` if `<rootDir>/.git` is missing
|
|
1201
|
+
* 3. Write `.gitattributes` (`* text=auto eol=lf`) if missing
|
|
1202
|
+
* 4. Write `README.md` if missing
|
|
1203
|
+
* 5. Apply fallback `user.name` / `user.email` to the repo config if
|
|
1204
|
+
* the global config is missing them
|
|
1205
|
+
* 6. Create the seed commit (`chore: initialize sidecar manifests`) if
|
|
1206
|
+
* the repo has no commits yet
|
|
1207
|
+
*
|
|
1208
|
+
* Subsequent calls don't reset config, so a user who overrode the
|
|
1209
|
+
* identity manually keeps their override.
|
|
1210
|
+
*
|
|
1211
|
+
* @docLink packages/library/concepts#sidecar-git
|
|
1212
|
+
*/
|
|
1213
|
+
async ensureInitialized() {
|
|
1214
|
+
if (!fs10.existsSync(this.rootDir)) {
|
|
1215
|
+
fs10.mkdirSync(this.rootDir, { recursive: true });
|
|
1216
|
+
}
|
|
1217
|
+
const gitDir = path5.join(this.rootDir, ".git");
|
|
1218
|
+
const freshRepo = !fs10.existsSync(gitDir);
|
|
1219
|
+
if (freshRepo) {
|
|
1220
|
+
const init = this.spawn(["init", "-b", "main"]);
|
|
1221
|
+
if (init.exitCode !== 0) {
|
|
1222
|
+
throw new Error(`git init failed: ${init.stderr || init.stdout}`);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
const attrsPath = path5.join(this.rootDir, ".gitattributes");
|
|
1226
|
+
if (!fs10.existsSync(attrsPath)) fs10.writeFileSync(attrsPath, GITATTRIBUTES, "utf-8");
|
|
1227
|
+
const readmePath = path5.join(this.rootDir, "README.md");
|
|
1228
|
+
if (!fs10.existsSync(readmePath)) fs10.writeFileSync(readmePath, ROOT_README, "utf-8");
|
|
1229
|
+
if (!this.hasGlobalGitConfig("user.name")) {
|
|
1230
|
+
this.spawn(["config", "user.name", FALLBACK_USER_NAME]);
|
|
1231
|
+
}
|
|
1232
|
+
if (!this.hasGlobalGitConfig("user.email")) {
|
|
1233
|
+
this.spawn(["config", "user.email", FALLBACK_USER_EMAIL]);
|
|
1234
|
+
}
|
|
1235
|
+
if (freshRepo || !this.hasAnyCommit()) {
|
|
1236
|
+
this.spawn(["add", ".gitattributes", "README.md"]);
|
|
1237
|
+
this.spawn(["commit", "-m", "chore: initialize sidecar manifests"]);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Stage everything under `<rootDir>/<slug>/` and create a commit.
|
|
1242
|
+
*
|
|
1243
|
+
* Idempotent: if there are no staged changes after `git add`, the commit
|
|
1244
|
+
* is skipped (and resolves successfully — a no-op is fine).
|
|
1245
|
+
*
|
|
1246
|
+
* @param slug - Sidecar slug (subdirectory name)
|
|
1247
|
+
* @param message - Commit message (conventional-commits style preferred;
|
|
1248
|
+
* the CLI uses `feat(<slug>): create sidecar...`, `chore(<slug>): ...`)
|
|
1249
|
+
* @param opts - `{ skip: true }` short-circuits without staging or committing
|
|
1250
|
+
*/
|
|
1251
|
+
async commit(slug, message, opts) {
|
|
1252
|
+
if (opts?.skip) return;
|
|
1253
|
+
const slugDir = path5.join(this.rootDir, slug);
|
|
1254
|
+
if (fs10.existsSync(slugDir)) {
|
|
1255
|
+
this.spawn(["add", "--", slug]);
|
|
1256
|
+
} else {
|
|
1257
|
+
this.spawn(["add", "-A"]);
|
|
1258
|
+
}
|
|
1259
|
+
const status = this.spawn(["status", "--porcelain"]);
|
|
1260
|
+
if (status.stdout.trim().length === 0) return;
|
|
1261
|
+
const result = this.spawn(["commit", "-m", message]);
|
|
1262
|
+
if (result.exitCode !== 0) {
|
|
1263
|
+
const combined = `${result.stdout}
|
|
1264
|
+
${result.stderr}`;
|
|
1265
|
+
if (/nothing to commit|nothing added to commit/i.test(combined)) return;
|
|
1266
|
+
throw new Error(`git commit failed: ${combined.trim()}`);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
/**
|
|
1270
|
+
* Check whether the sidecar repo has uncommitted changes.
|
|
1271
|
+
*
|
|
1272
|
+
* @returns `true` when `git status --porcelain` has any output.
|
|
1273
|
+
*/
|
|
1274
|
+
async hasChanges() {
|
|
1275
|
+
const result = this.spawn(["status", "--porcelain"]);
|
|
1276
|
+
return result.stdout.trim().length > 0;
|
|
1277
|
+
}
|
|
1278
|
+
/**
|
|
1279
|
+
* Run an arbitrary `git -C <rootDir> <args>` invocation and return the
|
|
1280
|
+
* captured stdout/stderr + exit code.
|
|
1281
|
+
*
|
|
1282
|
+
* Used by `skaile source sidecar git -- <args>` so users don't have to
|
|
1283
|
+
* `cd ~/.skaile/sources` to operate the repo manually.
|
|
1284
|
+
*
|
|
1285
|
+
* @param args - Git arguments (no leading `git` token)
|
|
1286
|
+
* @returns Combined output + exit code; never throws on non-zero exit
|
|
1287
|
+
* @docLink packages/library/concepts#sidecar-git
|
|
1288
|
+
*/
|
|
1289
|
+
async runRaw(args) {
|
|
1290
|
+
return this.spawn(args);
|
|
1291
|
+
}
|
|
1292
|
+
// -- Internals -----------------------------------------------------------
|
|
1293
|
+
spawn(args) {
|
|
1294
|
+
const result = spawnSync("git", ["-C", this.rootDir, ...args], {
|
|
1295
|
+
encoding: "utf-8"
|
|
1296
|
+
});
|
|
1297
|
+
return {
|
|
1298
|
+
stdout: result.stdout ?? "",
|
|
1299
|
+
stderr: result.stderr ?? "",
|
|
1300
|
+
exitCode: result.status ?? 1
|
|
1301
|
+
};
|
|
1302
|
+
}
|
|
1303
|
+
hasGlobalGitConfig(key) {
|
|
1304
|
+
const result = spawnSync("git", ["config", "--global", "--get", key], { encoding: "utf-8" });
|
|
1305
|
+
return result.status === 0 && (result.stdout ?? "").trim().length > 0;
|
|
1306
|
+
}
|
|
1307
|
+
hasAnyCommit() {
|
|
1308
|
+
const result = this.spawn(["rev-parse", "--verify", "HEAD"]);
|
|
1309
|
+
return result.exitCode === 0;
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1312
|
+
var PinPolicySchema = z2.enum(PIN_POLICIES);
|
|
1313
|
+
var LibraryInstanceRefSchema = z2.object({
|
|
1314
|
+
id: z2.string().uuid(),
|
|
1315
|
+
alias: z2.string().optional()
|
|
1316
|
+
});
|
|
1317
|
+
var LibrarySectionSchema = z2.object({
|
|
1318
|
+
pin_policy: PinPolicySchema.default("minor-track"),
|
|
1319
|
+
instances: z2.array(LibraryInstanceRefSchema).default([])
|
|
1320
|
+
});
|
|
1321
|
+
var PresetAppliedItemSchema = z2.object({
|
|
1322
|
+
instance_id: z2.string().uuid(),
|
|
1323
|
+
def_ref: z2.string()
|
|
1324
|
+
});
|
|
1325
|
+
var PresetAppliedSchema = z2.object({
|
|
1326
|
+
ref: z2.string(),
|
|
1327
|
+
applied_at: z2.string(),
|
|
1328
|
+
items: z2.array(PresetAppliedItemSchema).default([])
|
|
1329
|
+
});
|
|
1330
|
+
var WorkspaceConfigV2Schema = z2.object({
|
|
1331
|
+
version: z2.literal(2),
|
|
1332
|
+
library: LibrarySectionSchema.optional(),
|
|
1333
|
+
presets_applied: z2.array(PresetAppliedSchema).optional()
|
|
1334
|
+
});
|
|
1335
|
+
var LockSubscriptionSchema = z2.object({
|
|
1336
|
+
subscription_id: z2.string().uuid(),
|
|
1337
|
+
instance_id: z2.string().uuid(),
|
|
1338
|
+
def_ref: z2.string(),
|
|
1339
|
+
resolved_version: z2.string(),
|
|
1340
|
+
resolved_sha256: z2.string().optional(),
|
|
1341
|
+
pin_policy: PinPolicySchema
|
|
1342
|
+
});
|
|
1343
|
+
var RequiresEdgeSchema = z2.object({
|
|
1344
|
+
from: z2.string(),
|
|
1345
|
+
to: z2.string(),
|
|
1346
|
+
kind: z2.string().optional()
|
|
1347
|
+
});
|
|
1348
|
+
var PresetExpandedSchema = z2.object({
|
|
1349
|
+
preset_ref: z2.string(),
|
|
1350
|
+
instance_ids: z2.array(z2.string().uuid())
|
|
1351
|
+
});
|
|
1352
|
+
var LockFileSchema = z2.object({
|
|
1353
|
+
version: z2.literal(2),
|
|
1354
|
+
generated_at: z2.string(),
|
|
1355
|
+
subscriptions: z2.array(LockSubscriptionSchema).default([]),
|
|
1356
|
+
requires_graph: z2.array(RequiresEdgeSchema).default([]),
|
|
1357
|
+
presets_expanded: z2.array(PresetExpandedSchema).default([])
|
|
1358
|
+
});
|
|
1359
|
+
function parseWorkspaceV2(raw) {
|
|
1360
|
+
if (raw.version !== 2) return null;
|
|
1361
|
+
return WorkspaceConfigV2Schema.parse(raw);
|
|
1362
|
+
}
|
|
1363
|
+
function loadWorkspaceV2(dir, filename = "skaile.yaml") {
|
|
1364
|
+
const filePath = path5.join(dir, filename);
|
|
1365
|
+
if (!fs10.existsSync(filePath)) return null;
|
|
1366
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
1367
|
+
const raw = parse(content);
|
|
1368
|
+
if (!raw || typeof raw !== "object") return null;
|
|
1369
|
+
return parseWorkspaceV2(raw);
|
|
1370
|
+
}
|
|
1371
|
+
function saveWorkspaceV2(dir, v2, filename = "skaile.yaml") {
|
|
1372
|
+
const filePath = path5.join(dir, filename);
|
|
1373
|
+
let existing = {};
|
|
1374
|
+
if (fs10.existsSync(filePath)) {
|
|
1375
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
1376
|
+
existing = parse(content) ?? {};
|
|
1377
|
+
}
|
|
1378
|
+
existing.version = 2;
|
|
1379
|
+
if (v2.library !== void 0) existing.library = v2.library;
|
|
1380
|
+
if (v2.presets_applied !== void 0) existing.presets_applied = v2.presets_applied;
|
|
1381
|
+
if (!fs10.existsSync(dir)) {
|
|
1382
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
1383
|
+
}
|
|
1384
|
+
fs10.writeFileSync(filePath, stringify(existing, { indent: 2 }), "utf-8");
|
|
1385
|
+
}
|
|
1386
|
+
var LOCK_FILENAME = "skaile.lock.yaml";
|
|
1387
|
+
function loadLockFile(dir) {
|
|
1388
|
+
const filePath = path5.join(dir, LOCK_FILENAME);
|
|
1389
|
+
if (!fs10.existsSync(filePath)) return null;
|
|
1390
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
1391
|
+
const raw = parse(content);
|
|
1392
|
+
return LockFileSchema.parse(raw);
|
|
1393
|
+
}
|
|
1394
|
+
function saveLockFile(dir, lock) {
|
|
1395
|
+
const filePath = path5.join(dir, LOCK_FILENAME);
|
|
1396
|
+
if (!fs10.existsSync(dir)) {
|
|
1397
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
1398
|
+
}
|
|
1399
|
+
fs10.writeFileSync(
|
|
1400
|
+
filePath,
|
|
1401
|
+
`# Auto-generated by skaile. Do not edit manually.
|
|
1402
|
+
${stringify(lock, { indent: 2 })}`,
|
|
1403
|
+
"utf-8"
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1406
|
+
function createEmptyLockFile() {
|
|
1407
|
+
return {
|
|
1408
|
+
version: 2,
|
|
1409
|
+
generated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1410
|
+
subscriptions: [],
|
|
1411
|
+
requires_graph: [],
|
|
1412
|
+
presets_expanded: []
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1415
|
+
function detectWorkspaceVersion(dir, filename = "skaile.yaml") {
|
|
1416
|
+
const filePath = path5.join(dir, filename);
|
|
1417
|
+
if (!fs10.existsSync(filePath)) return null;
|
|
1418
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
1419
|
+
const raw = parse(content);
|
|
1420
|
+
if (!raw || typeof raw !== "object") return null;
|
|
1421
|
+
return raw.version === 2 ? 2 : 1;
|
|
1422
|
+
}
|
|
1423
|
+
var MANIFEST_FILENAME = ".skaile-source.yaml";
|
|
1424
|
+
async function writeManifestIfMissing(input) {
|
|
1425
|
+
const manifestPath = path5.join(input.libraryPath, MANIFEST_FILENAME);
|
|
1426
|
+
if (fs10.existsSync(manifestPath)) return { wrote: false, manifestPath };
|
|
1427
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1428
|
+
const yaml = `# Generated by skaile library add on ${now}
|
|
1429
|
+
# Edit by hand to inline discovered assets; or run \`skaile library refresh-manifest\`.
|
|
1430
|
+
version: 2
|
|
1431
|
+
structure: ${input.structure}
|
|
1432
|
+
publisher: ""
|
|
1433
|
+
assets: []
|
|
1434
|
+
`;
|
|
1435
|
+
fs10.writeFileSync(manifestPath, yaml, "utf-8");
|
|
1436
|
+
if (input.ownership !== "owner") {
|
|
1437
|
+
const excludePath = path5.join(input.libraryPath, ".git", "info", "exclude");
|
|
1438
|
+
if (fs10.existsSync(path5.dirname(excludePath))) {
|
|
1439
|
+
const current = fs10.existsSync(excludePath) ? fs10.readFileSync(excludePath, "utf-8") : "";
|
|
1440
|
+
if (!current.includes(MANIFEST_FILENAME)) {
|
|
1441
|
+
fs10.writeFileSync(
|
|
1442
|
+
excludePath,
|
|
1443
|
+
(current.endsWith("\n") || current === "" ? current : current + "\n") + `# skaile-managed local-overlay manifest
|
|
1444
|
+
${MANIFEST_FILENAME}
|
|
1445
|
+
`,
|
|
1446
|
+
"utf-8"
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
return { wrote: true, manifestPath };
|
|
1452
|
+
}
|
|
1453
|
+
function migrateWorkspaceConfig(dir, opts) {
|
|
1454
|
+
const filename = opts?.filename ?? "skaile.yaml";
|
|
1455
|
+
const filePath = path5.join(dir, filename);
|
|
1456
|
+
if (!fs10.existsSync(filePath)) {
|
|
1457
|
+
return { migrated: false, version: 1, warnings: ["No skaile.yaml found"] };
|
|
1458
|
+
}
|
|
1459
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
1460
|
+
const raw = parse(content);
|
|
1461
|
+
if (!raw || typeof raw !== "object") {
|
|
1462
|
+
return { migrated: false, version: 1, warnings: ["Invalid YAML content"] };
|
|
1463
|
+
}
|
|
1464
|
+
if (raw.version === 2) {
|
|
1465
|
+
return { migrated: false, version: 2, warnings: [] };
|
|
1466
|
+
}
|
|
1467
|
+
const warnings = [];
|
|
1468
|
+
if (raw.dependencies && Array.isArray(raw.dependencies)) {
|
|
1469
|
+
warnings.push(
|
|
1470
|
+
"v1 'dependencies' field found. In v2, use 'library.instances' to reference configured asset instances. Manual migration recommended."
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1473
|
+
if (raw.ai_resources) {
|
|
1474
|
+
warnings.push(
|
|
1475
|
+
"v1 'ai_resources' field found. In v2, sources are managed via 'skaile source add'. The field still works but is deprecated."
|
|
1476
|
+
);
|
|
1477
|
+
}
|
|
1478
|
+
if (!opts?.dryRun) {
|
|
1479
|
+
const doc = parseDocument(content);
|
|
1480
|
+
if (doc.contents && "items" in doc.contents) {
|
|
1481
|
+
const map = doc.contents;
|
|
1482
|
+
const items = map.items;
|
|
1483
|
+
const idx = items.findIndex((p) => p.key?.value === "version");
|
|
1484
|
+
if (idx >= 0) items.splice(idx, 1);
|
|
1485
|
+
doc.set("version", 2);
|
|
1486
|
+
const added = items.pop();
|
|
1487
|
+
if (added) items.unshift(added);
|
|
1488
|
+
} else {
|
|
1489
|
+
doc.set("version", 2);
|
|
1490
|
+
}
|
|
1491
|
+
fs10.writeFileSync(filePath, doc.toString(), "utf-8");
|
|
1492
|
+
}
|
|
1493
|
+
return {
|
|
1494
|
+
migrated: !opts?.dryRun,
|
|
1495
|
+
version: opts?.dryRun ? 1 : 2,
|
|
1496
|
+
warnings
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
// library/src/pin-resolver.ts
|
|
1501
|
+
function resolvePin(pin, availableVersions) {
|
|
1502
|
+
if (availableVersions.length === 0) return null;
|
|
1503
|
+
const parsed = availableVersions.map(parseSemVer).filter((v) => v !== null).sort((a, b) => compareSemVer(b, a));
|
|
1504
|
+
if (parsed.length === 0) return null;
|
|
1505
|
+
if (pin === "latest") {
|
|
1506
|
+
return { version: parsed[0].raw, match: "latest" };
|
|
1507
|
+
}
|
|
1508
|
+
if (pin.startsWith("exact:")) {
|
|
1509
|
+
const target = pin.slice(6);
|
|
1510
|
+
const found = parsed.find((v) => v.raw === target);
|
|
1511
|
+
return found ? { version: found.raw, match: "exact" } : null;
|
|
1512
|
+
}
|
|
1513
|
+
if (pin.startsWith("^")) {
|
|
1514
|
+
const target = parseRangeTarget(pin.slice(1));
|
|
1515
|
+
if (!target) return null;
|
|
1516
|
+
const match = parsed.find(
|
|
1517
|
+
(v) => v.major === target.major && (v.minor > target.minor || v.minor === target.minor && v.patch >= target.patch)
|
|
1518
|
+
);
|
|
1519
|
+
return match ? { version: match.raw, match: "range" } : null;
|
|
1520
|
+
}
|
|
1521
|
+
if (pin.startsWith("~")) {
|
|
1522
|
+
const target = parseRangeTarget(pin.slice(1));
|
|
1523
|
+
if (!target) return null;
|
|
1524
|
+
const match = parsed.find(
|
|
1525
|
+
(v) => v.major === target.major && v.minor === target.minor && v.patch >= target.patch
|
|
1526
|
+
);
|
|
1527
|
+
return match ? { version: match.raw, match: "range" } : null;
|
|
1528
|
+
}
|
|
1529
|
+
if (pin.endsWith(".x")) {
|
|
1530
|
+
const base = pin.slice(0, -2);
|
|
1531
|
+
const parts = base.split(".");
|
|
1532
|
+
const major = Number.parseInt(parts[0], 10);
|
|
1533
|
+
const minor = parts.length > 1 ? Number.parseInt(parts[1], 10) : 0;
|
|
1534
|
+
if (Number.isNaN(major)) return null;
|
|
1535
|
+
const match = parsed.find(
|
|
1536
|
+
(v) => v.major === major && (Number.isNaN(minor) || v.minor === minor)
|
|
1537
|
+
);
|
|
1538
|
+
return match ? { version: match.raw, match: "range" } : null;
|
|
1539
|
+
}
|
|
1540
|
+
const bareSemver = parseSemVer(pin);
|
|
1541
|
+
if (bareSemver) {
|
|
1542
|
+
const found = parsed.find((v) => v.raw === pin);
|
|
1543
|
+
return found ? { version: found.raw, match: "exact" } : null;
|
|
1544
|
+
}
|
|
1545
|
+
return null;
|
|
1546
|
+
}
|
|
1547
|
+
function parseSemVer(v) {
|
|
1548
|
+
const match = v.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
1549
|
+
if (!match) return null;
|
|
1550
|
+
return {
|
|
1551
|
+
major: Number.parseInt(match[1], 10),
|
|
1552
|
+
minor: Number.parseInt(match[2], 10),
|
|
1553
|
+
patch: Number.parseInt(match[3], 10),
|
|
1554
|
+
raw: v
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
function compareSemVer(a, b) {
|
|
1558
|
+
if (a.major !== b.major) return a.major - b.major;
|
|
1559
|
+
if (a.minor !== b.minor) return a.minor - b.minor;
|
|
1560
|
+
return a.patch - b.patch;
|
|
1561
|
+
}
|
|
1562
|
+
function parseRangeTarget(range) {
|
|
1563
|
+
const parts = range.split(".");
|
|
1564
|
+
const major = Number.parseInt(parts[0], 10);
|
|
1565
|
+
if (Number.isNaN(major)) return null;
|
|
1566
|
+
const minor = parts.length > 1 ? Number.parseInt(parts[1], 10) : 0;
|
|
1567
|
+
const patch = parts.length > 2 ? Number.parseInt(parts[2], 10) : 0;
|
|
1568
|
+
return {
|
|
1569
|
+
major,
|
|
1570
|
+
minor: Number.isNaN(minor) ? 0 : minor,
|
|
1571
|
+
patch: Number.isNaN(patch) ? 0 : patch
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
var LocalCatalogSource = class {
|
|
1575
|
+
constructor(library, sourceId, rootPath, registry, options) {
|
|
1576
|
+
this.library = library;
|
|
1577
|
+
this.sourceId = sourceId;
|
|
1578
|
+
this.rootPath = rootPath;
|
|
1579
|
+
this.registry = registry;
|
|
1580
|
+
this.id = `local:${sourceId}`;
|
|
1581
|
+
this.sidecarPath = options?.sidecarPath;
|
|
1582
|
+
}
|
|
1583
|
+
library;
|
|
1584
|
+
sourceId;
|
|
1585
|
+
rootPath;
|
|
1586
|
+
registry;
|
|
1587
|
+
id;
|
|
1588
|
+
sidecarPath;
|
|
1589
|
+
async resolve(ref) {
|
|
1590
|
+
const def = await this.library.getAssetDef(ref);
|
|
1591
|
+
if (!def || def.sourceId !== this.sourceId) return null;
|
|
1592
|
+
return defToCatalogAsset(def);
|
|
1593
|
+
}
|
|
1594
|
+
async listAssets(filter) {
|
|
1595
|
+
const libraryFilter = { sourceId: this.sourceId };
|
|
1596
|
+
if (filter?.kind) libraryFilter.kind = filter.kind;
|
|
1597
|
+
if (filter?.publisher) libraryFilter.publisher = filter.publisher;
|
|
1598
|
+
if (filter?.prefix) libraryFilter.prefix = filter.prefix;
|
|
1599
|
+
const defs = await this.library.listAssetDefs(libraryFilter);
|
|
1600
|
+
return defs.map(defToCatalogAsset);
|
|
1601
|
+
}
|
|
1602
|
+
async fetchTarball(_ref, _sha256) {
|
|
1603
|
+
throw new Error(
|
|
1604
|
+
"LocalCatalogSource does not support tarball delivery. Assets are available on disk."
|
|
1605
|
+
);
|
|
1606
|
+
}
|
|
1607
|
+
async listSources() {
|
|
1608
|
+
return [{ id: this.sourceId, type: "local", url: this.rootPath }];
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* Sync: discover assets in the source directory and cache them in the library.
|
|
1612
|
+
*
|
|
1613
|
+
* Runs the discovery pipeline (glob -> parse -> filter -> hash -> requires)
|
|
1614
|
+
* and upserts each discovered asset into the LocalLibrary cache.
|
|
1615
|
+
*
|
|
1616
|
+
* @returns Discovery statistics and any errors encountered.
|
|
1617
|
+
*/
|
|
1618
|
+
async sync() {
|
|
1619
|
+
const opts = {
|
|
1620
|
+
registry: this.registry,
|
|
1621
|
+
sidecarPath: this.sidecarPath
|
|
1622
|
+
};
|
|
1623
|
+
if (!this.sidecarPath) {
|
|
1624
|
+
opts.sourceConfig = loadSourceConfigIfPresent(this.rootPath);
|
|
1625
|
+
}
|
|
1626
|
+
const result = discoverAssetsInTree(this.rootPath, opts);
|
|
1627
|
+
let assetsUpdated = 0;
|
|
1628
|
+
const errors = [];
|
|
1629
|
+
for (const asset of result.assets) {
|
|
1630
|
+
if (asset.kind === "preset") continue;
|
|
1631
|
+
try {
|
|
1632
|
+
await this.library.upsertAssetDef({
|
|
1633
|
+
id: asset.ref,
|
|
1634
|
+
kind: asset.kind,
|
|
1635
|
+
publisher: asset.publisher,
|
|
1636
|
+
name: asset.name,
|
|
1637
|
+
version: asset.version,
|
|
1638
|
+
sha256: asset.sha256,
|
|
1639
|
+
description: typeof asset.manifest.description === "string" ? asset.manifest.description : void 0,
|
|
1640
|
+
license: typeof asset.manifest.license === "string" ? asset.manifest.license : void 0,
|
|
1641
|
+
category: typeof asset.manifest.category === "string" ? asset.manifest.category : void 0,
|
|
1642
|
+
manifest: asset.manifest,
|
|
1643
|
+
sourceId: this.sourceId,
|
|
1644
|
+
cachedAt: /* @__PURE__ */ new Date(),
|
|
1645
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1646
|
+
});
|
|
1647
|
+
assetsUpdated++;
|
|
1648
|
+
} catch (err) {
|
|
1649
|
+
errors.push(`${asset.ref}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
for (const err of result.errors) {
|
|
1653
|
+
errors.push(`${err.path}: ${err.error}`);
|
|
1654
|
+
}
|
|
1655
|
+
return { assetsFound: result.assets.length, assetsUpdated, errors };
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
function defToCatalogAsset(def) {
|
|
1659
|
+
return {
|
|
1660
|
+
id: def.id,
|
|
1661
|
+
kind: def.kind,
|
|
1662
|
+
publisher: def.publisher,
|
|
1663
|
+
name: def.name,
|
|
1664
|
+
version: def.version,
|
|
1665
|
+
sha256: def.sha256,
|
|
1666
|
+
description: def.description,
|
|
1667
|
+
license: def.license,
|
|
1668
|
+
category: def.category,
|
|
1669
|
+
manifest: def.manifest
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1672
|
+
function loadSourceConfigIfPresent(rootPath) {
|
|
1673
|
+
const configPath = path5.join(rootPath, ".skaile-source.yaml");
|
|
1674
|
+
if (!fs10.existsSync(configPath)) return void 0;
|
|
1675
|
+
try {
|
|
1676
|
+
const content = fs10.readFileSync(configPath, "utf-8");
|
|
1677
|
+
const result = loadSourceConfig(content);
|
|
1678
|
+
if (!result.ok) return void 0;
|
|
1679
|
+
return result.config;
|
|
1680
|
+
} catch {
|
|
1681
|
+
return void 0;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
function defaultCacheDir() {
|
|
1685
|
+
return path5.join(os.homedir(), ".skaile", "catalog-cache");
|
|
1686
|
+
}
|
|
1687
|
+
var INDEX_FILE = "index.json";
|
|
1688
|
+
var TARBALL_DIR = "tarballs";
|
|
1689
|
+
var CatalogCache = class {
|
|
1690
|
+
dir;
|
|
1691
|
+
ttlMs;
|
|
1692
|
+
nowFn;
|
|
1693
|
+
index = null;
|
|
1694
|
+
constructor(opts) {
|
|
1695
|
+
this.dir = opts.dir ?? defaultCacheDir();
|
|
1696
|
+
this.ttlMs = opts.ttlMs;
|
|
1697
|
+
this.nowFn = opts.now ?? Date.now;
|
|
1698
|
+
this.ensureDir();
|
|
1699
|
+
}
|
|
1700
|
+
// ── public: resolve cache ───────────────────────────────────────────────
|
|
1701
|
+
/**
|
|
1702
|
+
* Return a fresh resolve-cache entry for `ref`, or `null` if absent / stale.
|
|
1703
|
+
*
|
|
1704
|
+
* When `ttlMs === 0` (air-gapped), all entries are considered fresh
|
|
1705
|
+
* regardless of `fetchedAt`.
|
|
1706
|
+
*/
|
|
1707
|
+
getResolve(ref) {
|
|
1708
|
+
const idx = this.loadIndex();
|
|
1709
|
+
const entry = idx.resolve[ref];
|
|
1710
|
+
if (!entry) return null;
|
|
1711
|
+
if (this.ttlMs === 0) return entry;
|
|
1712
|
+
if (this.nowFn() - entry.fetchedAt > this.ttlMs) return null;
|
|
1713
|
+
return entry;
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Return a stale resolve-cache entry regardless of TTL — for stale-while-revalidate.
|
|
1717
|
+
*/
|
|
1718
|
+
getResolveStale(ref) {
|
|
1719
|
+
const idx = this.loadIndex();
|
|
1720
|
+
return idx.resolve[ref] ?? null;
|
|
1721
|
+
}
|
|
1722
|
+
/** Persist a resolve-cache entry (use `null` to negatively cache misses). */
|
|
1723
|
+
setResolve(ref, value) {
|
|
1724
|
+
const idx = this.loadIndex();
|
|
1725
|
+
idx.resolve[ref] = { fetchedAt: this.nowFn(), value };
|
|
1726
|
+
this.writeIndex(idx);
|
|
1727
|
+
}
|
|
1728
|
+
// ── public: list cache ──────────────────────────────────────────────────
|
|
1729
|
+
/**
|
|
1730
|
+
* Return a fresh list-cache entry for `filter`, or `null` if absent / stale.
|
|
1731
|
+
*/
|
|
1732
|
+
getList(filter) {
|
|
1733
|
+
const key = filterKey(filter);
|
|
1734
|
+
const idx = this.loadIndex();
|
|
1735
|
+
const entry = idx.list[key];
|
|
1736
|
+
if (!entry) return null;
|
|
1737
|
+
if (this.ttlMs === 0) return entry;
|
|
1738
|
+
if (this.nowFn() - entry.fetchedAt > this.ttlMs) return null;
|
|
1739
|
+
return entry;
|
|
1740
|
+
}
|
|
1741
|
+
/** Return a stale list-cache entry regardless of TTL — for stale-while-revalidate. */
|
|
1742
|
+
getListStale(filter) {
|
|
1743
|
+
const key = filterKey(filter);
|
|
1744
|
+
const idx = this.loadIndex();
|
|
1745
|
+
return idx.list[key] ?? null;
|
|
1746
|
+
}
|
|
1747
|
+
/** Persist a list-cache entry. */
|
|
1748
|
+
setList(filter, items) {
|
|
1749
|
+
const key = filterKey(filter);
|
|
1750
|
+
const idx = this.loadIndex();
|
|
1751
|
+
idx.list[key] = { fetchedAt: this.nowFn(), items };
|
|
1752
|
+
this.writeIndex(idx);
|
|
1753
|
+
}
|
|
1754
|
+
// ── public: tarball cache ───────────────────────────────────────────────
|
|
1755
|
+
/** Absolute path where a tarball with `sha256` would be cached. */
|
|
1756
|
+
tarballPath(sha256) {
|
|
1757
|
+
return path5.join(this.dir, TARBALL_DIR, `${sha256}.tgz`);
|
|
1758
|
+
}
|
|
1759
|
+
/** Read a cached tarball from disk if present, otherwise `null`. */
|
|
1760
|
+
readTarball(sha256) {
|
|
1761
|
+
const p = this.tarballPath(sha256);
|
|
1762
|
+
if (!fs10.existsSync(p)) return null;
|
|
1763
|
+
return fs10.readFileSync(p);
|
|
1764
|
+
}
|
|
1765
|
+
/** Persist a tarball blob to disk (atomic write). */
|
|
1766
|
+
writeTarball(sha256, bytes) {
|
|
1767
|
+
const dir = path5.join(this.dir, TARBALL_DIR);
|
|
1768
|
+
if (!fs10.existsSync(dir)) fs10.mkdirSync(dir, { recursive: true });
|
|
1769
|
+
const finalPath = this.tarballPath(sha256);
|
|
1770
|
+
const tmpPath = `${finalPath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
1771
|
+
fs10.writeFileSync(tmpPath, bytes);
|
|
1772
|
+
fs10.renameSync(tmpPath, finalPath);
|
|
1773
|
+
}
|
|
1774
|
+
// ── public: invalidation ────────────────────────────────────────────────
|
|
1775
|
+
/**
|
|
1776
|
+
* Wipe all cached metadata (resolve + list). Tarballs are content-addressed
|
|
1777
|
+
* and remain valid — they are not invalidated.
|
|
1778
|
+
*
|
|
1779
|
+
* Called by `skaile update`.
|
|
1780
|
+
*/
|
|
1781
|
+
invalidateAll() {
|
|
1782
|
+
const idx = { version: 1, resolve: {}, list: {} };
|
|
1783
|
+
this.index = idx;
|
|
1784
|
+
this.writeIndex(idx);
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* Wipe all cached metadata **and** delete tarball blobs. Used for full reset.
|
|
1788
|
+
*/
|
|
1789
|
+
invalidateEverything() {
|
|
1790
|
+
this.invalidateAll();
|
|
1791
|
+
const tarballDir = path5.join(this.dir, TARBALL_DIR);
|
|
1792
|
+
if (fs10.existsSync(tarballDir)) {
|
|
1793
|
+
fs10.rmSync(tarballDir, { recursive: true, force: true });
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
/** Return whether `ttlMs` is zero (air-gapped mode). */
|
|
1797
|
+
get airGapped() {
|
|
1798
|
+
return this.ttlMs === 0;
|
|
1799
|
+
}
|
|
1800
|
+
// ── private ─────────────────────────────────────────────────────────────
|
|
1801
|
+
ensureDir() {
|
|
1802
|
+
if (!fs10.existsSync(this.dir)) fs10.mkdirSync(this.dir, { recursive: true });
|
|
1803
|
+
const tarballDir = path5.join(this.dir, TARBALL_DIR);
|
|
1804
|
+
if (!fs10.existsSync(tarballDir)) fs10.mkdirSync(tarballDir, { recursive: true });
|
|
1805
|
+
}
|
|
1806
|
+
indexPath() {
|
|
1807
|
+
return path5.join(this.dir, INDEX_FILE);
|
|
1808
|
+
}
|
|
1809
|
+
loadIndex() {
|
|
1810
|
+
if (this.index) return this.index;
|
|
1811
|
+
const p = this.indexPath();
|
|
1812
|
+
if (!fs10.existsSync(p)) {
|
|
1813
|
+
this.index = { version: 1, resolve: {}, list: {} };
|
|
1814
|
+
return this.index;
|
|
1815
|
+
}
|
|
1816
|
+
try {
|
|
1817
|
+
const raw = JSON.parse(fs10.readFileSync(p, "utf-8"));
|
|
1818
|
+
if (raw && typeof raw === "object" && raw.version === 1) {
|
|
1819
|
+
this.index = {
|
|
1820
|
+
version: 1,
|
|
1821
|
+
resolve: raw.resolve ?? {},
|
|
1822
|
+
list: raw.list ?? {}
|
|
1823
|
+
};
|
|
1824
|
+
return this.index;
|
|
1825
|
+
}
|
|
1826
|
+
} catch {
|
|
1827
|
+
}
|
|
1828
|
+
this.index = { version: 1, resolve: {}, list: {} };
|
|
1829
|
+
return this.index;
|
|
1830
|
+
}
|
|
1831
|
+
writeIndex(idx) {
|
|
1832
|
+
this.index = idx;
|
|
1833
|
+
const p = this.indexPath();
|
|
1834
|
+
const tmp = `${p}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
1835
|
+
fs10.writeFileSync(tmp, JSON.stringify(idx, null, 2), "utf-8");
|
|
1836
|
+
fs10.renameSync(tmp, p);
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
function filterKey(filter) {
|
|
1840
|
+
if (!filter) return "__all__";
|
|
1841
|
+
const keys = Object.keys(filter).sort();
|
|
1842
|
+
const norm = {};
|
|
1843
|
+
for (const k of keys) {
|
|
1844
|
+
const v = filter[k];
|
|
1845
|
+
if (v !== void 0) norm[k] = v;
|
|
1846
|
+
}
|
|
1847
|
+
return Object.keys(norm).length === 0 ? "__all__" : JSON.stringify(norm);
|
|
1848
|
+
}
|
|
1849
|
+
function sha256Hex(bytes) {
|
|
1850
|
+
const h = crypto.createHash("sha256");
|
|
1851
|
+
h.update(bytes);
|
|
1852
|
+
return h.digest("hex");
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
// library/src/remote/remote-catalog-source.ts
|
|
1856
|
+
var TarballHashMismatchError = class extends Error {
|
|
1857
|
+
constructor(expected, actual) {
|
|
1858
|
+
super(`SHA256 mismatch: expected ${expected}, got ${actual}`);
|
|
1859
|
+
this.expected = expected;
|
|
1860
|
+
this.actual = actual;
|
|
1861
|
+
this.name = "TarballHashMismatchError";
|
|
1862
|
+
}
|
|
1863
|
+
expected;
|
|
1864
|
+
actual;
|
|
1865
|
+
};
|
|
1866
|
+
var OfflineError = class extends Error {
|
|
1867
|
+
constructor(message) {
|
|
1868
|
+
super(`${message} (air-gapped mode; run \`skaile update\` to refresh the cache)`);
|
|
1869
|
+
this.name = "OfflineError";
|
|
1870
|
+
}
|
|
1871
|
+
};
|
|
1872
|
+
var CatalogHttpError = class extends Error {
|
|
1873
|
+
constructor(message, status, url) {
|
|
1874
|
+
super(message);
|
|
1875
|
+
this.status = status;
|
|
1876
|
+
this.url = url;
|
|
1877
|
+
this.name = "CatalogHttpError";
|
|
1878
|
+
}
|
|
1879
|
+
status;
|
|
1880
|
+
url;
|
|
1881
|
+
};
|
|
1882
|
+
var DEFAULT_TTL_MS = 864e5;
|
|
1883
|
+
var RemoteCatalogSource = class {
|
|
1884
|
+
id;
|
|
1885
|
+
baseUrl;
|
|
1886
|
+
cache;
|
|
1887
|
+
cacheTtlMs;
|
|
1888
|
+
httpClient;
|
|
1889
|
+
silentBackgroundErrors;
|
|
1890
|
+
/** Tracks in-flight background revalidations so callers can `await` them in tests. */
|
|
1891
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
1892
|
+
constructor(opts) {
|
|
1893
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
1894
|
+
this.id = `remote:${this.baseUrl}`;
|
|
1895
|
+
this.cacheTtlMs = opts.cacheTtlMs ?? DEFAULT_TTL_MS;
|
|
1896
|
+
this.httpClient = opts.httpClient ?? defaultFetch;
|
|
1897
|
+
this.silentBackgroundErrors = opts.silentBackgroundErrors ?? false;
|
|
1898
|
+
this.cache = opts.cache ?? new CatalogCache({
|
|
1899
|
+
dir: opts.cacheDir,
|
|
1900
|
+
ttlMs: this.cacheTtlMs,
|
|
1901
|
+
now: opts.now
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
// ── ICatalogSource ──────────────────────────────────────────────────────
|
|
1905
|
+
/**
|
|
1906
|
+
* Resolve a single asset by canonical ref (`<publisher>/<name>@<version>`).
|
|
1907
|
+
*
|
|
1908
|
+
* Cache: hit returns immediately. Miss fetches `/trpc/catalog.get`. Stale
|
|
1909
|
+
* entry serves the cached value and triggers a background refresh.
|
|
1910
|
+
*
|
|
1911
|
+
* Air-gapped: throws {@link OfflineError} on cache miss.
|
|
1912
|
+
*/
|
|
1913
|
+
async resolve(ref) {
|
|
1914
|
+
const fresh = this.cache.getResolve(ref);
|
|
1915
|
+
if (fresh) return fresh.value;
|
|
1916
|
+
if (this.cache.airGapped) {
|
|
1917
|
+
const stale2 = this.cache.getResolveStale(ref);
|
|
1918
|
+
if (stale2) return stale2.value;
|
|
1919
|
+
throw new OfflineError(`Asset '${ref}' not in cache`);
|
|
1920
|
+
}
|
|
1921
|
+
const stale = this.cache.getResolveStale(ref);
|
|
1922
|
+
if (stale) {
|
|
1923
|
+
this.scheduleBackground(`resolve:${ref}`, () => this.fetchAndStoreResolve(ref));
|
|
1924
|
+
return stale.value;
|
|
1925
|
+
}
|
|
1926
|
+
return this.fetchAndStoreResolve(ref);
|
|
1927
|
+
}
|
|
1928
|
+
/**
|
|
1929
|
+
* List assets matching `filter`.
|
|
1930
|
+
*
|
|
1931
|
+
* Cache: hit returns immediately. Miss fetches `/trpc/catalog.list`. Stale
|
|
1932
|
+
* entry serves the cached array and triggers a background refresh.
|
|
1933
|
+
*
|
|
1934
|
+
* Air-gapped: throws {@link OfflineError} on cache miss.
|
|
1935
|
+
*/
|
|
1936
|
+
async listAssets(filter) {
|
|
1937
|
+
const fresh = this.cache.getList(filter);
|
|
1938
|
+
if (fresh) return fresh.items;
|
|
1939
|
+
if (this.cache.airGapped) {
|
|
1940
|
+
const stale2 = this.cache.getListStale(filter);
|
|
1941
|
+
if (stale2) return stale2.items;
|
|
1942
|
+
throw new OfflineError("Catalog list not in cache");
|
|
1943
|
+
}
|
|
1944
|
+
const stale = this.cache.getListStale(filter);
|
|
1945
|
+
if (stale) {
|
|
1946
|
+
const filterKey2 = JSON.stringify(filter ?? null);
|
|
1947
|
+
this.scheduleBackground(`list:${filterKey2}`, () => this.fetchAndStoreList(filter));
|
|
1948
|
+
return stale.items;
|
|
1949
|
+
}
|
|
1950
|
+
return this.fetchAndStoreList(filter);
|
|
1951
|
+
}
|
|
1952
|
+
/**
|
|
1953
|
+
* Fetch the content-addressed tarball for an asset. The bytes are downloaded
|
|
1954
|
+
* via the REST endpoint `GET /tarball/:sha256` (which 307-redirects to the
|
|
1955
|
+
* storage tier), then verified against `sha256` on the client side.
|
|
1956
|
+
*
|
|
1957
|
+
* Cache: tarballs are content-addressed and cached forever once written.
|
|
1958
|
+
*
|
|
1959
|
+
* Air-gapped: throws {@link OfflineError} on cache miss.
|
|
1960
|
+
*
|
|
1961
|
+
* @throws {@link TarballHashMismatchError} when the downloaded SHA256 does not match.
|
|
1962
|
+
*/
|
|
1963
|
+
async fetchTarball(_ref, sha256) {
|
|
1964
|
+
const cached = this.cache.readTarball(sha256);
|
|
1965
|
+
if (cached) {
|
|
1966
|
+
const actual2 = sha256Hex(cached);
|
|
1967
|
+
if (actual2 !== sha256) {
|
|
1968
|
+
throw new TarballHashMismatchError(sha256, actual2);
|
|
1969
|
+
}
|
|
1970
|
+
return cached;
|
|
1971
|
+
}
|
|
1972
|
+
if (this.cache.airGapped) {
|
|
1973
|
+
throw new OfflineError(`Tarball '${sha256}' not in cache`);
|
|
1974
|
+
}
|
|
1975
|
+
const url = `${this.baseUrl}/tarball/${encodeURIComponent(sha256)}`;
|
|
1976
|
+
const res = await this.httpClient(url, { method: "GET", redirect: "follow" });
|
|
1977
|
+
if (!res.ok) {
|
|
1978
|
+
throw new CatalogHttpError(
|
|
1979
|
+
`Failed to fetch tarball ${sha256}: ${res.status} ${res.statusText}`,
|
|
1980
|
+
res.status,
|
|
1981
|
+
url
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
const buf = new Uint8Array(await res.arrayBuffer());
|
|
1985
|
+
const actual = sha256Hex(buf);
|
|
1986
|
+
if (actual !== sha256) {
|
|
1987
|
+
throw new TarballHashMismatchError(sha256, actual);
|
|
1988
|
+
}
|
|
1989
|
+
this.cache.writeTarball(sha256, buf);
|
|
1990
|
+
return buf;
|
|
1991
|
+
}
|
|
1992
|
+
/**
|
|
1993
|
+
* Single synthetic Source pointing at the configured Catalog URL. Phase 2
|
|
1994
|
+
* is single-Source per spec; multi-source federation is Phase 4.8.
|
|
1995
|
+
*/
|
|
1996
|
+
async listSources() {
|
|
1997
|
+
return [{ id: this.id, type: "remote-catalog", url: this.baseUrl }];
|
|
1998
|
+
}
|
|
1999
|
+
// ── extension API ───────────────────────────────────────────────────────
|
|
2000
|
+
/**
|
|
2001
|
+
* Force a metadata-cache refresh. Wipes all resolve/list entries and
|
|
2002
|
+
* re-fetches `listAssets()` (no filter) to pre-warm the canonical query.
|
|
2003
|
+
*
|
|
2004
|
+
* Driven by `skaile update`. Tarballs (content-addressed) are not touched
|
|
2005
|
+
* — they remain valid across refreshes.
|
|
2006
|
+
*
|
|
2007
|
+
* In air-gapped mode this method **does** make a network call (bypassing
|
|
2008
|
+
* the TTL=0 gate); it is the only way to repopulate the cache.
|
|
2009
|
+
*/
|
|
2010
|
+
async refresh() {
|
|
2011
|
+
this.cache.invalidateAll();
|
|
2012
|
+
const items = await this.fetchListNetwork(void 0);
|
|
2013
|
+
this.cache.setList(void 0, items);
|
|
2014
|
+
for (const item of items) {
|
|
2015
|
+
this.cache.setResolve(item.id, item);
|
|
2016
|
+
}
|
|
2017
|
+
return { assetsCached: items.length };
|
|
2018
|
+
}
|
|
2019
|
+
/**
|
|
2020
|
+
* Wait for any in-flight stale-while-revalidate background fetches to settle.
|
|
2021
|
+
* Test-only escape hatch.
|
|
2022
|
+
*/
|
|
2023
|
+
async waitForBackground() {
|
|
2024
|
+
const promises = Array.from(this.inFlight.values());
|
|
2025
|
+
await Promise.allSettled(promises);
|
|
2026
|
+
}
|
|
2027
|
+
// ── private ─────────────────────────────────────────────────────────────
|
|
2028
|
+
scheduleBackground(key, fn) {
|
|
2029
|
+
if (this.inFlight.has(key)) return;
|
|
2030
|
+
const p = (async () => {
|
|
2031
|
+
try {
|
|
2032
|
+
await fn();
|
|
2033
|
+
} catch (err) {
|
|
2034
|
+
if (!this.silentBackgroundErrors) {
|
|
2035
|
+
process.stderr.write(
|
|
2036
|
+
`[skaile/catalog] Background refresh failed for ${key}: ${err instanceof Error ? err.message : String(err)}
|
|
2037
|
+
`
|
|
2038
|
+
);
|
|
2039
|
+
}
|
|
2040
|
+
} finally {
|
|
2041
|
+
this.inFlight.delete(key);
|
|
2042
|
+
}
|
|
2043
|
+
})();
|
|
2044
|
+
this.inFlight.set(key, p);
|
|
2045
|
+
}
|
|
2046
|
+
async fetchAndStoreResolve(ref) {
|
|
2047
|
+
const value = await this.fetchResolveNetwork(ref);
|
|
2048
|
+
this.cache.setResolve(ref, value);
|
|
2049
|
+
return value;
|
|
2050
|
+
}
|
|
2051
|
+
async fetchAndStoreList(filter) {
|
|
2052
|
+
const items = await this.fetchListNetwork(filter);
|
|
2053
|
+
this.cache.setList(filter, items);
|
|
2054
|
+
return items;
|
|
2055
|
+
}
|
|
2056
|
+
/** Raw network call: GET /trpc/catalog.get?input=<superjson> */
|
|
2057
|
+
async fetchResolveNetwork(ref) {
|
|
2058
|
+
const url = trpcGetUrl(this.baseUrl, "catalog.get", { ref });
|
|
2059
|
+
const res = await this.httpClient(url, {
|
|
2060
|
+
method: "GET",
|
|
2061
|
+
headers: { Accept: "application/json" }
|
|
2062
|
+
});
|
|
2063
|
+
if (!res.ok) {
|
|
2064
|
+
throw new CatalogHttpError(
|
|
2065
|
+
`catalog.get ${ref} failed: ${res.status} ${res.statusText}`,
|
|
2066
|
+
res.status,
|
|
2067
|
+
url
|
|
2068
|
+
);
|
|
2069
|
+
}
|
|
2070
|
+
const data = await parseTrpcGet(res);
|
|
2071
|
+
if (data === null || data === void 0) return null;
|
|
2072
|
+
return normalizeCatalogAsset(data);
|
|
2073
|
+
}
|
|
2074
|
+
/** Raw network call: GET /trpc/catalog.list?input=<superjson> */
|
|
2075
|
+
async fetchListNetwork(filter) {
|
|
2076
|
+
const input = filter ? { filter } : {};
|
|
2077
|
+
const url = trpcGetUrl(this.baseUrl, "catalog.list", input);
|
|
2078
|
+
const res = await this.httpClient(url, {
|
|
2079
|
+
method: "GET",
|
|
2080
|
+
headers: { Accept: "application/json" }
|
|
2081
|
+
});
|
|
2082
|
+
if (!res.ok) {
|
|
2083
|
+
throw new CatalogHttpError(
|
|
2084
|
+
`catalog.list failed: ${res.status} ${res.statusText}`,
|
|
2085
|
+
res.status,
|
|
2086
|
+
url
|
|
2087
|
+
);
|
|
2088
|
+
}
|
|
2089
|
+
const data = await parseTrpcGet(res);
|
|
2090
|
+
if (!Array.isArray(data)) {
|
|
2091
|
+
throw new CatalogHttpError(
|
|
2092
|
+
`catalog.list returned non-array payload (got ${typeof data})`,
|
|
2093
|
+
200,
|
|
2094
|
+
url
|
|
2095
|
+
);
|
|
2096
|
+
}
|
|
2097
|
+
return data.map(normalizeCatalogAsset);
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2100
|
+
function trpcGetUrl(baseUrl, procedure, input) {
|
|
2101
|
+
const wrapped = JSON.stringify({ json: input });
|
|
2102
|
+
return `${baseUrl.replace(/\/+$/, "")}/trpc/${procedure}?input=${encodeURIComponent(wrapped)}`;
|
|
2103
|
+
}
|
|
2104
|
+
async function parseTrpcGet(res) {
|
|
2105
|
+
const text2 = await res.text();
|
|
2106
|
+
let body;
|
|
2107
|
+
try {
|
|
2108
|
+
body = text2.length > 0 ? JSON.parse(text2) : null;
|
|
2109
|
+
} catch {
|
|
2110
|
+
throw new CatalogHttpError(
|
|
2111
|
+
`tRPC response is not valid JSON: ${text2.slice(0, 200)}`,
|
|
2112
|
+
res.status
|
|
2113
|
+
);
|
|
2114
|
+
}
|
|
2115
|
+
if (body && typeof body === "object" && "error" in body) {
|
|
2116
|
+
const err = body.error;
|
|
2117
|
+
throw new CatalogHttpError(
|
|
2118
|
+
`tRPC error: ${err.message ?? "unknown"}${err.data?.code ? ` (${err.data.code})` : ""}`,
|
|
2119
|
+
res.status
|
|
2120
|
+
);
|
|
2121
|
+
}
|
|
2122
|
+
const result = body?.result;
|
|
2123
|
+
if (!result || !("data" in result)) {
|
|
2124
|
+
throw new CatalogHttpError(`tRPC response missing result.data envelope`, res.status);
|
|
2125
|
+
}
|
|
2126
|
+
const data = result.data;
|
|
2127
|
+
if (data && typeof data === "object" && !Array.isArray(data) && "json" in data) {
|
|
2128
|
+
return data.json;
|
|
2129
|
+
}
|
|
2130
|
+
return data;
|
|
2131
|
+
}
|
|
2132
|
+
function normalizeCatalogAsset(raw) {
|
|
2133
|
+
if (!raw || typeof raw !== "object") {
|
|
2134
|
+
throw new CatalogHttpError("Catalog response item is not an object", 200);
|
|
2135
|
+
}
|
|
2136
|
+
const r = raw;
|
|
2137
|
+
const publisher = pickString(r, "publisher") ?? pickString(r, "publisherSlug") ?? "";
|
|
2138
|
+
const name = pickString(r, "name") ?? "";
|
|
2139
|
+
const version = pickString(r, "version") ?? "";
|
|
2140
|
+
const id = pickString(r, "id") ?? `${publisher}/${name}@${version}`;
|
|
2141
|
+
const kind = pickString(r, "kind") ?? "";
|
|
2142
|
+
const manifest = typeof r.manifest === "object" && r.manifest !== null ? r.manifest : typeof r.manifestJson === "object" && r.manifestJson !== null ? r.manifestJson : {};
|
|
2143
|
+
const asset = {
|
|
2144
|
+
id,
|
|
2145
|
+
kind,
|
|
2146
|
+
publisher,
|
|
2147
|
+
name,
|
|
2148
|
+
version,
|
|
2149
|
+
manifest
|
|
2150
|
+
};
|
|
2151
|
+
const sha = pickString(r, "sha256") ?? pickString(r, "tarballSha256");
|
|
2152
|
+
if (sha) asset.sha256 = sha;
|
|
2153
|
+
const description = pickString(r, "description");
|
|
2154
|
+
if (description) asset.description = description;
|
|
2155
|
+
const license = pickString(r, "license");
|
|
2156
|
+
if (license) asset.license = license;
|
|
2157
|
+
const category = pickString(r, "category");
|
|
2158
|
+
if (category) asset.category = category;
|
|
2159
|
+
return asset;
|
|
2160
|
+
}
|
|
2161
|
+
function pickString(r, key) {
|
|
2162
|
+
const v = r[key];
|
|
2163
|
+
return typeof v === "string" ? v : void 0;
|
|
2164
|
+
}
|
|
2165
|
+
var defaultFetch = async (url, init) => {
|
|
2166
|
+
if (typeof fetch === "undefined") {
|
|
2167
|
+
throw new Error("global fetch is not available; pass an httpClient explicitly");
|
|
2168
|
+
}
|
|
2169
|
+
return fetch(url, init);
|
|
2170
|
+
};
|
|
2171
|
+
|
|
2172
|
+
// library/src/remote/rest-catalog-source.ts
|
|
2173
|
+
var DEFAULT_TTL_MS2 = 864e5;
|
|
2174
|
+
var RestCatalogSource = class {
|
|
2175
|
+
id;
|
|
2176
|
+
baseUrl;
|
|
2177
|
+
cache;
|
|
2178
|
+
cacheTtlMs;
|
|
2179
|
+
httpClient;
|
|
2180
|
+
silentBackgroundErrors;
|
|
2181
|
+
/** Tracks in-flight background revalidations so callers can `await` them in tests. */
|
|
2182
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
2183
|
+
constructor(opts) {
|
|
2184
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
2185
|
+
this.id = `rest:${this.baseUrl}`;
|
|
2186
|
+
this.cacheTtlMs = opts.cacheTtlMs ?? DEFAULT_TTL_MS2;
|
|
2187
|
+
this.httpClient = opts.httpClient ?? defaultFetch2;
|
|
2188
|
+
this.silentBackgroundErrors = opts.silentBackgroundErrors ?? false;
|
|
2189
|
+
this.cache = opts.cache ?? new CatalogCache({
|
|
2190
|
+
dir: opts.cacheDir,
|
|
2191
|
+
ttlMs: this.cacheTtlMs,
|
|
2192
|
+
now: opts.now
|
|
2193
|
+
});
|
|
2194
|
+
}
|
|
2195
|
+
// ── ICatalogSource ──────────────────────────────────────────────────────
|
|
2196
|
+
/**
|
|
2197
|
+
* Resolve a single asset by canonical ref (`<publisher>/<name>@<version>`).
|
|
2198
|
+
*
|
|
2199
|
+
* Cache: hit returns immediately. Miss fetches `/api/catalog/get?ref=<ref>`. Stale
|
|
2200
|
+
* entry serves the cached value and triggers a background refresh.
|
|
2201
|
+
*
|
|
2202
|
+
* Air-gapped: throws {@link OfflineError} on cache miss.
|
|
2203
|
+
*/
|
|
2204
|
+
async resolve(ref) {
|
|
2205
|
+
const fresh = this.cache.getResolve(ref);
|
|
2206
|
+
if (fresh) return fresh.value;
|
|
2207
|
+
if (this.cache.airGapped) {
|
|
2208
|
+
const stale2 = this.cache.getResolveStale(ref);
|
|
2209
|
+
if (stale2) return stale2.value;
|
|
2210
|
+
throw new OfflineError(`Asset '${ref}' not in cache`);
|
|
2211
|
+
}
|
|
2212
|
+
const stale = this.cache.getResolveStale(ref);
|
|
2213
|
+
if (stale) {
|
|
2214
|
+
this.scheduleBackground(`resolve:${ref}`, () => this.fetchAndStoreResolve(ref));
|
|
2215
|
+
return stale.value;
|
|
2216
|
+
}
|
|
2217
|
+
return this.fetchAndStoreResolve(ref);
|
|
2218
|
+
}
|
|
2219
|
+
/**
|
|
2220
|
+
* List assets matching `filter`.
|
|
2221
|
+
*
|
|
2222
|
+
* Cache: hit returns immediately. Miss fetches `/api/catalog/list`. Stale
|
|
2223
|
+
* entry serves the cached array and triggers a background refresh.
|
|
2224
|
+
*
|
|
2225
|
+
* Air-gapped: throws {@link OfflineError} on cache miss.
|
|
2226
|
+
*
|
|
2227
|
+
* Note: `filter.prefix` is not supported by the forge-store REST API and is silently ignored.
|
|
2228
|
+
*/
|
|
2229
|
+
async listAssets(filter) {
|
|
2230
|
+
const fresh = this.cache.getList(filter);
|
|
2231
|
+
if (fresh) return fresh.items;
|
|
2232
|
+
if (this.cache.airGapped) {
|
|
2233
|
+
const stale2 = this.cache.getListStale(filter);
|
|
2234
|
+
if (stale2) return stale2.items;
|
|
2235
|
+
throw new OfflineError("Catalog list not in cache");
|
|
2236
|
+
}
|
|
2237
|
+
const stale = this.cache.getListStale(filter);
|
|
2238
|
+
if (stale) {
|
|
2239
|
+
const filterKey2 = JSON.stringify(filter ?? null);
|
|
2240
|
+
this.scheduleBackground(`list:${filterKey2}`, () => this.fetchAndStoreList(filter));
|
|
2241
|
+
return stale.items;
|
|
2242
|
+
}
|
|
2243
|
+
return this.fetchAndStoreList(filter);
|
|
2244
|
+
}
|
|
2245
|
+
/**
|
|
2246
|
+
* Fetch the content-addressed tarball for an asset.
|
|
2247
|
+
*
|
|
2248
|
+
* Steps:
|
|
2249
|
+
* 1. `GET /api/tarball/manifest?sha256=<sha256>` → JSON with `{ url, ... }`
|
|
2250
|
+
* 2. `GET <manifest.url>` following redirects → raw bytes
|
|
2251
|
+
* 3. Verify SHA256 client-side — hard fail on mismatch
|
|
2252
|
+
* 4. Write to cache on success
|
|
2253
|
+
*
|
|
2254
|
+
* Cache: tarballs are content-addressed and cached forever once written.
|
|
2255
|
+
*
|
|
2256
|
+
* Air-gapped: throws {@link OfflineError} on cache miss.
|
|
2257
|
+
*
|
|
2258
|
+
* @throws {@link TarballHashMismatchError} when the downloaded SHA256 does not match.
|
|
2259
|
+
*/
|
|
2260
|
+
async fetchTarball(_ref, sha256) {
|
|
2261
|
+
const cached = this.cache.readTarball(sha256);
|
|
2262
|
+
if (cached) {
|
|
2263
|
+
const actual2 = sha256Hex(cached);
|
|
2264
|
+
if (actual2 !== sha256) {
|
|
2265
|
+
throw new TarballHashMismatchError(sha256, actual2);
|
|
2266
|
+
}
|
|
2267
|
+
return cached;
|
|
2268
|
+
}
|
|
2269
|
+
if (this.cache.airGapped) {
|
|
2270
|
+
throw new OfflineError(`Tarball '${sha256}' not in cache`);
|
|
2271
|
+
}
|
|
2272
|
+
const manifestUrl = `${this.baseUrl}/api/tarball/manifest?sha256=${encodeURIComponent(sha256)}`;
|
|
2273
|
+
const manifestRes = await this.httpClient(manifestUrl, {
|
|
2274
|
+
method: "GET",
|
|
2275
|
+
headers: { Accept: "application/json" }
|
|
2276
|
+
});
|
|
2277
|
+
if (!manifestRes.ok) {
|
|
2278
|
+
throw new CatalogHttpError(
|
|
2279
|
+
`Failed to fetch tarball manifest for ${sha256}: ${manifestRes.status} ${manifestRes.statusText}`,
|
|
2280
|
+
manifestRes.status,
|
|
2281
|
+
manifestUrl
|
|
2282
|
+
);
|
|
2283
|
+
}
|
|
2284
|
+
const manifestText = await manifestRes.text();
|
|
2285
|
+
let manifest;
|
|
2286
|
+
try {
|
|
2287
|
+
manifest = JSON.parse(manifestText);
|
|
2288
|
+
} catch {
|
|
2289
|
+
throw new CatalogHttpError(
|
|
2290
|
+
`Tarball manifest response is not valid JSON: ${manifestText.slice(0, 200)}`,
|
|
2291
|
+
manifestRes.status,
|
|
2292
|
+
manifestUrl
|
|
2293
|
+
);
|
|
2294
|
+
}
|
|
2295
|
+
const downloadUrl = manifest && typeof manifest === "object" && "url" in manifest ? manifest.url : void 0;
|
|
2296
|
+
if (typeof downloadUrl !== "string") {
|
|
2297
|
+
throw new CatalogHttpError(
|
|
2298
|
+
`Tarball manifest missing 'url' field`,
|
|
2299
|
+
manifestRes.status,
|
|
2300
|
+
manifestUrl
|
|
2301
|
+
);
|
|
2302
|
+
}
|
|
2303
|
+
const tarballRes = await this.httpClient(downloadUrl, { method: "GET", redirect: "follow" });
|
|
2304
|
+
if (!tarballRes.ok) {
|
|
2305
|
+
throw new CatalogHttpError(
|
|
2306
|
+
`Failed to fetch tarball ${sha256}: ${tarballRes.status} ${tarballRes.statusText}`,
|
|
2307
|
+
tarballRes.status,
|
|
2308
|
+
downloadUrl
|
|
2309
|
+
);
|
|
2310
|
+
}
|
|
2311
|
+
const buf = new Uint8Array(await tarballRes.arrayBuffer());
|
|
2312
|
+
const actual = sha256Hex(buf);
|
|
2313
|
+
if (actual !== sha256) {
|
|
2314
|
+
throw new TarballHashMismatchError(sha256, actual);
|
|
2315
|
+
}
|
|
2316
|
+
this.cache.writeTarball(sha256, buf);
|
|
2317
|
+
return buf;
|
|
2318
|
+
}
|
|
2319
|
+
/**
|
|
2320
|
+
* Single synthetic Source pointing at the configured forge-store URL.
|
|
2321
|
+
*/
|
|
2322
|
+
async listSources() {
|
|
2323
|
+
return [{ id: this.id, type: "rest-catalog", url: this.baseUrl }];
|
|
2324
|
+
}
|
|
2325
|
+
// ── extension API ───────────────────────────────────────────────────────
|
|
2326
|
+
/**
|
|
2327
|
+
* Force a metadata-cache refresh. Wipes all resolve/list entries and
|
|
2328
|
+
* re-fetches `listAssets()` (no filter) to pre-warm the canonical query.
|
|
2329
|
+
*
|
|
2330
|
+
* Driven by `skaile update`. Tarballs (content-addressed) are not touched.
|
|
2331
|
+
*
|
|
2332
|
+
* In air-gapped mode this method **does** make a network call (bypassing
|
|
2333
|
+
* the TTL=0 gate); it is the only way to repopulate the cache.
|
|
2334
|
+
*/
|
|
2335
|
+
async refresh() {
|
|
2336
|
+
this.cache.invalidateAll();
|
|
2337
|
+
const items = await this.fetchListNetwork(void 0);
|
|
2338
|
+
this.cache.setList(void 0, items);
|
|
2339
|
+
for (const item of items) {
|
|
2340
|
+
this.cache.setResolve(item.id, item);
|
|
2341
|
+
}
|
|
2342
|
+
return { assetsCached: items.length };
|
|
2343
|
+
}
|
|
2344
|
+
/**
|
|
2345
|
+
* Wait for any in-flight stale-while-revalidate background fetches to settle.
|
|
2346
|
+
* Test-only escape hatch.
|
|
2347
|
+
*/
|
|
2348
|
+
async waitForBackground() {
|
|
2349
|
+
const promises = Array.from(this.inFlight.values());
|
|
2350
|
+
await Promise.allSettled(promises);
|
|
2351
|
+
}
|
|
2352
|
+
// ── private ─────────────────────────────────────────────────────────────
|
|
2353
|
+
scheduleBackground(key, fn) {
|
|
2354
|
+
if (this.inFlight.has(key)) return;
|
|
2355
|
+
const p = (async () => {
|
|
2356
|
+
try {
|
|
2357
|
+
await fn();
|
|
2358
|
+
} catch (err) {
|
|
2359
|
+
if (!this.silentBackgroundErrors) {
|
|
2360
|
+
process.stderr.write(
|
|
2361
|
+
`[skaile/catalog] Background refresh failed for ${key}: ${err instanceof Error ? err.message : String(err)}
|
|
2362
|
+
`
|
|
2363
|
+
);
|
|
2364
|
+
}
|
|
2365
|
+
} finally {
|
|
2366
|
+
this.inFlight.delete(key);
|
|
2367
|
+
}
|
|
2368
|
+
})();
|
|
2369
|
+
this.inFlight.set(key, p);
|
|
2370
|
+
}
|
|
2371
|
+
async fetchAndStoreResolve(ref) {
|
|
2372
|
+
const value = await this.fetchResolveNetwork(ref);
|
|
2373
|
+
this.cache.setResolve(ref, value);
|
|
2374
|
+
return value;
|
|
2375
|
+
}
|
|
2376
|
+
async fetchAndStoreList(filter) {
|
|
2377
|
+
const items = await this.fetchListNetwork(filter);
|
|
2378
|
+
this.cache.setList(filter, items);
|
|
2379
|
+
return items;
|
|
2380
|
+
}
|
|
2381
|
+
/** Raw network call: GET /api/catalog/get?ref=<ref> */
|
|
2382
|
+
async fetchResolveNetwork(ref) {
|
|
2383
|
+
const url = `${this.baseUrl}/api/catalog/get?ref=${encodeURIComponent(ref)}`;
|
|
2384
|
+
const res = await this.httpClient(url, {
|
|
2385
|
+
method: "GET",
|
|
2386
|
+
headers: { Accept: "application/json" }
|
|
2387
|
+
});
|
|
2388
|
+
if (!res.ok) {
|
|
2389
|
+
throw new CatalogHttpError(
|
|
2390
|
+
`catalog/get ${ref} failed: ${res.status} ${res.statusText}`,
|
|
2391
|
+
res.status,
|
|
2392
|
+
url
|
|
2393
|
+
);
|
|
2394
|
+
}
|
|
2395
|
+
const data = await parseRestResponse(res, url);
|
|
2396
|
+
if (data === null || data === void 0) return null;
|
|
2397
|
+
return normalizeRestAsset(data);
|
|
2398
|
+
}
|
|
2399
|
+
/** Raw network call: GET /api/catalog/list?publisher=&kind=&category= */
|
|
2400
|
+
async fetchListNetwork(filter) {
|
|
2401
|
+
const params = new URLSearchParams();
|
|
2402
|
+
if (filter?.publisher) params.set("publisher", filter.publisher);
|
|
2403
|
+
if (filter?.kind) params.set("kind", filter.kind);
|
|
2404
|
+
const qs = params.toString();
|
|
2405
|
+
const url = `${this.baseUrl}/api/catalog/list${qs ? `?${qs}` : ""}`;
|
|
2406
|
+
const res = await this.httpClient(url, {
|
|
2407
|
+
method: "GET",
|
|
2408
|
+
headers: { Accept: "application/json" }
|
|
2409
|
+
});
|
|
2410
|
+
if (!res.ok) {
|
|
2411
|
+
throw new CatalogHttpError(
|
|
2412
|
+
`catalog/list failed: ${res.status} ${res.statusText}`,
|
|
2413
|
+
res.status,
|
|
2414
|
+
url
|
|
2415
|
+
);
|
|
2416
|
+
}
|
|
2417
|
+
const data = await parseRestResponse(res, url);
|
|
2418
|
+
if (!Array.isArray(data)) {
|
|
2419
|
+
throw new CatalogHttpError(
|
|
2420
|
+
`catalog/list returned non-array payload (got ${typeof data})`,
|
|
2421
|
+
200,
|
|
2422
|
+
url
|
|
2423
|
+
);
|
|
2424
|
+
}
|
|
2425
|
+
return data.map(normalizeRestAsset);
|
|
2426
|
+
}
|
|
2427
|
+
};
|
|
2428
|
+
async function parseRestResponse(res, url) {
|
|
2429
|
+
const text2 = await res.text();
|
|
2430
|
+
if (text2.length === 0) return null;
|
|
2431
|
+
try {
|
|
2432
|
+
return JSON.parse(text2);
|
|
2433
|
+
} catch {
|
|
2434
|
+
throw new CatalogHttpError(
|
|
2435
|
+
`REST response is not valid JSON: ${text2.slice(0, 200)}`,
|
|
2436
|
+
res.status,
|
|
2437
|
+
url
|
|
2438
|
+
);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
function normalizeRestAsset(raw) {
|
|
2442
|
+
if (!raw || typeof raw !== "object") {
|
|
2443
|
+
throw new CatalogHttpError("Catalog REST response item is not an object", 200);
|
|
2444
|
+
}
|
|
2445
|
+
const r = raw;
|
|
2446
|
+
const publisher = pickString2(r, "publisherNamespace") ?? pickString2(r, "publisher") ?? "";
|
|
2447
|
+
const name = pickString2(r, "name") ?? "";
|
|
2448
|
+
const version = pickString2(r, "version") ?? "";
|
|
2449
|
+
const kind = pickString2(r, "kind") ?? "";
|
|
2450
|
+
const id = `${publisher}/${name}@${version}`;
|
|
2451
|
+
const requiresParsed = tryParseJson(pickString2(r, "requiresJson"));
|
|
2452
|
+
const filesParsed = tryParseJson(pickString2(r, "filesJson"));
|
|
2453
|
+
const manifest = { ...requiresParsed, ...filesParsed };
|
|
2454
|
+
const asset = {
|
|
2455
|
+
id,
|
|
2456
|
+
kind,
|
|
2457
|
+
publisher,
|
|
2458
|
+
name,
|
|
2459
|
+
version,
|
|
2460
|
+
manifest
|
|
2461
|
+
};
|
|
2462
|
+
const sha = pickString2(r, "sha256");
|
|
2463
|
+
if (sha) asset.sha256 = sha;
|
|
2464
|
+
const description = pickString2(r, "description");
|
|
2465
|
+
if (description) asset.description = description;
|
|
2466
|
+
const license = pickString2(r, "license");
|
|
2467
|
+
if (license) asset.license = license;
|
|
2468
|
+
const category = pickString2(r, "category");
|
|
2469
|
+
if (category) asset.category = category;
|
|
2470
|
+
return asset;
|
|
2471
|
+
}
|
|
2472
|
+
function pickString2(r, key) {
|
|
2473
|
+
const v = r[key];
|
|
2474
|
+
return typeof v === "string" ? v : void 0;
|
|
2475
|
+
}
|
|
2476
|
+
function tryParseJson(s) {
|
|
2477
|
+
if (!s) return {};
|
|
2478
|
+
try {
|
|
2479
|
+
const parsed = JSON.parse(s);
|
|
2480
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2481
|
+
return parsed;
|
|
2482
|
+
}
|
|
2483
|
+
} catch {
|
|
2484
|
+
}
|
|
2485
|
+
return {};
|
|
2486
|
+
}
|
|
2487
|
+
var defaultFetch2 = async (url, init) => {
|
|
2488
|
+
if (typeof fetch === "undefined") {
|
|
2489
|
+
throw new Error("global fetch is not available; pass an httpClient explicitly");
|
|
2490
|
+
}
|
|
2491
|
+
return fetch(url, init);
|
|
2492
|
+
};
|
|
2493
|
+
var KnowledgeManifestSchema = z2.object({
|
|
2494
|
+
name: z2.string().optional(),
|
|
2495
|
+
description: z2.string().optional(),
|
|
2496
|
+
version: z2.string().optional(),
|
|
2497
|
+
files: z2.array(z2.string()).optional(),
|
|
2498
|
+
keywords: z2.array(z2.string()).optional(),
|
|
2499
|
+
license: z2.string().optional()
|
|
2500
|
+
}).passthrough();
|
|
2501
|
+
function validateKnowledge(data) {
|
|
2502
|
+
const result = KnowledgeManifestSchema.safeParse(data);
|
|
2503
|
+
if (result.success) {
|
|
2504
|
+
return { ok: true, data: result.data };
|
|
2505
|
+
}
|
|
2506
|
+
return {
|
|
2507
|
+
ok: false,
|
|
2508
|
+
errors: result.error.issues.map((issue) => ({
|
|
2509
|
+
path: issue.path.join("."),
|
|
2510
|
+
message: issue.message
|
|
2511
|
+
}))
|
|
2512
|
+
};
|
|
2513
|
+
}
|
|
2514
|
+
function collectDirRecursive(baseDir, relativeDir) {
|
|
2515
|
+
const full = path5.join(baseDir, relativeDir);
|
|
2516
|
+
if (!fs10.existsSync(full) || !fs10.statSync(full).isDirectory()) return [];
|
|
2517
|
+
const results = [];
|
|
2518
|
+
for (const entry of fs10.readdirSync(full, { withFileTypes: true })) {
|
|
2519
|
+
const rel = path5.posix.join(relativeDir, entry.name);
|
|
2520
|
+
if (entry.isDirectory()) {
|
|
2521
|
+
results.push(...collectDirRecursive(baseDir, rel));
|
|
2522
|
+
} else if (entry.isFile()) {
|
|
2523
|
+
results.push(rel);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
return results;
|
|
2527
|
+
}
|
|
2528
|
+
var knowledgeKindProvider = {
|
|
2529
|
+
kind: "knowledge",
|
|
2530
|
+
displayName: "Knowledge",
|
|
2531
|
+
providerVersion: "1.0.0",
|
|
2532
|
+
discoveryPatterns: ["**/knowledge.yaml", "**/knowledge/index.yaml"],
|
|
2533
|
+
matchesPath(relativePath) {
|
|
2534
|
+
const parts = relativePath.split("/");
|
|
2535
|
+
const filename = parts[parts.length - 1] ?? "";
|
|
2536
|
+
if (filename === "knowledge.yaml") return true;
|
|
2537
|
+
if (filename === "index.yaml" && parts.length >= 2 && parts[parts.length - 2] === "knowledge") {
|
|
2538
|
+
return true;
|
|
2539
|
+
}
|
|
2540
|
+
return false;
|
|
2541
|
+
},
|
|
2542
|
+
validateManifest(data) {
|
|
2543
|
+
return validateKnowledge(data);
|
|
2544
|
+
},
|
|
2545
|
+
defaultFileFilter(manifestPath) {
|
|
2546
|
+
const dir = path5.dirname(manifestPath);
|
|
2547
|
+
const manifestName = path5.basename(manifestPath);
|
|
2548
|
+
const files = [manifestName];
|
|
2549
|
+
files.push(...collectDirRecursive(dir, "documents"));
|
|
2550
|
+
files.sort();
|
|
2551
|
+
return { assetRoot: dir, files };
|
|
2552
|
+
}
|
|
2553
|
+
// Knowledge has no cross-asset dependency edges — omit extractRequires
|
|
2554
|
+
};
|
|
2555
|
+
function parsePreset(data) {
|
|
2556
|
+
const zodResult = PresetManifestSchema.safeParse(data);
|
|
2557
|
+
if (!zodResult.success) {
|
|
2558
|
+
return {
|
|
2559
|
+
ok: false,
|
|
2560
|
+
errors: zodResult.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
|
2561
|
+
};
|
|
2562
|
+
}
|
|
2563
|
+
const preset = zodResult.data;
|
|
2564
|
+
const errors = [];
|
|
2565
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2566
|
+
const refCounts = /* @__PURE__ */ new Map();
|
|
2567
|
+
for (const item of preset.items) {
|
|
2568
|
+
if (item.id) {
|
|
2569
|
+
if (ids.has(item.id)) {
|
|
2570
|
+
errors.push(`Duplicate item id: "${item.id}"`);
|
|
2571
|
+
}
|
|
2572
|
+
ids.add(item.id);
|
|
2573
|
+
} else {
|
|
2574
|
+
refCounts.set(item.ref, (refCounts.get(item.ref) ?? 0) + 1);
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
for (const [ref, count] of refCounts) {
|
|
2578
|
+
if (count > 1) {
|
|
2579
|
+
errors.push(
|
|
2580
|
+
`${count} items share ref "${ref}" without distinct "id" fields \u2014 upgrade matching will be ambiguous`
|
|
2581
|
+
);
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
for (const item of preset.items) {
|
|
2585
|
+
if (item.composes) {
|
|
2586
|
+
for (const compose of item.composes) {
|
|
2587
|
+
if (compose.ref.startsWith("#")) {
|
|
2588
|
+
const targetId = compose.ref.slice(1);
|
|
2589
|
+
if (!ids.has(targetId)) {
|
|
2590
|
+
errors.push(
|
|
2591
|
+
`Cross-item ref "${compose.ref}" in item "${item.id ?? item.ref}" references undeclared id "${targetId}"`
|
|
2592
|
+
);
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
for (const item of preset.items) {
|
|
2599
|
+
if (item.placeholders) {
|
|
2600
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2601
|
+
for (const ph of item.placeholders) {
|
|
2602
|
+
if (keys.has(ph.key)) {
|
|
2603
|
+
errors.push(`Duplicate placeholder key "${ph.key}" in item "${item.id ?? item.ref}"`);
|
|
2604
|
+
}
|
|
2605
|
+
keys.add(ph.key);
|
|
2606
|
+
if (ph.type === "enum" && (!ph.values || ph.values.length === 0)) {
|
|
2607
|
+
errors.push(`Placeholder "${ph.key}" has type "enum" but no values defined`);
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2612
|
+
if (errors.length > 0) {
|
|
2613
|
+
return { ok: false, preset, errors };
|
|
2614
|
+
}
|
|
2615
|
+
return { ok: true, preset, errors: [] };
|
|
2616
|
+
}
|
|
2617
|
+
function parsePresetYaml(yamlContent) {
|
|
2618
|
+
let data;
|
|
2619
|
+
try {
|
|
2620
|
+
data = parse(yamlContent);
|
|
2621
|
+
} catch (err) {
|
|
2622
|
+
return {
|
|
2623
|
+
ok: false,
|
|
2624
|
+
errors: [`YAML parse error: ${err instanceof Error ? err.message : String(err)}`]
|
|
2625
|
+
};
|
|
2626
|
+
}
|
|
2627
|
+
return parsePreset(data);
|
|
2628
|
+
}
|
|
2629
|
+
function detectNestedPresetRefs(preset, knownPresetRefs) {
|
|
2630
|
+
const nested = [];
|
|
2631
|
+
for (const item of preset.items) {
|
|
2632
|
+
if (item.ref.startsWith("library://") || item.ref.startsWith("#")) continue;
|
|
2633
|
+
if (knownPresetRefs?.has(item.ref)) {
|
|
2634
|
+
nested.push(item.ref);
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
return nested;
|
|
2638
|
+
}
|
|
2639
|
+
function validateNestingDepth(presetRef, currentDepth) {
|
|
2640
|
+
const MAX_DEPTH = 3;
|
|
2641
|
+
if (currentDepth >= MAX_DEPTH) {
|
|
2642
|
+
return `Preset "${presetRef}" exceeds maximum nesting depth (${MAX_DEPTH} levels allowed, depth ${currentDepth} reached)`;
|
|
2643
|
+
}
|
|
2644
|
+
return void 0;
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
// library/src/preset/resolve-item.ts
|
|
2648
|
+
function classifyRef(ref) {
|
|
2649
|
+
if (ref.startsWith("library://")) return "library-instance";
|
|
2650
|
+
if (ref.startsWith("#")) return "cross-item";
|
|
2651
|
+
return "asset";
|
|
2652
|
+
}
|
|
2653
|
+
function extractLibraryInstanceId(ref) {
|
|
2654
|
+
const match = ref.match(/^library:\/\/[^/]+\/instances\/([a-f0-9-]+)$/i);
|
|
2655
|
+
return match ? match[1] : null;
|
|
2656
|
+
}
|
|
2657
|
+
async function resolveItem(item, library, knownPresetRefs) {
|
|
2658
|
+
const ref = item.ref;
|
|
2659
|
+
if (ref.startsWith("#")) {
|
|
2660
|
+
return { kind: "cross-item", item, targetId: ref.slice(1) };
|
|
2661
|
+
}
|
|
2662
|
+
if (ref.startsWith("library://")) {
|
|
2663
|
+
const instanceId = extractLibraryInstanceId(ref);
|
|
2664
|
+
if (!instanceId) {
|
|
2665
|
+
return { kind: "library-instance", item, instanceId: "", instance: null };
|
|
2666
|
+
}
|
|
2667
|
+
const instance = await library.getInstance(instanceId);
|
|
2668
|
+
return { kind: "library-instance", item, instanceId, instance };
|
|
2669
|
+
}
|
|
2670
|
+
if (knownPresetRefs?.has(ref)) {
|
|
2671
|
+
return { kind: "nested-preset", item, presetRef: ref };
|
|
2672
|
+
}
|
|
2673
|
+
const assetDef = await library.getAssetDef(ref);
|
|
2674
|
+
return { kind: "asset", item, defRef: ref, assetDef };
|
|
2675
|
+
}
|
|
2676
|
+
async function resolveAllItems(items, library, knownPresetRefs) {
|
|
2677
|
+
return Promise.all(items.map((item) => resolveItem(item, library, knownPresetRefs)));
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
// library/src/preset/placeholders.ts
|
|
2681
|
+
function validatePlaceholder(placeholder, value) {
|
|
2682
|
+
const { key, type = "text", required } = placeholder;
|
|
2683
|
+
if (value === void 0 || value === null || value === "") {
|
|
2684
|
+
if (placeholder.default !== void 0) {
|
|
2685
|
+
return { valid: true, errors: [], value: placeholder.default };
|
|
2686
|
+
}
|
|
2687
|
+
if (required === true || required === void 0) {
|
|
2688
|
+
return { valid: false, errors: [`Placeholder "${key}" is required`] };
|
|
2689
|
+
}
|
|
2690
|
+
return { valid: true, errors: [], value: void 0 };
|
|
2691
|
+
}
|
|
2692
|
+
switch (type) {
|
|
2693
|
+
case "text":
|
|
2694
|
+
return validateText(key, value);
|
|
2695
|
+
case "multiline":
|
|
2696
|
+
return validateMultiline(key, value);
|
|
2697
|
+
case "secret":
|
|
2698
|
+
return validateSecret(key, value);
|
|
2699
|
+
case "number":
|
|
2700
|
+
return validateNumber(key, value);
|
|
2701
|
+
case "boolean":
|
|
2702
|
+
return validateBoolean(key, value);
|
|
2703
|
+
case "enum":
|
|
2704
|
+
return validateEnum(key, value, placeholder.values);
|
|
2705
|
+
case "oauth":
|
|
2706
|
+
return validateOauth(key, value);
|
|
2707
|
+
case "instance-picker":
|
|
2708
|
+
return validateInstancePicker(key, value);
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
function validateAllPlaceholders(placeholders, inputs) {
|
|
2712
|
+
const values = {};
|
|
2713
|
+
const errors = [];
|
|
2714
|
+
for (const ph of placeholders) {
|
|
2715
|
+
const result = validatePlaceholder(ph, inputs[ph.key]);
|
|
2716
|
+
if (!result.valid) {
|
|
2717
|
+
errors.push(...result.errors);
|
|
2718
|
+
} else if (result.value !== void 0) {
|
|
2719
|
+
values[ph.key] = result.value;
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
return { valid: errors.length === 0, values, errors };
|
|
2723
|
+
}
|
|
2724
|
+
async function queryInstancePickerChoices(library, options) {
|
|
2725
|
+
const filter = {};
|
|
2726
|
+
if (options?.defRefPrefix) {
|
|
2727
|
+
filter.defRef = options.defRefPrefix;
|
|
2728
|
+
}
|
|
2729
|
+
const instances2 = await library.listInstances(filter);
|
|
2730
|
+
return instances2.map((inst) => ({
|
|
2731
|
+
instanceId: inst.id,
|
|
2732
|
+
defRef: inst.defRef,
|
|
2733
|
+
label: `${inst.defRef} (${inst.id.slice(0, 8)})`
|
|
2734
|
+
}));
|
|
2735
|
+
}
|
|
2736
|
+
function getDefaultValue(placeholder) {
|
|
2737
|
+
return placeholder.default;
|
|
2738
|
+
}
|
|
2739
|
+
function isSecretPlaceholder(placeholder) {
|
|
2740
|
+
return placeholder.type === "secret" || placeholder.type === "oauth";
|
|
2741
|
+
}
|
|
2742
|
+
function validateText(key, value) {
|
|
2743
|
+
if (typeof value !== "string") {
|
|
2744
|
+
return { valid: false, errors: [`Placeholder "${key}" must be a string`] };
|
|
2745
|
+
}
|
|
2746
|
+
return { valid: true, errors: [], value };
|
|
2747
|
+
}
|
|
2748
|
+
function validateMultiline(key, value) {
|
|
2749
|
+
if (typeof value !== "string") {
|
|
2750
|
+
return { valid: false, errors: [`Placeholder "${key}" must be a string`] };
|
|
2751
|
+
}
|
|
2752
|
+
return { valid: true, errors: [], value };
|
|
2753
|
+
}
|
|
2754
|
+
function validateSecret(key, value) {
|
|
2755
|
+
if (typeof value !== "string") {
|
|
2756
|
+
return { valid: false, errors: [`Placeholder "${key}" must be a string`] };
|
|
2757
|
+
}
|
|
2758
|
+
if (value.length === 0) {
|
|
2759
|
+
return { valid: false, errors: [`Placeholder "${key}" (secret) cannot be empty`] };
|
|
2760
|
+
}
|
|
2761
|
+
return { valid: true, errors: [], value };
|
|
2762
|
+
}
|
|
2763
|
+
function validateNumber(key, value) {
|
|
2764
|
+
if (typeof value === "number" && !Number.isNaN(value)) {
|
|
2765
|
+
return { valid: true, errors: [], value };
|
|
2766
|
+
}
|
|
2767
|
+
if (typeof value === "string") {
|
|
2768
|
+
const parsed = Number(value);
|
|
2769
|
+
if (!Number.isNaN(parsed)) {
|
|
2770
|
+
return { valid: true, errors: [], value: parsed };
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
return { valid: false, errors: [`Placeholder "${key}" must be a valid number`] };
|
|
2774
|
+
}
|
|
2775
|
+
function validateBoolean(key, value) {
|
|
2776
|
+
if (typeof value === "boolean") {
|
|
2777
|
+
return { valid: true, errors: [], value };
|
|
2778
|
+
}
|
|
2779
|
+
if (typeof value === "string") {
|
|
2780
|
+
const lower = value.toLowerCase();
|
|
2781
|
+
if (lower === "true" || lower === "1" || lower === "yes") {
|
|
2782
|
+
return { valid: true, errors: [], value: true };
|
|
2783
|
+
}
|
|
2784
|
+
if (lower === "false" || lower === "0" || lower === "no") {
|
|
2785
|
+
return { valid: true, errors: [], value: false };
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
return { valid: false, errors: [`Placeholder "${key}" must be a boolean`] };
|
|
2789
|
+
}
|
|
2790
|
+
function validateEnum(key, value, allowedValues) {
|
|
2791
|
+
if (!allowedValues || allowedValues.length === 0) {
|
|
2792
|
+
return { valid: false, errors: [`Placeholder "${key}" (enum) has no allowed values defined`] };
|
|
2793
|
+
}
|
|
2794
|
+
const stringValue = String(value);
|
|
2795
|
+
const matches = allowedValues.some((v) => String(v) === stringValue);
|
|
2796
|
+
if (!matches) {
|
|
2797
|
+
return {
|
|
2798
|
+
valid: false,
|
|
2799
|
+
errors: [
|
|
2800
|
+
`Placeholder "${key}" value "${stringValue}" is not in allowed values: [${allowedValues.join(", ")}]`
|
|
2801
|
+
]
|
|
2802
|
+
};
|
|
2803
|
+
}
|
|
2804
|
+
const matched = allowedValues.find((v) => String(v) === stringValue);
|
|
2805
|
+
return { valid: true, errors: [], value: matched };
|
|
2806
|
+
}
|
|
2807
|
+
function validateOauth(key, value) {
|
|
2808
|
+
if (typeof value !== "string") {
|
|
2809
|
+
return { valid: false, errors: [`Placeholder "${key}" (oauth) must be a string`] };
|
|
2810
|
+
}
|
|
2811
|
+
if (value.length === 0) {
|
|
2812
|
+
return { valid: false, errors: [`Placeholder "${key}" (oauth) cannot be empty`] };
|
|
2813
|
+
}
|
|
2814
|
+
return { valid: true, errors: [], value };
|
|
2815
|
+
}
|
|
2816
|
+
function validateInstancePicker(key, value) {
|
|
2817
|
+
if (typeof value !== "string") {
|
|
2818
|
+
return {
|
|
2819
|
+
valid: false,
|
|
2820
|
+
errors: [`Placeholder "${key}" (instance-picker) must be a string UUID`]
|
|
2821
|
+
};
|
|
2822
|
+
}
|
|
2823
|
+
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
2824
|
+
if (!uuidPattern.test(value)) {
|
|
2825
|
+
return {
|
|
2826
|
+
valid: false,
|
|
2827
|
+
errors: [`Placeholder "${key}" (instance-picker) must be a valid UUID`]
|
|
2828
|
+
};
|
|
2829
|
+
}
|
|
2830
|
+
return { valid: true, errors: [], value };
|
|
2831
|
+
}
|
|
2832
|
+
|
|
2833
|
+
// library/src/preset/interpolate.ts
|
|
2834
|
+
var InterpolationError = class extends Error {
|
|
2835
|
+
constructor(message) {
|
|
2836
|
+
super(message);
|
|
2837
|
+
this.name = "InterpolationError";
|
|
2838
|
+
}
|
|
2839
|
+
};
|
|
2840
|
+
function interpolate(materialize, baseConfig, context, credentialRefPrefix) {
|
|
2841
|
+
const config = { ...baseConfig ?? {} };
|
|
2842
|
+
const secretsToStore = [];
|
|
2843
|
+
let credentialRef;
|
|
2844
|
+
if (!materialize) {
|
|
2845
|
+
for (const [key, value] of Object.entries(context.inputs)) {
|
|
2846
|
+
config[key] = value;
|
|
2847
|
+
}
|
|
2848
|
+
if (Object.keys(context.secrets).length > 0) {
|
|
2849
|
+
credentialRef = `${credentialRefPrefix}/creds`;
|
|
2850
|
+
for (const [key, value] of Object.entries(context.secrets)) {
|
|
2851
|
+
secretsToStore.push({ ref: `${credentialRef}/${key}`, value });
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
return { config, credentialRef, secretsToStore };
|
|
2855
|
+
}
|
|
2856
|
+
for (const [configPath, template] of Object.entries(materialize)) {
|
|
2857
|
+
const resolved = resolveTemplate(template, context);
|
|
2858
|
+
if (resolved.hasSecret) {
|
|
2859
|
+
if (!credentialRef) {
|
|
2860
|
+
credentialRef = `${credentialRefPrefix}/creds`;
|
|
2861
|
+
}
|
|
2862
|
+
const secretRef = `${credentialRef}/${configPath}`;
|
|
2863
|
+
secretsToStore.push({ ref: secretRef, value: resolved.value });
|
|
2864
|
+
setNestedValue(config, configPath, `secret://${secretRef}`);
|
|
2865
|
+
} else {
|
|
2866
|
+
setNestedValue(config, configPath, resolved.value);
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
return { config, credentialRef, secretsToStore };
|
|
2870
|
+
}
|
|
2871
|
+
async function storeSecrets(router, secretsToStore) {
|
|
2872
|
+
for (const { ref, value } of secretsToStore) {
|
|
2873
|
+
const encoded = new TextEncoder().encode(value);
|
|
2874
|
+
await router.setSecret(ref, encoded);
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
function hasInterpolationTokens(template) {
|
|
2878
|
+
return INTERPOLATION_PATTERN.test(template);
|
|
2879
|
+
}
|
|
2880
|
+
function extractReferencedKeys(materialize) {
|
|
2881
|
+
const inputKeys = /* @__PURE__ */ new Set();
|
|
2882
|
+
const secretKeys = /* @__PURE__ */ new Set();
|
|
2883
|
+
for (const template of Object.values(materialize)) {
|
|
2884
|
+
const pattern = new RegExp(INTERPOLATION_PATTERN.source, "g");
|
|
2885
|
+
for (const match of template.matchAll(pattern)) {
|
|
2886
|
+
const namespace = match[1];
|
|
2887
|
+
const key = match[2];
|
|
2888
|
+
if (namespace === "INPUT") inputKeys.add(key);
|
|
2889
|
+
else if (namespace === "SECRET") secretKeys.add(key);
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
return { inputKeys: [...inputKeys], secretKeys: [...secretKeys] };
|
|
2893
|
+
}
|
|
2894
|
+
var INTERPOLATION_PATTERN = /\$\{(INPUT|SECRET):([^}]+)\}/;
|
|
2895
|
+
function resolveTemplate(template, context) {
|
|
2896
|
+
const singleMatch = template.match(/^\$\{(INPUT|SECRET):([^}]+)\}$/);
|
|
2897
|
+
if (singleMatch) {
|
|
2898
|
+
const [, namespace, key] = singleMatch;
|
|
2899
|
+
if (namespace === "SECRET") {
|
|
2900
|
+
if (!(key in context.secrets)) {
|
|
2901
|
+
throw new InterpolationError(`Missing secret key "${key}" in interpolation context`);
|
|
2902
|
+
}
|
|
2903
|
+
return { value: context.secrets[key], hasSecret: true };
|
|
2904
|
+
}
|
|
2905
|
+
if (!(key in context.inputs)) {
|
|
2906
|
+
throw new InterpolationError(`Missing input key "${key}" in interpolation context`);
|
|
2907
|
+
}
|
|
2908
|
+
return { value: context.inputs[key], hasSecret: false };
|
|
2909
|
+
}
|
|
2910
|
+
const tokens = [...template.matchAll(/\$\{(INPUT|SECRET):([^}]+)\}/g)];
|
|
2911
|
+
const hasSecretToken = tokens.some(([, ns]) => ns === "SECRET");
|
|
2912
|
+
if (hasSecretToken) {
|
|
2913
|
+
throw new InterpolationError(
|
|
2914
|
+
`Template "${template}" mixes \${SECRET:...} with other tokens. SECRET must be the sole token in a template value.`
|
|
2915
|
+
);
|
|
2916
|
+
}
|
|
2917
|
+
const result = template.replace(/\$\{INPUT:([^}]+)\}/g, (_, key) => {
|
|
2918
|
+
if (!(key in context.inputs)) {
|
|
2919
|
+
throw new InterpolationError(`Missing input key "${key}" in interpolation context`);
|
|
2920
|
+
}
|
|
2921
|
+
return String(context.inputs[key] ?? "");
|
|
2922
|
+
});
|
|
2923
|
+
return { value: result, hasSecret: false };
|
|
2924
|
+
}
|
|
2925
|
+
function setNestedValue(obj, path13, value) {
|
|
2926
|
+
const parts = path13.split(".");
|
|
2927
|
+
let current = obj;
|
|
2928
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
2929
|
+
const key = parts[i];
|
|
2930
|
+
if (current[key] === void 0 || current[key] === null || typeof current[key] !== "object") {
|
|
2931
|
+
current[key] = {};
|
|
2932
|
+
}
|
|
2933
|
+
current = current[key];
|
|
2934
|
+
}
|
|
2935
|
+
current[parts[parts.length - 1]] = value;
|
|
2936
|
+
}
|
|
2937
|
+
|
|
2938
|
+
// library/src/preset/apply.ts
|
|
2939
|
+
async function applyPreset(presetRef, manifest, inputs, opts) {
|
|
2940
|
+
const depth = opts._depth ?? 0;
|
|
2941
|
+
const pinPolicy = opts.pinPolicy ?? "minor-track";
|
|
2942
|
+
const depthError = validateNestingDepth(presetRef, depth);
|
|
2943
|
+
if (depthError) {
|
|
2944
|
+
return { instances: [], subscriptions: [], errors: [depthError] };
|
|
2945
|
+
}
|
|
2946
|
+
const result = { instances: [], subscriptions: [], errors: [] };
|
|
2947
|
+
const itemResults = /* @__PURE__ */ new Map();
|
|
2948
|
+
for (const item of manifest.items) {
|
|
2949
|
+
const itemResult = await applyItemImpl(
|
|
2950
|
+
presetRef,
|
|
2951
|
+
item,
|
|
2952
|
+
inputs,
|
|
2953
|
+
opts,
|
|
2954
|
+
depth,
|
|
2955
|
+
pinPolicy,
|
|
2956
|
+
itemResults
|
|
2957
|
+
);
|
|
2958
|
+
result.errors.push(...itemResult.errors);
|
|
2959
|
+
for (const inst of itemResult.instances) {
|
|
2960
|
+
result.instances.push(inst);
|
|
2961
|
+
if (item.id && itemResult.instances.length > 0) {
|
|
2962
|
+
itemResults.set(item.id, itemResult.instances[0]);
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2965
|
+
result.subscriptions.push(...itemResult.subscriptions);
|
|
2966
|
+
}
|
|
2967
|
+
return result;
|
|
2968
|
+
}
|
|
2969
|
+
async function applyPresetFromData(presetRef, data, inputs, opts) {
|
|
2970
|
+
const parseResult = parsePreset(data);
|
|
2971
|
+
if (!parseResult.ok || !parseResult.preset) {
|
|
2972
|
+
return {
|
|
2973
|
+
instances: [],
|
|
2974
|
+
subscriptions: [],
|
|
2975
|
+
errors: parseResult.errors.map((e) => `Parse: ${e}`)
|
|
2976
|
+
};
|
|
2977
|
+
}
|
|
2978
|
+
return applyPreset(presetRef, parseResult.preset, inputs, opts);
|
|
2979
|
+
}
|
|
2980
|
+
async function applyItemImpl(presetRef, item, inputs, opts, depth, pinPolicy, itemResults) {
|
|
2981
|
+
const { library } = opts;
|
|
2982
|
+
const resolved = await resolveItem(item, library, opts.knownPresetRefs);
|
|
2983
|
+
switch (resolved.kind) {
|
|
2984
|
+
case "cross-item": {
|
|
2985
|
+
const target = itemResults.get(resolved.targetId);
|
|
2986
|
+
if (!target) {
|
|
2987
|
+
return {
|
|
2988
|
+
instances: [],
|
|
2989
|
+
subscriptions: [],
|
|
2990
|
+
errors: [
|
|
2991
|
+
`Cross-item ref "#${resolved.targetId}" not yet resolved (items must be ordered)`
|
|
2992
|
+
]
|
|
2993
|
+
};
|
|
2994
|
+
}
|
|
2995
|
+
return { instances: [target], subscriptions: [], errors: [] };
|
|
2996
|
+
}
|
|
2997
|
+
case "library-instance": {
|
|
2998
|
+
if (!resolved.instance) {
|
|
2999
|
+
return {
|
|
3000
|
+
instances: [],
|
|
3001
|
+
subscriptions: [],
|
|
3002
|
+
errors: [`Library instance "${resolved.instanceId}" not found`]
|
|
3003
|
+
};
|
|
3004
|
+
}
|
|
3005
|
+
try {
|
|
3006
|
+
const sub = await library.subscribe(opts.workspaceId, resolved.instanceId, pinPolicy);
|
|
3007
|
+
return { instances: [resolved.instance], subscriptions: [sub], errors: [] };
|
|
3008
|
+
} catch {
|
|
3009
|
+
return { instances: [resolved.instance], subscriptions: [], errors: [] };
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
case "nested-preset": {
|
|
3013
|
+
if (!opts.loadPreset) {
|
|
3014
|
+
return {
|
|
3015
|
+
instances: [],
|
|
3016
|
+
subscriptions: [],
|
|
3017
|
+
errors: [`Cannot resolve nested preset "${resolved.presetRef}" \u2014 no loader provided`]
|
|
3018
|
+
};
|
|
3019
|
+
}
|
|
3020
|
+
const nestedData = await opts.loadPreset(resolved.presetRef);
|
|
3021
|
+
if (!nestedData) {
|
|
3022
|
+
return {
|
|
3023
|
+
instances: [],
|
|
3024
|
+
subscriptions: [],
|
|
3025
|
+
errors: [`Nested preset "${resolved.presetRef}" not found`]
|
|
3026
|
+
};
|
|
3027
|
+
}
|
|
3028
|
+
const parseResult = parsePreset(nestedData);
|
|
3029
|
+
if (!parseResult.ok || !parseResult.preset) {
|
|
3030
|
+
return { instances: [], subscriptions: [], errors: parseResult.errors };
|
|
3031
|
+
}
|
|
3032
|
+
const nestedInputs = {
|
|
3033
|
+
...item.inputs ?? {},
|
|
3034
|
+
...inputs
|
|
3035
|
+
};
|
|
3036
|
+
const nestedResult = await applyPreset(resolved.presetRef, parseResult.preset, nestedInputs, {
|
|
3037
|
+
...opts,
|
|
3038
|
+
_depth: depth + 1
|
|
3039
|
+
});
|
|
3040
|
+
return {
|
|
3041
|
+
instances: nestedResult.instances,
|
|
3042
|
+
subscriptions: nestedResult.subscriptions,
|
|
3043
|
+
errors: nestedResult.errors
|
|
3044
|
+
};
|
|
3045
|
+
}
|
|
3046
|
+
case "asset": {
|
|
3047
|
+
const itemInputs = { ...inputs };
|
|
3048
|
+
let validatedValues = {};
|
|
3049
|
+
const secretValues = {};
|
|
3050
|
+
if (item.placeholders && item.placeholders.length > 0) {
|
|
3051
|
+
const nonSecretPhs = item.placeholders.filter((ph) => !isSecretPlaceholder(ph));
|
|
3052
|
+
const secretPhs = item.placeholders.filter((ph) => isSecretPlaceholder(ph));
|
|
3053
|
+
const validation = validateAllPlaceholders(nonSecretPhs, itemInputs);
|
|
3054
|
+
if (!validation.valid) {
|
|
3055
|
+
return { instances: [], subscriptions: [], errors: validation.errors };
|
|
3056
|
+
}
|
|
3057
|
+
validatedValues = validation.values;
|
|
3058
|
+
const secretValidation = validateAllPlaceholders(secretPhs, itemInputs);
|
|
3059
|
+
if (!secretValidation.valid) {
|
|
3060
|
+
return { instances: [], subscriptions: [], errors: secretValidation.errors };
|
|
3061
|
+
}
|
|
3062
|
+
for (const [key, value] of Object.entries(secretValidation.values)) {
|
|
3063
|
+
secretValues[key] = String(value);
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
const credentialRefPrefix = `preset/${presetRef}/${item.id ?? resolved.defRef}`;
|
|
3067
|
+
const context = {
|
|
3068
|
+
inputs: validatedValues,
|
|
3069
|
+
secrets: secretValues
|
|
3070
|
+
};
|
|
3071
|
+
const interpolated = interpolate(
|
|
3072
|
+
item.materialize,
|
|
3073
|
+
item.config,
|
|
3074
|
+
context,
|
|
3075
|
+
credentialRefPrefix
|
|
3076
|
+
);
|
|
3077
|
+
if (opts.secretsRouter && interpolated.secretsToStore.length > 0) {
|
|
3078
|
+
try {
|
|
3079
|
+
await storeSecrets(opts.secretsRouter, interpolated.secretsToStore);
|
|
3080
|
+
} catch (err) {
|
|
3081
|
+
return {
|
|
3082
|
+
instances: [],
|
|
3083
|
+
subscriptions: [],
|
|
3084
|
+
errors: [
|
|
3085
|
+
`Secret storage failed for "${item.ref}": ${err instanceof Error ? err.message : String(err)}`
|
|
3086
|
+
]
|
|
3087
|
+
};
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
try {
|
|
3091
|
+
const instance = await library.createInstance({
|
|
3092
|
+
defRef: resolved.defRef,
|
|
3093
|
+
defPin: pinPolicy,
|
|
3094
|
+
config: interpolated.config,
|
|
3095
|
+
credentialRef: interpolated.credentialRef,
|
|
3096
|
+
createdBy: opts.createdBy ?? `preset:${presetRef}`
|
|
3097
|
+
});
|
|
3098
|
+
const subscriptions2 = [];
|
|
3099
|
+
try {
|
|
3100
|
+
const sub = await library.subscribe(opts.workspaceId, instance.id, pinPolicy);
|
|
3101
|
+
subscriptions2.push(sub);
|
|
3102
|
+
} catch {
|
|
3103
|
+
}
|
|
3104
|
+
return { instances: [instance], subscriptions: subscriptions2, errors: [] };
|
|
3105
|
+
} catch (err) {
|
|
3106
|
+
return {
|
|
3107
|
+
instances: [],
|
|
3108
|
+
subscriptions: [],
|
|
3109
|
+
errors: [
|
|
3110
|
+
`Instance creation failed for "${item.ref}": ${err instanceof Error ? err.message : String(err)}`
|
|
3111
|
+
]
|
|
3112
|
+
};
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
|
|
3118
|
+
// library/src/preset/upgrade.ts
|
|
3119
|
+
function detectChanges(oldManifest, newManifest) {
|
|
3120
|
+
const oldItems = indexItems(oldManifest.items);
|
|
3121
|
+
const newItems = indexItems(newManifest.items);
|
|
3122
|
+
const addedItems = [];
|
|
3123
|
+
const removedItems = [];
|
|
3124
|
+
const changedRefItems = [];
|
|
3125
|
+
const configChangedItems = [];
|
|
3126
|
+
for (const [key, oldItem] of oldItems) {
|
|
3127
|
+
if (!newItems.has(key)) {
|
|
3128
|
+
removedItems.push(oldItem);
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
for (const [key, newItem] of newItems) {
|
|
3132
|
+
if (!oldItems.has(key)) {
|
|
3133
|
+
addedItems.push(newItem);
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
for (const [key, newItem] of newItems) {
|
|
3137
|
+
const oldItem = oldItems.get(key);
|
|
3138
|
+
if (!oldItem) continue;
|
|
3139
|
+
if (oldItem.ref !== newItem.ref) {
|
|
3140
|
+
changedRefItems.push({ old: oldItem, new: newItem });
|
|
3141
|
+
} else if (!deepEqual(oldItem.placeholders, newItem.placeholders) || !deepEqual(oldItem.materialize, newItem.materialize)) {
|
|
3142
|
+
changedRefItems.push({ old: oldItem, new: newItem });
|
|
3143
|
+
} else if (!deepEqual(oldItem.config, newItem.config)) {
|
|
3144
|
+
configChangedItems.push({ old: oldItem, new: newItem });
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
const isStructural = addedItems.length > 0 || removedItems.length > 0 || changedRefItems.length > 0;
|
|
3148
|
+
const kind = isStructural ? "structural" : "non-structural";
|
|
3149
|
+
const summaryParts = [];
|
|
3150
|
+
if (addedItems.length > 0) summaryParts.push(`+${addedItems.length} items`);
|
|
3151
|
+
if (removedItems.length > 0) summaryParts.push(`-${removedItems.length} items`);
|
|
3152
|
+
if (changedRefItems.length > 0) summaryParts.push(`${changedRefItems.length} ref changes`);
|
|
3153
|
+
if (configChangedItems.length > 0)
|
|
3154
|
+
summaryParts.push(`${configChangedItems.length} config changes`);
|
|
3155
|
+
const summary = summaryParts.length > 0 ? `${kind}: ${summaryParts.join(", ")}` : "no changes";
|
|
3156
|
+
return {
|
|
3157
|
+
kind,
|
|
3158
|
+
addedItems,
|
|
3159
|
+
removedItems,
|
|
3160
|
+
changedRefItems,
|
|
3161
|
+
configChangedItems,
|
|
3162
|
+
summary
|
|
3163
|
+
};
|
|
3164
|
+
}
|
|
3165
|
+
function evaluateUpgrade(oldManifest, newManifest) {
|
|
3166
|
+
const diff = detectChanges(oldManifest, newManifest);
|
|
3167
|
+
if (diff.kind === "non-structural") {
|
|
3168
|
+
return { autoUpgradable: true, diff };
|
|
3169
|
+
}
|
|
3170
|
+
const requiredActions = [];
|
|
3171
|
+
if (diff.addedItems.length > 0) {
|
|
3172
|
+
requiredActions.push(
|
|
3173
|
+
`Create ${diff.addedItems.length} new instance(s): ${diff.addedItems.map((i) => i.ref).join(", ")}`
|
|
3174
|
+
);
|
|
3175
|
+
}
|
|
3176
|
+
if (diff.removedItems.length > 0) {
|
|
3177
|
+
requiredActions.push(
|
|
3178
|
+
`Remove ${diff.removedItems.length} instance(s): ${diff.removedItems.map((i) => i.ref).join(", ")}`
|
|
3179
|
+
);
|
|
3180
|
+
}
|
|
3181
|
+
if (diff.changedRefItems.length > 0) {
|
|
3182
|
+
requiredActions.push(`Replace ${diff.changedRefItems.length} instance(s) with new refs`);
|
|
3183
|
+
}
|
|
3184
|
+
return { autoUpgradable: false, diff, requiredActions };
|
|
3185
|
+
}
|
|
3186
|
+
async function applyNonStructuralUpgrade(newManifest, existingInstances, library) {
|
|
3187
|
+
let updated = 0;
|
|
3188
|
+
const errors = [];
|
|
3189
|
+
for (const item of newManifest.items) {
|
|
3190
|
+
const key = itemKey(item);
|
|
3191
|
+
const instanceId = existingInstances.get(key);
|
|
3192
|
+
if (!instanceId) continue;
|
|
3193
|
+
if (item.config) {
|
|
3194
|
+
try {
|
|
3195
|
+
await library.updateInstance(instanceId, {
|
|
3196
|
+
config: item.config
|
|
3197
|
+
});
|
|
3198
|
+
updated++;
|
|
3199
|
+
} catch (err) {
|
|
3200
|
+
errors.push(
|
|
3201
|
+
`Failed to update instance "${instanceId}": ${err instanceof Error ? err.message : String(err)}`
|
|
3202
|
+
);
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
return { updated, errors };
|
|
3207
|
+
}
|
|
3208
|
+
function itemKey(item) {
|
|
3209
|
+
return item.id ?? item.ref;
|
|
3210
|
+
}
|
|
3211
|
+
function indexItems(items) {
|
|
3212
|
+
const map = /* @__PURE__ */ new Map();
|
|
3213
|
+
for (const item of items) {
|
|
3214
|
+
map.set(itemKey(item), item);
|
|
3215
|
+
}
|
|
3216
|
+
return map;
|
|
3217
|
+
}
|
|
3218
|
+
function deepEqual(a, b) {
|
|
3219
|
+
if (a === b) return true;
|
|
3220
|
+
if (a === void 0 && b === void 0) return true;
|
|
3221
|
+
if (a === null && b === null) return true;
|
|
3222
|
+
if (a === void 0 || b === void 0) return false;
|
|
3223
|
+
if (a === null || b === null) return false;
|
|
3224
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
3225
|
+
}
|
|
3226
|
+
|
|
3227
|
+
export { CatalogCache, CatalogConfigSchema, CatalogHttpError, DuplicateLibraryNameError, DuplicateSubscriptionError, GitSyncDriver, InstanceHasConsumersError, InstanceNotFoundError, InterpolationError, KNOWN_ASSET_KINDS, KnowledgeManifestSchema, LIBRARY_BACKENDS, LIBRARY_OWNERSHIPS, LIBRARY_STRUCTURES, LOCAL_CATALOG_URL, LibraryConfigSchema, LibraryError, LibraryInstanceRefSchema, LibrarySectionSchema, LibrarySyncError, LocalCatalogSource, LocalLibrary, LocalSyncDriver, LockFileSchema, LockSubscriptionSchema, OfflineError, OperationNotPermittedError, PIN_POLICIES, PinPolicySchema, PresetAppliedSchema, PresetExpandedSchema, RemoteCatalogSource, RequiresEdgeSchema, RestCatalogSource, SidecarGit, SkaileConfigSchema, SourceNotFoundError, StoreSyncDriver, SubscriptionNotFoundError, TarballHashMismatchError, UserLibraryManager, UserLibraryNotFoundError, WorkspaceConfigV2Schema, applyNonStructuralUpgrade, applyPreset, applyPresetFromData, classifyRef, createEmptyLockFile, deriveSlug, detectChanges, detectNestedPresetRefs, detectWorkspaceVersion, evaluateUpgrade, extractLibraryInstanceId, extractReferencedKeys, filterKey, getConfigDefaults, getDefaultValue, getSidecarRoot, hasInterpolationTokens, interpolate, isLocalCatalogUrl, isSecretPlaceholder, knowledgeKindProvider, listSidecarSlugsOnDisk, loadLockFile, loadWorkspaceV2, migrateWorkspaceConfig, parsePreset, parsePresetYaml, parseWorkspaceV2, projectConfigPath, queryInstancePickerChoices, resolveAllItems, resolveConfig, resolveItem, resolveLibraryDir, resolvePin, resolveSidecarPaths, saveConfig, saveLockFile, saveWorkspaceV2, sha256Hex, storeSecrets, trpcGetUrl, userConfigPath, validateAllPlaceholders, validateKnowledge, validateNestingDepth, validatePlaceholder, writeManifestIfMissing };
|
|
3228
|
+
//# sourceMappingURL=chunk-DOMCYP7D.js.map
|
|
3229
|
+
//# sourceMappingURL=chunk-DOMCYP7D.js.map
|