@skaile/workspaces 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +128 -0
- package/README.md +1 -1
- package/dist/app-sdk/index.d.ts +2 -0
- package/dist/app-sdk/index.js +295 -0
- package/dist/app-sdk/index.js.map +1 -0
- package/dist/app-sdk/src/app.d.ts +101 -0
- package/dist/app-sdk/src/app.d.ts.map +1 -0
- package/dist/app-sdk/src/define-app-capability.d.ts +139 -0
- package/dist/app-sdk/src/define-app-capability.d.ts.map +1 -0
- package/dist/app-sdk/src/index.d.ts +16 -0
- package/dist/app-sdk/src/index.d.ts.map +1 -0
- package/dist/app-sdk/src/logger.d.ts +26 -0
- package/dist/app-sdk/src/logger.d.ts.map +1 -0
- package/dist/app-sdk/src/transport.d.ts +84 -0
- package/dist/app-sdk/src/transport.d.ts.map +1 -0
- package/dist/app-sdk/src/ws-transport.d.ts +63 -0
- package/dist/app-sdk/src/ws-transport.d.ts.map +1 -0
- package/dist/{asset-feeds-OBPWVUDL.js → asset-feeds-NG5TKB3V.js} +10 -10
- package/dist/{asset-feeds-OBPWVUDL.js.map → asset-feeds-NG5TKB3V.js.map} +1 -1
- package/dist/asset-manager/index.js +9 -9
- package/dist/asset-manager/installer.js +8 -8
- package/dist/asset-manager/renderers.js +2 -2
- package/dist/asset-manager/src/index.d.ts +42 -6
- package/dist/asset-manager/src/index.d.ts.map +1 -1
- package/dist/bridge/drivers/claude-sdk.js +41 -6
- package/dist/bridge/drivers/claude-sdk.js.map +1 -1
- package/dist/bridge/drivers/codex.js +1 -1
- package/dist/bridge/drivers/continue.js +2 -2
- package/dist/bridge/drivers/echo.js +1 -1
- package/dist/bridge/drivers/gemini.js +3 -3
- package/dist/bridge/drivers/goose.js +2 -2
- package/dist/bridge/drivers/omp.js +1 -1
- package/dist/bridge/drivers/opencode.js +2 -2
- package/dist/bridge/drivers/qwen.js +3 -3
- package/dist/bridge/index.js +4 -3
- package/dist/bridge/src/cloud.d.ts +89 -0
- package/dist/bridge/src/cloud.d.ts.map +1 -0
- package/dist/bridge/src/drivers/claude-sdk.d.ts +12 -1
- package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
- package/dist/bridge/src/index.d.ts +1 -0
- package/dist/bridge/src/index.d.ts.map +1 -1
- package/dist/bridge/src/types.d.ts +31 -0
- package/dist/bridge/src/types.d.ts.map +1 -1
- package/dist/{chunk-MG6UIS7G.js → chunk-26YCXWCU.js} +52 -3
- package/dist/chunk-26YCXWCU.js.map +1 -0
- package/dist/{chunk-SKADPHAM.js → chunk-4N5XR5DQ.js} +2 -2
- package/dist/chunk-4N5XR5DQ.js.map +1 -0
- package/dist/{chunk-CLUJLV7Z.js → chunk-77OXU44H.js} +6 -6
- package/dist/{chunk-CLUJLV7Z.js.map → chunk-77OXU44H.js.map} +1 -1
- package/dist/{chunk-TTTLCSEQ.js → chunk-AAGD2J4H.js} +121 -41
- package/dist/chunk-AAGD2J4H.js.map +1 -0
- package/dist/{chunk-KVZ6XKVN.js → chunk-B6SSXVF2.js} +4 -4
- package/dist/chunk-B6SSXVF2.js.map +1 -0
- package/dist/{chunk-BCJL2UNH.js → chunk-BDUANIAR.js} +3 -3
- package/dist/{chunk-BCJL2UNH.js.map → chunk-BDUANIAR.js.map} +1 -1
- package/dist/{chunk-YI5OZ7QO.js → chunk-BE5KTS2L.js} +3 -3
- package/dist/{chunk-YI5OZ7QO.js.map → chunk-BE5KTS2L.js.map} +1 -1
- package/dist/{chunk-ZUE2PIJ5.js → chunk-BJHZHNKR.js} +3 -3
- package/dist/{chunk-ZUE2PIJ5.js.map → chunk-BJHZHNKR.js.map} +1 -1
- package/dist/{chunk-MQEZE6TU.js → chunk-DNFIKRO6.js} +3 -3
- package/dist/{chunk-MQEZE6TU.js.map → chunk-DNFIKRO6.js.map} +1 -1
- package/dist/{chunk-VCBLXF7D.js → chunk-GWDZW44L.js} +5 -5
- package/dist/{chunk-VCBLXF7D.js.map → chunk-GWDZW44L.js.map} +1 -1
- package/dist/{chunk-UY5Q2NZH.js → chunk-HKX5VSWQ.js} +3 -3
- package/dist/{chunk-UY5Q2NZH.js.map → chunk-HKX5VSWQ.js.map} +1 -1
- package/dist/{chunk-NUS5L5ZJ.js → chunk-HWTQ6HPO.js} +5 -5
- package/dist/{chunk-NUS5L5ZJ.js.map → chunk-HWTQ6HPO.js.map} +1 -1
- package/dist/{chunk-WRBF34YE.js → chunk-IEX5YV4R.js} +3 -3
- package/dist/{chunk-WRBF34YE.js.map → chunk-IEX5YV4R.js.map} +1 -1
- package/dist/{chunk-CU5Z7GH3.js → chunk-IRORTHGA.js} +20 -6
- package/dist/chunk-IRORTHGA.js.map +1 -0
- package/dist/chunk-ISQWMBKD.js +74 -0
- package/dist/chunk-ISQWMBKD.js.map +1 -0
- package/dist/{chunk-W65IK4MH.js → chunk-JZPEEMIM.js} +6 -6
- package/dist/{chunk-W65IK4MH.js.map → chunk-JZPEEMIM.js.map} +1 -1
- package/dist/{chunk-35TLBMHX.js → chunk-LCTRCWBK.js} +6 -6
- package/dist/{chunk-35TLBMHX.js.map → chunk-LCTRCWBK.js.map} +1 -1
- package/dist/{chunk-U5J77IIZ.js → chunk-NKTFEV7Q.js} +4 -4
- package/dist/{chunk-U5J77IIZ.js.map → chunk-NKTFEV7Q.js.map} +1 -1
- package/dist/{chunk-EPLYVB3L.js → chunk-OSCJRUKM.js} +2 -2
- package/dist/{chunk-EPLYVB3L.js.map → chunk-OSCJRUKM.js.map} +1 -1
- package/dist/{chunk-5AGARSQT.js → chunk-OUWNTFDG.js} +31 -3
- package/dist/chunk-OUWNTFDG.js.map +1 -0
- package/dist/{chunk-EVZKWY5J.js → chunk-PK7Q7MC7.js} +5 -4
- package/dist/chunk-PK7Q7MC7.js.map +1 -0
- package/dist/{chunk-XWLVIEWD.js → chunk-QM2TT2PJ.js} +20 -12
- package/dist/chunk-QM2TT2PJ.js.map +1 -0
- package/dist/{chunk-BM37QD6U.js → chunk-TJRWGMD2.js} +3 -3
- package/dist/{chunk-BM37QD6U.js.map → chunk-TJRWGMD2.js.map} +1 -1
- package/dist/{chunk-QVE3ILCY.js → chunk-TNSCHS4I.js} +2 -2
- package/dist/chunk-TNSCHS4I.js.map +1 -0
- package/dist/{chunk-Z5Z3MYDL.js → chunk-UPZGQZEJ.js} +3 -3
- package/dist/{chunk-Z5Z3MYDL.js.map → chunk-UPZGQZEJ.js.map} +1 -1
- package/dist/{chunk-52XHXSBN.js → chunk-UQ5FK2AB.js} +3 -3
- package/dist/{chunk-52XHXSBN.js.map → chunk-UQ5FK2AB.js.map} +1 -1
- package/dist/{chunk-KAWKKMU4.js → chunk-X57AMTAH.js} +74 -11
- package/dist/chunk-X57AMTAH.js.map +1 -0
- package/dist/{chunk-OIGYDVCM.js → chunk-XBG2YDQQ.js} +3 -3
- package/dist/{chunk-OIGYDVCM.js.map → chunk-XBG2YDQQ.js.map} +1 -1
- package/dist/cli/index.js +770 -188
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/preset-apply.d.ts +59 -0
- package/dist/cli/src/commands/preset-apply.d.ts.map +1 -0
- package/dist/cli/src/commands/preset-cmd.d.ts +2 -2
- package/dist/cli/src/commands/preset-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/preset-export.d.ts +93 -0
- package/dist/cli/src/commands/preset-export.d.ts.map +1 -0
- package/dist/cli/src/commands/source.d.ts.map +1 -1
- package/dist/cli/src/commands/why.d.ts +18 -0
- package/dist/cli/src/commands/why.d.ts.map +1 -1
- package/dist/connectors/config.js +5 -5
- package/dist/connectors/index.js +7 -7
- package/dist/core/index.js +4 -4
- package/dist/core/runtime-assets.js +2 -2
- package/dist/core/src/index.d.ts +2 -2
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/core/src/settings.d.ts +18 -0
- package/dist/core/src/settings.d.ts.map +1 -1
- package/dist/core/src/workspace-config.d.ts +45 -0
- package/dist/core/src/workspace-config.d.ts.map +1 -1
- package/dist/core/src/workspace-yaml-editor.d.ts +14 -1
- package/dist/core/src/workspace-yaml-editor.d.ts.map +1 -1
- package/dist/core/workspace-config.js +1 -1
- package/dist/deploy/index.js +4 -4
- package/dist/discovery/index.js +2 -2
- package/dist/{ensure-sources-BQI2TOZZ.js → ensure-sources-CHC7X7AJ.js} +12 -12
- package/dist/{ensure-sources-BQI2TOZZ.js.map → ensure-sources-CHC7X7AJ.js.map} +1 -1
- package/dist/factory-assets/connectors/box.js +7 -7
- package/dist/factory-assets/connectors/deploy.js +7 -7
- package/dist/factory-assets/connectors/devserver.js +7 -7
- package/dist/factory-assets/connectors/flow/adapter.js +7 -7
- package/dist/factory-assets/connectors/flow/engine/engine.d.ts +4 -1
- package/dist/factory-assets/connectors/flow/engine/engine.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/engine/types.d.ts +41 -6
- package/dist/factory-assets/connectors/flow/engine/types.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/engine.js +5 -5
- package/dist/factory-assets/connectors/flow/run-flow.js +8 -8
- package/dist/factory-assets/connectors/flow.js +7 -7
- package/dist/factory-assets/connectors/git.js +7 -7
- package/dist/factory-assets/connectors/gmail.js +7 -7
- package/dist/factory-assets/connectors/googledrive.js +7 -7
- package/dist/factory-assets/connectors/local.js +7 -7
- package/dist/factory-assets/connectors/mattermost.js +7 -7
- package/dist/factory-assets/connectors/memory.js +7 -7
- package/dist/factory-assets/connectors/minio.js +7 -7
- package/dist/factory-assets/connectors/postgres.js +7 -7
- package/dist/factory-assets/connectors/s3.js +7 -7
- package/dist/factory-assets/connectors/sharepoint.js +7 -7
- package/dist/factory-assets/connectors/sqlite.js +7 -7
- package/dist/factory-assets/connectors/static-server.js +7 -7
- package/dist/factory-assets/connectors/tunnel.js +7 -7
- package/dist/factory-assets/connectors/webdav.js +7 -7
- package/dist/factory-assets/connectors/xstate-store.js +7 -7
- package/dist/factory-assets/connectors/xstate.js +7 -7
- package/dist/factory-assets/skills/skaile-author-asset/SKILL.md +1 -1
- package/dist/factory-assets/skills/skaile-manage-workspace/SKILL.md +1 -1
- package/dist/{flows-4Z74KY2H.js → flows-CGOCUNO6.js} +4 -4
- package/dist/{flows-4Z74KY2H.js.map → flows-CGOCUNO6.js.map} +1 -1
- package/dist/{helpers-SC4PWN2F.js → helpers-GWG4CYYC.js} +12 -12
- package/dist/{helpers-SC4PWN2F.js.map → helpers-GWG4CYYC.js.map} +1 -1
- package/dist/library/index.js +8 -8
- package/dist/library/install.js +4 -4
- package/dist/{open-library-ZNYIND7N.js → open-library-37PXN6MK.js} +17 -17
- package/dist/{open-library-ZNYIND7N.js.map → open-library-37PXN6MK.js.map} +1 -1
- package/dist/{paths-S7QNXYMB.js → paths-UVOHWUPY.js} +7 -7
- package/dist/{paths-S7QNXYMB.js.map → paths-UVOHWUPY.js.map} +1 -1
- package/dist/{plugin-store-3DAVGKHN.js → plugin-store-EIMVEH3O.js} +6 -6
- package/dist/{plugin-store-3DAVGKHN.js.map → plugin-store-EIMVEH3O.js.map} +1 -1
- package/dist/runner/index.js +14 -13
- package/dist/runner/src/capability-registry.d.ts +15 -4
- package/dist/runner/src/capability-registry.d.ts.map +1 -1
- package/dist/runner/src/cloud-bundle.d.ts +36 -0
- package/dist/runner/src/cloud-bundle.d.ts.map +1 -0
- package/dist/runner/src/serve.d.ts.map +1 -1
- package/dist/runner/src/session-builder.d.ts +32 -0
- package/dist/runner/src/session-builder.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +9 -9
- package/dist/sdk/bridge.js +4 -3
- package/dist/sdk/core.js +4 -4
- package/dist/sdk/flow.js +5 -5
- package/dist/sdk/index.js +14 -13
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/runner.js +14 -13
- package/dist/sdk/session.js +2 -2
- package/dist/sdk/types.js +1 -1
- package/dist/session/index.js +2 -2
- package/dist/{setup-WBGDT2WY.js → setup-DINVR6ZQ.js} +10 -9
- package/dist/setup-DINVR6ZQ.js.map +1 -0
- package/dist/{source-SBFVULTG.js → source-RXAHIGMD.js} +18 -18
- package/dist/{source-SBFVULTG.js.map → source-RXAHIGMD.js.map} +1 -1
- package/dist/{store-client-YGDN4L2G.js → store-client-T3F663YG.js} +7 -7
- package/dist/{store-client-YGDN4L2G.js.map → store-client-T3F663YG.js.map} +1 -1
- package/dist/tui/index.js +14 -13
- package/dist/tui/index.js.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/manifests.js +1 -1
- package/dist/types/src/capabilities.d.ts +8 -2
- package/dist/types/src/capabilities.d.ts.map +1 -1
- package/dist/types/src/logging.d.ts +3 -2
- package/dist/types/src/logging.d.ts.map +1 -1
- package/dist/types/src/manifests/_shared.d.ts +4 -4
- package/dist/types/src/manifests/agent.d.ts +47 -8
- package/dist/types/src/manifests/agent.d.ts.map +1 -1
- package/dist/types/src/manifests/index.d.ts +3 -3
- package/dist/types/src/manifests/index.d.ts.map +1 -1
- package/dist/types/src/manifests/preset.d.ts +10 -0
- package/dist/types/src/manifests/preset.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +11 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/dist/workspace-plugin/adapters/mcp.js +2 -2
- package/dist/workspace-plugin/adapters/omp.js +3 -3
- package/dist/workspace-plugin/index.js +1 -1
- package/package.json +7 -1
- package/dist/chunk-5AGARSQT.js.map +0 -1
- package/dist/chunk-CU5Z7GH3.js.map +0 -1
- package/dist/chunk-EVZKWY5J.js.map +0 -1
- package/dist/chunk-KAWKKMU4.js.map +0 -1
- package/dist/chunk-KVZ6XKVN.js.map +0 -1
- package/dist/chunk-MG6UIS7G.js.map +0 -1
- package/dist/chunk-QVE3ILCY.js.map +0 -1
- package/dist/chunk-SKADPHAM.js.map +0 -1
- package/dist/chunk-TTTLCSEQ.js.map +0 -1
- package/dist/chunk-XWLVIEWD.js.map +0 -1
- package/dist/setup-WBGDT2WY.js.map +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { AI_RESOURCES, aiResourceRoots } from '../chunk-XBG2YDQQ.js';
|
|
3
|
+
import { makeSourceCommand, syncProjectSources } from '../chunk-QM2TT2PJ.js';
|
|
4
|
+
import { openCatalogSource, openLibraryManager, createFullRegistry, openLibrary } from '../chunk-77OXU44H.js';
|
|
5
|
+
import { logErr, S, logOk, logInfo, colorRef, logWarn, kindColorPad, kindColor, formatSoftDepSection, bareSoftDepName, formatSoftDepHint, formatRelativeTime, fitWidth, formatSoftDepRemovePreview, formatSoftDepAddPreview } from '../chunk-DNFIKRO6.js';
|
|
6
|
+
import { getStoreConfig, storeFetch, saveStoreTokens, clearStoreTokens, isStoreAuthenticated } from '../chunk-BJHZHNKR.js';
|
|
7
7
|
import { LocalSecretsProvider } from '../chunk-6BEGKO2Q.js';
|
|
8
|
-
import { resolveLibraryDir } from '../chunk-
|
|
9
|
-
import '../chunk-
|
|
8
|
+
import { resolveLibraryDir, getDefaultValue, isSecretPlaceholder } from '../chunk-HWTQ6HPO.js';
|
|
9
|
+
import '../chunk-B6SSXVF2.js';
|
|
10
|
+
import '../chunk-JXT46QFC.js';
|
|
10
11
|
import '../chunk-UKJMQZV6.js';
|
|
11
12
|
import '../chunk-R7FOF242.js';
|
|
12
|
-
import '../chunk-
|
|
13
|
-
import { runFlow, resumeFlow } from '../chunk-W65IK4MH.js';
|
|
13
|
+
import { runFlow, resumeFlow } from '../chunk-JZPEEMIM.js';
|
|
14
14
|
import '../chunk-4R6DROGN.js';
|
|
15
15
|
import { validateFlowVersions, parseSkillFrontmatter } from '../chunk-GXC3TYMQ.js';
|
|
16
|
-
import { runAgentChat, loadSessionById, loadSession, listSessions, setCurrentSession, deleteSession, clearSession, loadAgentManifest, compileComposition, MarkdownStreamer, resolveMixin } from '../chunk-
|
|
17
|
-
import { buildClaudePluginFiles } from '../chunk-
|
|
16
|
+
import { runAgentChat, loadSessionById, loadSession, listSessions, setCurrentSession, deleteSession, clearSession, loadAgentManifest, compileComposition, MarkdownStreamer, resolveMixin } from '../chunk-AAGD2J4H.js';
|
|
17
|
+
import { buildClaudePluginFiles } from '../chunk-OSCJRUKM.js';
|
|
18
18
|
import '../chunk-X5YPJV4N.js';
|
|
19
19
|
import '../chunk-O7SG5PC2.js';
|
|
20
20
|
import '../chunk-7QBNJTTQ.js';
|
|
@@ -22,37 +22,38 @@ import '../chunk-GTS2FODO.js';
|
|
|
22
22
|
import '../chunk-WQ7DE5UC.js';
|
|
23
23
|
import '../chunk-32NA4TVC.js';
|
|
24
24
|
import '../chunk-W3UDISS2.js';
|
|
25
|
-
import '../chunk-
|
|
26
|
-
import '../chunk-
|
|
25
|
+
import '../chunk-HKX5VSWQ.js';
|
|
26
|
+
import '../chunk-ISQWMBKD.js';
|
|
27
|
+
import '../chunk-RRVQAE5D.js';
|
|
27
28
|
import '../chunk-BMQKMOQY.js';
|
|
28
29
|
import '../chunk-GAH4YRCI.js';
|
|
29
|
-
import '../chunk-
|
|
30
|
-
import '../chunk-QVE3ILCY.js';
|
|
30
|
+
import '../chunk-TNSCHS4I.js';
|
|
31
31
|
import '../chunk-LV2HPH3C.js';
|
|
32
|
-
import '../chunk-
|
|
33
|
-
import '../chunk-
|
|
32
|
+
import '../chunk-GWDZW44L.js';
|
|
33
|
+
import '../chunk-BDUANIAR.js';
|
|
34
34
|
import '../chunk-6E6PKKAD.js';
|
|
35
|
-
import { loadFlow, loadAllFlows } from '../chunk-
|
|
35
|
+
import { loadFlow, loadAllFlows } from '../chunk-4N5XR5DQ.js';
|
|
36
36
|
import '../chunk-DEYYRFQU.js';
|
|
37
37
|
import '../chunk-IFGTRL2I.js';
|
|
38
|
-
import
|
|
39
|
-
import '../chunk-
|
|
40
|
-
import
|
|
41
|
-
import '../chunk-
|
|
42
|
-
import {
|
|
38
|
+
import '../chunk-PK7Q7MC7.js';
|
|
39
|
+
import { AssetManager, NON_DEPLOYABLE_KINDS, MissingManifestError, normalizeRepoUrl, FACTORY_SOURCE_URL } from '../chunk-X57AMTAH.js';
|
|
40
|
+
import '../chunk-LCTRCWBK.js';
|
|
41
|
+
import '../chunk-CGYEHQOX.js';
|
|
42
|
+
import { readLock, resolveSettings, globalSettingsPath, projectSettingsPath, loadSettings, saveSettings, portableSpawn, portableSpawnSync, WorkspaceYamlEditor, checkAgentSkillConformance } from '../chunk-26YCXWCU.js';
|
|
43
|
+
import { assetSearchDirs, detectDomains } from '../chunk-ZAP2BDHG.js';
|
|
44
|
+
import '../chunk-TJRWGMD2.js';
|
|
45
|
+
import { globalCacheRoot, sourceCacheKey, getGlobalCacheDir, resolveAgentDir, loadSkWorkspaceConfig, resolveSkWorkspaceConfig } from '../chunk-OUWNTFDG.js';
|
|
43
46
|
import { SKAILE_MANIFEST_FILENAME, decodeSkaileManifest, loadSkPublishManifest, saveSkPublishManifest } from '../chunk-DZCK7GRW.js';
|
|
44
47
|
import { parseFrontmatter } from '../chunk-BQCGFPHW.js';
|
|
45
48
|
import { parseAssetRef, ASSET_KINDS, isValidAssetName, slugifyAssetName, ASSET_NAME_HINT, assetRefToStr } from '../chunk-GEEW6SY2.js';
|
|
46
49
|
import '../chunk-F3HNW354.js';
|
|
47
50
|
import { SUPPORTED_DRIVER_TARGETS } from '../chunk-MENCWIHW.js';
|
|
48
51
|
import { DRIVER_DEFAULTS } from '../chunk-K5GBV4SA.js';
|
|
49
|
-
import { assetSearchDirs, detectDomains } from '../chunk-ZAP2BDHG.js';
|
|
50
52
|
import { openSqlite } from '../chunk-JB35MVBN.js';
|
|
51
53
|
import '../chunk-KTBKW2FI.js';
|
|
52
54
|
import '../chunk-UQ6LFBPZ.js';
|
|
53
|
-
import '../chunk-
|
|
54
|
-
import '../chunk-
|
|
55
|
-
import '../chunk-CGYEHQOX.js';
|
|
55
|
+
import '../chunk-IEX5YV4R.js';
|
|
56
|
+
import { validatePreset } from '../chunk-IRORTHGA.js';
|
|
56
57
|
import '../chunk-NSBPE2FW.js';
|
|
57
58
|
import * as fs12 from 'fs';
|
|
58
59
|
import fs12__default, { readFileSync, existsSync, mkdirSync, writeFileSync, lstatSync, rmSync, readdirSync, statSync } from 'fs';
|
|
@@ -70,6 +71,7 @@ import { createInterface } from 'readline';
|
|
|
70
71
|
import fs6 from 'fs/promises';
|
|
71
72
|
import { parse as parse$1, stringify as stringify$1 } from 'smol-toml';
|
|
72
73
|
import { execSync } from 'child_process';
|
|
74
|
+
import * as readline2 from 'readline/promises';
|
|
73
75
|
import { createTRPCUntypedClient, httpLink, httpSubscriptionLink } from '@trpc/client';
|
|
74
76
|
|
|
75
77
|
async function runSearch(kind, query, opts) {
|
|
@@ -92,7 +94,7 @@ async function searchLocal(query, kind, opts, showStore, airGapped) {
|
|
|
92
94
|
const projectDir = path14__default.resolve(opts.projectDir);
|
|
93
95
|
let entries = new AssetManager({ projectDir }).search(query, kind);
|
|
94
96
|
if (entries.length === 0 && !query && !kind && !airGapped) {
|
|
95
|
-
const { autoSyncForSearch } = await import('../source-
|
|
97
|
+
const { autoSyncForSearch } = await import('../source-RXAHIGMD.js');
|
|
96
98
|
if (await autoSyncForSearch(projectDir)) {
|
|
97
99
|
entries = new AssetManager({ projectDir }).search(query, kind);
|
|
98
100
|
}
|
|
@@ -145,7 +147,7 @@ async function searchStore(query, kind, opts, airGapped) {
|
|
|
145
147
|
return;
|
|
146
148
|
}
|
|
147
149
|
try {
|
|
148
|
-
const { getStoreConfig: getStoreConfig2, storeFetch: storeFetch2 } = await import('../store-client-
|
|
150
|
+
const { getStoreConfig: getStoreConfig2, storeFetch: storeFetch2 } = await import('../store-client-T3F663YG.js');
|
|
149
151
|
const config = getStoreConfig2();
|
|
150
152
|
const params = {};
|
|
151
153
|
if (query) params.q = query;
|
|
@@ -1005,7 +1007,7 @@ function makeCatalogCommand() {
|
|
|
1005
1007
|
return catalog;
|
|
1006
1008
|
}
|
|
1007
1009
|
async function runLocalCatalogTest(projectDir) {
|
|
1008
|
-
const { resolveCatalogSource } = await import('../open-library-
|
|
1010
|
+
const { resolveCatalogSource } = await import('../open-library-37PXN6MK.js');
|
|
1009
1011
|
let resolved;
|
|
1010
1012
|
try {
|
|
1011
1013
|
resolved = await resolveCatalogSource({ projectDir });
|
|
@@ -1995,7 +1997,7 @@ async function ensureTargetsRegistered(projectDir) {
|
|
|
1995
1997
|
const { resolveSkWorkspaceConfig: resolveSkWorkspaceConfig2 } = await import('../core/index.js');
|
|
1996
1998
|
const config = resolveSkWorkspaceConfig2(projectDir);
|
|
1997
1999
|
if (config.plugins && config.plugins.length > 0) {
|
|
1998
|
-
const { ensurePluginsLoaded } = await import('../plugin-store-
|
|
2000
|
+
const { ensurePluginsLoaded } = await import('../plugin-store-EIMVEH3O.js');
|
|
1999
2001
|
const result = await ensurePluginsLoaded(projectDir, config.plugins, pluginRegistry);
|
|
2000
2002
|
for (const f of result.failed) logWarn(f.error);
|
|
2001
2003
|
}
|
|
@@ -3711,7 +3713,7 @@ async function previewSoftDepsUnderCursor() {
|
|
|
3711
3713
|
}
|
|
3712
3714
|
async function loadAssets() {
|
|
3713
3715
|
softDepPreviewCache.clear();
|
|
3714
|
-
const { gatherAssetFeeds } = await import('../asset-feeds-
|
|
3716
|
+
const { gatherAssetFeeds } = await import('../asset-feeds-NG5TKB3V.js');
|
|
3715
3717
|
const { entries, domains, notes } = await gatherAssetFeeds(am, am.projectDir);
|
|
3716
3718
|
if (notes.length > 0) {
|
|
3717
3719
|
state.message = notes.map((n) => `[${n.feed}] ${n.message}`).join(" \u2022 ");
|
|
@@ -3878,7 +3880,7 @@ function reconcileCollapsedSets(rows) {
|
|
|
3878
3880
|
async function loadSourcesAndLibraries() {
|
|
3879
3881
|
try {
|
|
3880
3882
|
const [{ openLibraryManager: openLibraryManager2 }, { skaileHomeDir }, { getGlobalCacheDir: getGlobalCacheDir2 }] = await Promise.all([
|
|
3881
|
-
import('../open-library-
|
|
3883
|
+
import('../open-library-37PXN6MK.js'),
|
|
3882
3884
|
import('../library/index.js'),
|
|
3883
3885
|
import('../core/index.js')
|
|
3884
3886
|
]);
|
|
@@ -4964,7 +4966,7 @@ function action2(fn) {
|
|
|
4964
4966
|
};
|
|
4965
4967
|
}
|
|
4966
4968
|
async function reconcileAndReport(projectDir, plugins) {
|
|
4967
|
-
const { reconcilePlugins } = await import('../plugin-store-
|
|
4969
|
+
const { reconcilePlugins } = await import('../plugin-store-EIMVEH3O.js');
|
|
4968
4970
|
if (plugins.length === 0) {
|
|
4969
4971
|
logInfo("No plugins declared \u2014 nothing to reconcile.");
|
|
4970
4972
|
return;
|
|
@@ -4980,7 +4982,7 @@ async function reconcileAndReport(projectDir, plugins) {
|
|
|
4980
4982
|
async function runInstall2(spec, opts) {
|
|
4981
4983
|
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4982
4984
|
const { WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
|
|
4983
|
-
const { specName } = await import('../plugin-store-
|
|
4985
|
+
const { specName } = await import('../plugin-store-EIMVEH3O.js');
|
|
4984
4986
|
const yamlPath = path14__default.join(projectDir, "skaile.yaml");
|
|
4985
4987
|
const editor = WorkspaceYamlEditor2.load(yamlPath);
|
|
4986
4988
|
const replaced = editor.addPlugin(spec, specName);
|
|
@@ -4992,7 +4994,7 @@ async function runInstall2(spec, opts) {
|
|
|
4992
4994
|
async function runRemove(name, opts) {
|
|
4993
4995
|
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4994
4996
|
const { WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
|
|
4995
|
-
const { specName } = await import('../plugin-store-
|
|
4997
|
+
const { specName } = await import('../plugin-store-EIMVEH3O.js');
|
|
4996
4998
|
const yamlPath = path14__default.join(projectDir, "skaile.yaml");
|
|
4997
4999
|
const editor = WorkspaceYamlEditor2.load(yamlPath);
|
|
4998
5000
|
const removed = editor.removePlugin(name, specName);
|
|
@@ -5020,7 +5022,7 @@ async function runList(opts) {
|
|
|
5020
5022
|
const registry = createPluginRegistry();
|
|
5021
5023
|
if (declared.length > 0) {
|
|
5022
5024
|
try {
|
|
5023
|
-
const { loadPlugins } = await import('../plugin-store-
|
|
5025
|
+
const { loadPlugins } = await import('../plugin-store-EIMVEH3O.js');
|
|
5024
5026
|
const result = await loadPlugins(projectDir, declared, registry);
|
|
5025
5027
|
for (const f of result.failed) logWarn(f.error);
|
|
5026
5028
|
} catch (err) {
|
|
@@ -5054,150 +5056,93 @@ function makePluginCommand() {
|
|
|
5054
5056
|
cmd.action(() => cmd.help());
|
|
5055
5057
|
return cmd;
|
|
5056
5058
|
}
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
async function loadPresetForValidation(resolved) {
|
|
5081
|
-
if (!existsSync(resolved)) {
|
|
5082
|
-
logErr(`File not found: ${resolved}`);
|
|
5083
|
-
process.exit(1);
|
|
5084
|
-
}
|
|
5085
|
-
const content = readFileSync(resolved, "utf-8");
|
|
5086
|
-
const { parsePresetYaml } = await import('../library/index.js');
|
|
5087
|
-
const parseResult = parsePresetYaml(content);
|
|
5088
|
-
if (!parseResult.ok) {
|
|
5089
|
-
logErr("Preset validation failed (parse errors):");
|
|
5090
|
-
for (const err of parseResult.errors) {
|
|
5091
|
-
console.log(` ${S.err("\u2717")} ${err}`);
|
|
5092
|
-
}
|
|
5093
|
-
process.exit(1);
|
|
5094
|
-
}
|
|
5095
|
-
if (!parseResult.preset) {
|
|
5096
|
-
logErr("Preset validation failed: parser returned no manifest");
|
|
5097
|
-
process.exit(1);
|
|
5098
|
-
}
|
|
5099
|
-
return parseResult.preset;
|
|
5100
|
-
}
|
|
5101
|
-
async function reportNestedPresetRefs(preset) {
|
|
5102
|
-
const { detectNestedPresetRefs } = await import('../library/index.js');
|
|
5103
|
-
const nestedRefs = detectNestedPresetRefs(preset);
|
|
5104
|
-
if (nestedRefs.length > 0) {
|
|
5105
|
-
logInfo(`Nested preset refs: ${nestedRefs.length} (depth validated at apply-time)`);
|
|
5106
|
-
}
|
|
5107
|
-
}
|
|
5108
|
-
async function checkPresetCycles(preset, resolved) {
|
|
5109
|
-
const { detectCycles } = await import('../discovery/index.js');
|
|
5110
|
-
const presetRef = path14__default.basename(resolved, ".preset.yaml");
|
|
5111
|
-
const edges = [];
|
|
5059
|
+
|
|
5060
|
+
// cli/src/commands/preset-apply.ts
|
|
5061
|
+
var TOKEN_RE = /\$\{(INPUT|SECRET):([^}]+)\}/g;
|
|
5062
|
+
var NESTED_PRESET_UNSUPPORTED = "nested presets are not supported by `preset apply` yet";
|
|
5063
|
+
function resolvePlaceholderValue(placeholder, providedValue) {
|
|
5064
|
+
if (isSecretPlaceholder(placeholder)) {
|
|
5065
|
+
return { envRef: `env:${placeholder.key}` };
|
|
5066
|
+
}
|
|
5067
|
+
const fallback = getDefaultValue(placeholder);
|
|
5068
|
+
const resolved = providedValue ?? (fallback !== void 0 ? String(fallback) : void 0);
|
|
5069
|
+
if (resolved === void 0) {
|
|
5070
|
+
if (placeholder.required !== false) {
|
|
5071
|
+
throw new Error(`Placeholder "${placeholder.key}" is required but no value was provided`);
|
|
5072
|
+
}
|
|
5073
|
+
return { value: "" };
|
|
5074
|
+
}
|
|
5075
|
+
return { value: resolved };
|
|
5076
|
+
}
|
|
5077
|
+
function presetItemsToWorkspace(preset, values) {
|
|
5078
|
+
const dependencies = [];
|
|
5079
|
+
const connectors = [];
|
|
5080
|
+
const mcpServers = [];
|
|
5081
|
+
const envVarsToSet = /* @__PURE__ */ new Set();
|
|
5112
5082
|
for (const item of preset.items) {
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5083
|
+
const ref = item.ref;
|
|
5084
|
+
if (ref.startsWith("preset:")) throw new Error(NESTED_PRESET_UNSUPPORTED);
|
|
5085
|
+
if (item.id && ref.startsWith("connector:")) {
|
|
5086
|
+
const config = resolveItemConfig(item, preset, values, envVarsToSet);
|
|
5087
|
+
connectors.push({
|
|
5088
|
+
id: item.id,
|
|
5089
|
+
driver: ref.slice("connector:".length),
|
|
5090
|
+
...config
|
|
5091
|
+
});
|
|
5092
|
+
} else if (item.id && ref.startsWith("mcp:")) {
|
|
5093
|
+
const config = resolveItemConfig(item, preset, values, envVarsToSet);
|
|
5094
|
+
mcpServers.push({ id: item.id, ...config });
|
|
5095
|
+
} else {
|
|
5096
|
+
dependencies.push(ref);
|
|
5123
5097
|
}
|
|
5124
|
-
process.exit(1);
|
|
5125
5098
|
}
|
|
5099
|
+
const sources = (preset.sources ?? []).map(
|
|
5100
|
+
(s) => s.pin ? { url: s.url, pin: s.pin } : { url: s.url }
|
|
5101
|
+
);
|
|
5102
|
+
return { dependencies, connectors, mcpServers, sources, envVarsToSet: [...envVarsToSet] };
|
|
5126
5103
|
}
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
const
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5104
|
+
function resolveItemConfig(item, preset, values, envVarsToSet) {
|
|
5105
|
+
const byKey = placeholderIndex(item, preset);
|
|
5106
|
+
const resolve5 = (key) => {
|
|
5107
|
+
const ph = byKey.get(key) ?? { key, type: "text", required: true };
|
|
5108
|
+
return resolvePlaceholderValue(ph, values[key]);
|
|
5109
|
+
};
|
|
5110
|
+
return substituteNode(item.config ?? {}, resolve5, envVarsToSet);
|
|
5111
|
+
}
|
|
5112
|
+
function placeholderIndex(item, preset) {
|
|
5113
|
+
const map = /* @__PURE__ */ new Map();
|
|
5114
|
+
for (const input of preset.inputs ?? []) map.set(input.key, input);
|
|
5115
|
+
for (const ph of item.placeholders ?? []) map.set(ph.key, ph);
|
|
5116
|
+
return map;
|
|
5117
|
+
}
|
|
5118
|
+
function substituteNode(node, resolve5, envVarsToSet) {
|
|
5119
|
+
if (typeof node === "string") return substituteString(node, resolve5, envVarsToSet);
|
|
5120
|
+
if (Array.isArray(node)) return node.map((el) => substituteNode(el, resolve5, envVarsToSet));
|
|
5121
|
+
if (node && typeof node === "object") {
|
|
5122
|
+
const out = {};
|
|
5123
|
+
for (const [k, v] of Object.entries(node)) out[k] = substituteNode(v, resolve5, envVarsToSet);
|
|
5124
|
+
return out;
|
|
5125
|
+
}
|
|
5126
|
+
return node;
|
|
5127
|
+
}
|
|
5128
|
+
function substituteString(value, resolve5, envVarsToSet) {
|
|
5129
|
+
const tokens = [...value.matchAll(TOKEN_RE)];
|
|
5130
|
+
if (tokens.length === 0) return value;
|
|
5131
|
+
const secret = tokens.find(([, ns]) => ns === "SECRET") ?? tokens.find(([, , key]) => "envRef" in resolve5(key));
|
|
5132
|
+
if (secret) {
|
|
5133
|
+
const [full, , key] = secret;
|
|
5134
|
+
if (tokens.length > 1 || full !== value) {
|
|
5135
|
+
throw new Error(
|
|
5136
|
+
`Secret "${key}" must be the only token in its value \u2014 remove the surrounding tokens/text`
|
|
5137
|
+
);
|
|
5135
5138
|
}
|
|
5139
|
+
envVarsToSet.add(key);
|
|
5140
|
+
return `env:${key}`;
|
|
5136
5141
|
}
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
}
|
|
5142
|
-
return true;
|
|
5143
|
-
}
|
|
5144
|
-
function printPresetSummary(preset, placeholderCount, hasWarnings) {
|
|
5145
|
-
console.log();
|
|
5146
|
-
console.log(S.heading(" Preset Validation"));
|
|
5147
|
-
console.log(` ${S.rule(40)}`);
|
|
5148
|
-
console.log(` ${S.label("Name")} ${preset.name}`);
|
|
5149
|
-
console.log(` ${S.label("Version")} ${preset.version ?? "unversioned"}`);
|
|
5150
|
-
console.log(` ${S.label("Items")} ${preset.items.length}`);
|
|
5151
|
-
console.log(` ${S.label("Inputs")} ${preset.inputs?.length ?? 0}`);
|
|
5152
|
-
console.log(` ${S.label("Placeholders")} ${placeholderCount}`);
|
|
5153
|
-
console.log();
|
|
5154
|
-
if (hasWarnings) {
|
|
5155
|
-
logWarn("Validation passed with warnings");
|
|
5156
|
-
} else {
|
|
5157
|
-
logOk("Preset is valid");
|
|
5158
|
-
}
|
|
5159
|
-
}
|
|
5160
|
-
async function runPresetValidate(filePath) {
|
|
5161
|
-
const resolved = path14__default.resolve(filePath);
|
|
5162
|
-
const preset = await loadPresetForValidation(resolved);
|
|
5163
|
-
await reportNestedPresetRefs(preset);
|
|
5164
|
-
await checkPresetCycles(preset, resolved);
|
|
5165
|
-
const allPlaceholders = preset.items.flatMap((item) => item.placeholders ?? []);
|
|
5166
|
-
const hasWarnings = await checkPresetPlaceholders(allPlaceholders);
|
|
5167
|
-
printPresetSummary(preset, allPlaceholders.length, hasWarnings);
|
|
5168
|
-
}
|
|
5169
|
-
function generatePresetTemplate(name) {
|
|
5170
|
-
return `# ${name}.preset.yaml
|
|
5171
|
-
# Polymorphic Preset \u2014 composition + configuration primitive for the asset store.
|
|
5172
|
-
# See: _devlog/specs/2026-05-03-ai-asset-store-v2-design.md \xA7 Presets
|
|
5173
|
-
|
|
5174
|
-
name: "${name}"
|
|
5175
|
-
version: "1.0.0"
|
|
5176
|
-
description: "TODO: describe what this preset configures"
|
|
5177
|
-
|
|
5178
|
-
# Placeholders \u2014 values the user provides at apply-time.
|
|
5179
|
-
# Types: text, multiline, secret, number, boolean, enum, oauth, instance-picker
|
|
5180
|
-
placeholders:
|
|
5181
|
-
- key: EXAMPLE_KEY
|
|
5182
|
-
type: text
|
|
5183
|
-
label: "Example placeholder"
|
|
5184
|
-
required: true
|
|
5185
|
-
# default: "some-value"
|
|
5186
|
-
# hint: "Help text shown to the user"
|
|
5187
|
-
|
|
5188
|
-
# Items \u2014 each becomes a Library Instance when the preset is applied.
|
|
5189
|
-
# Ref types:
|
|
5190
|
-
# - Asset ref (kind:publisher/name@pin) \u2192 creates new Instance
|
|
5191
|
-
# - Library Instance ref (#uuid) \u2192 reuses existing Instance
|
|
5192
|
-
# - Nested Preset ref (preset:path.preset.yaml) \u2192 recursive apply (max depth 3)
|
|
5193
|
-
items:
|
|
5194
|
-
- id: example-item
|
|
5195
|
-
ref: "skill:@skaile/example-skill@^1.0"
|
|
5196
|
-
config:
|
|
5197
|
-
# Use \${INPUT:EXAMPLE_KEY} for placeholder interpolation
|
|
5198
|
-
setting: "\${INPUT:EXAMPLE_KEY}"
|
|
5199
|
-
# credential_ref: "\${SECRET:EXAMPLE_KEY}" # for secret placeholders
|
|
5200
|
-
`;
|
|
5142
|
+
return value.replace(TOKEN_RE, (_m, _ns, key) => {
|
|
5143
|
+
const resolved = resolve5(key);
|
|
5144
|
+
return "envRef" in resolved ? resolved.envRef : resolved.value;
|
|
5145
|
+
});
|
|
5201
5146
|
}
|
|
5202
5147
|
var REF_HINT = "kind:@<publisher>/<name>#<version> (e.g. skill:@skaile/use-exa#1.0.0)";
|
|
5203
5148
|
function isValidAssetRef(ref) {
|
|
@@ -5274,7 +5219,7 @@ async function runRefInstall(ref, opts) {
|
|
|
5274
5219
|
const spinner5 = p6.spinner();
|
|
5275
5220
|
spinner5.start(`Installing ${ref}`);
|
|
5276
5221
|
try {
|
|
5277
|
-
const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-
|
|
5222
|
+
const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-37PXN6MK.js');
|
|
5278
5223
|
const catalog = await openCatalogSource2({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
5279
5224
|
if (!supportsInstallManifest(catalog)) {
|
|
5280
5225
|
throw new Error(
|
|
@@ -5311,7 +5256,7 @@ async function runYamlInstall(opts) {
|
|
|
5311
5256
|
return;
|
|
5312
5257
|
}
|
|
5313
5258
|
try {
|
|
5314
|
-
const { ensureSourcesCloned } = await import('../ensure-sources-
|
|
5259
|
+
const { ensureSourcesCloned } = await import('../ensure-sources-CHC7X7AJ.js');
|
|
5315
5260
|
const hydrate = ensureSourcesCloned(projectDir, { quiet: true });
|
|
5316
5261
|
if (hydrate.cloned.length > 0) {
|
|
5317
5262
|
logOk(`Cloned source(s): ${hydrate.cloned.join(", ")}`);
|
|
@@ -5467,6 +5412,612 @@ function makeCleanCommand() {
|
|
|
5467
5412
|
}
|
|
5468
5413
|
});
|
|
5469
5414
|
}
|
|
5415
|
+
|
|
5416
|
+
// cli/src/commands/preset-export.ts
|
|
5417
|
+
function buildPresetFromWorkspace(config, name, sources = []) {
|
|
5418
|
+
const items = [];
|
|
5419
|
+
for (const ref of config.dependencies ?? []) {
|
|
5420
|
+
items.push({ ref });
|
|
5421
|
+
}
|
|
5422
|
+
for (const connector of config.connectors ?? []) {
|
|
5423
|
+
const config_ = compact({
|
|
5424
|
+
access: connector.access,
|
|
5425
|
+
auth: connector.auth,
|
|
5426
|
+
options: connector.options,
|
|
5427
|
+
version: connector.version,
|
|
5428
|
+
tags: connector.tags
|
|
5429
|
+
});
|
|
5430
|
+
items.push({
|
|
5431
|
+
id: connector.id,
|
|
5432
|
+
ref: `connector:${connector.driver}`,
|
|
5433
|
+
...config_ ? { config: config_ } : {}
|
|
5434
|
+
});
|
|
5435
|
+
}
|
|
5436
|
+
for (const mcp of config.mcp_servers ?? []) {
|
|
5437
|
+
const config_ = compact({
|
|
5438
|
+
transport: mcp.transport,
|
|
5439
|
+
command: mcp.command,
|
|
5440
|
+
args: mcp.args,
|
|
5441
|
+
env: mcp.env,
|
|
5442
|
+
url: mcp.url,
|
|
5443
|
+
headers: mcp.headers
|
|
5444
|
+
});
|
|
5445
|
+
items.push({
|
|
5446
|
+
id: mcp.id,
|
|
5447
|
+
ref: `mcp:${mcp.id}`,
|
|
5448
|
+
...config_ ? { config: config_ } : {}
|
|
5449
|
+
});
|
|
5450
|
+
}
|
|
5451
|
+
const project = config.name ?? name;
|
|
5452
|
+
return {
|
|
5453
|
+
name,
|
|
5454
|
+
version: "1.0.0",
|
|
5455
|
+
description: `Exported from ${project} workspace`,
|
|
5456
|
+
items,
|
|
5457
|
+
// Never let a credential-bearing source URL reach a shareable preset.
|
|
5458
|
+
...sources.length > 0 ? { sources: sources.map((s) => ({ ...s, url: stripUrlCredentials(s.url) })) } : {}
|
|
5459
|
+
};
|
|
5460
|
+
}
|
|
5461
|
+
function neededSources(config, lock) {
|
|
5462
|
+
const factoryUrl = normalizeRepoUrl(FACTORY_SOURCE_URL);
|
|
5463
|
+
const nonFactory = (config.sources ?? []).filter((s) => normalizeRepoUrl(s.url) !== factoryUrl);
|
|
5464
|
+
if (!lock) return nonFactory;
|
|
5465
|
+
const inClosure = new Set(lock.sources.map((s) => normalizeRepoUrl(s.url)));
|
|
5466
|
+
return nonFactory.filter((s) => inClosure.has(normalizeRepoUrl(s.url)));
|
|
5467
|
+
}
|
|
5468
|
+
function compact(obj) {
|
|
5469
|
+
const out = {};
|
|
5470
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
5471
|
+
if (v !== void 0 && v !== null) out[k] = v;
|
|
5472
|
+
}
|
|
5473
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
5474
|
+
}
|
|
5475
|
+
var SECRET_REFERENCE_PREFIXES = ["env", "forge", "secret", "op", "kp", "oauth", "pat"];
|
|
5476
|
+
var SECRET_REFERENCE_RE = new RegExp(`^(${SECRET_REFERENCE_PREFIXES.join("|")}):`);
|
|
5477
|
+
function isSecretReference(value) {
|
|
5478
|
+
return SECRET_REFERENCE_RE.test(value);
|
|
5479
|
+
}
|
|
5480
|
+
var PLACEHOLDER_RE = /^\$\{(INPUT|SECRET):[^}]+\}$/;
|
|
5481
|
+
var SUSPICIOUS_KEY_RE = /(?:^|[_-])(?:token|password|passwd|secret|apikey|key|dsn|credential|auth|authorization|bearer)(?:[_-]|$)/i;
|
|
5482
|
+
var PROTO_CREDENTIAL_URL_RE = /\w+:\/\/[^/@\s]+:[^/@\s]+@/;
|
|
5483
|
+
function urlHasCredentials(url) {
|
|
5484
|
+
return PROTO_CREDENTIAL_URL_RE.test(url);
|
|
5485
|
+
}
|
|
5486
|
+
function stripUrlCredentials(url) {
|
|
5487
|
+
return url.replace(/^(\w+:\/\/)[^/@]*:[^/@]*@/, "$1");
|
|
5488
|
+
}
|
|
5489
|
+
function isLongEntropic(value) {
|
|
5490
|
+
if (value.length < 20) return false;
|
|
5491
|
+
if (/^\w+:\/\//.test(value) || value.startsWith("/")) return false;
|
|
5492
|
+
const classes = [/[a-z]/, /[A-Z]/, /[0-9]/].filter((re) => re.test(value)).length;
|
|
5493
|
+
return classes >= 2;
|
|
5494
|
+
}
|
|
5495
|
+
function scanInlineSecrets(preset) {
|
|
5496
|
+
const findings = [];
|
|
5497
|
+
for (const item of preset.items) {
|
|
5498
|
+
const itemId = typeof item.id === "string" ? item.id : "";
|
|
5499
|
+
if (item.config) scanNode(item.config, [], false, itemId, findings);
|
|
5500
|
+
}
|
|
5501
|
+
return findings;
|
|
5502
|
+
}
|
|
5503
|
+
function scanNode(node, segments, inCredentialField, itemId, findings) {
|
|
5504
|
+
if (typeof node === "string") {
|
|
5505
|
+
if (isInlineSecret(node, segments.at(-1) ?? "", inCredentialField)) {
|
|
5506
|
+
findings.push({ itemId, path: segments.join("."), maskedValue: maskSecret(node) });
|
|
5507
|
+
}
|
|
5508
|
+
return;
|
|
5509
|
+
}
|
|
5510
|
+
if (Array.isArray(node)) {
|
|
5511
|
+
node.forEach(
|
|
5512
|
+
(el, i) => scanNode(el, [...segments, String(i)], inCredentialField, itemId, findings)
|
|
5513
|
+
);
|
|
5514
|
+
return;
|
|
5515
|
+
}
|
|
5516
|
+
if (node && typeof node === "object") {
|
|
5517
|
+
for (const [k, v] of Object.entries(node)) {
|
|
5518
|
+
const credField = inCredentialField || k === "auth";
|
|
5519
|
+
scanNode(v, [...segments, k], credField, itemId, findings);
|
|
5520
|
+
}
|
|
5521
|
+
}
|
|
5522
|
+
}
|
|
5523
|
+
function isInlineSecret(value, key, inCredentialField) {
|
|
5524
|
+
if (isSecretReference(value) || PLACEHOLDER_RE.test(value)) return false;
|
|
5525
|
+
if (inCredentialField) return true;
|
|
5526
|
+
if (SUSPICIOUS_KEY_RE.test(key)) return true;
|
|
5527
|
+
if (PROTO_CREDENTIAL_URL_RE.test(value)) return true;
|
|
5528
|
+
return isLongEntropic(value);
|
|
5529
|
+
}
|
|
5530
|
+
function maskSecret(value) {
|
|
5531
|
+
const proto = value.match(/^(\w+):\/\/[^/@\s]+:[^/@\s]+@/);
|
|
5532
|
+
if (proto) return `${proto[1]}://\u2026:****@\u2026`;
|
|
5533
|
+
return "****";
|
|
5534
|
+
}
|
|
5535
|
+
function redactSecrets(preset, findings) {
|
|
5536
|
+
const next = structuredClone(preset);
|
|
5537
|
+
const keys = [];
|
|
5538
|
+
const used = /* @__PURE__ */ new Set();
|
|
5539
|
+
for (const finding of findings) {
|
|
5540
|
+
const item = next.items.find((it) => it.id === finding.itemId);
|
|
5541
|
+
if (!item?.config) continue;
|
|
5542
|
+
const base = placeholderKey(finding.itemId, finding.path);
|
|
5543
|
+
let key = base;
|
|
5544
|
+
for (let n = 2; used.has(key); n++) key = `${base}_${n}`;
|
|
5545
|
+
if (!setAtPath(item.config, finding.path.split("."), `\${INPUT:${key}}`)) continue;
|
|
5546
|
+
used.add(key);
|
|
5547
|
+
const placeholder = {
|
|
5548
|
+
key,
|
|
5549
|
+
type: "secret",
|
|
5550
|
+
required: true,
|
|
5551
|
+
prompt: `Secret value for ${finding.itemId}.${finding.path}`
|
|
5552
|
+
};
|
|
5553
|
+
item.placeholders = [...item.placeholders ?? [], placeholder];
|
|
5554
|
+
keys.push(key);
|
|
5555
|
+
}
|
|
5556
|
+
return { preset: next, keys };
|
|
5557
|
+
}
|
|
5558
|
+
function placeholderKey(itemId, path36) {
|
|
5559
|
+
return `${itemId}_${path36}`.replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
5560
|
+
}
|
|
5561
|
+
function setAtPath(root, segments, value) {
|
|
5562
|
+
let node = root;
|
|
5563
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
5564
|
+
if (!node || typeof node !== "object") return false;
|
|
5565
|
+
node = node[segments[i]];
|
|
5566
|
+
}
|
|
5567
|
+
if (!node || typeof node !== "object") return false;
|
|
5568
|
+
node[segments.at(-1)] = value;
|
|
5569
|
+
return true;
|
|
5570
|
+
}
|
|
5571
|
+
var INLINE_SECRETS_HEADER = "# \u26A0\uFE0F CONTAINS INLINE SECRETS \u2014 replace with placeholders before sharing or publishing";
|
|
5572
|
+
function secretHeaderComment(findings) {
|
|
5573
|
+
return findings.length > 0 ? INLINE_SECRETS_HEADER : null;
|
|
5574
|
+
}
|
|
5575
|
+
|
|
5576
|
+
// cli/src/commands/preset-cmd.ts
|
|
5577
|
+
function makePresetCommand() {
|
|
5578
|
+
const cmd = new Command("preset").description("Scaffold and validate preset YAML files");
|
|
5579
|
+
cmd.command("init [name]").description("Scaffold a new .preset.yaml file").option("--dir <path>", "Output directory", process.cwd()).action(async (name, opts) => {
|
|
5580
|
+
const presetName = name ?? "my-preset";
|
|
5581
|
+
const filename = `${presetName}.preset.yaml`;
|
|
5582
|
+
const outPath = path14__default.join(path14__default.resolve(opts.dir), filename);
|
|
5583
|
+
if (existsSync(outPath)) {
|
|
5584
|
+
logErr(`File already exists: ${outPath}`);
|
|
5585
|
+
logInfo("Choose a different name or remove the existing file.");
|
|
5586
|
+
process.exit(1);
|
|
5587
|
+
}
|
|
5588
|
+
const template = generatePresetTemplate(presetName);
|
|
5589
|
+
writeFileSync(outPath, template, "utf-8");
|
|
5590
|
+
logOk(`Created ${S.brand(filename)}`);
|
|
5591
|
+
logInfo(`Path: ${outPath}`);
|
|
5592
|
+
logInfo("Edit the file to define your preset items, then validate with:");
|
|
5593
|
+
logInfo(` skaile preset validate ${filename}`);
|
|
5594
|
+
});
|
|
5595
|
+
cmd.command("validate <path>").description("Validate a preset YAML file (schema + cycles + nesting depth)").action(async (filePath) => {
|
|
5596
|
+
await runPresetValidate(filePath);
|
|
5597
|
+
});
|
|
5598
|
+
cmd.command("export [name]").description("Snapshot the workspace's skaile.yaml into a shareable .preset.yaml").option("--project-dir <path>", "Project directory to read skaile.yaml from", process.cwd()).option("--out <file>", "Explicit output file path").option("--dir <path>", "Output directory (default: cwd)", process.cwd()).option("--redact", "Replace every detected inline secret with a placeholder").option(
|
|
5599
|
+
"--allow-inline-secrets",
|
|
5600
|
+
"Exit 0 even when inline secrets remain unredacted (opt-in; unsafe for CI)"
|
|
5601
|
+
).option("--force", "Overwrite the output file if it already exists").action(async (name, opts) => {
|
|
5602
|
+
await runPresetExport(name, opts);
|
|
5603
|
+
});
|
|
5604
|
+
cmd.command("apply <path>").description("Apply a .preset.yaml additively into the workspace's skaile.yaml").option("--project-dir <path>", "Project directory holding skaile.yaml", process.cwd()).option(
|
|
5605
|
+
"--input <KEY=VAL>",
|
|
5606
|
+
"Provide a placeholder value (repeatable)",
|
|
5607
|
+
collectInput,
|
|
5608
|
+
[]
|
|
5609
|
+
).option("--yes", "Skip interactive prompts; use defaults where available").option("--no-deploy", "Skip the final `skaile install` step").action(async (filePath, opts) => {
|
|
5610
|
+
await runPresetApply(filePath, opts);
|
|
5611
|
+
});
|
|
5612
|
+
return cmd;
|
|
5613
|
+
}
|
|
5614
|
+
async function runPresetExport(name, opts) {
|
|
5615
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
5616
|
+
const file = loadSkWorkspaceConfig(projectDir);
|
|
5617
|
+
if (!file) {
|
|
5618
|
+
logErr(`No skaile.yaml found in ${projectDir}`);
|
|
5619
|
+
logInfo("Run this from a project directory or pass --project-dir <path>.");
|
|
5620
|
+
process.exit(1);
|
|
5621
|
+
}
|
|
5622
|
+
const presetName = name ?? file.config.name ?? "my-preset";
|
|
5623
|
+
let lock = null;
|
|
5624
|
+
try {
|
|
5625
|
+
lock = readLock(path14__default.join(projectDir, "skaile.lock.yaml"));
|
|
5626
|
+
} catch {
|
|
5627
|
+
lock = null;
|
|
5628
|
+
}
|
|
5629
|
+
const sources = neededSources(file.config, lock);
|
|
5630
|
+
if (lock === null && sources.length > 0) {
|
|
5631
|
+
logInfo("No lock file \u2014 exporting all non-factory sources conservatively.");
|
|
5632
|
+
}
|
|
5633
|
+
const strippedCreds = sources.filter((s) => urlHasCredentials(s.url)).length;
|
|
5634
|
+
if (strippedCreds > 0) {
|
|
5635
|
+
logWarn(`Stripped credentials from ${strippedCreds} source URL(s) \u2014 resolved via git auth on apply.`);
|
|
5636
|
+
}
|
|
5637
|
+
let preset = buildPresetFromWorkspace(file.config, presetName, sources);
|
|
5638
|
+
if (preset.items.length === 0) {
|
|
5639
|
+
logErr("Nothing to export \u2014 skaile.yaml has no dependencies, connectors, or mcp_servers.");
|
|
5640
|
+
process.exit(1);
|
|
5641
|
+
}
|
|
5642
|
+
const result = validatePreset(preset);
|
|
5643
|
+
if (!result.ok) {
|
|
5644
|
+
logErr("Internal error: generated preset failed validation:");
|
|
5645
|
+
for (const err of result.errors) console.error(` ${S.err("\u2717")} ${err.path}: ${err.message}`);
|
|
5646
|
+
process.exit(1);
|
|
5647
|
+
}
|
|
5648
|
+
const findings = scanInlineSecrets(preset);
|
|
5649
|
+
reportFindings(findings);
|
|
5650
|
+
const toRedact = await resolveRedactions(findings, opts.redact === true);
|
|
5651
|
+
if (toRedact.length > 0) preset = redactSecrets(preset, toRedact).preset;
|
|
5652
|
+
const unresolved = scanInlineSecrets(preset);
|
|
5653
|
+
const header = secretHeaderComment(unresolved);
|
|
5654
|
+
const body = stringify(preset);
|
|
5655
|
+
const contents = header ? `${header}
|
|
5656
|
+
${body}` : body;
|
|
5657
|
+
if (opts.out && opts.dir !== process.cwd()) logWarn("--dir is ignored when --out is set.");
|
|
5658
|
+
const outPath = opts.out ? path14__default.resolve(opts.out) : path14__default.join(path14__default.resolve(opts.dir), `${presetName}.preset.yaml`);
|
|
5659
|
+
if (existsSync(outPath) && !opts.force) {
|
|
5660
|
+
logErr(`File already exists: ${outPath}`);
|
|
5661
|
+
logInfo("Pass --force to overwrite, or choose a different --out/--dir.");
|
|
5662
|
+
process.exit(1);
|
|
5663
|
+
}
|
|
5664
|
+
try {
|
|
5665
|
+
writeFileSync(outPath, contents, "utf-8");
|
|
5666
|
+
} catch (e) {
|
|
5667
|
+
logErr(`Failed to write ${outPath}: ${e.message}`);
|
|
5668
|
+
process.exit(1);
|
|
5669
|
+
}
|
|
5670
|
+
logOk(`Exported ${S.brand(path14__default.basename(outPath))}`);
|
|
5671
|
+
logInfo(`Path: ${outPath}`);
|
|
5672
|
+
if (unresolved.length > 0) {
|
|
5673
|
+
console.error(S.err("This file is NOT safe to share."));
|
|
5674
|
+
if (!opts.allowInlineSecrets) {
|
|
5675
|
+
logErr(`${unresolved.length} inline secret(s) left unredacted.`);
|
|
5676
|
+
logInfo(
|
|
5677
|
+
"Re-run with --redact to placeholder them, or --allow-inline-secrets to accept the risk."
|
|
5678
|
+
);
|
|
5679
|
+
process.exit(1);
|
|
5680
|
+
}
|
|
5681
|
+
}
|
|
5682
|
+
}
|
|
5683
|
+
function reportFindings(findings) {
|
|
5684
|
+
if (findings.length === 0) return;
|
|
5685
|
+
console.error(S.err(`\u26A0\uFE0F ${findings.length} potential INLINE secret(s) found`));
|
|
5686
|
+
for (const f of findings) {
|
|
5687
|
+
console.error(` ${S.err("\u2022")} ${f.itemId} ${S.dim(f.path)} ${f.maskedValue}`);
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5690
|
+
async function resolveRedactions(findings, redactAll) {
|
|
5691
|
+
if (findings.length === 0) return [];
|
|
5692
|
+
if (redactAll) return findings;
|
|
5693
|
+
if (!process.stdin.isTTY) return [];
|
|
5694
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
|
|
5695
|
+
try {
|
|
5696
|
+
const chosen = [];
|
|
5697
|
+
for (const f of findings) {
|
|
5698
|
+
const answer = await rl.question(`Redact ${f.itemId}.${f.path}? [y/N] `);
|
|
5699
|
+
if (/^y(es)?$/i.test(answer.trim())) chosen.push(f);
|
|
5700
|
+
}
|
|
5701
|
+
return chosen;
|
|
5702
|
+
} finally {
|
|
5703
|
+
rl.close();
|
|
5704
|
+
}
|
|
5705
|
+
}
|
|
5706
|
+
function collectInput(value, acc) {
|
|
5707
|
+
acc.push(value);
|
|
5708
|
+
return acc;
|
|
5709
|
+
}
|
|
5710
|
+
async function runPresetApply(filePath, opts) {
|
|
5711
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
5712
|
+
const file = loadSkWorkspaceConfig(projectDir);
|
|
5713
|
+
if (!file) {
|
|
5714
|
+
logErr("No skaile.yaml \u2014 run `skaile init` first");
|
|
5715
|
+
process.exit(1);
|
|
5716
|
+
}
|
|
5717
|
+
const resolved = path14__default.resolve(filePath);
|
|
5718
|
+
if (!existsSync(resolved)) {
|
|
5719
|
+
logErr(`File not found: ${resolved}`);
|
|
5720
|
+
process.exit(1);
|
|
5721
|
+
}
|
|
5722
|
+
const { parsePresetYaml } = await import('../library/index.js');
|
|
5723
|
+
const parseResult = parsePresetYaml(readFileSync(resolved, "utf-8"));
|
|
5724
|
+
if (!parseResult.ok || !parseResult.preset) {
|
|
5725
|
+
logErr("Preset validation failed:");
|
|
5726
|
+
for (const err of parseResult.errors) console.error(` ${S.err("\u2717")} ${err}`);
|
|
5727
|
+
process.exit(1);
|
|
5728
|
+
}
|
|
5729
|
+
const preset = parseResult.preset;
|
|
5730
|
+
if (preset.items.some((it) => it.ref.startsWith("preset:"))) {
|
|
5731
|
+
logErr(NESTED_PRESET_UNSUPPORTED);
|
|
5732
|
+
logInfo("Remove the nested `preset:` item(s) and re-run.");
|
|
5733
|
+
process.exit(1);
|
|
5734
|
+
}
|
|
5735
|
+
const values = parseInputs(opts.input);
|
|
5736
|
+
await promptMissingInputs(preset.items, preset.inputs, values, opts.yes === true);
|
|
5737
|
+
let items;
|
|
5738
|
+
try {
|
|
5739
|
+
items = presetItemsToWorkspace(preset, values);
|
|
5740
|
+
} catch (err) {
|
|
5741
|
+
logErr(err.message);
|
|
5742
|
+
process.exit(1);
|
|
5743
|
+
}
|
|
5744
|
+
const editor = WorkspaceYamlEditor.load(file.path);
|
|
5745
|
+
const summary = applyItems(editor, file.config, items);
|
|
5746
|
+
const changed = summary.addedSources.length + summary.addedDeps.length + summary.addedConnectors.length + summary.addedMcp.length;
|
|
5747
|
+
if (changed > 0) editor.save();
|
|
5748
|
+
printApplySummary(summary, items.envVarsToSet);
|
|
5749
|
+
if (opts.deploy) {
|
|
5750
|
+
await runPresetInstall(projectDir);
|
|
5751
|
+
} else {
|
|
5752
|
+
logInfo("Skipped deploy (--no-deploy). Run `skaile install` to deploy the new dependencies.");
|
|
5753
|
+
}
|
|
5754
|
+
}
|
|
5755
|
+
function parseInputs(pairs) {
|
|
5756
|
+
const out = {};
|
|
5757
|
+
for (const pair of pairs) {
|
|
5758
|
+
const eq = pair.indexOf("=");
|
|
5759
|
+
if (eq <= 0) {
|
|
5760
|
+
logErr(`Invalid --input "${pair}" \u2014 expected KEY=VALUE.`);
|
|
5761
|
+
process.exit(1);
|
|
5762
|
+
}
|
|
5763
|
+
out[pair.slice(0, eq)] = pair.slice(eq + 1);
|
|
5764
|
+
}
|
|
5765
|
+
return out;
|
|
5766
|
+
}
|
|
5767
|
+
async function promptMissingInputs(presetItems, presetInputs, values, yes) {
|
|
5768
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5769
|
+
const toPrompt = [];
|
|
5770
|
+
const collect = (ph) => {
|
|
5771
|
+
if (seen.has(ph.key) || isSecretPlaceholder(ph)) return;
|
|
5772
|
+
seen.add(ph.key);
|
|
5773
|
+
if (values[ph.key] === void 0) toPrompt.push(ph);
|
|
5774
|
+
};
|
|
5775
|
+
for (const input of presetInputs ?? []) collect(input);
|
|
5776
|
+
for (const item of presetItems) for (const ph of item.placeholders ?? []) collect(ph);
|
|
5777
|
+
if (toPrompt.length === 0 || yes || !process.stdin.isTTY) return;
|
|
5778
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
|
|
5779
|
+
try {
|
|
5780
|
+
for (const ph of toPrompt) {
|
|
5781
|
+
const def = getDefaultValue(ph);
|
|
5782
|
+
const suffix = def !== void 0 ? ` [${String(def)}]` : "";
|
|
5783
|
+
const answer = (await rl.question(`${ph.prompt ?? ph.key}${suffix}: `)).trim();
|
|
5784
|
+
if (answer) values[ph.key] = answer;
|
|
5785
|
+
else if (def !== void 0) values[ph.key] = String(def);
|
|
5786
|
+
}
|
|
5787
|
+
} finally {
|
|
5788
|
+
rl.close();
|
|
5789
|
+
}
|
|
5790
|
+
}
|
|
5791
|
+
function applyItems(editor, config, items) {
|
|
5792
|
+
const s = {
|
|
5793
|
+
addedDeps: [],
|
|
5794
|
+
skippedDeps: [],
|
|
5795
|
+
addedConnectors: [],
|
|
5796
|
+
skippedConnectors: [],
|
|
5797
|
+
unchangedConnectors: [],
|
|
5798
|
+
addedMcp: [],
|
|
5799
|
+
skippedMcp: [],
|
|
5800
|
+
unchangedMcp: [],
|
|
5801
|
+
addedSources: [],
|
|
5802
|
+
skippedSources: [],
|
|
5803
|
+
unchangedSources: []
|
|
5804
|
+
};
|
|
5805
|
+
const existingSourceUrls = new Map(
|
|
5806
|
+
editor.getSources().map((src) => [normalizeRepoUrl(src.url), src])
|
|
5807
|
+
);
|
|
5808
|
+
for (const src of items.sources) {
|
|
5809
|
+
const key = normalizeRepoUrl(src.url);
|
|
5810
|
+
const existing = existingSourceUrls.get(key);
|
|
5811
|
+
if (!existing) {
|
|
5812
|
+
editor.setSource(src);
|
|
5813
|
+
existingSourceUrls.set(key, src);
|
|
5814
|
+
s.addedSources.push(src.url);
|
|
5815
|
+
} else if ((existing.pin ?? void 0) !== (src.pin ?? void 0)) {
|
|
5816
|
+
s.skippedSources.push({ url: src.url, keptPin: existing.pin, presetPin: src.pin });
|
|
5817
|
+
} else {
|
|
5818
|
+
s.unchangedSources.push(src.url);
|
|
5819
|
+
}
|
|
5820
|
+
}
|
|
5821
|
+
for (const ref of items.dependencies) {
|
|
5822
|
+
if (editor.addDependency(ref)) s.addedDeps.push(ref);
|
|
5823
|
+
else s.skippedDeps.push(ref);
|
|
5824
|
+
}
|
|
5825
|
+
const existingConnectors = new Map((config.connectors ?? []).map((c) => [c.id, c]));
|
|
5826
|
+
for (const conn of items.connectors) {
|
|
5827
|
+
const existing = existingConnectors.get(conn.id);
|
|
5828
|
+
if (existing) {
|
|
5829
|
+
(stableEqual(existing, conn) ? s.unchangedConnectors : s.skippedConnectors).push(conn.id);
|
|
5830
|
+
continue;
|
|
5831
|
+
}
|
|
5832
|
+
editor.setConnector(conn);
|
|
5833
|
+
s.addedConnectors.push(conn.id);
|
|
5834
|
+
}
|
|
5835
|
+
const existingMcp = new Map((config.mcp_servers ?? []).map((m) => [m.id, m]));
|
|
5836
|
+
for (const mcp of items.mcpServers) {
|
|
5837
|
+
const existing = existingMcp.get(mcp.id);
|
|
5838
|
+
if (existing) {
|
|
5839
|
+
(stableEqual(existing, mcp) ? s.unchangedMcp : s.skippedMcp).push(mcp.id);
|
|
5840
|
+
continue;
|
|
5841
|
+
}
|
|
5842
|
+
editor.setMcpServer(mcp);
|
|
5843
|
+
s.addedMcp.push(mcp.id);
|
|
5844
|
+
}
|
|
5845
|
+
return s;
|
|
5846
|
+
}
|
|
5847
|
+
function stableEqual(a, b) {
|
|
5848
|
+
return canonicalJson(a) === canonicalJson(b);
|
|
5849
|
+
}
|
|
5850
|
+
function canonicalJson(value) {
|
|
5851
|
+
return JSON.stringify(
|
|
5852
|
+
value,
|
|
5853
|
+
(_k, v) => v && typeof v === "object" && !Array.isArray(v) ? Object.fromEntries(
|
|
5854
|
+
Object.entries(v).sort(([x], [y]) => x.localeCompare(y))
|
|
5855
|
+
) : v
|
|
5856
|
+
);
|
|
5857
|
+
}
|
|
5858
|
+
function printApplySummary(summary, envVarsToSet) {
|
|
5859
|
+
const added = summary.addedSources.length + summary.addedDeps.length + summary.addedConnectors.length + summary.addedMcp.length;
|
|
5860
|
+
if (added === 0) {
|
|
5861
|
+
logInfo("Nothing to apply \u2014 everything was already present.");
|
|
5862
|
+
} else {
|
|
5863
|
+
if (summary.addedSources.length > 0) {
|
|
5864
|
+
logOk(`Registered ${summary.addedSources.length} source(s).`);
|
|
5865
|
+
}
|
|
5866
|
+
logOk(
|
|
5867
|
+
`Applied ${summary.addedDeps.length} dependency(ies), ${summary.addedConnectors.length} connector(s), ${summary.addedMcp.length} mcp server(s).`
|
|
5868
|
+
);
|
|
5869
|
+
}
|
|
5870
|
+
const skipped = [
|
|
5871
|
+
...summary.skippedSources.map(
|
|
5872
|
+
(s) => `source ${s.url} (kept pin '${s.keptPin ?? "none"}', preset had '${s.presetPin ?? "none"}')`
|
|
5873
|
+
),
|
|
5874
|
+
...summary.skippedDeps.map((d) => `dependency ${d} (already present)`),
|
|
5875
|
+
...summary.skippedConnectors.map((c) => `connector ${c} (id exists, differs)`),
|
|
5876
|
+
...summary.skippedMcp.map((m) => `mcp ${m} (id exists, differs)`)
|
|
5877
|
+
];
|
|
5878
|
+
for (const line of skipped) logWarn(`Skipped ${line}`);
|
|
5879
|
+
const unchanged = summary.unchangedConnectors.length + summary.unchangedMcp.length + summary.unchangedSources.length;
|
|
5880
|
+
if (unchanged > 0) logInfo(`${unchanged} source/connector/mcp entry(ies) already matched \u2014 left as-is.`);
|
|
5881
|
+
if (envVarsToSet.length > 0) {
|
|
5882
|
+
logWarn(`Set these env vars before running: ${envVarsToSet.join(", ")}`);
|
|
5883
|
+
}
|
|
5884
|
+
}
|
|
5885
|
+
async function runPresetInstall(projectDir) {
|
|
5886
|
+
try {
|
|
5887
|
+
const { AssetManager: AssetManager2 } = await import('../asset-manager/index.js');
|
|
5888
|
+
const am2 = new AssetManager2({ projectDir });
|
|
5889
|
+
logInfo("Installing new dependencies\u2026");
|
|
5890
|
+
const result = await am2.install({});
|
|
5891
|
+
for (const d of result.deployed) logOk(d);
|
|
5892
|
+
for (const m of result.missing) logErr(`Missing: ${m}`);
|
|
5893
|
+
await reportInstalledSoftDeps(am2);
|
|
5894
|
+
} catch (err) {
|
|
5895
|
+
logErr(`Install failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
5896
|
+
logInfo("Run `skaile install` to deploy the new dependencies.");
|
|
5897
|
+
}
|
|
5898
|
+
}
|
|
5899
|
+
async function loadPresetForValidation(resolved) {
|
|
5900
|
+
if (!existsSync(resolved)) {
|
|
5901
|
+
logErr(`File not found: ${resolved}`);
|
|
5902
|
+
process.exit(1);
|
|
5903
|
+
}
|
|
5904
|
+
const content = readFileSync(resolved, "utf-8");
|
|
5905
|
+
const { parsePresetYaml } = await import('../library/index.js');
|
|
5906
|
+
const parseResult = parsePresetYaml(content);
|
|
5907
|
+
if (!parseResult.ok) {
|
|
5908
|
+
logErr("Preset validation failed (parse errors):");
|
|
5909
|
+
for (const err of parseResult.errors) {
|
|
5910
|
+
console.log(` ${S.err("\u2717")} ${err}`);
|
|
5911
|
+
}
|
|
5912
|
+
process.exit(1);
|
|
5913
|
+
}
|
|
5914
|
+
if (!parseResult.preset) {
|
|
5915
|
+
logErr("Preset validation failed: parser returned no manifest");
|
|
5916
|
+
process.exit(1);
|
|
5917
|
+
}
|
|
5918
|
+
return parseResult.preset;
|
|
5919
|
+
}
|
|
5920
|
+
async function reportNestedPresetRefs(preset) {
|
|
5921
|
+
const { detectNestedPresetRefs } = await import('../library/index.js');
|
|
5922
|
+
const nestedRefs = detectNestedPresetRefs(preset);
|
|
5923
|
+
if (nestedRefs.length > 0) {
|
|
5924
|
+
logInfo(`Nested preset refs: ${nestedRefs.length} (depth validated at apply-time)`);
|
|
5925
|
+
}
|
|
5926
|
+
}
|
|
5927
|
+
async function checkPresetCycles(preset, resolved) {
|
|
5928
|
+
const { detectCycles } = await import('../discovery/index.js');
|
|
5929
|
+
const presetRef = path14__default.basename(resolved, ".preset.yaml");
|
|
5930
|
+
const edges = [];
|
|
5931
|
+
for (const item of preset.items) {
|
|
5932
|
+
if (item.ref) {
|
|
5933
|
+
edges.push({ from: presetRef, to: item.ref, field: "items[].ref" });
|
|
5934
|
+
}
|
|
5935
|
+
}
|
|
5936
|
+
if (edges.length === 0) return;
|
|
5937
|
+
const cycleResult = detectCycles(edges);
|
|
5938
|
+
if (!cycleResult.acyclic) {
|
|
5939
|
+
logErr("Cycle detected in preset references:");
|
|
5940
|
+
if (cycleResult.cyclePath) {
|
|
5941
|
+
console.log(` ${S.err("\u2717")} ${cycleResult.cyclePath.join(" \u2192 ")}`);
|
|
5942
|
+
}
|
|
5943
|
+
process.exit(1);
|
|
5944
|
+
}
|
|
5945
|
+
}
|
|
5946
|
+
async function checkPresetPlaceholders(allPlaceholders) {
|
|
5947
|
+
if (allPlaceholders.length === 0) return false;
|
|
5948
|
+
const { validatePlaceholder } = await import('../library/index.js');
|
|
5949
|
+
const invalidEntries = [];
|
|
5950
|
+
for (const ph of allPlaceholders) {
|
|
5951
|
+
const result = validatePlaceholder(ph, ph.default);
|
|
5952
|
+
if (!result.valid) {
|
|
5953
|
+
invalidEntries.push({ key: ph.key, errors: result.errors });
|
|
5954
|
+
}
|
|
5955
|
+
}
|
|
5956
|
+
if (invalidEntries.length === 0) return false;
|
|
5957
|
+
logWarn("Placeholder issues:");
|
|
5958
|
+
for (const r of invalidEntries) {
|
|
5959
|
+
console.log(` ${S.warn("!")} ${r.key}: ${r.errors.join(", ")}`);
|
|
5960
|
+
}
|
|
5961
|
+
return true;
|
|
5962
|
+
}
|
|
5963
|
+
function printPresetSummary(preset, placeholderCount, hasWarnings) {
|
|
5964
|
+
console.log();
|
|
5965
|
+
console.log(S.heading(" Preset Validation"));
|
|
5966
|
+
console.log(` ${S.rule(40)}`);
|
|
5967
|
+
console.log(` ${S.label("Name")} ${preset.name}`);
|
|
5968
|
+
console.log(` ${S.label("Version")} ${preset.version ?? "unversioned"}`);
|
|
5969
|
+
console.log(` ${S.label("Items")} ${preset.items.length}`);
|
|
5970
|
+
console.log(` ${S.label("Inputs")} ${preset.inputs?.length ?? 0}`);
|
|
5971
|
+
console.log(` ${S.label("Placeholders")} ${placeholderCount}`);
|
|
5972
|
+
console.log();
|
|
5973
|
+
if (hasWarnings) {
|
|
5974
|
+
logWarn("Validation passed with warnings");
|
|
5975
|
+
} else {
|
|
5976
|
+
logOk("Preset is valid");
|
|
5977
|
+
}
|
|
5978
|
+
}
|
|
5979
|
+
async function runPresetValidate(filePath) {
|
|
5980
|
+
const resolved = path14__default.resolve(filePath);
|
|
5981
|
+
const preset = await loadPresetForValidation(resolved);
|
|
5982
|
+
await reportNestedPresetRefs(preset);
|
|
5983
|
+
await checkPresetCycles(preset, resolved);
|
|
5984
|
+
const allPlaceholders = preset.items.flatMap((item) => item.placeholders ?? []);
|
|
5985
|
+
const hasWarnings = await checkPresetPlaceholders(allPlaceholders);
|
|
5986
|
+
printPresetSummary(preset, allPlaceholders.length, hasWarnings);
|
|
5987
|
+
}
|
|
5988
|
+
function generatePresetTemplate(name) {
|
|
5989
|
+
return `# ${name}.preset.yaml
|
|
5990
|
+
# Polymorphic Preset \u2014 composition + configuration primitive for the asset store.
|
|
5991
|
+
# See: _devlog/specs/2026-05-03-ai-asset-store-v2-design.md \xA7 Presets
|
|
5992
|
+
|
|
5993
|
+
name: "${name}"
|
|
5994
|
+
version: "1.0.0"
|
|
5995
|
+
description: "TODO: describe what this preset configures"
|
|
5996
|
+
|
|
5997
|
+
# Placeholders \u2014 values the user provides at apply-time.
|
|
5998
|
+
# Types: text, multiline, secret, number, boolean, enum, oauth, instance-picker
|
|
5999
|
+
placeholders:
|
|
6000
|
+
- key: EXAMPLE_KEY
|
|
6001
|
+
type: text
|
|
6002
|
+
label: "Example placeholder"
|
|
6003
|
+
required: true
|
|
6004
|
+
# default: "some-value"
|
|
6005
|
+
# hint: "Help text shown to the user"
|
|
6006
|
+
|
|
6007
|
+
# Items \u2014 each becomes a Library Instance when the preset is applied.
|
|
6008
|
+
# Ref types:
|
|
6009
|
+
# - Asset ref (kind:publisher/name@pin) \u2192 creates new Instance
|
|
6010
|
+
# - Library Instance ref (#uuid) \u2192 reuses existing Instance
|
|
6011
|
+
# - Nested Preset ref (preset:path.preset.yaml) \u2192 recursive apply (max depth 3)
|
|
6012
|
+
items:
|
|
6013
|
+
- id: example-item
|
|
6014
|
+
ref: "skill:@skaile/example-skill@^1.0"
|
|
6015
|
+
config:
|
|
6016
|
+
# Use \${INPUT:EXAMPLE_KEY} for placeholder interpolation
|
|
6017
|
+
setting: "\${INPUT:EXAMPLE_KEY}"
|
|
6018
|
+
# credential_ref: "\${SECRET:EXAMPLE_KEY}" # for secret placeholders
|
|
6019
|
+
`;
|
|
6020
|
+
}
|
|
5470
6021
|
function makeRebuildCommand() {
|
|
5471
6022
|
return new Command("rebuild").description("Re-snapshot inline-snapshot composition items and bump prompt version").argument("[agent]", "Agent name or path (defaults to current project agent)").option("--project-dir <dir>", "Project directory", process.cwd()).action(async (agentArg, opts) => {
|
|
5472
6023
|
const projectDir = path14__default.resolve(opts.projectDir);
|
|
@@ -5785,12 +6336,12 @@ function makeServeCommand() {
|
|
|
5785
6336
|
);
|
|
5786
6337
|
}
|
|
5787
6338
|
async function ensurePluginsLoadedForServe(projectDir) {
|
|
5788
|
-
const { logInfo: logInfo2, logWarn: logWarn2 } = await import('../helpers-
|
|
6339
|
+
const { logInfo: logInfo2, logWarn: logWarn2 } = await import('../helpers-GWG4CYYC.js');
|
|
5789
6340
|
try {
|
|
5790
6341
|
const { resolveSkWorkspaceConfig: resolveSkWorkspaceConfig2 } = await import('../core/index.js');
|
|
5791
6342
|
const config = resolveSkWorkspaceConfig2(projectDir);
|
|
5792
6343
|
if (!config.plugins || config.plugins.length === 0) return;
|
|
5793
|
-
const { ensurePluginsLoaded } = await import('../plugin-store-
|
|
6344
|
+
const { ensurePluginsLoaded } = await import('../plugin-store-EIMVEH3O.js');
|
|
5794
6345
|
const { pluginRegistry } = await import('../plugin-registry/index.js');
|
|
5795
6346
|
const result = await ensurePluginsLoaded(projectDir, config.plugins, pluginRegistry);
|
|
5796
6347
|
if (result.loaded.length > 0) {
|
|
@@ -5804,14 +6355,14 @@ async function ensurePluginsLoadedForServe(projectDir) {
|
|
|
5804
6355
|
}
|
|
5805
6356
|
}
|
|
5806
6357
|
async function runCompileTest(opts) {
|
|
5807
|
-
const { logOk: logOk2, logErr: logErr2, logInfo: logInfo2, S: S2 } = await import('../helpers-
|
|
6358
|
+
const { logOk: logOk2, logErr: logErr2, logInfo: logInfo2, S: S2 } = await import('../helpers-GWG4CYYC.js');
|
|
5808
6359
|
const { tmpdir } = await import('os');
|
|
5809
6360
|
const { dirname: dirname4, join: join5, resolve: resolve5 } = await import('path');
|
|
5810
6361
|
const { fileURLToPath: fileURLToPath2 } = await import('url');
|
|
5811
6362
|
const { unlinkSync, existsSync: existsSync13 } = await import('fs');
|
|
5812
6363
|
const { spawn } = await import('child_process');
|
|
5813
6364
|
const { portableSpawnSync: portableSpawnSync2 } = await import('../core/index.js');
|
|
5814
|
-
const { MONOREPO_ROOT } = await import('../paths-
|
|
6365
|
+
const { MONOREPO_ROOT } = await import('../paths-UVOHWUPY.js');
|
|
5815
6366
|
if (MONOREPO_ROOT === null) {
|
|
5816
6367
|
logErr2("--compile-test is only available inside the skaile-dev workspace.");
|
|
5817
6368
|
logInfo2("Run it from a checkout of skaile-ai/skaile-dev (the monorepo shell).");
|
|
@@ -6629,8 +7180,8 @@ function makeStoreCommand() {
|
|
|
6629
7180
|
store.command("login").description("Authenticate with the store").option("--email <email>", "Login with email instead of GitHub").action(async (opts) => {
|
|
6630
7181
|
const config = getStoreConfig();
|
|
6631
7182
|
if (opts.email) {
|
|
6632
|
-
const
|
|
6633
|
-
const rl =
|
|
7183
|
+
const readline3 = await import('readline');
|
|
7184
|
+
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
6634
7185
|
const password = await new Promise((resolve5) => {
|
|
6635
7186
|
rl.question("Password: ", (answer) => {
|
|
6636
7187
|
rl.close();
|
|
@@ -7447,12 +7998,43 @@ function makeVerifyCommand() {
|
|
|
7447
7998
|
}
|
|
7448
7999
|
});
|
|
7449
8000
|
}
|
|
8001
|
+
function refKindName(ref) {
|
|
8002
|
+
const trimmed = ref.trim();
|
|
8003
|
+
const colon = trimmed.indexOf(":");
|
|
8004
|
+
let kind = colon === -1 ? void 0 : trimmed.slice(0, colon);
|
|
8005
|
+
if (kind === "mcp") kind = "mcp-server";
|
|
8006
|
+
let rest = colon === -1 ? trimmed : trimmed.slice(colon + 1);
|
|
8007
|
+
const hash = rest.indexOf("#");
|
|
8008
|
+
if (hash !== -1) rest = rest.slice(0, hash);
|
|
8009
|
+
if (rest.startsWith("@")) {
|
|
8010
|
+
const slash = rest.indexOf("/");
|
|
8011
|
+
if (slash !== -1) rest = rest.slice(slash + 1);
|
|
8012
|
+
}
|
|
8013
|
+
return { kind, name: rest };
|
|
8014
|
+
}
|
|
8015
|
+
function whyEmptyMessage(ref, declared) {
|
|
8016
|
+
const { kind, name } = refKindName(ref);
|
|
8017
|
+
const isDeclared = declared.some(
|
|
8018
|
+
(d) => d.name === name && (kind === void 0 || d.kind === kind)
|
|
8019
|
+
);
|
|
8020
|
+
if (isDeclared) {
|
|
8021
|
+
return `${ref} not found in lock file. Run \`skaile install\` first.`;
|
|
8022
|
+
}
|
|
8023
|
+
return `${ref} is not a dependency of this project \u2014 nothing in skaile.yaml requires it. Run \`skaile list\` to see declared dependencies.`;
|
|
8024
|
+
}
|
|
7450
8025
|
function makeWhyCommand() {
|
|
7451
8026
|
return new Command("why").description("Show why an asset is installed (dependency chain)").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action(async (ref, opts) => {
|
|
7452
8027
|
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
7453
8028
|
const chain = am2.why(ref);
|
|
7454
8029
|
if (chain.length === 0) {
|
|
7455
|
-
|
|
8030
|
+
let declared;
|
|
8031
|
+
try {
|
|
8032
|
+
declared = am2.listDeclared();
|
|
8033
|
+
} catch {
|
|
8034
|
+
logErr(`${ref} not found in lock file. Run \`skaile install\` first.`);
|
|
8035
|
+
return;
|
|
8036
|
+
}
|
|
8037
|
+
logErr(whyEmptyMessage(ref, declared));
|
|
7456
8038
|
return;
|
|
7457
8039
|
}
|
|
7458
8040
|
console.log();
|
|
@@ -7598,7 +8180,7 @@ program.command("init [project-dir]").description("Initialize a project director
|
|
|
7598
8180
|
);
|
|
7599
8181
|
async function runInit(projectDir, opts) {
|
|
7600
8182
|
const { mkdirSync: mkdirSync5, writeFileSync: writeFileSync4 } = await import('fs');
|
|
7601
|
-
const { stringify } = await import('yaml');
|
|
8183
|
+
const { stringify: stringify2 } = await import('yaml');
|
|
7602
8184
|
const { DRIVER_TARGETS, SUPPORTED_DRIVER_TARGETS: SUPPORTED_DRIVER_TARGETS2 } = await import('../core/index.js');
|
|
7603
8185
|
const backend = opts.backend;
|
|
7604
8186
|
if (!SUPPORTED_DRIVER_TARGETS2.includes(backend)) {
|
|
@@ -7626,7 +8208,7 @@ async function runInit(projectDir, opts) {
|
|
|
7626
8208
|
}
|
|
7627
8209
|
const wsConfigPath = path14__default.join(resolved, "skaile.yaml");
|
|
7628
8210
|
if (!existsSync13(wsConfigPath)) {
|
|
7629
|
-
writeFileSync4(wsConfigPath,
|
|
8211
|
+
writeFileSync4(wsConfigPath, stringify2(buildInitWorkspaceConfig(projectName, backend)));
|
|
7630
8212
|
created.push("skaile.yaml");
|
|
7631
8213
|
}
|
|
7632
8214
|
for (const dir of new Set(Object.values(DRIVER_TARGETS[backend].local))) {
|
|
@@ -7717,7 +8299,7 @@ async function bootstrapUserConfig() {
|
|
|
7717
8299
|
}
|
|
7718
8300
|
async function hydrateInitSources(resolved, created) {
|
|
7719
8301
|
try {
|
|
7720
|
-
const { ensureSourcesCloned } = await import('../ensure-sources-
|
|
8302
|
+
const { ensureSourcesCloned } = await import('../ensure-sources-CHC7X7AJ.js');
|
|
7721
8303
|
const hydrate = ensureSourcesCloned(resolved, { quiet: true });
|
|
7722
8304
|
for (const n of hydrate.cloned) created.push(`~/.skaile/cache/sources/${n}/`);
|
|
7723
8305
|
if (hydrate.failed.length > 0) {
|
|
@@ -7753,7 +8335,7 @@ function printInitSummary(resolved, projectDir, created) {
|
|
|
7753
8335
|
console.log();
|
|
7754
8336
|
}
|
|
7755
8337
|
program.command("setup").description("Interactive provider setup wizard").action(async () => {
|
|
7756
|
-
const { cmdSetup } = await import('../setup-
|
|
8338
|
+
const { cmdSetup } = await import('../setup-DINVR6ZQ.js');
|
|
7757
8339
|
await cmdSetup([], { projectDir: process.cwd() });
|
|
7758
8340
|
});
|
|
7759
8341
|
program.addCommand(makeInstallCommand());
|