@skaile/workspaces 0.22.0-beta.0 → 0.22.0-beta.1
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 +136 -0
- package/dist/{asset-feeds-PJDJ3QYI.js → asset-feeds-QXCSAJRN.js} +9 -9
- package/dist/{asset-feeds-PJDJ3QYI.js.map → asset-feeds-QXCSAJRN.js.map} +1 -1
- 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.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-UZVHJ7LX.js → chunk-3ECS5PFD.js} +4 -4
- package/dist/{chunk-UZVHJ7LX.js.map → chunk-3ECS5PFD.js.map} +1 -1
- package/dist/{chunk-WIR34WMU.js → chunk-4AZKT2BU.js} +13 -13
- package/dist/chunk-4AZKT2BU.js.map +1 -0
- package/dist/{chunk-UZRY5UI2.js → chunk-6E6PKKAD.js} +68 -3
- package/dist/chunk-6E6PKKAD.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-GKM6MDUC.js → chunk-APAOQLPT.js} +3 -3
- package/dist/{chunk-GKM6MDUC.js.map → chunk-APAOQLPT.js.map} +1 -1
- package/dist/{chunk-SL6JVGRD.js → chunk-D7K72XEY.js} +3 -3
- package/dist/{chunk-SL6JVGRD.js.map → chunk-D7K72XEY.js.map} +1 -1
- package/dist/{chunk-CSDQBWE6.js → chunk-DKGDOALM.js} +5 -5
- package/dist/{chunk-CSDQBWE6.js.map → chunk-DKGDOALM.js.map} +1 -1
- package/dist/{chunk-TTY56FQQ.js → chunk-GFNW72LW.js} +17 -5
- package/dist/chunk-GFNW72LW.js.map +1 -0
- package/dist/{chunk-X5Y4EGZB.js → chunk-I3UEM3FX.js} +36 -8
- package/dist/chunk-I3UEM3FX.js.map +1 -0
- package/dist/{chunk-TKOLD2O7.js → chunk-J3VKAEQP.js} +497 -143
- package/dist/chunk-J3VKAEQP.js.map +1 -0
- package/dist/{chunk-KA46DUM4.js → chunk-JHF66MCK.js} +49 -3
- package/dist/chunk-JHF66MCK.js.map +1 -0
- package/dist/{chunk-G6GKWGOW.js → chunk-LT4DLEYE.js} +6 -6
- package/dist/chunk-LT4DLEYE.js.map +1 -0
- 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-J2FCO6TM.js → chunk-NJLHHZIW.js} +2 -2
- package/dist/{chunk-J2FCO6TM.js.map → chunk-NJLHHZIW.js.map} +1 -1
- package/dist/{chunk-MO4JPTRD.js → chunk-PTIHB2TV.js} +5 -5
- package/dist/{chunk-MO4JPTRD.js.map → chunk-PTIHB2TV.js.map} +1 -1
- package/dist/{chunk-RENHNO4J.js → chunk-UMOENHVH.js} +206 -137
- package/dist/chunk-UMOENHVH.js.map +1 -0
- package/dist/{chunk-NGC7ZQI4.js → chunk-V3QMSM5I.js} +38 -43
- package/dist/chunk-V3QMSM5I.js.map +1 -0
- package/dist/{chunk-2DNSSQ22.js → chunk-VCYXVP2S.js} +263 -177
- package/dist/chunk-VCYXVP2S.js.map +1 -0
- package/dist/{chunk-F3MGZ5E6.js → chunk-XIHFJVOD.js} +3 -3
- package/dist/{chunk-F3MGZ5E6.js.map → chunk-XIHFJVOD.js.map} +1 -1
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +102 -100
- 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 +1 -1
- package/dist/cli/src/commands/project.d.ts.map +1 -1
- package/dist/cli/src/commands/source.d.ts.map +1 -1
- package/dist/cli/src/commands/update.d.ts.map +1 -1
- package/dist/cli/src/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/models.d.ts +53 -47
- package/dist/core/src/models.d.ts.map +1 -1
- package/dist/core/src/repo-manager.d.ts +62 -34
- 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 +34 -15
- package/dist/deploy/index.js.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/podman.d.ts +1 -0
- package/dist/deploy/src/targets/podman.d.ts.map +1 -1
- 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-SL2S4UEX.js} +20 -16
- package/dist/ensure-sources-SL2S4UEX.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-M4DB3D3J.js +13 -0
- package/dist/{open-library-DWAQFUSQ.js.map → open-library-M4DB3D3J.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/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-AJ3FGXIC.js} +8 -8
- package/dist/{plugin-store-6OENKNFW.js.map → plugin-store-AJ3FGXIC.js.map} +1 -1
- package/dist/plugins/index.d.ts +2 -0
- package/dist/resolver/index.d.ts +2 -0
- package/dist/runner/index.d.ts +2 -0
- package/dist/runner/index.js +13 -13
- 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.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 +49 -16
- 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 +13 -13
- 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/server.d.ts +2 -0
- package/dist/sdk/transport/ws.d.ts +2 -0
- package/dist/sdk/transport.d.ts +2 -0
- 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-GBSQX7JF.js} +10 -10
- package/dist/{setup-ACMP3QZC.js.map → setup-GBSQX7JF.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-5WBRUC5U.js +14 -0
- package/dist/{store-client-ZSLNOOQG.js.map → store-client-5WBRUC5U.js.map} +1 -1
- package/dist/telemetry/index.d.ts +2 -0
- package/dist/transport/index.d.ts +2 -0
- package/dist/transport/ws/client.d.ts +2 -0
- package/dist/transport/ws/server.d.ts +2 -0
- package/dist/transport/ws.d.ts +2 -0
- package/dist/tui/index.d.ts +2 -0
- package/dist/tui/index.js +13 -13
- 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/chunk-2DNSSQ22.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-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-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-4AZKT2BU.js';
|
|
2
|
+
import { parseAssetRef } from './chunk-I3UEM3FX.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");
|
|
@@ -162,8 +165,8 @@ function scanRepo(repoDir, repoName) {
|
|
|
162
165
|
}
|
|
163
166
|
function resolveAsset(ref, repositories, reposDir, opts) {
|
|
164
167
|
let repoNames;
|
|
165
|
-
if (ref.
|
|
166
|
-
repoNames = [ref.
|
|
168
|
+
if (ref.publisher) {
|
|
169
|
+
repoNames = [ref.publisher];
|
|
167
170
|
} else if (opts?.preferRepo && opts.preferRepo in repositories) {
|
|
168
171
|
const rest = Object.keys(repositories).filter((n) => n !== opts.preferRepo);
|
|
169
172
|
repoNames = [opts.preferRepo, ...rest];
|
|
@@ -199,67 +202,149 @@ function resolveRepoDir(decl, name, reposDir, projectDir) {
|
|
|
199
202
|
if (existsSync(join(globalDest, ".git"))) return globalDest;
|
|
200
203
|
return null;
|
|
201
204
|
}
|
|
202
|
-
|
|
205
|
+
var CanonicalRefConflictError = class extends Error {
|
|
206
|
+
constructor(ref, candidates, depChain) {
|
|
207
|
+
super(
|
|
208
|
+
[
|
|
209
|
+
`error: divergent sha256 for ${ref}`,
|
|
210
|
+
"",
|
|
211
|
+
" pulled in via:",
|
|
212
|
+
...depChain.map((s, i) => ` ${" ".repeat(i * 2)}${s}`),
|
|
213
|
+
"",
|
|
214
|
+
" candidates:",
|
|
215
|
+
...candidates.map(
|
|
216
|
+
(c) => ` ${c.sourceUrl} @ ${c.commit.slice(0, 8)}
|
|
217
|
+
sha256: ${c.sha256}`
|
|
218
|
+
),
|
|
219
|
+
"",
|
|
220
|
+
"resolve by:",
|
|
221
|
+
" 1. removing one source from skaile.yaml,",
|
|
222
|
+
" 2. configuring a store and using its canonical digest, or",
|
|
223
|
+
" 3. adding to overrides: (with a non-empty reason:)"
|
|
224
|
+
].join("\n")
|
|
225
|
+
);
|
|
226
|
+
this.ref = ref;
|
|
227
|
+
this.candidates = candidates;
|
|
228
|
+
this.depChain = depChain;
|
|
229
|
+
this.name = "CanonicalRefConflictError";
|
|
230
|
+
}
|
|
231
|
+
ref;
|
|
232
|
+
candidates;
|
|
233
|
+
depChain;
|
|
234
|
+
};
|
|
235
|
+
var SHA_PIN_RE = /^[0-9a-f]{40}$/i;
|
|
236
|
+
async function resolveAll(deps, opts) {
|
|
203
237
|
const resolved = [];
|
|
204
238
|
const seen = /* @__PURE__ */ new Set();
|
|
205
239
|
const missing = [];
|
|
206
240
|
const resolvedBy = /* @__PURE__ */ new Map();
|
|
207
|
-
|
|
241
|
+
const overridesApplied = /* @__PURE__ */ new Set();
|
|
242
|
+
const overridesByRef = new Map(opts.overrides.map((o) => [o.ref, o]));
|
|
243
|
+
async function visit(refStr, parent, depChain) {
|
|
208
244
|
const ref = parseAssetRef(refStr);
|
|
209
|
-
|
|
245
|
+
if (!ref.publisher) throw new Error(`dep "${refStr}" missing publisher`);
|
|
246
|
+
const key = `${ref.publisher}/${ref.kind}:${ref.name}`;
|
|
210
247
|
if (seen.has(key)) return;
|
|
211
248
|
seen.add(key);
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
249
|
+
const sourceCandidates = opts.provenanceIndex.get(key) ?? [];
|
|
250
|
+
const storeCandidates = [];
|
|
251
|
+
if (opts.stores.length > 0 && opts.storeFetcher) {
|
|
252
|
+
const candidateVersions = enumerateVersionsForPin(
|
|
253
|
+
ref.pin,
|
|
254
|
+
sourceCandidates.map((c) => c.version)
|
|
255
|
+
);
|
|
256
|
+
for (const store of opts.stores) {
|
|
257
|
+
for (const v of candidateVersions) {
|
|
258
|
+
if (!v) continue;
|
|
259
|
+
const m = await opts.storeFetcher.getInstallManifest(
|
|
260
|
+
store.url,
|
|
261
|
+
`${ref.publisher}/${ref.kind}:${ref.name}@${v}`
|
|
262
|
+
);
|
|
263
|
+
if (m) {
|
|
264
|
+
storeCandidates.push({
|
|
265
|
+
publisher: ref.publisher,
|
|
266
|
+
kind: ref.kind,
|
|
267
|
+
name: ref.name,
|
|
268
|
+
version: v,
|
|
269
|
+
sourceUrl: m.sourceUrl,
|
|
270
|
+
commit: m.commit,
|
|
271
|
+
files: m.files,
|
|
272
|
+
sha256: m.sha256
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const all = [...sourceCandidates, ...storeCandidates];
|
|
279
|
+
if (all.length === 0) {
|
|
218
280
|
missing.push(refStr);
|
|
219
281
|
return;
|
|
220
282
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
283
|
+
const filtered = all.filter((c) => matchPin(ref.pin, c.version));
|
|
284
|
+
if (filtered.length === 0) {
|
|
285
|
+
missing.push(refStr);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const versions = Array.from(new Set(filtered.map((c) => c.version)));
|
|
289
|
+
const best = versions.sort((a, b) => semver.rcompare(coerceVersion(a), coerceVersion(b)))[0];
|
|
290
|
+
const finalists = filtered.filter((c) => c.version === best);
|
|
291
|
+
const canonicalRef = `${ref.publisher}/${ref.kind}:${ref.name}@${best}`;
|
|
292
|
+
const uniqueShas = Array.from(new Set(finalists.map((c) => c.sha256)));
|
|
293
|
+
let chosen;
|
|
294
|
+
if (uniqueShas.length > 1) {
|
|
295
|
+
const override = overridesByRef.get(canonicalRef);
|
|
296
|
+
if (!override) {
|
|
297
|
+
throw new CanonicalRefConflictError(canonicalRef, finalists, [...depChain, refStr]);
|
|
298
|
+
}
|
|
299
|
+
const pick = finalists.find((c) => c.sourceUrl === override.source);
|
|
300
|
+
if (!pick) {
|
|
301
|
+
throw new Error(
|
|
302
|
+
`override for ${canonicalRef} points at ${override.source}, which is not among the resolved candidates`
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
chosen = pick;
|
|
306
|
+
overridesApplied.add(canonicalRef);
|
|
307
|
+
} else {
|
|
308
|
+
chosen = [...finalists].sort((a, b) => a.sourceUrl.localeCompare(b.sourceUrl))[0];
|
|
225
309
|
}
|
|
226
|
-
|
|
227
|
-
|
|
310
|
+
if (opts.storeFetcher && opts.stores.length > 0 && sourceCandidates.some((c) => c.version === best) && storeCandidates.some((c) => c.version === best)) {
|
|
311
|
+
for (const store of opts.stores) {
|
|
312
|
+
const d = await opts.storeFetcher.getCanonicalDigest(store.url, canonicalRef);
|
|
313
|
+
if (d && d.sha256 !== chosen.sha256) {
|
|
314
|
+
throw new CanonicalRefConflictError(
|
|
315
|
+
canonicalRef,
|
|
316
|
+
[...finalists, { ...chosen, sourceUrl: store.url, sha256: d.sha256 }],
|
|
317
|
+
[...depChain, refStr]
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
228
321
|
}
|
|
229
|
-
resolved.push(
|
|
322
|
+
resolved.push(chosen);
|
|
323
|
+
resolvedBy.set(key, parent);
|
|
230
324
|
}
|
|
231
325
|
for (const dep of deps) {
|
|
232
|
-
visit(dep, "direct");
|
|
326
|
+
await visit(dep, "direct", []);
|
|
233
327
|
}
|
|
234
|
-
|
|
235
|
-
return { resolved, missing, resolvedBy, collisions };
|
|
328
|
+
return { resolved, missing, resolvedBy, overridesApplied };
|
|
236
329
|
}
|
|
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
|
-
}
|
|
330
|
+
function coerceVersion(v) {
|
|
331
|
+
return semver.valid(v) ? v : semver.coerce(v)?.version ?? "0.0.0";
|
|
332
|
+
}
|
|
333
|
+
function matchPin(pin, version) {
|
|
334
|
+
if (!pin) return true;
|
|
335
|
+
if (SHA_PIN_RE.test(pin)) {
|
|
336
|
+
return version === `0.0.0-sha.${pin.slice(0, 7)}`;
|
|
261
337
|
}
|
|
262
|
-
|
|
338
|
+
if (version.startsWith("0.0.0-sha.")) {
|
|
339
|
+
return version === pin;
|
|
340
|
+
}
|
|
341
|
+
if (!semver.valid(version)) return version === pin;
|
|
342
|
+
return semver.satisfies(version, pin, { includePrerelease: false });
|
|
343
|
+
}
|
|
344
|
+
function enumerateVersionsForPin(pin, sourceVersionsHint) {
|
|
345
|
+
if (!pin) return sourceVersionsHint.length > 0 ? sourceVersionsHint : [];
|
|
346
|
+
if (semver.valid(pin)) return [pin];
|
|
347
|
+
return sourceVersionsHint;
|
|
263
348
|
}
|
|
264
349
|
function checkRepoStatus(decl, name, reposDir, projectDir) {
|
|
265
350
|
if (projectDir) {
|
|
@@ -320,8 +405,185 @@ function checkRepoStatus(decl, name, reposDir, projectDir) {
|
|
|
320
405
|
base.upToDate = base.behind === 0;
|
|
321
406
|
return base;
|
|
322
407
|
}
|
|
408
|
+
function fileSha256(p) {
|
|
409
|
+
return createHash("sha256").update(readFileSync(p)).digest("hex");
|
|
410
|
+
}
|
|
411
|
+
function compositeSha256(files) {
|
|
412
|
+
const lines = files.slice().sort((a, b) => a.path.localeCompare(b.path)).map((f) => `${f.path}:${f.sha256}
|
|
413
|
+
`).join("");
|
|
414
|
+
return createHash("sha256").update(lines).digest("hex");
|
|
415
|
+
}
|
|
416
|
+
function publisherFromGithubUrl(url) {
|
|
417
|
+
const m = url.match(/github\.com[/:]([^/]+)\/[^/]+/);
|
|
418
|
+
return m?.[1];
|
|
419
|
+
}
|
|
420
|
+
function syntheticVersion(commit) {
|
|
421
|
+
return `0.0.0-sha.${commit.slice(0, 7)}`;
|
|
422
|
+
}
|
|
423
|
+
var KIND_DIRS = [
|
|
424
|
+
{ dir: "skills", kind: "skill", mdName: "SKILL.md" },
|
|
425
|
+
{ dir: "agents", kind: "agent", mdName: "AGENT.md" },
|
|
426
|
+
{ dir: "bundles", kind: "bundle", mdName: "BUNDLE.md" },
|
|
427
|
+
{ dir: "mcp-servers", kind: "mcp-server", mdName: "MCP.md" },
|
|
428
|
+
{ dir: "connectors", kind: "connector", mdName: "CONNECTOR.md" },
|
|
429
|
+
{ dir: "prompts", kind: "prompt", mdName: "PROMPT.md" },
|
|
430
|
+
{ dir: "contracts", kind: "contract", mdName: "CONTRACT.md" }
|
|
431
|
+
];
|
|
432
|
+
var MD_FILE_BY_KIND = Object.fromEntries(
|
|
433
|
+
KIND_DIRS.map((k) => [k.kind, k.mdName])
|
|
434
|
+
);
|
|
435
|
+
function buildProvenanceIndex(clones, _opts) {
|
|
436
|
+
const index = /* @__PURE__ */ new Map();
|
|
437
|
+
for (const clone of clones) walkOne(clone, index);
|
|
438
|
+
return index;
|
|
439
|
+
}
|
|
440
|
+
function walkOne(clone, index) {
|
|
441
|
+
const yamlPath = join(clone.localPath, "skaile.yaml");
|
|
442
|
+
if (existsSync(yamlPath)) {
|
|
443
|
+
walkWithManifest(clone, yamlPath, index);
|
|
444
|
+
} else {
|
|
445
|
+
walkFilenameConvention(clone, index);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
function walkWithManifest(clone, yamlPath, index) {
|
|
449
|
+
const raw = parse(readFileSync(yamlPath, "utf8")) ?? {};
|
|
450
|
+
const publisher = typeof raw.publisher === "string" && raw.publisher.length > 0 ? raw.publisher : publisherFromGithubUrl(clone.sourceUrl);
|
|
451
|
+
if (!publisher) {
|
|
452
|
+
throw new Error(
|
|
453
|
+
`${clone.sourceUrl}: publisher must be declared in skaile.yaml (non-GitHub source URL \u2014 auto-derivation not available).`
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
const sourceVersion = (typeof raw.version === "string" ? raw.version : void 0) ?? (clone.tag ? clone.tag.replace(/^v/, "") : void 0) ?? syntheticVersion(clone.commit);
|
|
457
|
+
const assets = Array.isArray(raw.assets) ? raw.assets : [];
|
|
458
|
+
if (assets.length === 0) {
|
|
459
|
+
walkFilenameConvention(clone, index, publisher, sourceVersion);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
for (const a of assets) {
|
|
463
|
+
const assetPublisher = a.publisher ?? publisher;
|
|
464
|
+
const version = a.version ?? sourceVersion;
|
|
465
|
+
const files = expandAssetFiles(clone.localPath, a);
|
|
466
|
+
verifyNameMatch(clone.localPath, files, a.name, a.kind);
|
|
467
|
+
const metadata = readMetadata(clone.localPath, files, a.kind);
|
|
468
|
+
const candidate = {
|
|
469
|
+
publisher: assetPublisher,
|
|
470
|
+
kind: a.kind,
|
|
471
|
+
name: a.name,
|
|
472
|
+
version,
|
|
473
|
+
sourceUrl: clone.sourceUrl,
|
|
474
|
+
commit: clone.commit,
|
|
475
|
+
files,
|
|
476
|
+
sha256: compositeSha256(files),
|
|
477
|
+
metadata
|
|
478
|
+
};
|
|
479
|
+
push(index, `${assetPublisher}/${a.kind}:${a.name}`, candidate);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
function expandAssetFiles(repoRoot, a) {
|
|
483
|
+
const out = [];
|
|
484
|
+
if (a.root) {
|
|
485
|
+
walkDirRecursive(join(repoRoot, a.root), repoRoot, out);
|
|
486
|
+
}
|
|
487
|
+
if (a.files) {
|
|
488
|
+
const matches = fg.sync(a.files, { cwd: repoRoot, onlyFiles: true, dot: false });
|
|
489
|
+
for (const rel of matches) {
|
|
490
|
+
out.push({ path: rel, sha256: fileSha256(join(repoRoot, rel)) });
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
const seen = /* @__PURE__ */ new Set();
|
|
494
|
+
return out.filter((f) => seen.has(f.path) ? false : (seen.add(f.path), true));
|
|
495
|
+
}
|
|
496
|
+
function walkDirRecursive(abs, root, out) {
|
|
497
|
+
if (!existsSync(abs)) return;
|
|
498
|
+
for (const entry of readdirSync(abs, { withFileTypes: true })) {
|
|
499
|
+
if (entry.name === ".git" || entry.name === "node_modules") continue;
|
|
500
|
+
const childAbs = join(abs, entry.name);
|
|
501
|
+
if (entry.isDirectory()) {
|
|
502
|
+
walkDirRecursive(childAbs, root, out);
|
|
503
|
+
} else if (entry.isFile()) {
|
|
504
|
+
out.push({ path: relative(root, childAbs), sha256: fileSha256(childAbs) });
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
function walkFilenameConvention(clone, index, publisherOverride, versionOverride) {
|
|
509
|
+
const publisher = publisherOverride ?? publisherFromGithubUrl(clone.sourceUrl);
|
|
510
|
+
if (!publisher) {
|
|
511
|
+
throw new Error(
|
|
512
|
+
`${clone.sourceUrl}: publisher must be declared in skaile.yaml (non-GitHub source URL).`
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
const version = versionOverride ?? (clone.tag ? clone.tag.replace(/^v/, "") : void 0) ?? syntheticVersion(clone.commit);
|
|
516
|
+
for (const { dir, kind, mdName } of KIND_DIRS) {
|
|
517
|
+
const base = join(clone.localPath, dir);
|
|
518
|
+
if (!existsSync(base) || !statSync(base).isDirectory()) continue;
|
|
519
|
+
for (const entry of readdirSync(base, { withFileTypes: true })) {
|
|
520
|
+
if (!entry.isDirectory()) continue;
|
|
521
|
+
const assetDir = join(base, entry.name);
|
|
522
|
+
if (!existsSync(join(assetDir, mdName))) continue;
|
|
523
|
+
const files = [];
|
|
524
|
+
walkDirRecursive(assetDir, clone.localPath, files);
|
|
525
|
+
const metadata = readMetadata(clone.localPath, files, kind);
|
|
526
|
+
const candidate = {
|
|
527
|
+
publisher,
|
|
528
|
+
kind,
|
|
529
|
+
name: entry.name,
|
|
530
|
+
version,
|
|
531
|
+
sourceUrl: clone.sourceUrl,
|
|
532
|
+
commit: clone.commit,
|
|
533
|
+
files,
|
|
534
|
+
sha256: compositeSha256(files),
|
|
535
|
+
metadata
|
|
536
|
+
};
|
|
537
|
+
push(index, `${publisher}/${kind}:${entry.name}`, candidate);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
function verifyNameMatch(repoRoot, files, expectedName, kind) {
|
|
542
|
+
const mdName = MD_FILE_BY_KIND[kind];
|
|
543
|
+
if (!mdName) return;
|
|
544
|
+
const md = files.find((f) => f.path.endsWith(mdName));
|
|
545
|
+
if (!md) return;
|
|
546
|
+
const { data } = parseFrontmatter(readFileSync(join(repoRoot, md.path), "utf8"));
|
|
547
|
+
const declared = typeof data.name === "string" ? data.name : void 0;
|
|
548
|
+
if (declared && declared !== expectedName) {
|
|
549
|
+
throw new Error(
|
|
550
|
+
`name mismatch: ${mdName} says "${declared}", skaile.yaml says "${expectedName}" \u2014 index-time hard error.`
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
function readMetadata(repoRoot, files, kind) {
|
|
555
|
+
if (kind !== "mcp-server") return void 0;
|
|
556
|
+
const mcpMd = files.find((f) => f.path.endsWith("MCP.md"));
|
|
557
|
+
if (!mcpMd) return void 0;
|
|
558
|
+
const { data } = parseFrontmatter(readFileSync(join(repoRoot, mcpMd.path), "utf8"));
|
|
559
|
+
return data;
|
|
560
|
+
}
|
|
561
|
+
function push(index, key, candidate) {
|
|
562
|
+
const arr = index.get(key) ?? [];
|
|
563
|
+
arr.push(candidate);
|
|
564
|
+
index.set(key, arr);
|
|
565
|
+
}
|
|
323
566
|
|
|
324
567
|
// core/src/workspace-config.ts
|
|
568
|
+
var DEFAULT_RECIPE_ATTR = "default";
|
|
569
|
+
function validateAssetRecipeFlake(flake) {
|
|
570
|
+
if (typeof flake !== "string" || flake.length === 0) {
|
|
571
|
+
throw new Error("AssetRecipe.flake must be a non-empty string");
|
|
572
|
+
}
|
|
573
|
+
if (flake.length > 500) {
|
|
574
|
+
throw new Error(`AssetRecipe.flake too long (${flake.length} chars, max 500)`);
|
|
575
|
+
}
|
|
576
|
+
if (flake === ".") return;
|
|
577
|
+
const ALLOWED_SCHEME = /^(github:|git\+https:\/\/|git\+ssh:\/\/|path:\/)/;
|
|
578
|
+
if (!ALLOWED_SCHEME.test(flake)) {
|
|
579
|
+
throw new Error(
|
|
580
|
+
`AssetRecipe.flake "${flake}" has an unsupported source. Allowed: "." or a flake URL (github:, git+https://, git+ssh://, path:/).`
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
if (/[\s`$;|&<>(){}#\n\r]/.test(flake)) {
|
|
584
|
+
throw new Error(`AssetRecipe.flake "${flake}" contains forbidden characters.`);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
325
587
|
function validateAssetRecipeAttr(attr) {
|
|
326
588
|
if (typeof attr !== "string" || attr.length === 0) {
|
|
327
589
|
throw new Error("AssetRecipe.attr must be a non-empty string");
|
|
@@ -401,13 +663,20 @@ function listSkWorkspaceConfigs(dir) {
|
|
|
401
663
|
function resolveSkWorkspaceConfig(projectDir, opts) {
|
|
402
664
|
const name = opts?.name ?? SK_WORKSPACE_DEFAULT_NAME;
|
|
403
665
|
const configs = [];
|
|
666
|
+
const assertNoLegacyKey = (file) => {
|
|
667
|
+
const d = file?.diagnostics?.find((x) => x.code === "legacy_key_rejected");
|
|
668
|
+
if (d) throw new Error(d.message);
|
|
669
|
+
};
|
|
404
670
|
const userConfig = loadSkWorkspaceConfig(join(homedir(), ".skaile"), name);
|
|
671
|
+
assertNoLegacyKey(userConfig);
|
|
405
672
|
if (userConfig) configs.push(userConfig.config);
|
|
406
673
|
if (opts?.appDir) {
|
|
407
674
|
const appConfig = loadSkWorkspaceConfig(opts.appDir, name);
|
|
675
|
+
assertNoLegacyKey(appConfig);
|
|
408
676
|
if (appConfig) configs.push(appConfig.config);
|
|
409
677
|
}
|
|
410
678
|
const projectConfig = loadSkWorkspaceConfig(projectDir, name);
|
|
679
|
+
assertNoLegacyKey(projectConfig);
|
|
411
680
|
if (projectConfig) configs.push(projectConfig.config);
|
|
412
681
|
if (configs.length > 0) return configs.reduce(mergeSkWorkspaceConfigs);
|
|
413
682
|
return {};
|
|
@@ -443,10 +712,12 @@ function mergeSkWorkspaceConfigs(base, overlay) {
|
|
|
443
712
|
},
|
|
444
713
|
// startup: overlay wins (project-level only)
|
|
445
714
|
startup: overlay.startup ?? base.startup,
|
|
446
|
-
//
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
715
|
+
// publication half — scalars: overlay wins when defined; assets: by kind+name
|
|
716
|
+
publisher: overlay.publisher ?? base.publisher,
|
|
717
|
+
version: overlay.version ?? base.version,
|
|
718
|
+
assets: dedupeByKey(
|
|
719
|
+
[...base.assets ?? [], ...overlay.assets ?? []],
|
|
720
|
+
(a) => `${a.kind}:${a.name}`
|
|
450
721
|
),
|
|
451
722
|
// mounts: by id — overlay wins
|
|
452
723
|
mounts: mergeById(base.mounts ?? [], overlay.mounts ?? []),
|
|
@@ -511,14 +782,14 @@ function mergeSkWorkspaceConfigs(base, overlay) {
|
|
|
511
782
|
secrets: overlay.secrets ?? base.secrets,
|
|
512
783
|
// telemetry: overlay wins entirely (raw pass-through)
|
|
513
784
|
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
785
|
// dependencies: concatenate and dedupe
|
|
519
786
|
dependencies: dedupe([...base.dependencies ?? [], ...overlay.dependencies ?? []]),
|
|
520
|
-
// sources: dedupe by
|
|
521
|
-
sources: dedupeByKey([...base.sources ?? [], ...overlay.sources ?? []], "
|
|
787
|
+
// sources: dedupe by url — overlay entry wins for the same url
|
|
788
|
+
sources: dedupeByKey([...base.sources ?? [], ...overlay.sources ?? []], "url"),
|
|
789
|
+
// stores: dedupe by url — overlay wins
|
|
790
|
+
stores: dedupeByKey([...base.stores ?? [], ...overlay.stores ?? []], "url"),
|
|
791
|
+
// overrides: dedupe by ref — overlay wins
|
|
792
|
+
overrides: dedupeByKey([...base.overrides ?? [], ...overlay.overrides ?? []], "ref"),
|
|
522
793
|
// plugins: concatenate + dedupe (like dependencies)
|
|
523
794
|
plugins: dedupe([...base.plugins ?? [], ...overlay.plugins ?? []]),
|
|
524
795
|
// deploy: overlay wins entirely (scalar-like selection)
|
|
@@ -600,46 +871,75 @@ function normalizeConfigInternal(raw) {
|
|
|
600
871
|
if (Array.isArray(raw.startup)) {
|
|
601
872
|
config.startup = raw.startup;
|
|
602
873
|
}
|
|
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
|
-
});
|
|
874
|
+
if (raw.repositories !== void 0) {
|
|
875
|
+
throw new Error(
|
|
876
|
+
"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."
|
|
877
|
+
);
|
|
619
878
|
}
|
|
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
|
-
|
|
879
|
+
if (raw.ai_resources !== void 0 || raw.aiResources !== void 0) {
|
|
880
|
+
throw new Error(
|
|
881
|
+
"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."
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
if (typeof raw.publisher === "string" && raw.publisher.length > 0) {
|
|
885
|
+
config.publisher = raw.publisher;
|
|
886
|
+
}
|
|
887
|
+
if (typeof raw.version === "string" && raw.version.length > 0) {
|
|
888
|
+
config.version = raw.version;
|
|
889
|
+
}
|
|
890
|
+
if (Array.isArray(raw.assets)) {
|
|
891
|
+
const entries = [];
|
|
892
|
+
for (const item of raw.assets) {
|
|
893
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
894
|
+
const a = item;
|
|
895
|
+
const kind = typeof a.kind === "string" ? a.kind : "";
|
|
896
|
+
const name = typeof a.name === "string" ? a.name : "";
|
|
897
|
+
if (!kind || !name) continue;
|
|
898
|
+
const entry = { kind, name };
|
|
899
|
+
if (typeof a.root === "string") entry.root = a.root;
|
|
900
|
+
if (Array.isArray(a.files)) {
|
|
901
|
+
entry.files = a.files.filter(
|
|
902
|
+
(f) => typeof f === "string"
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
if (typeof a.version === "string") entry.version = a.version;
|
|
906
|
+
if (typeof a.publisher === "string") entry.publisher = a.publisher;
|
|
907
|
+
entries.push(entry);
|
|
908
|
+
}
|
|
909
|
+
if (entries.length > 0) config.assets = entries;
|
|
910
|
+
}
|
|
911
|
+
if (Array.isArray(raw.stores)) {
|
|
912
|
+
const entries = [];
|
|
913
|
+
for (const item of raw.stores) {
|
|
914
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
915
|
+
const s = item;
|
|
916
|
+
const url = typeof s.url === "string" ? s.url : "";
|
|
917
|
+
if (!url) continue;
|
|
918
|
+
entries.push({ url });
|
|
919
|
+
}
|
|
920
|
+
if (entries.length > 0) config.stores = entries;
|
|
921
|
+
}
|
|
922
|
+
if (Array.isArray(raw.overrides)) {
|
|
923
|
+
const entries = [];
|
|
924
|
+
for (const item of raw.overrides) {
|
|
925
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
926
|
+
const o = item;
|
|
927
|
+
const ref = typeof o.ref === "string" ? o.ref : "";
|
|
928
|
+
const source = typeof o.source === "string" ? o.source : "";
|
|
929
|
+
if (!ref || !source) continue;
|
|
930
|
+
if (typeof o.reason !== "string") {
|
|
931
|
+
throw new Error(
|
|
932
|
+
`skaile.yaml: overrides[] entry for ${ref}: reason is required and must be a non-empty string.`
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
if (o.reason.trim().length === 0) {
|
|
936
|
+
throw new Error(
|
|
937
|
+
`skaile.yaml: overrides[] entry for ${ref}: reason must not be empty.`
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
entries.push({ ref, source, reason: o.reason });
|
|
941
|
+
}
|
|
942
|
+
if (entries.length > 0) config.overrides = entries;
|
|
643
943
|
}
|
|
644
944
|
if (Array.isArray(raw.mounts)) {
|
|
645
945
|
config.mounts = raw.mounts;
|
|
@@ -678,13 +978,12 @@ function normalizeConfigInternal(raw) {
|
|
|
678
978
|
if (Array.isArray(raw.sources)) {
|
|
679
979
|
const entries = [];
|
|
680
980
|
for (const item of raw.sources) {
|
|
681
|
-
if (!item || typeof item !== "object") continue;
|
|
981
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
682
982
|
const s = item;
|
|
683
|
-
const name = typeof s.name === "string" ? s.name : "";
|
|
684
983
|
const url = typeof s.url === "string" ? s.url : "";
|
|
685
|
-
if (!
|
|
686
|
-
const entry = {
|
|
687
|
-
if (typeof s.
|
|
984
|
+
if (!url) continue;
|
|
985
|
+
const entry = { url };
|
|
986
|
+
if (typeof s.pin === "string" && s.pin.length > 0) entry.pin = s.pin;
|
|
688
987
|
entries.push(entry);
|
|
689
988
|
}
|
|
690
989
|
if (entries.length > 0) config.sources = entries;
|
|
@@ -722,7 +1021,21 @@ function decodeSkaileYaml(text) {
|
|
|
722
1021
|
]
|
|
723
1022
|
};
|
|
724
1023
|
}
|
|
725
|
-
|
|
1024
|
+
let result;
|
|
1025
|
+
try {
|
|
1026
|
+
result = normalizeConfigInternal(parsed);
|
|
1027
|
+
} catch (err) {
|
|
1028
|
+
return {
|
|
1029
|
+
config: {},
|
|
1030
|
+
diagnostics: [
|
|
1031
|
+
{
|
|
1032
|
+
code: "legacy_key_rejected",
|
|
1033
|
+
severity: "error",
|
|
1034
|
+
message: err instanceof Error ? err.message : String(err)
|
|
1035
|
+
}
|
|
1036
|
+
]
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
726
1039
|
validateConfigValues(result.config, result.diagnostics);
|
|
727
1040
|
return result;
|
|
728
1041
|
}
|
|
@@ -764,12 +1077,16 @@ function validateConfigValues(config, diagnostics) {
|
|
|
764
1077
|
var CANONICAL_KEY_ORDER = [
|
|
765
1078
|
"name",
|
|
766
1079
|
"description",
|
|
1080
|
+
"publisher",
|
|
1081
|
+
"version",
|
|
1082
|
+
"assets",
|
|
767
1083
|
"agent_config",
|
|
768
1084
|
"dependencies",
|
|
769
1085
|
"plugins",
|
|
770
1086
|
"sources",
|
|
1087
|
+
"stores",
|
|
1088
|
+
"overrides",
|
|
771
1089
|
"startup",
|
|
772
|
-
"ai_resources",
|
|
773
1090
|
"connectors",
|
|
774
1091
|
"mcp_servers",
|
|
775
1092
|
"deploy",
|
|
@@ -779,8 +1096,7 @@ var CANONICAL_KEY_ORDER = [
|
|
|
779
1096
|
"secrets",
|
|
780
1097
|
"telemetry",
|
|
781
1098
|
"compaction",
|
|
782
|
-
"patches"
|
|
783
|
-
"repositories"
|
|
1099
|
+
"patches"
|
|
784
1100
|
];
|
|
785
1101
|
var CONFIG_KEY_TO_YAML = {
|
|
786
1102
|
agent_config: "agent-config"
|
|
@@ -814,10 +1130,11 @@ function dedupe(arr) {
|
|
|
814
1130
|
return [...new Set(arr)];
|
|
815
1131
|
}
|
|
816
1132
|
function dedupeByKey(arr, key) {
|
|
1133
|
+
const keyOf = typeof key === "function" ? key : (item) => String(item[key] ?? "");
|
|
817
1134
|
const seen = /* @__PURE__ */ new Set();
|
|
818
1135
|
const result = [];
|
|
819
1136
|
for (let i = arr.length - 1; i >= 0; i--) {
|
|
820
|
-
const val =
|
|
1137
|
+
const val = keyOf(arr[i]);
|
|
821
1138
|
if (!seen.has(val)) {
|
|
822
1139
|
seen.add(val);
|
|
823
1140
|
result.unshift(arr[i]);
|
|
@@ -854,13 +1171,22 @@ function mcpDeclFromCatalogEntry(entry) {
|
|
|
854
1171
|
if (entry.description) decl.description = entry.description;
|
|
855
1172
|
if (m.recipe && typeof m.recipe === "object" && !Array.isArray(m.recipe)) {
|
|
856
1173
|
const r = m.recipe;
|
|
857
|
-
|
|
1174
|
+
const hasFlake = typeof r.flake === "string";
|
|
1175
|
+
const rawAttr = typeof r.attr === "string" ? r.attr : void 0;
|
|
1176
|
+
const effectiveAttr = rawAttr ?? (hasFlake ? DEFAULT_RECIPE_ATTR : void 0);
|
|
1177
|
+
if (effectiveAttr !== void 0) {
|
|
858
1178
|
try {
|
|
859
|
-
validateAssetRecipeAttr(
|
|
860
|
-
|
|
1179
|
+
validateAssetRecipeAttr(effectiveAttr);
|
|
1180
|
+
if (hasFlake) {
|
|
1181
|
+
validateAssetRecipeFlake(r.flake);
|
|
1182
|
+
decl.recipe = { attr: effectiveAttr, flake: r.flake };
|
|
1183
|
+
if (typeof r.publisher === "string") decl.recipe.publisher = r.publisher;
|
|
1184
|
+
} else {
|
|
1185
|
+
decl.recipe = { attr: effectiveAttr };
|
|
1186
|
+
}
|
|
861
1187
|
} catch (err) {
|
|
862
1188
|
console.warn(
|
|
863
|
-
`[workspace-config] mcpDeclFromCatalogEntry: invalid recipe
|
|
1189
|
+
`[workspace-config] mcpDeclFromCatalogEntry: invalid recipe for entry "${entry.name}": ${err instanceof Error ? err.message : String(err)}`
|
|
864
1190
|
);
|
|
865
1191
|
}
|
|
866
1192
|
}
|
|
@@ -932,33 +1258,49 @@ function loadMaterializedMcpDeclarations(projectDir) {
|
|
|
932
1258
|
}
|
|
933
1259
|
return result;
|
|
934
1260
|
}
|
|
1261
|
+
function sourceSlug(url) {
|
|
1262
|
+
return url.replace(/\.git$/, "").split(/[/:]/).pop() ?? "source";
|
|
1263
|
+
}
|
|
1264
|
+
function buildSourceClones(sources) {
|
|
1265
|
+
const home = process.env.SKAILE_HOME ?? join(homedir(), ".skaile");
|
|
1266
|
+
const sourcesDir = join(home, "sources");
|
|
1267
|
+
const clones = [];
|
|
1268
|
+
for (const s of sources) {
|
|
1269
|
+
const localPath = join(sourcesDir, sourceSlug(s.url));
|
|
1270
|
+
if (!existsSync(localPath)) continue;
|
|
1271
|
+
const commit = getRepoCommit(localPath) ?? "0".repeat(40);
|
|
1272
|
+
clones.push({ localPath, sourceUrl: s.url, commit, tag: s.pin });
|
|
1273
|
+
}
|
|
1274
|
+
return clones;
|
|
1275
|
+
}
|
|
1276
|
+
function catalogEntryFromCandidate(c) {
|
|
1277
|
+
const md = c.metadata ?? {};
|
|
1278
|
+
return {
|
|
1279
|
+
name: c.name,
|
|
1280
|
+
kind: c.kind,
|
|
1281
|
+
description: typeof md.description === "string" ? md.description : "",
|
|
1282
|
+
source: c.files[0]?.path ?? "",
|
|
1283
|
+
publisher: c.publisher,
|
|
1284
|
+
version: c.version,
|
|
1285
|
+
requires: [],
|
|
1286
|
+
dependencies: [],
|
|
1287
|
+
metadata: c.metadata
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
935
1290
|
function loadMcpServerDeclarations(projectDir) {
|
|
936
1291
|
const config = resolveSkWorkspaceConfig(projectDir);
|
|
937
1292
|
const explicit = config.mcp_servers ?? [];
|
|
938
1293
|
const materialized = loadMaterializedMcpDeclarations(projectDir);
|
|
939
1294
|
const mcpRefStrings = [];
|
|
940
1295
|
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 ?? []) {
|
|
1296
|
+
try {
|
|
946
1297
|
const ref = parseAssetRef(dep);
|
|
947
1298
|
if (ref.kind === "mcp-server") mcpRefStrings.push(dep);
|
|
1299
|
+
} catch {
|
|
948
1300
|
}
|
|
949
1301
|
}
|
|
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();
|
|
1302
|
+
const sources = config.sources ?? [];
|
|
1303
|
+
const provenanceIndex = sources.length > 0 ? buildProvenanceIndex(buildSourceClones(sources)) : /* @__PURE__ */ new Map();
|
|
962
1304
|
const byId = /* @__PURE__ */ new Map();
|
|
963
1305
|
const order = [];
|
|
964
1306
|
const upsert = (decl) => {
|
|
@@ -972,12 +1314,29 @@ function loadMcpServerDeclarations(projectDir) {
|
|
|
972
1314
|
};
|
|
973
1315
|
const seen = /* @__PURE__ */ new Set();
|
|
974
1316
|
for (const refStr of mcpRefStrings) {
|
|
975
|
-
|
|
1317
|
+
let ref;
|
|
1318
|
+
try {
|
|
1319
|
+
ref = parseAssetRef(refStr);
|
|
1320
|
+
} catch {
|
|
1321
|
+
continue;
|
|
1322
|
+
}
|
|
976
1323
|
if (seen.has(ref.name)) continue;
|
|
977
1324
|
seen.add(ref.name);
|
|
978
|
-
|
|
979
|
-
if (
|
|
980
|
-
|
|
1325
|
+
let candidates;
|
|
1326
|
+
if (ref.publisher) {
|
|
1327
|
+
candidates = provenanceIndex.get(`${ref.publisher}/${ref.kind}:${ref.name}`);
|
|
1328
|
+
}
|
|
1329
|
+
if (!candidates) {
|
|
1330
|
+
for (const [key, arr] of provenanceIndex) {
|
|
1331
|
+
if (key.endsWith(`/${ref.kind}:${ref.name}`)) {
|
|
1332
|
+
candidates = arr;
|
|
1333
|
+
break;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
const candidate = candidates?.[0];
|
|
1338
|
+
if (!candidate) continue;
|
|
1339
|
+
const catalogDecl = mcpDeclFromCatalogEntry(catalogEntryFromCandidate(candidate));
|
|
981
1340
|
if (!catalogDecl) continue;
|
|
982
1341
|
upsert(catalogDecl);
|
|
983
1342
|
}
|
|
@@ -1011,16 +1370,11 @@ function resolveAgentDir(projectDir) {
|
|
|
1011
1370
|
return join(aiAssetsDir, relPath);
|
|
1012
1371
|
}
|
|
1013
1372
|
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);
|
|
1373
|
+
return void 0;
|
|
1020
1374
|
}
|
|
1021
1375
|
return resolve(projectDir, definition);
|
|
1022
1376
|
}
|
|
1023
1377
|
|
|
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-
|
|
1378
|
+
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 };
|
|
1379
|
+
//# sourceMappingURL=chunk-J3VKAEQP.js.map
|
|
1380
|
+
//# sourceMappingURL=chunk-J3VKAEQP.js.map
|