@skaile/workspaces 0.22.0-beta.0 → 0.22.0-beta.2
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 +221 -0
- package/dist/{asset-feeds-PJDJ3QYI.js → asset-feeds-2M6UKEJ7.js} +13 -14
- package/dist/asset-feeds-2M6UKEJ7.js.map +1 -0
- package/dist/asset-manager/catalog-deployer.d.ts +2 -0
- package/dist/asset-manager/contrib.d.ts +2 -0
- package/dist/asset-manager/fragments.d.ts +2 -0
- package/dist/asset-manager/history.d.ts +2 -0
- package/dist/asset-manager/index.d.ts +2 -0
- package/dist/asset-manager/index.js +7 -7
- package/dist/asset-manager/installer.d.ts +2 -0
- package/dist/asset-manager/installer.js +6 -6
- package/dist/asset-manager/renderers.d.ts +2 -0
- package/dist/asset-manager/src/index.d.ts +18 -7
- package/dist/asset-manager/src/index.d.ts.map +1 -1
- package/dist/asset-manager/src/installer.d.ts +3 -3
- package/dist/asset-manager/src/installer.d.ts.map +1 -1
- package/dist/base-assets/connectors/deploy.d.ts +2 -0
- package/dist/base-assets/connectors/deploy.js +8 -8
- package/dist/base-assets/connectors/devserver.d.ts +2 -0
- package/dist/base-assets/connectors/devserver.js +8 -8
- package/dist/base-assets/connectors/flow/adapter.js +8 -8
- package/dist/base-assets/connectors/flow/engine.d.ts +2 -0
- package/dist/base-assets/connectors/flow/run-flow.js +9 -9
- package/dist/base-assets/connectors/flow.d.ts +2 -0
- package/dist/base-assets/connectors/flow.js +8 -8
- package/dist/base-assets/connectors/git/driver.d.ts.map +1 -1
- package/dist/base-assets/connectors/git.d.ts +2 -0
- package/dist/base-assets/connectors/git.js +8 -8
- package/dist/base-assets/connectors/gmail.d.ts +2 -0
- package/dist/base-assets/connectors/gmail.js +8 -8
- package/dist/base-assets/connectors/googledrive.d.ts +2 -0
- package/dist/base-assets/connectors/googledrive.js +8 -8
- package/dist/base-assets/connectors/local.d.ts +2 -0
- package/dist/base-assets/connectors/local.js +8 -8
- package/dist/base-assets/connectors/mattermost.d.ts +2 -0
- package/dist/base-assets/connectors/mattermost.js +8 -8
- package/dist/base-assets/connectors/memory.d.ts +2 -0
- package/dist/base-assets/connectors/memory.js +8 -8
- package/dist/base-assets/connectors/minio.d.ts +2 -0
- package/dist/base-assets/connectors/minio.js +8 -8
- package/dist/base-assets/connectors/postgres.d.ts +2 -0
- package/dist/base-assets/connectors/postgres.js +8 -8
- package/dist/base-assets/connectors/s3.d.ts +2 -0
- package/dist/base-assets/connectors/s3.js +8 -8
- package/dist/base-assets/connectors/sharepoint.d.ts +2 -0
- package/dist/base-assets/connectors/sharepoint.js +8 -8
- package/dist/base-assets/connectors/sqlite.d.ts +2 -0
- package/dist/base-assets/connectors/sqlite.js +8 -8
- package/dist/base-assets/connectors/static-server.d.ts +2 -0
- package/dist/base-assets/connectors/static-server.js +8 -8
- package/dist/base-assets/connectors/tunnel.d.ts +2 -0
- package/dist/base-assets/connectors/tunnel.js +8 -8
- package/dist/base-assets/connectors/webdav.d.ts +2 -0
- package/dist/base-assets/connectors/webdav.js +8 -8
- package/dist/base-assets/connectors/xstate-store.d.ts +2 -0
- package/dist/base-assets/connectors/xstate-store.js +8 -8
- package/dist/base-assets/connectors/xstate.d.ts +2 -0
- package/dist/base-assets/connectors/xstate.js +8 -8
- package/dist/bridge/drivers/claude-sdk.d.ts +2 -0
- package/dist/bridge/drivers/claude-sdk.js +2 -2
- package/dist/bridge/drivers/codex.d.ts +2 -0
- package/dist/bridge/drivers/codex.js +2 -2
- package/dist/bridge/drivers/echo.d.ts +2 -0
- package/dist/bridge/drivers/echo.js +2 -2
- package/dist/bridge/drivers/omp.d.ts +2 -0
- package/dist/bridge/drivers/omp.js +2 -2
- package/dist/bridge/index.d.ts +2 -0
- package/dist/bridge/index.js +3 -3
- package/dist/bridge/src/registry.d.ts +4 -2
- package/dist/bridge/src/registry.d.ts.map +1 -1
- package/dist/chunk-32NA4TVC.js +30 -0
- package/dist/chunk-32NA4TVC.js.map +1 -0
- package/dist/{chunk-CSDQBWE6.js → chunk-3KLWGHDE.js} +5 -5
- package/dist/{chunk-CSDQBWE6.js.map → chunk-3KLWGHDE.js.map} +1 -1
- package/dist/{chunk-UZRY5UI2.js → chunk-6E6PKKAD.js} +68 -3
- package/dist/chunk-6E6PKKAD.js.map +1 -0
- package/dist/{chunk-G6GKWGOW.js → chunk-6SA2SIOU.js} +26 -10
- package/dist/chunk-6SA2SIOU.js.map +1 -0
- package/dist/{chunk-IGQEXBBG.js → chunk-6VTG73UY.js} +13 -9
- package/dist/chunk-6VTG73UY.js.map +1 -0
- package/dist/{chunk-TTY56FQQ.js → chunk-74GTZ4TJ.js} +17 -5
- package/dist/chunk-74GTZ4TJ.js.map +1 -0
- package/dist/chunk-7QBNJTTQ.js +3 -0
- package/dist/{chunk-W2O5LWYU.js.map → chunk-7QBNJTTQ.js.map} +1 -1
- package/dist/{chunk-SL6JVGRD.js → chunk-CEUHU3C4.js} +3 -3
- package/dist/{chunk-SL6JVGRD.js.map → chunk-CEUHU3C4.js.map} +1 -1
- package/dist/{chunk-J2FCO6TM.js → chunk-FIHVQFXB.js} +2 -2
- package/dist/{chunk-J2FCO6TM.js.map → chunk-FIHVQFXB.js.map} +1 -1
- package/dist/{chunk-F3MGZ5E6.js → chunk-FVZLCBSX.js} +3 -3
- package/dist/{chunk-F3MGZ5E6.js.map → chunk-FVZLCBSX.js.map} +1 -1
- package/dist/{chunk-7PTP3SQJ.js → chunk-GTS2FODO.js} +32 -7
- package/dist/chunk-GTS2FODO.js.map +1 -0
- package/dist/{chunk-KA46DUM4.js → chunk-I5SGBFMM.js} +51 -3
- package/dist/chunk-I5SGBFMM.js.map +1 -0
- package/dist/{chunk-MO4JPTRD.js → chunk-LDLZFYLR.js} +5 -5
- package/dist/{chunk-MO4JPTRD.js.map → chunk-LDLZFYLR.js.map} +1 -1
- package/dist/{chunk-TKOLD2O7.js → chunk-LDYPQVRU.js} +516 -145
- package/dist/chunk-LDYPQVRU.js.map +1 -0
- package/dist/{chunk-GKM6MDUC.js → chunk-M5JDVO6D.js} +3 -3
- package/dist/{chunk-GKM6MDUC.js.map → chunk-M5JDVO6D.js.map} +1 -1
- package/dist/{chunk-XHFMUGDD.js → chunk-M5TE6YI5.js} +3 -3
- package/dist/{chunk-XHFMUGDD.js.map → chunk-M5TE6YI5.js.map} +1 -1
- package/dist/{chunk-NGC7ZQI4.js → chunk-NICAMYPV.js} +39 -45
- package/dist/chunk-NICAMYPV.js.map +1 -0
- package/dist/{chunk-WIR34WMU.js → chunk-NQL3T75I.js} +24 -59
- package/dist/chunk-NQL3T75I.js.map +1 -0
- package/dist/{chunk-RENHNO4J.js → chunk-P4FYHEHW.js} +206 -137
- package/dist/chunk-P4FYHEHW.js.map +1 -0
- package/dist/{chunk-2DNSSQ22.js → chunk-TWQPDBHB.js} +270 -173
- package/dist/chunk-TWQPDBHB.js.map +1 -0
- package/dist/{chunk-UZVHJ7LX.js → chunk-UBLTUFFI.js} +4 -4
- package/dist/{chunk-UZVHJ7LX.js.map → chunk-UBLTUFFI.js.map} +1 -1
- package/dist/{chunk-X5Y4EGZB.js → chunk-VUCPJBAG.js} +43 -10
- package/dist/chunk-VUCPJBAG.js.map +1 -0
- package/dist/{chunk-PBWMV5GM.js → chunk-WQ7DE5UC.js} +18 -4
- package/dist/chunk-WQ7DE5UC.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +258 -262
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/deploy.d.ts.map +1 -1
- package/dist/cli/src/commands/manage.d.ts +22 -31
- package/dist/cli/src/commands/manage.d.ts.map +1 -1
- package/dist/cli/src/commands/npx.d.ts +5 -3
- package/dist/cli/src/commands/npx.d.ts.map +1 -1
- package/dist/cli/src/commands/project.d.ts.map +1 -1
- package/dist/cli/src/commands/source.d.ts +7 -0
- package/dist/cli/src/commands/source.d.ts.map +1 -1
- package/dist/cli/src/commands/update.d.ts.map +1 -1
- package/dist/cli/src/ensure-sources.d.ts.map +1 -1
- package/dist/client/index.d.ts +2 -0
- package/dist/connectors/config.d.ts +2 -0
- package/dist/connectors/config.js +6 -6
- package/dist/connectors/index.d.ts +2 -0
- package/dist/connectors/index.js +8 -8
- package/dist/connectors/rclone-config.d.ts +2 -0
- package/dist/connectors/rclone.d.ts +2 -0
- package/dist/connectors-shared/index.d.ts +2 -0
- package/dist/core/discovery.d.ts +2 -0
- package/dist/core/driver-targets.d.ts +2 -0
- package/dist/core/framework.d.ts +2 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +5 -5
- package/dist/core/logging.d.ts +2 -0
- package/dist/core/manifest.d.ts +2 -0
- package/dist/core/manifest.js +2 -2
- package/dist/core/models.d.ts +2 -0
- package/dist/core/models.js +1 -1
- package/dist/core/runtime-assets.d.ts +2 -0
- package/dist/core/runtime-assets.js +4 -4
- package/dist/core/src/index.d.ts +7 -5
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/core/src/lock.d.ts +47 -26
- package/dist/core/src/lock.d.ts.map +1 -1
- package/dist/core/src/manifest.d.ts.map +1 -1
- package/dist/core/src/models.d.ts +61 -49
- package/dist/core/src/models.d.ts.map +1 -1
- package/dist/core/src/repo-manager.d.ts +79 -36
- package/dist/core/src/repo-manager.d.ts.map +1 -1
- package/dist/core/src/runtime-assets.d.ts.map +1 -1
- package/dist/core/src/walker.d.ts +52 -0
- package/dist/core/src/walker.d.ts.map +1 -0
- package/dist/core/src/workspace-config.d.ts +160 -45
- package/dist/core/src/workspace-config.d.ts.map +1 -1
- package/dist/core/src/workspace-yaml-editor.d.ts +33 -16
- package/dist/core/src/workspace-yaml-editor.d.ts.map +1 -1
- package/dist/core/store.d.ts +2 -0
- package/dist/core/workspace-config.d.ts +2 -0
- package/dist/core/workspace-config.js +3 -3
- package/dist/deploy/index.d.ts +2 -0
- package/dist/deploy/index.js +167 -52
- package/dist/deploy/index.js.map +1 -1
- package/dist/deploy/src/index.d.ts +4 -3
- package/dist/deploy/src/index.d.ts.map +1 -1
- package/dist/deploy/src/targets/container-runtime.d.ts +1 -0
- package/dist/deploy/src/targets/container-runtime.d.ts.map +1 -1
- package/dist/deploy/src/targets/docker.d.ts +1 -0
- package/dist/deploy/src/targets/docker.d.ts.map +1 -1
- package/dist/deploy/src/targets/local.d.ts.map +1 -1
- package/dist/deploy/src/targets/nix.d.ts +36 -0
- package/dist/deploy/src/targets/nix.d.ts.map +1 -0
- package/dist/deploy/src/targets/podman.d.ts +1 -0
- package/dist/deploy/src/targets/podman.d.ts.map +1 -1
- package/dist/deploy/src/targets/process-handle.d.ts +34 -0
- package/dist/deploy/src/targets/process-handle.d.ts.map +1 -0
- package/dist/discovery/index.d.ts +2 -0
- package/dist/discovery/index.js +3 -3
- package/dist/discovery/src/source-config.d.ts +2 -2
- package/dist/{ensure-sources-COGVKY44.js → ensure-sources-ALTI5PXR.js} +20 -16
- package/dist/ensure-sources-ALTI5PXR.js.map +1 -0
- package/dist/library/index.d.ts +2 -0
- package/dist/library/index.js +4 -4
- package/dist/library/src/remote/remote-catalog-source.d.ts +17 -0
- package/dist/library/src/remote/remote-catalog-source.d.ts.map +1 -1
- package/dist/open-library-EEGG6RDN.js +13 -0
- package/dist/{open-library-DWAQFUSQ.js.map → open-library-EEGG6RDN.js.map} +1 -1
- package/dist/plugin-registry/index.d.ts +2 -0
- package/dist/plugin-registry/index.js +1 -1
- package/dist/plugin-registry/src/context.d.ts +30 -1
- package/dist/plugin-registry/src/context.d.ts.map +1 -1
- package/dist/plugin-registry/src/deploy-handle.d.ts +17 -1
- package/dist/plugin-registry/src/deploy-handle.d.ts.map +1 -1
- package/dist/plugin-registry/src/deploy-helpers.d.ts +69 -0
- package/dist/plugin-registry/src/deploy-helpers.d.ts.map +1 -0
- package/dist/plugin-registry/src/index.d.ts +6 -4
- package/dist/plugin-registry/src/index.d.ts.map +1 -1
- package/dist/plugin-registry/src/internal.d.ts.map +1 -1
- package/dist/plugin-registry/src/registry.d.ts +1 -0
- package/dist/plugin-registry/src/registry.d.ts.map +1 -1
- package/dist/plugin-registry/src/targets.d.ts +4 -0
- package/dist/plugin-registry/src/targets.d.ts.map +1 -1
- package/dist/{plugin-store-6OENKNFW.js → plugin-store-G277ZX3B.js} +8 -8
- package/dist/{plugin-store-6OENKNFW.js.map → plugin-store-G277ZX3B.js.map} +1 -1
- package/dist/plugins/index.d.ts +2 -0
- package/dist/plugins/src/catalog-source.d.ts +5 -0
- package/dist/plugins/src/catalog-source.d.ts.map +1 -1
- package/dist/resolver/index.d.ts +2 -0
- package/dist/runner/index.d.ts +2 -0
- package/dist/runner/index.js +17 -16
- package/dist/runner/prompt-assembly.d.ts +2 -0
- package/dist/runner/src/resources.d.ts.map +1 -1
- package/dist/runner/src/serve.d.ts +7 -0
- package/dist/runner/src/serve.d.ts.map +1 -1
- package/dist/sdk/asset-manager.d.ts +2 -0
- package/dist/sdk/asset-manager.js +7 -7
- package/dist/sdk/bridge.d.ts +2 -0
- package/dist/sdk/bridge.js +3 -3
- package/dist/sdk/client.d.ts +2 -0
- package/dist/sdk/core.d.ts +2 -0
- package/dist/sdk/core.js +5 -5
- package/dist/sdk/flow.d.ts +2 -0
- package/dist/sdk/index.d.ts +2 -0
- package/dist/sdk/index.js +53 -19
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/resolver.d.ts +2 -0
- package/dist/sdk/runner.d.ts +2 -0
- package/dist/sdk/runner.js +17 -16
- package/dist/sdk/session.d.ts +2 -0
- package/dist/sdk/src/local-runtime.d.ts +8 -0
- package/dist/sdk/src/local-runtime.d.ts.map +1 -1
- package/dist/sdk/src/transport.d.ts +7 -1
- package/dist/sdk/src/transport.d.ts.map +1 -1
- package/dist/sdk/store.d.ts +2 -0
- package/dist/sdk/telemetry.d.ts +2 -0
- package/dist/sdk/transport/ws/client.d.ts +2 -0
- package/dist/sdk/transport/ws/client.js +2 -1
- package/dist/sdk/transport/ws/server.d.ts +2 -0
- package/dist/sdk/transport/ws/server.js +2 -1
- package/dist/sdk/transport/ws.d.ts +2 -0
- package/dist/sdk/transport/ws.js +4 -3
- package/dist/sdk/transport.d.ts +2 -0
- package/dist/sdk/transport.js +4 -3
- package/dist/sdk/types.d.ts +2 -0
- package/dist/secrets/index.d.ts +2 -0
- package/dist/session/index.d.ts +2 -0
- package/dist/{setup-ACMP3QZC.js → setup-REX4I5NE.js} +10 -10
- package/dist/{setup-ACMP3QZC.js.map → setup-REX4I5NE.js.map} +1 -1
- package/dist/store/index.d.ts +2 -0
- package/dist/store/react.d.ts +2 -0
- package/dist/store/vue.d.ts +2 -0
- package/dist/store-client-IX3Y67NK.js +14 -0
- package/dist/{store-client-ZSLNOOQG.js.map → store-client-IX3Y67NK.js.map} +1 -1
- package/dist/telemetry/index.d.ts +2 -0
- package/dist/transport/index.d.ts +2 -0
- package/dist/transport/index.js +4 -3
- package/dist/transport/src/ws/auth.d.ts +34 -0
- package/dist/transport/src/ws/auth.d.ts.map +1 -0
- package/dist/transport/src/ws/client.d.ts +4 -0
- package/dist/transport/src/ws/client.d.ts.map +1 -1
- package/dist/transport/src/ws/index.d.ts +3 -2
- package/dist/transport/src/ws/index.d.ts.map +1 -1
- package/dist/transport/src/ws/server.d.ts +5 -0
- package/dist/transport/src/ws/server.d.ts.map +1 -1
- package/dist/transport/ws/client.d.ts +2 -0
- package/dist/transport/ws/client.js +2 -1
- package/dist/transport/ws/server.d.ts +2 -0
- package/dist/transport/ws/server.js +2 -1
- package/dist/transport/ws.d.ts +2 -0
- package/dist/transport/ws.js +4 -3
- package/dist/tui/index.d.ts +2 -0
- package/dist/tui/index.js +17 -16
- package/dist/tui/index.js.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/manifests.d.ts +2 -0
- package/dist/workspace-plugin/adapters/mcp.d.ts +2 -0
- package/dist/workspace-plugin/adapters/omp.d.ts +2 -0
- package/dist/workspace-plugin/index.d.ts +2 -0
- package/dist/workspace-plugin/index.js +1 -1
- package/package.json +4 -2
- package/dist/asset-feeds-PJDJ3QYI.js.map +0 -1
- package/dist/chunk-2DNSSQ22.js.map +0 -1
- package/dist/chunk-7PTP3SQJ.js.map +0 -1
- package/dist/chunk-G6GKWGOW.js.map +0 -1
- package/dist/chunk-IGQEXBBG.js.map +0 -1
- package/dist/chunk-KA46DUM4.js.map +0 -1
- package/dist/chunk-NGC7ZQI4.js.map +0 -1
- package/dist/chunk-PBWMV5GM.js.map +0 -1
- package/dist/chunk-RENHNO4J.js.map +0 -1
- package/dist/chunk-TKOLD2O7.js.map +0 -1
- package/dist/chunk-TTY56FQQ.js.map +0 -1
- package/dist/chunk-UZRY5UI2.js.map +0 -1
- package/dist/chunk-W2O5LWYU.js +0 -3
- package/dist/chunk-WIR34WMU.js.map +0 -1
- package/dist/chunk-X5Y4EGZB.js.map +0 -1
- package/dist/ensure-sources-COGVKY44.js.map +0 -1
- package/dist/open-library-DWAQFUSQ.js +0 -13
- package/dist/store-client-ZSLNOOQG.js +0 -14
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { scanDirectory, fromMcpServerMd } from './chunk-
|
|
2
|
-
import { parseAssetRef } from './chunk-
|
|
3
|
-
import { mkdirSync, existsSync, readFileSync, writeFileSync, lstatSync, symlinkSync, rmSync, readdirSync } from 'fs';
|
|
1
|
+
import { scanDirectory, parseFrontmatter, fromMcpServerMd } from './chunk-NQL3T75I.js';
|
|
2
|
+
import { parseAssetRef } from './chunk-VUCPJBAG.js';
|
|
3
|
+
import { mkdirSync, existsSync, readFileSync, writeFileSync, lstatSync, symlinkSync, rmSync, readdirSync, statSync } from 'fs';
|
|
4
4
|
import { homedir } from 'os';
|
|
5
|
-
import { join, resolve, parse as parse$1, dirname } from 'path';
|
|
5
|
+
import { join, resolve, relative, parse as parse$1, dirname } from 'path';
|
|
6
6
|
import { parse, stringify } from 'yaml';
|
|
7
7
|
import { spawnSync } from 'child_process';
|
|
8
|
+
import semver from 'semver';
|
|
9
|
+
import { createHash } from 'crypto';
|
|
10
|
+
import fg from 'fast-glob';
|
|
8
11
|
|
|
9
12
|
function getGlobalCacheDir() {
|
|
10
13
|
return process.env.SKAILE_CACHE_DIR ?? join(homedir(), ".skaile", "repos");
|
|
@@ -117,9 +120,14 @@ function ensureRepo(decl, name, reposDir, opts) {
|
|
|
117
120
|
if (decl.path) {
|
|
118
121
|
const projectDir = opts?.projectDir ?? resolve(reposDir, "..");
|
|
119
122
|
const resolved = resolve(projectDir, decl.path);
|
|
120
|
-
if (
|
|
123
|
+
if (existsSync(resolved)) return resolved;
|
|
124
|
+
if (!decl.url) {
|
|
121
125
|
throw new Error(`Local repository path not found: ${decl.path} (resolved: ${resolved})`);
|
|
122
126
|
}
|
|
127
|
+
if (!cloneRepo(decl.url, decl.branch ?? "main", resolved)) {
|
|
128
|
+
throw new Error(`Failed to clone ${decl.url} into ${resolved}`);
|
|
129
|
+
}
|
|
130
|
+
if (opts?.pin) checkoutPin(resolved, opts.pin);
|
|
123
131
|
return resolved;
|
|
124
132
|
}
|
|
125
133
|
if (decl.url) {
|
|
@@ -157,13 +165,25 @@ function ensureRepo(decl, name, reposDir, opts) {
|
|
|
157
165
|
}
|
|
158
166
|
throw new Error(`Repository "${name}" has neither url nor path`);
|
|
159
167
|
}
|
|
168
|
+
function repoSlugFromGitRemote(rootDir) {
|
|
169
|
+
const r = spawnSync("git", ["-C", rootDir, "config", "--get", "remote.origin.url"], {
|
|
170
|
+
encoding: "utf8",
|
|
171
|
+
stdio: "pipe",
|
|
172
|
+
env: GIT_ENV
|
|
173
|
+
});
|
|
174
|
+
if (r.status !== 0) return void 0;
|
|
175
|
+
const m = /github\.com[/:]([^/]+)\/([^/]+?)(?:\.git)?\/?$/.exec(r.stdout.trim());
|
|
176
|
+
return m ? `${m[1]}/${m[2]}` : void 0;
|
|
177
|
+
}
|
|
160
178
|
function scanRepo(repoDir, repoName) {
|
|
161
|
-
|
|
179
|
+
const repo = repoSlugFromGitRemote(repoDir);
|
|
180
|
+
const entries = scanDirectory(repoDir, repoName);
|
|
181
|
+
return repo ? entries.map((e) => ({ ...e, repo })) : entries;
|
|
162
182
|
}
|
|
163
183
|
function resolveAsset(ref, repositories, reposDir, opts) {
|
|
164
184
|
let repoNames;
|
|
165
|
-
if (ref.
|
|
166
|
-
repoNames = [ref.
|
|
185
|
+
if (ref.publisher) {
|
|
186
|
+
repoNames = [ref.publisher];
|
|
167
187
|
} else if (opts?.preferRepo && opts.preferRepo in repositories) {
|
|
168
188
|
const rest = Object.keys(repositories).filter((n) => n !== opts.preferRepo);
|
|
169
189
|
repoNames = [opts.preferRepo, ...rest];
|
|
@@ -199,67 +219,149 @@ function resolveRepoDir(decl, name, reposDir, projectDir) {
|
|
|
199
219
|
if (existsSync(join(globalDest, ".git"))) return globalDest;
|
|
200
220
|
return null;
|
|
201
221
|
}
|
|
202
|
-
|
|
222
|
+
var CanonicalRefConflictError = class extends Error {
|
|
223
|
+
constructor(ref, candidates, depChain) {
|
|
224
|
+
super(
|
|
225
|
+
[
|
|
226
|
+
`error: divergent sha256 for ${ref}`,
|
|
227
|
+
"",
|
|
228
|
+
" pulled in via:",
|
|
229
|
+
...depChain.map((s, i) => ` ${" ".repeat(i * 2)}${s}`),
|
|
230
|
+
"",
|
|
231
|
+
" candidates:",
|
|
232
|
+
...candidates.map(
|
|
233
|
+
(c) => ` ${c.sourceUrl} @ ${c.commit.slice(0, 8)}
|
|
234
|
+
sha256: ${c.sha256}`
|
|
235
|
+
),
|
|
236
|
+
"",
|
|
237
|
+
"resolve by:",
|
|
238
|
+
" 1. removing one source from skaile.yaml,",
|
|
239
|
+
" 2. configuring a store and using its canonical digest, or",
|
|
240
|
+
" 3. adding to overrides: (with a non-empty reason:)"
|
|
241
|
+
].join("\n")
|
|
242
|
+
);
|
|
243
|
+
this.ref = ref;
|
|
244
|
+
this.candidates = candidates;
|
|
245
|
+
this.depChain = depChain;
|
|
246
|
+
this.name = "CanonicalRefConflictError";
|
|
247
|
+
}
|
|
248
|
+
ref;
|
|
249
|
+
candidates;
|
|
250
|
+
depChain;
|
|
251
|
+
};
|
|
252
|
+
var SHA_PIN_RE = /^[0-9a-f]{40}$/i;
|
|
253
|
+
async function resolveAll(deps, opts) {
|
|
203
254
|
const resolved = [];
|
|
204
255
|
const seen = /* @__PURE__ */ new Set();
|
|
205
256
|
const missing = [];
|
|
206
257
|
const resolvedBy = /* @__PURE__ */ new Map();
|
|
207
|
-
|
|
258
|
+
const overridesApplied = /* @__PURE__ */ new Set();
|
|
259
|
+
const overridesByRef = new Map(opts.overrides.map((o) => [o.ref, o]));
|
|
260
|
+
async function visit(refStr, parent, depChain) {
|
|
208
261
|
const ref = parseAssetRef(refStr);
|
|
209
|
-
|
|
262
|
+
if (!ref.publisher) throw new Error(`dep "${refStr}" missing publisher`);
|
|
263
|
+
const key = `${ref.publisher}/${ref.kind}:${ref.name}`;
|
|
210
264
|
if (seen.has(key)) return;
|
|
211
265
|
seen.add(key);
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
266
|
+
const sourceCandidates = opts.provenanceIndex.get(key) ?? [];
|
|
267
|
+
const storeCandidates = [];
|
|
268
|
+
if (opts.stores.length > 0 && opts.storeFetcher) {
|
|
269
|
+
const candidateVersions = enumerateVersionsForPin(
|
|
270
|
+
ref.pin,
|
|
271
|
+
sourceCandidates.map((c) => c.version)
|
|
272
|
+
);
|
|
273
|
+
for (const store of opts.stores) {
|
|
274
|
+
for (const v of candidateVersions) {
|
|
275
|
+
if (!v) continue;
|
|
276
|
+
const m = await opts.storeFetcher.getInstallManifest(
|
|
277
|
+
store.url,
|
|
278
|
+
`${ref.publisher}/${ref.kind}:${ref.name}@${v}`
|
|
279
|
+
);
|
|
280
|
+
if (m) {
|
|
281
|
+
storeCandidates.push({
|
|
282
|
+
publisher: ref.publisher,
|
|
283
|
+
kind: ref.kind,
|
|
284
|
+
name: ref.name,
|
|
285
|
+
version: v,
|
|
286
|
+
sourceUrl: m.sourceUrl,
|
|
287
|
+
commit: m.commit,
|
|
288
|
+
files: m.files,
|
|
289
|
+
sha256: m.sha256
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
const all = [...sourceCandidates, ...storeCandidates];
|
|
296
|
+
if (all.length === 0) {
|
|
218
297
|
missing.push(refStr);
|
|
219
298
|
return;
|
|
220
299
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
300
|
+
const filtered = all.filter((c) => matchPin(ref.pin, c.version));
|
|
301
|
+
if (filtered.length === 0) {
|
|
302
|
+
missing.push(refStr);
|
|
303
|
+
return;
|
|
225
304
|
}
|
|
226
|
-
|
|
227
|
-
|
|
305
|
+
const versions = Array.from(new Set(filtered.map((c) => c.version)));
|
|
306
|
+
const best = versions.sort((a, b) => semver.rcompare(coerceVersion(a), coerceVersion(b)))[0];
|
|
307
|
+
const finalists = filtered.filter((c) => c.version === best);
|
|
308
|
+
const canonicalRef = `${ref.publisher}/${ref.kind}:${ref.name}@${best}`;
|
|
309
|
+
const uniqueShas = Array.from(new Set(finalists.map((c) => c.sha256)));
|
|
310
|
+
let chosen;
|
|
311
|
+
if (uniqueShas.length > 1) {
|
|
312
|
+
const override = overridesByRef.get(canonicalRef);
|
|
313
|
+
if (!override) {
|
|
314
|
+
throw new CanonicalRefConflictError(canonicalRef, finalists, [...depChain, refStr]);
|
|
315
|
+
}
|
|
316
|
+
const pick = finalists.find((c) => c.sourceUrl === override.source);
|
|
317
|
+
if (!pick) {
|
|
318
|
+
throw new Error(
|
|
319
|
+
`override for ${canonicalRef} points at ${override.source}, which is not among the resolved candidates`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
chosen = pick;
|
|
323
|
+
overridesApplied.add(canonicalRef);
|
|
324
|
+
} else {
|
|
325
|
+
chosen = [...finalists].sort((a, b) => a.sourceUrl.localeCompare(b.sourceUrl))[0];
|
|
326
|
+
}
|
|
327
|
+
if (opts.storeFetcher && opts.stores.length > 0 && sourceCandidates.some((c) => c.version === best) && storeCandidates.some((c) => c.version === best)) {
|
|
328
|
+
for (const store of opts.stores) {
|
|
329
|
+
const d = await opts.storeFetcher.getCanonicalDigest(store.url, canonicalRef);
|
|
330
|
+
if (d && d.sha256 !== chosen.sha256) {
|
|
331
|
+
throw new CanonicalRefConflictError(
|
|
332
|
+
canonicalRef,
|
|
333
|
+
[...finalists, { ...chosen, sourceUrl: store.url, sha256: d.sha256 }],
|
|
334
|
+
[...depChain, refStr]
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
228
338
|
}
|
|
229
|
-
resolved.push(
|
|
339
|
+
resolved.push(chosen);
|
|
340
|
+
resolvedBy.set(key, parent);
|
|
230
341
|
}
|
|
231
342
|
for (const dep of deps) {
|
|
232
|
-
visit(dep, "direct");
|
|
343
|
+
await visit(dep, "direct", []);
|
|
233
344
|
}
|
|
234
|
-
|
|
235
|
-
return { resolved, missing, resolvedBy, collisions };
|
|
345
|
+
return { resolved, missing, resolvedBy, overridesApplied };
|
|
236
346
|
}
|
|
237
|
-
function
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const repoDir = resolveRepoDir(decl, repoName, reposDir, projectDir);
|
|
245
|
-
if (!repoDir || !existsSync(repoDir)) continue;
|
|
246
|
-
repoEntries.set(repoName, scanRepo(repoDir, repoName));
|
|
247
|
-
}
|
|
248
|
-
const collisions = [];
|
|
249
|
-
for (const entry of resolved) {
|
|
250
|
-
const key = `${entry.kind}:${entry.name}`;
|
|
251
|
-
const shadowedIn = [];
|
|
252
|
-
for (const [repoName, entries] of repoEntries) {
|
|
253
|
-
if (repoName === entry.repository) continue;
|
|
254
|
-
if (entries.some((e) => e.kind === entry.kind && e.name === entry.name)) {
|
|
255
|
-
shadowedIn.push(repoName);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
if (shadowedIn.length > 0 && entry.repository) {
|
|
259
|
-
collisions.push({ key, resolvedFrom: entry.repository, shadowedIn });
|
|
260
|
-
}
|
|
347
|
+
function coerceVersion(v) {
|
|
348
|
+
return semver.valid(v) ? v : semver.coerce(v)?.version ?? "0.0.0";
|
|
349
|
+
}
|
|
350
|
+
function matchPin(pin, version) {
|
|
351
|
+
if (!pin) return true;
|
|
352
|
+
if (SHA_PIN_RE.test(pin)) {
|
|
353
|
+
return version === `0.0.0-sha.${pin.slice(0, 7)}`;
|
|
261
354
|
}
|
|
262
|
-
|
|
355
|
+
if (version.startsWith("0.0.0-sha.")) {
|
|
356
|
+
return version === pin;
|
|
357
|
+
}
|
|
358
|
+
if (!semver.valid(version)) return version === pin;
|
|
359
|
+
return semver.satisfies(version, pin, { includePrerelease: false });
|
|
360
|
+
}
|
|
361
|
+
function enumerateVersionsForPin(pin, sourceVersionsHint) {
|
|
362
|
+
if (!pin) return sourceVersionsHint.length > 0 ? sourceVersionsHint : [];
|
|
363
|
+
if (semver.valid(pin)) return [pin];
|
|
364
|
+
return sourceVersionsHint;
|
|
263
365
|
}
|
|
264
366
|
function checkRepoStatus(decl, name, reposDir, projectDir) {
|
|
265
367
|
if (projectDir) {
|
|
@@ -320,8 +422,185 @@ function checkRepoStatus(decl, name, reposDir, projectDir) {
|
|
|
320
422
|
base.upToDate = base.behind === 0;
|
|
321
423
|
return base;
|
|
322
424
|
}
|
|
425
|
+
function fileSha256(p) {
|
|
426
|
+
return createHash("sha256").update(readFileSync(p)).digest("hex");
|
|
427
|
+
}
|
|
428
|
+
function compositeSha256(files) {
|
|
429
|
+
const lines = files.slice().sort((a, b) => a.path.localeCompare(b.path)).map((f) => `${f.path}:${f.sha256}
|
|
430
|
+
`).join("");
|
|
431
|
+
return createHash("sha256").update(lines).digest("hex");
|
|
432
|
+
}
|
|
433
|
+
function publisherFromGithubUrl(url) {
|
|
434
|
+
const m = url.match(/github\.com[/:]([^/]+)\/[^/]+/);
|
|
435
|
+
return m?.[1];
|
|
436
|
+
}
|
|
437
|
+
function syntheticVersion(commit) {
|
|
438
|
+
return `0.0.0-sha.${commit.slice(0, 7)}`;
|
|
439
|
+
}
|
|
440
|
+
var KIND_DIRS = [
|
|
441
|
+
{ dir: "skills", kind: "skill", mdName: "SKILL.md" },
|
|
442
|
+
{ dir: "agents", kind: "agent", mdName: "AGENT.md" },
|
|
443
|
+
{ dir: "bundles", kind: "bundle", mdName: "BUNDLE.md" },
|
|
444
|
+
{ dir: "mcp-servers", kind: "mcp-server", mdName: "MCP.md" },
|
|
445
|
+
{ dir: "connectors", kind: "connector", mdName: "CONNECTOR.md" },
|
|
446
|
+
{ dir: "prompts", kind: "prompt", mdName: "PROMPT.md" },
|
|
447
|
+
{ dir: "contracts", kind: "contract", mdName: "CONTRACT.md" }
|
|
448
|
+
];
|
|
449
|
+
var MD_FILE_BY_KIND = Object.fromEntries(
|
|
450
|
+
KIND_DIRS.map((k) => [k.kind, k.mdName])
|
|
451
|
+
);
|
|
452
|
+
function buildProvenanceIndex(clones, _opts) {
|
|
453
|
+
const index = /* @__PURE__ */ new Map();
|
|
454
|
+
for (const clone of clones) walkOne(clone, index);
|
|
455
|
+
return index;
|
|
456
|
+
}
|
|
457
|
+
function walkOne(clone, index) {
|
|
458
|
+
const yamlPath = join(clone.localPath, "skaile.yaml");
|
|
459
|
+
if (existsSync(yamlPath)) {
|
|
460
|
+
walkWithManifest(clone, yamlPath, index);
|
|
461
|
+
} else {
|
|
462
|
+
walkFilenameConvention(clone, index);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
function walkWithManifest(clone, yamlPath, index) {
|
|
466
|
+
const raw = parse(readFileSync(yamlPath, "utf8")) ?? {};
|
|
467
|
+
const publisher = typeof raw.publisher === "string" && raw.publisher.length > 0 ? raw.publisher : publisherFromGithubUrl(clone.sourceUrl);
|
|
468
|
+
if (!publisher) {
|
|
469
|
+
throw new Error(
|
|
470
|
+
`${clone.sourceUrl}: publisher must be declared in skaile.yaml (non-GitHub source URL \u2014 auto-derivation not available).`
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
const sourceVersion = (typeof raw.version === "string" ? raw.version : void 0) ?? (clone.tag ? clone.tag.replace(/^v/, "") : void 0) ?? syntheticVersion(clone.commit);
|
|
474
|
+
const assets = Array.isArray(raw.assets) ? raw.assets : [];
|
|
475
|
+
if (assets.length === 0) {
|
|
476
|
+
walkFilenameConvention(clone, index, publisher, sourceVersion);
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
for (const a of assets) {
|
|
480
|
+
const assetPublisher = a.publisher ?? publisher;
|
|
481
|
+
const version = a.version ?? sourceVersion;
|
|
482
|
+
const files = expandAssetFiles(clone.localPath, a);
|
|
483
|
+
verifyNameMatch(clone.localPath, files, a.name, a.kind);
|
|
484
|
+
const metadata = readMetadata(clone.localPath, files, a.kind);
|
|
485
|
+
const candidate = {
|
|
486
|
+
publisher: assetPublisher,
|
|
487
|
+
kind: a.kind,
|
|
488
|
+
name: a.name,
|
|
489
|
+
version,
|
|
490
|
+
sourceUrl: clone.sourceUrl,
|
|
491
|
+
commit: clone.commit,
|
|
492
|
+
files,
|
|
493
|
+
sha256: compositeSha256(files),
|
|
494
|
+
metadata
|
|
495
|
+
};
|
|
496
|
+
push(index, `${assetPublisher}/${a.kind}:${a.name}`, candidate);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
function expandAssetFiles(repoRoot, a) {
|
|
500
|
+
const out = [];
|
|
501
|
+
if (a.root) {
|
|
502
|
+
walkDirRecursive(join(repoRoot, a.root), repoRoot, out);
|
|
503
|
+
}
|
|
504
|
+
if (a.files) {
|
|
505
|
+
const matches = fg.sync(a.files, { cwd: repoRoot, onlyFiles: true, dot: false });
|
|
506
|
+
for (const rel of matches) {
|
|
507
|
+
out.push({ path: rel, sha256: fileSha256(join(repoRoot, rel)) });
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
const seen = /* @__PURE__ */ new Set();
|
|
511
|
+
return out.filter((f) => seen.has(f.path) ? false : (seen.add(f.path), true));
|
|
512
|
+
}
|
|
513
|
+
function walkDirRecursive(abs, root, out) {
|
|
514
|
+
if (!existsSync(abs)) return;
|
|
515
|
+
for (const entry of readdirSync(abs, { withFileTypes: true })) {
|
|
516
|
+
if (entry.name === ".git" || entry.name === "node_modules") continue;
|
|
517
|
+
const childAbs = join(abs, entry.name);
|
|
518
|
+
if (entry.isDirectory()) {
|
|
519
|
+
walkDirRecursive(childAbs, root, out);
|
|
520
|
+
} else if (entry.isFile()) {
|
|
521
|
+
out.push({ path: relative(root, childAbs), sha256: fileSha256(childAbs) });
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function walkFilenameConvention(clone, index, publisherOverride, versionOverride) {
|
|
526
|
+
const publisher = publisherOverride ?? publisherFromGithubUrl(clone.sourceUrl);
|
|
527
|
+
if (!publisher) {
|
|
528
|
+
throw new Error(
|
|
529
|
+
`${clone.sourceUrl}: publisher must be declared in skaile.yaml (non-GitHub source URL).`
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
const version = versionOverride ?? (clone.tag ? clone.tag.replace(/^v/, "") : void 0) ?? syntheticVersion(clone.commit);
|
|
533
|
+
for (const { dir, kind, mdName } of KIND_DIRS) {
|
|
534
|
+
const base = join(clone.localPath, dir);
|
|
535
|
+
if (!existsSync(base) || !statSync(base).isDirectory()) continue;
|
|
536
|
+
for (const entry of readdirSync(base, { withFileTypes: true })) {
|
|
537
|
+
if (!entry.isDirectory()) continue;
|
|
538
|
+
const assetDir = join(base, entry.name);
|
|
539
|
+
if (!existsSync(join(assetDir, mdName))) continue;
|
|
540
|
+
const files = [];
|
|
541
|
+
walkDirRecursive(assetDir, clone.localPath, files);
|
|
542
|
+
const metadata = readMetadata(clone.localPath, files, kind);
|
|
543
|
+
const candidate = {
|
|
544
|
+
publisher,
|
|
545
|
+
kind,
|
|
546
|
+
name: entry.name,
|
|
547
|
+
version,
|
|
548
|
+
sourceUrl: clone.sourceUrl,
|
|
549
|
+
commit: clone.commit,
|
|
550
|
+
files,
|
|
551
|
+
sha256: compositeSha256(files),
|
|
552
|
+
metadata
|
|
553
|
+
};
|
|
554
|
+
push(index, `${publisher}/${kind}:${entry.name}`, candidate);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
function verifyNameMatch(repoRoot, files, expectedName, kind) {
|
|
559
|
+
const mdName = MD_FILE_BY_KIND[kind];
|
|
560
|
+
if (!mdName) return;
|
|
561
|
+
const md = files.find((f) => f.path.endsWith(mdName));
|
|
562
|
+
if (!md) return;
|
|
563
|
+
const { data } = parseFrontmatter(readFileSync(join(repoRoot, md.path), "utf8"));
|
|
564
|
+
const declared = typeof data.name === "string" ? data.name : void 0;
|
|
565
|
+
if (declared && declared !== expectedName) {
|
|
566
|
+
throw new Error(
|
|
567
|
+
`name mismatch: ${mdName} says "${declared}", skaile.yaml says "${expectedName}" \u2014 index-time hard error.`
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
function readMetadata(repoRoot, files, kind) {
|
|
572
|
+
if (kind !== "mcp-server") return void 0;
|
|
573
|
+
const mcpMd = files.find((f) => f.path.endsWith("MCP.md"));
|
|
574
|
+
if (!mcpMd) return void 0;
|
|
575
|
+
const { data } = parseFrontmatter(readFileSync(join(repoRoot, mcpMd.path), "utf8"));
|
|
576
|
+
return data;
|
|
577
|
+
}
|
|
578
|
+
function push(index, key, candidate) {
|
|
579
|
+
const arr = index.get(key) ?? [];
|
|
580
|
+
arr.push(candidate);
|
|
581
|
+
index.set(key, arr);
|
|
582
|
+
}
|
|
323
583
|
|
|
324
584
|
// core/src/workspace-config.ts
|
|
585
|
+
var DEFAULT_RECIPE_ATTR = "default";
|
|
586
|
+
function validateAssetRecipeFlake(flake) {
|
|
587
|
+
if (typeof flake !== "string" || flake.length === 0) {
|
|
588
|
+
throw new Error("AssetRecipe.flake must be a non-empty string");
|
|
589
|
+
}
|
|
590
|
+
if (flake.length > 500) {
|
|
591
|
+
throw new Error(`AssetRecipe.flake too long (${flake.length} chars, max 500)`);
|
|
592
|
+
}
|
|
593
|
+
if (flake === ".") return;
|
|
594
|
+
const ALLOWED_SCHEME = /^(github:|git\+https:\/\/|git\+ssh:\/\/|path:\/)/;
|
|
595
|
+
if (!ALLOWED_SCHEME.test(flake)) {
|
|
596
|
+
throw new Error(
|
|
597
|
+
`AssetRecipe.flake "${flake}" has an unsupported source. Allowed: "." or a flake URL (github:, git+https://, git+ssh://, path:/).`
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
if (/[\s`$;|&<>(){}#\n\r]/.test(flake)) {
|
|
601
|
+
throw new Error(`AssetRecipe.flake "${flake}" contains forbidden characters.`);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
325
604
|
function validateAssetRecipeAttr(attr) {
|
|
326
605
|
if (typeof attr !== "string" || attr.length === 0) {
|
|
327
606
|
throw new Error("AssetRecipe.attr must be a non-empty string");
|
|
@@ -401,13 +680,20 @@ function listSkWorkspaceConfigs(dir) {
|
|
|
401
680
|
function resolveSkWorkspaceConfig(projectDir, opts) {
|
|
402
681
|
const name = opts?.name ?? SK_WORKSPACE_DEFAULT_NAME;
|
|
403
682
|
const configs = [];
|
|
683
|
+
const assertNoLegacyKey = (file) => {
|
|
684
|
+
const d = file?.diagnostics?.find((x) => x.code === "legacy_key_rejected");
|
|
685
|
+
if (d) throw new Error(d.message);
|
|
686
|
+
};
|
|
404
687
|
const userConfig = loadSkWorkspaceConfig(join(homedir(), ".skaile"), name);
|
|
688
|
+
assertNoLegacyKey(userConfig);
|
|
405
689
|
if (userConfig) configs.push(userConfig.config);
|
|
406
690
|
if (opts?.appDir) {
|
|
407
691
|
const appConfig = loadSkWorkspaceConfig(opts.appDir, name);
|
|
692
|
+
assertNoLegacyKey(appConfig);
|
|
408
693
|
if (appConfig) configs.push(appConfig.config);
|
|
409
694
|
}
|
|
410
695
|
const projectConfig = loadSkWorkspaceConfig(projectDir, name);
|
|
696
|
+
assertNoLegacyKey(projectConfig);
|
|
411
697
|
if (projectConfig) configs.push(projectConfig.config);
|
|
412
698
|
if (configs.length > 0) return configs.reduce(mergeSkWorkspaceConfigs);
|
|
413
699
|
return {};
|
|
@@ -443,10 +729,12 @@ function mergeSkWorkspaceConfigs(base, overlay) {
|
|
|
443
729
|
},
|
|
444
730
|
// startup: overlay wins (project-level only)
|
|
445
731
|
startup: overlay.startup ?? base.startup,
|
|
446
|
-
//
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
732
|
+
// publication half — scalars: overlay wins when defined; assets: by kind+name
|
|
733
|
+
publisher: overlay.publisher ?? base.publisher,
|
|
734
|
+
version: overlay.version ?? base.version,
|
|
735
|
+
assets: dedupeByKey(
|
|
736
|
+
[...base.assets ?? [], ...overlay.assets ?? []],
|
|
737
|
+
(a) => `${a.kind}:${a.name}`
|
|
450
738
|
),
|
|
451
739
|
// mounts: by id — overlay wins
|
|
452
740
|
mounts: mergeById(base.mounts ?? [], overlay.mounts ?? []),
|
|
@@ -511,14 +799,14 @@ function mergeSkWorkspaceConfigs(base, overlay) {
|
|
|
511
799
|
secrets: overlay.secrets ?? base.secrets,
|
|
512
800
|
// telemetry: overlay wins entirely (raw pass-through)
|
|
513
801
|
telemetry: overlay.telemetry ?? base.telemetry,
|
|
514
|
-
// repositories: always empty in merged output; the schema no longer
|
|
515
|
-
// accepts this key. The internal install pipeline builds its own map
|
|
516
|
-
// from `ai_resources[]` entries.
|
|
517
|
-
repositories: {},
|
|
518
802
|
// dependencies: concatenate and dedupe
|
|
519
803
|
dependencies: dedupe([...base.dependencies ?? [], ...overlay.dependencies ?? []]),
|
|
520
|
-
// sources: dedupe by
|
|
521
|
-
sources: dedupeByKey([...base.sources ?? [], ...overlay.sources ?? []], "
|
|
804
|
+
// sources: dedupe by url — overlay entry wins for the same url
|
|
805
|
+
sources: dedupeByKey([...base.sources ?? [], ...overlay.sources ?? []], "url"),
|
|
806
|
+
// stores: dedupe by url — overlay wins
|
|
807
|
+
stores: dedupeByKey([...base.stores ?? [], ...overlay.stores ?? []], "url"),
|
|
808
|
+
// overrides: dedupe by ref — overlay wins
|
|
809
|
+
overrides: dedupeByKey([...base.overrides ?? [], ...overlay.overrides ?? []], "ref"),
|
|
522
810
|
// plugins: concatenate + dedupe (like dependencies)
|
|
523
811
|
plugins: dedupe([...base.plugins ?? [], ...overlay.plugins ?? []]),
|
|
524
812
|
// deploy: overlay wins entirely (scalar-like selection)
|
|
@@ -600,46 +888,75 @@ function normalizeConfigInternal(raw) {
|
|
|
600
888
|
if (Array.isArray(raw.startup)) {
|
|
601
889
|
config.startup = raw.startup;
|
|
602
890
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
aiResKey = "ai_resources";
|
|
608
|
-
} else if (raw.aiResources !== void 0) {
|
|
609
|
-
aiResRaw = raw.aiResources;
|
|
610
|
-
aiResKey = "aiResources";
|
|
611
|
-
}
|
|
612
|
-
if (aiResKey === "aiResources") {
|
|
613
|
-
diagnostics.push({
|
|
614
|
-
code: "legacy_key_camelcase",
|
|
615
|
-
severity: "warning",
|
|
616
|
-
message: 'Non-canonical key "aiResources" \u2014 use "ai_resources".',
|
|
617
|
-
path: "aiResources"
|
|
618
|
-
});
|
|
891
|
+
if (raw.repositories !== void 0) {
|
|
892
|
+
throw new Error(
|
|
893
|
+
"skaile.yaml: unknown top-level key `repositories:`. The schema changed in @skaile/workspaces 4.x \u2014 see docs/concepts/manifest-schema.md, or ask your AI assistant to apply the `migrate-skaile-manifest` skill."
|
|
894
|
+
);
|
|
619
895
|
}
|
|
620
|
-
if (
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
if (
|
|
639
|
-
|
|
640
|
-
if (
|
|
641
|
-
|
|
642
|
-
|
|
896
|
+
if (raw.ai_resources !== void 0 || raw.aiResources !== void 0) {
|
|
897
|
+
throw new Error(
|
|
898
|
+
"skaile.yaml: unknown top-level key `ai_resources:`. The schema changed in @skaile/workspaces 4.x \u2014 see docs/concepts/manifest-schema.md, or ask your AI assistant to apply the `migrate-skaile-manifest` skill."
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
if (typeof raw.publisher === "string" && raw.publisher.length > 0) {
|
|
902
|
+
config.publisher = raw.publisher;
|
|
903
|
+
}
|
|
904
|
+
if (typeof raw.version === "string" && raw.version.length > 0) {
|
|
905
|
+
config.version = raw.version;
|
|
906
|
+
}
|
|
907
|
+
if (Array.isArray(raw.assets)) {
|
|
908
|
+
const entries = [];
|
|
909
|
+
for (const item of raw.assets) {
|
|
910
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
911
|
+
const a = item;
|
|
912
|
+
const kind = typeof a.kind === "string" ? a.kind : "";
|
|
913
|
+
const name = typeof a.name === "string" ? a.name : "";
|
|
914
|
+
if (!kind || !name) continue;
|
|
915
|
+
const entry = { kind, name };
|
|
916
|
+
if (typeof a.root === "string") entry.root = a.root;
|
|
917
|
+
if (Array.isArray(a.files)) {
|
|
918
|
+
entry.files = a.files.filter(
|
|
919
|
+
(f) => typeof f === "string"
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
if (typeof a.version === "string") entry.version = a.version;
|
|
923
|
+
if (typeof a.publisher === "string") entry.publisher = a.publisher;
|
|
924
|
+
entries.push(entry);
|
|
925
|
+
}
|
|
926
|
+
if (entries.length > 0) config.assets = entries;
|
|
927
|
+
}
|
|
928
|
+
if (Array.isArray(raw.stores)) {
|
|
929
|
+
const entries = [];
|
|
930
|
+
for (const item of raw.stores) {
|
|
931
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
932
|
+
const s = item;
|
|
933
|
+
const url = typeof s.url === "string" ? s.url : "";
|
|
934
|
+
if (!url) continue;
|
|
935
|
+
entries.push({ url });
|
|
936
|
+
}
|
|
937
|
+
if (entries.length > 0) config.stores = entries;
|
|
938
|
+
}
|
|
939
|
+
if (Array.isArray(raw.overrides)) {
|
|
940
|
+
const entries = [];
|
|
941
|
+
for (const item of raw.overrides) {
|
|
942
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
943
|
+
const o = item;
|
|
944
|
+
const ref = typeof o.ref === "string" ? o.ref : "";
|
|
945
|
+
const source = typeof o.source === "string" ? o.source : "";
|
|
946
|
+
if (!ref || !source) continue;
|
|
947
|
+
if (typeof o.reason !== "string") {
|
|
948
|
+
throw new Error(
|
|
949
|
+
`skaile.yaml: overrides[] entry for ${ref}: reason is required and must be a non-empty string.`
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
if (o.reason.trim().length === 0) {
|
|
953
|
+
throw new Error(
|
|
954
|
+
`skaile.yaml: overrides[] entry for ${ref}: reason must not be empty.`
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
entries.push({ ref, source, reason: o.reason });
|
|
958
|
+
}
|
|
959
|
+
if (entries.length > 0) config.overrides = entries;
|
|
643
960
|
}
|
|
644
961
|
if (Array.isArray(raw.mounts)) {
|
|
645
962
|
config.mounts = raw.mounts;
|
|
@@ -678,13 +995,12 @@ function normalizeConfigInternal(raw) {
|
|
|
678
995
|
if (Array.isArray(raw.sources)) {
|
|
679
996
|
const entries = [];
|
|
680
997
|
for (const item of raw.sources) {
|
|
681
|
-
if (!item || typeof item !== "object") continue;
|
|
998
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
682
999
|
const s = item;
|
|
683
|
-
const name = typeof s.name === "string" ? s.name : "";
|
|
684
1000
|
const url = typeof s.url === "string" ? s.url : "";
|
|
685
|
-
if (!
|
|
686
|
-
const entry = {
|
|
687
|
-
if (typeof s.
|
|
1001
|
+
if (!url) continue;
|
|
1002
|
+
const entry = { url };
|
|
1003
|
+
if (typeof s.pin === "string" && s.pin.length > 0) entry.pin = s.pin;
|
|
688
1004
|
entries.push(entry);
|
|
689
1005
|
}
|
|
690
1006
|
if (entries.length > 0) config.sources = entries;
|
|
@@ -722,7 +1038,21 @@ function decodeSkaileYaml(text) {
|
|
|
722
1038
|
]
|
|
723
1039
|
};
|
|
724
1040
|
}
|
|
725
|
-
|
|
1041
|
+
let result;
|
|
1042
|
+
try {
|
|
1043
|
+
result = normalizeConfigInternal(parsed);
|
|
1044
|
+
} catch (err) {
|
|
1045
|
+
return {
|
|
1046
|
+
config: {},
|
|
1047
|
+
diagnostics: [
|
|
1048
|
+
{
|
|
1049
|
+
code: "legacy_key_rejected",
|
|
1050
|
+
severity: "error",
|
|
1051
|
+
message: err instanceof Error ? err.message : String(err)
|
|
1052
|
+
}
|
|
1053
|
+
]
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
726
1056
|
validateConfigValues(result.config, result.diagnostics);
|
|
727
1057
|
return result;
|
|
728
1058
|
}
|
|
@@ -764,12 +1094,16 @@ function validateConfigValues(config, diagnostics) {
|
|
|
764
1094
|
var CANONICAL_KEY_ORDER = [
|
|
765
1095
|
"name",
|
|
766
1096
|
"description",
|
|
1097
|
+
"publisher",
|
|
1098
|
+
"version",
|
|
1099
|
+
"assets",
|
|
767
1100
|
"agent_config",
|
|
768
1101
|
"dependencies",
|
|
769
1102
|
"plugins",
|
|
770
1103
|
"sources",
|
|
1104
|
+
"stores",
|
|
1105
|
+
"overrides",
|
|
771
1106
|
"startup",
|
|
772
|
-
"ai_resources",
|
|
773
1107
|
"connectors",
|
|
774
1108
|
"mcp_servers",
|
|
775
1109
|
"deploy",
|
|
@@ -779,8 +1113,7 @@ var CANONICAL_KEY_ORDER = [
|
|
|
779
1113
|
"secrets",
|
|
780
1114
|
"telemetry",
|
|
781
1115
|
"compaction",
|
|
782
|
-
"patches"
|
|
783
|
-
"repositories"
|
|
1116
|
+
"patches"
|
|
784
1117
|
];
|
|
785
1118
|
var CONFIG_KEY_TO_YAML = {
|
|
786
1119
|
agent_config: "agent-config"
|
|
@@ -814,10 +1147,11 @@ function dedupe(arr) {
|
|
|
814
1147
|
return [...new Set(arr)];
|
|
815
1148
|
}
|
|
816
1149
|
function dedupeByKey(arr, key) {
|
|
1150
|
+
const keyOf = typeof key === "function" ? key : (item) => String(item[key] ?? "");
|
|
817
1151
|
const seen = /* @__PURE__ */ new Set();
|
|
818
1152
|
const result = [];
|
|
819
1153
|
for (let i = arr.length - 1; i >= 0; i--) {
|
|
820
|
-
const val =
|
|
1154
|
+
const val = keyOf(arr[i]);
|
|
821
1155
|
if (!seen.has(val)) {
|
|
822
1156
|
seen.add(val);
|
|
823
1157
|
result.unshift(arr[i]);
|
|
@@ -854,13 +1188,22 @@ function mcpDeclFromCatalogEntry(entry) {
|
|
|
854
1188
|
if (entry.description) decl.description = entry.description;
|
|
855
1189
|
if (m.recipe && typeof m.recipe === "object" && !Array.isArray(m.recipe)) {
|
|
856
1190
|
const r = m.recipe;
|
|
857
|
-
|
|
1191
|
+
const hasFlake = typeof r.flake === "string";
|
|
1192
|
+
const rawAttr = typeof r.attr === "string" ? r.attr : void 0;
|
|
1193
|
+
const effectiveAttr = rawAttr ?? (hasFlake ? DEFAULT_RECIPE_ATTR : void 0);
|
|
1194
|
+
if (effectiveAttr !== void 0) {
|
|
858
1195
|
try {
|
|
859
|
-
validateAssetRecipeAttr(
|
|
860
|
-
|
|
1196
|
+
validateAssetRecipeAttr(effectiveAttr);
|
|
1197
|
+
if (hasFlake) {
|
|
1198
|
+
validateAssetRecipeFlake(r.flake);
|
|
1199
|
+
decl.recipe = { attr: effectiveAttr, flake: r.flake };
|
|
1200
|
+
if (typeof r.publisher === "string") decl.recipe.publisher = r.publisher;
|
|
1201
|
+
} else {
|
|
1202
|
+
decl.recipe = { attr: effectiveAttr };
|
|
1203
|
+
}
|
|
861
1204
|
} catch (err) {
|
|
862
1205
|
console.warn(
|
|
863
|
-
`[workspace-config] mcpDeclFromCatalogEntry: invalid recipe
|
|
1206
|
+
`[workspace-config] mcpDeclFromCatalogEntry: invalid recipe for entry "${entry.name}": ${err instanceof Error ? err.message : String(err)}`
|
|
864
1207
|
);
|
|
865
1208
|
}
|
|
866
1209
|
}
|
|
@@ -932,33 +1275,49 @@ function loadMaterializedMcpDeclarations(projectDir) {
|
|
|
932
1275
|
}
|
|
933
1276
|
return result;
|
|
934
1277
|
}
|
|
1278
|
+
function sourceSlug(url) {
|
|
1279
|
+
return url.replace(/\.git$/, "").split(/[/:]/).pop() ?? "source";
|
|
1280
|
+
}
|
|
1281
|
+
function buildSourceClones(sources) {
|
|
1282
|
+
const home = process.env.SKAILE_HOME ?? join(homedir(), ".skaile");
|
|
1283
|
+
const sourcesDir = join(home, "sources");
|
|
1284
|
+
const clones = [];
|
|
1285
|
+
for (const s of sources) {
|
|
1286
|
+
const localPath = join(sourcesDir, sourceSlug(s.url));
|
|
1287
|
+
if (!existsSync(localPath)) continue;
|
|
1288
|
+
const commit = getRepoCommit(localPath) ?? "0".repeat(40);
|
|
1289
|
+
clones.push({ localPath, sourceUrl: s.url, commit, tag: s.pin });
|
|
1290
|
+
}
|
|
1291
|
+
return clones;
|
|
1292
|
+
}
|
|
1293
|
+
function catalogEntryFromCandidate(c) {
|
|
1294
|
+
const md = c.metadata ?? {};
|
|
1295
|
+
return {
|
|
1296
|
+
name: c.name,
|
|
1297
|
+
kind: c.kind,
|
|
1298
|
+
description: typeof md.description === "string" ? md.description : "",
|
|
1299
|
+
source: c.files[0]?.path ?? "",
|
|
1300
|
+
publisher: c.publisher,
|
|
1301
|
+
version: c.version,
|
|
1302
|
+
requires: [],
|
|
1303
|
+
dependencies: [],
|
|
1304
|
+
metadata: c.metadata
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
935
1307
|
function loadMcpServerDeclarations(projectDir) {
|
|
936
1308
|
const config = resolveSkWorkspaceConfig(projectDir);
|
|
937
1309
|
const explicit = config.mcp_servers ?? [];
|
|
938
1310
|
const materialized = loadMaterializedMcpDeclarations(projectDir);
|
|
939
1311
|
const mcpRefStrings = [];
|
|
940
1312
|
for (const dep of config.dependencies ?? []) {
|
|
941
|
-
|
|
942
|
-
if (ref.kind === "mcp-server") mcpRefStrings.push(dep);
|
|
943
|
-
}
|
|
944
|
-
for (const res of config.ai_resources ?? []) {
|
|
945
|
-
for (const dep of res.dependencies ?? []) {
|
|
1313
|
+
try {
|
|
946
1314
|
const ref = parseAssetRef(dep);
|
|
947
1315
|
if (ref.kind === "mcp-server") mcpRefStrings.push(dep);
|
|
1316
|
+
} catch {
|
|
948
1317
|
}
|
|
949
1318
|
}
|
|
950
|
-
const
|
|
951
|
-
const
|
|
952
|
-
for (const res of config.ai_resources ?? []) {
|
|
953
|
-
if (res.name && res.path && !(res.name in allRepos)) {
|
|
954
|
-
allRepos[res.name] = {
|
|
955
|
-
url: res.path.startsWith("/") ? void 0 : res.path,
|
|
956
|
-
path: res.path.startsWith("/") ? res.path : void 0,
|
|
957
|
-
branch: res.branch
|
|
958
|
-
};
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
const reposDir = getGlobalCacheDir();
|
|
1319
|
+
const sources = config.sources ?? [];
|
|
1320
|
+
const provenanceIndex = sources.length > 0 ? buildProvenanceIndex(buildSourceClones(sources)) : /* @__PURE__ */ new Map();
|
|
962
1321
|
const byId = /* @__PURE__ */ new Map();
|
|
963
1322
|
const order = [];
|
|
964
1323
|
const upsert = (decl) => {
|
|
@@ -972,12 +1331,29 @@ function loadMcpServerDeclarations(projectDir) {
|
|
|
972
1331
|
};
|
|
973
1332
|
const seen = /* @__PURE__ */ new Set();
|
|
974
1333
|
for (const refStr of mcpRefStrings) {
|
|
975
|
-
|
|
1334
|
+
let ref;
|
|
1335
|
+
try {
|
|
1336
|
+
ref = parseAssetRef(refStr);
|
|
1337
|
+
} catch {
|
|
1338
|
+
continue;
|
|
1339
|
+
}
|
|
976
1340
|
if (seen.has(ref.name)) continue;
|
|
977
1341
|
seen.add(ref.name);
|
|
978
|
-
|
|
979
|
-
if (
|
|
980
|
-
|
|
1342
|
+
let candidates;
|
|
1343
|
+
if (ref.publisher) {
|
|
1344
|
+
candidates = provenanceIndex.get(`${ref.publisher}/${ref.kind}:${ref.name}`);
|
|
1345
|
+
}
|
|
1346
|
+
if (!candidates) {
|
|
1347
|
+
for (const [key, arr] of provenanceIndex) {
|
|
1348
|
+
if (key.endsWith(`/${ref.kind}:${ref.name}`)) {
|
|
1349
|
+
candidates = arr;
|
|
1350
|
+
break;
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
const candidate = candidates?.[0];
|
|
1355
|
+
if (!candidate) continue;
|
|
1356
|
+
const catalogDecl = mcpDeclFromCatalogEntry(catalogEntryFromCandidate(candidate));
|
|
981
1357
|
if (!catalogDecl) continue;
|
|
982
1358
|
upsert(catalogDecl);
|
|
983
1359
|
}
|
|
@@ -1011,16 +1387,11 @@ function resolveAgentDir(projectDir) {
|
|
|
1011
1387
|
return join(aiAssetsDir, relPath);
|
|
1012
1388
|
}
|
|
1013
1389
|
if (definition.startsWith("agent:")) {
|
|
1014
|
-
|
|
1015
|
-
const repositories = config.repositories ?? {};
|
|
1016
|
-
const reposDir = getGlobalCacheDir();
|
|
1017
|
-
const entry = resolveAsset(ref, repositories, reposDir, { projectDir });
|
|
1018
|
-
if (!entry) return void 0;
|
|
1019
|
-
return dirname(entry.source);
|
|
1390
|
+
return void 0;
|
|
1020
1391
|
}
|
|
1021
1392
|
return resolve(projectDir, definition);
|
|
1022
1393
|
}
|
|
1023
1394
|
|
|
1024
|
-
export { COMPACTION_DEFAULTS, SKAILE_YAML_DEFAULT, SKAILE_YAML_SUFFIX, SK_WORKSPACE_DEFAULT_NAME, SK_WORKSPACE_SUFFIX, checkRepoStatus, checkoutPin, cloneRepo, decodeSkaileYaml, encodeSkaileYaml, ensureRepo, findWorkspaceRoot, getGlobalCacheDir, getRepoCommit, isWorkspaceConfigFilename, linkRepo, listSkWorkspaceConfigs, loadMcpServerDeclarations, loadSkWorkspaceConfig, mergeSkWorkspaceConfigs, normalizeConfig, pullRepo, readLinks, resolveAgentDir, resolveAll, resolveAsset, resolveSkWorkspaceConfig, saveSkWorkspaceConfig, scanRepo, unlinkRepo, validateAssetRecipeAttr, workspaceConfigFilename, workspaceNameFromFilename, writeLinks };
|
|
1025
|
-
//# sourceMappingURL=chunk-
|
|
1026
|
-
//# sourceMappingURL=chunk-
|
|
1395
|
+
export { COMPACTION_DEFAULTS, CanonicalRefConflictError, DEFAULT_RECIPE_ATTR, SKAILE_YAML_DEFAULT, SKAILE_YAML_SUFFIX, SK_WORKSPACE_DEFAULT_NAME, SK_WORKSPACE_SUFFIX, buildProvenanceIndex, checkRepoStatus, checkoutPin, cloneRepo, decodeSkaileYaml, encodeSkaileYaml, ensureRepo, findWorkspaceRoot, getGlobalCacheDir, getRepoCommit, isWorkspaceConfigFilename, linkRepo, listSkWorkspaceConfigs, loadMcpServerDeclarations, loadSkWorkspaceConfig, mergeSkWorkspaceConfigs, normalizeConfig, pullRepo, readLinks, resolveAgentDir, resolveAll, resolveAsset, resolveSkWorkspaceConfig, saveSkWorkspaceConfig, scanRepo, unlinkRepo, validateAssetRecipeAttr, validateAssetRecipeFlake, workspaceConfigFilename, workspaceNameFromFilename, writeLinks };
|
|
1396
|
+
//# sourceMappingURL=chunk-LDYPQVRU.js.map
|
|
1397
|
+
//# sourceMappingURL=chunk-LDYPQVRU.js.map
|