@skaile/workspaces 1.3.0 → 1.5.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 +395 -0
- package/README.md +1 -1
- package/dist/app-sdk/index.d.ts +2 -0
- package/dist/app-sdk/index.js +481 -0
- package/dist/app-sdk/index.js.map +1 -0
- package/dist/app-sdk/src/app.d.ts +152 -0
- package/dist/app-sdk/src/app.d.ts.map +1 -0
- package/dist/app-sdk/src/connection-params.d.ts +117 -0
- package/dist/app-sdk/src/connection-params.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 +17 -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 +93 -0
- package/dist/app-sdk/src/transport.d.ts.map +1 -0
- package/dist/app-sdk/src/ws-transport.d.ts +79 -0
- package/dist/app-sdk/src/ws-transport.d.ts.map +1 -0
- package/dist/{asset-feeds-NEZKG6YS.js → asset-feeds-T35ELX2O.js} +11 -11
- package/dist/{asset-feeds-NEZKG6YS.js.map → asset-feeds-T35ELX2O.js.map} +1 -1
- package/dist/asset-manager/index.js +15 -10
- package/dist/asset-manager/installer.js +9 -9
- 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 +2 -2
- 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 +3 -3
- package/dist/{chunk-YOPSHV7V.js → chunk-2DWXGUZA.js} +3 -3
- package/dist/{chunk-YOPSHV7V.js.map → chunk-2DWXGUZA.js.map} +1 -1
- package/dist/{chunk-XBG2YDQQ.js → chunk-2ZMO4CFG.js} +3 -3
- package/dist/{chunk-XBG2YDQQ.js.map → chunk-2ZMO4CFG.js.map} +1 -1
- package/dist/{chunk-OBSSORCE.js → chunk-3CHARYD4.js} +84 -12
- package/dist/chunk-3CHARYD4.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-WFEPI5LA.js → chunk-6NR2BEIY.js} +6 -6
- package/dist/{chunk-WFEPI5LA.js.map → chunk-6NR2BEIY.js.map} +1 -1
- package/dist/{chunk-7CNIRF42.js → chunk-BGIC25VK.js} +26 -15
- package/dist/chunk-BGIC25VK.js.map +1 -0
- package/dist/{chunk-YXEPZ7LP.js → chunk-CNSNN7N6.js} +6 -6
- package/dist/{chunk-YXEPZ7LP.js.map → chunk-CNSNN7N6.js.map} +1 -1
- package/dist/{chunk-PSMW5HLX.js → chunk-DMG6NJH7.js} +5 -5
- package/dist/{chunk-PSMW5HLX.js.map → chunk-DMG6NJH7.js.map} +1 -1
- package/dist/{chunk-P3MJYPZE.js → chunk-FDE7XRQA.js} +57 -9
- package/dist/chunk-FDE7XRQA.js.map +1 -0
- package/dist/{chunk-K5SD7FSF.js → chunk-HKX5VSWQ.js} +3 -3
- package/dist/{chunk-K5SD7FSF.js.map → chunk-HKX5VSWQ.js.map} +1 -1
- package/dist/{chunk-AZAS3FKN.js → chunk-HY33RMEA.js} +49 -3
- package/dist/chunk-HY33RMEA.js.map +1 -0
- package/dist/{chunk-XKARS6EE.js → chunk-IEX5YV4R.js} +3 -3
- package/dist/{chunk-XKARS6EE.js.map → chunk-IEX5YV4R.js.map} +1 -1
- package/dist/{chunk-GB4SEEK4.js → chunk-IRORTHGA.js} +10 -4
- package/dist/chunk-IRORTHGA.js.map +1 -0
- package/dist/chunk-J5TI55E7.js +203 -0
- package/dist/chunk-J5TI55E7.js.map +1 -0
- package/dist/chunk-JIDKX7GC.js +122 -0
- package/dist/chunk-JIDKX7GC.js.map +1 -0
- package/dist/{chunk-BDUANIAR.js → chunk-KEQ4GLVM.js} +3 -3
- package/dist/{chunk-BDUANIAR.js.map → chunk-KEQ4GLVM.js.map} +1 -1
- package/dist/{chunk-5XS3BFJS.js → chunk-KMY7HVQ6.js} +3 -3
- package/dist/{chunk-5XS3BFJS.js.map → chunk-KMY7HVQ6.js.map} +1 -1
- package/dist/{chunk-BZMTR5WW.js → chunk-MZV6WCF3.js} +83 -51
- package/dist/chunk-MZV6WCF3.js.map +1 -0
- package/dist/{chunk-QK5JDAFF.js → chunk-NKTFEV7Q.js} +4 -4
- package/dist/{chunk-QK5JDAFF.js.map → chunk-NKTFEV7Q.js.map} +1 -1
- package/dist/{chunk-DZCK7GRW.js → chunk-P4VHQA4N.js} +22 -6
- package/dist/chunk-P4VHQA4N.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-ETYDLXI5.js → chunk-RDYOU6N6.js} +2 -2
- package/dist/{chunk-ETYDLXI5.js.map → chunk-RDYOU6N6.js.map} +1 -1
- package/dist/{chunk-RHMQPLIK.js → chunk-RSYV7XEN.js} +14 -8
- package/dist/chunk-RSYV7XEN.js.map +1 -0
- package/dist/{chunk-SUOGVHGJ.js → chunk-TNSCHS4I.js} +2 -2
- package/dist/{chunk-SUOGVHGJ.js.map → chunk-TNSCHS4I.js.map} +1 -1
- 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-RJ3HUSBC.js → chunk-UQ5FK2AB.js} +3 -3
- package/dist/{chunk-RJ3HUSBC.js.map → chunk-UQ5FK2AB.js.map} +1 -1
- package/dist/{chunk-OUWNTFDG.js → chunk-UQKYT4V6.js} +38 -6
- package/dist/chunk-UQKYT4V6.js.map +1 -0
- package/dist/chunk-WYGXYGJH.js +688 -0
- package/dist/chunk-WYGXYGJH.js.map +1 -0
- package/dist/{chunk-TJRWGMD2.js → chunk-ZBZQC5R7.js} +3 -3
- package/dist/{chunk-TJRWGMD2.js.map → chunk-ZBZQC5R7.js.map} +1 -1
- package/dist/cli/index.js +1022 -374
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/catalog.d.ts +18 -0
- package/dist/cli/src/commands/catalog.d.ts.map +1 -1
- package/dist/cli/src/commands/library-cmd.d.ts +2 -2
- package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/library-publish.d.ts +53 -0
- package/dist/cli/src/commands/library-publish.d.ts.map +1 -0
- 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 +8 -2
- package/dist/cli/src/commands/preset-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/preset-export.d.ts +102 -0
- package/dist/cli/src/commands/preset-export.d.ts.map +1 -0
- package/dist/cli/src/commands/project.d.ts.map +1 -1
- package/dist/cli/src/commands/publish-core.d.ts +75 -0
- package/dist/cli/src/commands/publish-core.d.ts.map +1 -0
- package/dist/cli/src/commands/run.d.ts.map +1 -1
- package/dist/cli/src/commands/source-manifest-publish.d.ts +82 -0
- package/dist/cli/src/commands/source-manifest-publish.d.ts.map +1 -0
- package/dist/cli/src/commands/source-manifest.d.ts +65 -6
- package/dist/cli/src/commands/source-manifest.d.ts.map +1 -1
- package/dist/cli/src/commands/source.d.ts +13 -0
- package/dist/cli/src/commands/source.d.ts.map +1 -1
- package/dist/cli/src/commands/store.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/cli/src/driver-error.d.ts +12 -0
- package/dist/cli/src/driver-error.d.ts.map +1 -0
- package/dist/cli/src/open-library.d.ts +4 -0
- package/dist/cli/src/open-library.d.ts.map +1 -1
- package/dist/cli/src/store-auth.d.ts +42 -0
- package/dist/cli/src/store-auth.d.ts.map +1 -0
- package/dist/cli/src/store-client.d.ts +20 -22
- package/dist/cli/src/store-client.d.ts.map +1 -1
- package/dist/cli/src/store-publisher.d.ts +91 -0
- package/dist/cli/src/store-publisher.d.ts.map +1 -0
- package/dist/connectors/config.js +6 -6
- package/dist/connectors/index.js +8 -8
- package/dist/core/index.js +5 -5
- package/dist/core/publish-manifest.js +1 -1
- package/dist/core/runtime-assets.js +3 -3
- package/dist/core/src/cache-paths.d.ts +17 -0
- package/dist/core/src/cache-paths.d.ts.map +1 -1
- package/dist/core/src/index.d.ts +2 -2
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/core/src/publish-manifest.d.ts.map +1 -1
- package/dist/core/src/repo-manager.d.ts +13 -2
- package/dist/core/src/repo-manager.d.ts.map +1 -1
- package/dist/core/src/walker.d.ts +10 -0
- package/dist/core/src/walker.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 +2 -2
- package/dist/deploy/index.js +5 -5
- package/dist/discovery/index.js +3 -3
- package/dist/discovery/src/discover-manifest.d.ts.map +1 -1
- package/dist/discovery/src/discover.d.ts +17 -4
- package/dist/discovery/src/discover.d.ts.map +1 -1
- package/dist/discovery/src/index.d.ts +1 -1
- package/dist/discovery/src/index.d.ts.map +1 -1
- package/dist/discovery/src/reference-lint.d.ts +7 -0
- package/dist/discovery/src/reference-lint.d.ts.map +1 -1
- package/dist/discovery/src/source-config.d.ts +28 -0
- package/dist/discovery/src/source-config.d.ts.map +1 -1
- package/dist/discovery/src/tree-entries.d.ts.map +1 -1
- package/dist/{ensure-sources-4BAJGJRK.js → ensure-sources-QDVFUIUP.js} +18 -13
- package/dist/ensure-sources-QDVFUIUP.js.map +1 -0
- package/dist/factory-assets/connectors/box.js +8 -8
- package/dist/factory-assets/connectors/deploy.js +8 -8
- package/dist/factory-assets/connectors/devserver.js +8 -8
- package/dist/factory-assets/connectors/flow/adapter.js +8 -8
- 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 +6 -6
- package/dist/factory-assets/connectors/flow/run-flow.js +9 -9
- package/dist/factory-assets/connectors/flow.js +8 -8
- package/dist/factory-assets/connectors/git.js +8 -8
- package/dist/factory-assets/connectors/gmail.js +8 -8
- package/dist/factory-assets/connectors/googledrive.js +8 -8
- package/dist/factory-assets/connectors/local.js +8 -8
- package/dist/factory-assets/connectors/mattermost.js +8 -8
- package/dist/factory-assets/connectors/memory.js +8 -8
- package/dist/factory-assets/connectors/minio.js +8 -8
- package/dist/factory-assets/connectors/postgres.js +8 -8
- package/dist/factory-assets/connectors/s3.js +8 -8
- package/dist/factory-assets/connectors/sharepoint.js +8 -8
- package/dist/factory-assets/connectors/sqlite.js +8 -8
- package/dist/factory-assets/connectors/static-server.js +8 -8
- package/dist/factory-assets/connectors/tunnel.js +8 -8
- package/dist/factory-assets/connectors/webdav.js +8 -8
- package/dist/factory-assets/connectors/xstate-store.js +8 -8
- package/dist/factory-assets/connectors/xstate.js +8 -8
- 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-UFCOGAAM.js → flows-MRVXTYWC.js} +4 -4
- package/dist/{flows-UFCOGAAM.js.map → flows-MRVXTYWC.js.map} +1 -1
- package/dist/helpers-TF7GCBRQ.js +27 -0
- package/dist/{helpers-2OL4FRFB.js.map → helpers-TF7GCBRQ.js.map} +1 -1
- package/dist/library/index.js +9 -9
- package/dist/library/install.js +5 -5
- package/dist/library/src/index.d.ts +2 -2
- package/dist/library/src/index.d.ts.map +1 -1
- package/dist/library/src/local/local-catalog-source.d.ts +12 -1
- package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
- package/dist/library/src/sync/manifest-writeback.d.ts +36 -0
- package/dist/library/src/sync/manifest-writeback.d.ts.map +1 -1
- package/dist/library-publish-K5IBE44D.js +249 -0
- package/dist/library-publish-K5IBE44D.js.map +1 -0
- package/dist/open-library-4HMIDK3N.js +29 -0
- package/dist/{open-library-RPV2LIKL.js.map → open-library-4HMIDK3N.js.map} +1 -1
- package/dist/{paths-ML33B5SB.js → paths-P3DWFUPS.js} +8 -8
- package/dist/{paths-ML33B5SB.js.map → paths-P3DWFUPS.js.map} +1 -1
- package/dist/{plugin-store-G4HKWCTU.js → plugin-store-S7OMGI7N.js} +7 -7
- package/dist/{plugin-store-G4HKWCTU.js.map → plugin-store-S7OMGI7N.js.map} +1 -1
- package/dist/runner/index.js +14 -14
- package/dist/runner/src/agent.d.ts.map +1 -1
- package/dist/runner/src/capability-registry.d.ts +15 -4
- package/dist/runner/src/capability-registry.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +15 -10
- package/dist/sdk/bridge.js +3 -3
- package/dist/sdk/core.js +5 -5
- package/dist/sdk/flow.js +6 -6
- package/dist/sdk/index.js +14 -14
- package/dist/sdk/runner.js +14 -14
- package/dist/sdk/session.js +2 -2
- package/dist/sdk/types.js +1 -1
- package/dist/session/index.js +2 -2
- package/dist/{setup-WS6PF6JQ.js → setup-2CCS63L6.js} +10 -10
- package/dist/{setup-WS6PF6JQ.js.map → setup-2CCS63L6.js.map} +1 -1
- package/dist/source-LOAM7IIQ.js +30 -0
- package/dist/{source-22U5NOY4.js.map → source-LOAM7IIQ.js.map} +1 -1
- package/dist/source-manifest-publish-TGVZ6KMC.js +228 -0
- package/dist/source-manifest-publish-TGVZ6KMC.js.map +1 -0
- package/dist/tui/index.js +14 -14
- 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/index.d.ts +2 -2
- 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-7CNIRF42.js.map +0 -1
- package/dist/chunk-AZAS3FKN.js.map +0 -1
- package/dist/chunk-BZMTR5WW.js.map +0 -1
- package/dist/chunk-DZCK7GRW.js.map +0 -1
- package/dist/chunk-EVZKWY5J.js.map +0 -1
- package/dist/chunk-GB4SEEK4.js.map +0 -1
- package/dist/chunk-JQMIG7D3.js +0 -93
- package/dist/chunk-JQMIG7D3.js.map +0 -1
- package/dist/chunk-OBSSORCE.js.map +0 -1
- package/dist/chunk-OUWNTFDG.js.map +0 -1
- package/dist/chunk-P3MJYPZE.js.map +0 -1
- package/dist/chunk-RHMQPLIK.js.map +0 -1
- package/dist/chunk-RYRJEVQ4.js +0 -377
- package/dist/chunk-RYRJEVQ4.js.map +0 -1
- package/dist/chunk-SKADPHAM.js.map +0 -1
- package/dist/ensure-sources-4BAJGJRK.js.map +0 -1
- package/dist/helpers-2OL4FRFB.js +0 -22
- package/dist/open-library-RPV2LIKL.js +0 -29
- package/dist/source-22U5NOY4.js +0 -30
- package/dist/store-client-YLMBH5MF.js +0 -15
- package/dist/store-client-YLMBH5MF.js.map +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { AI_RESOURCES, aiResourceRoots } from '../chunk-2ZMO4CFG.js';
|
|
3
|
+
import { getStoreConfig, storeFetch, deviceLogin, loadStoreAuthConfig, logout, hasStoredAuth, isStoreAuthenticated, getStoreToken } from '../chunk-J5TI55E7.js';
|
|
4
|
+
import { makeSourceCommand, syncProjectSources } from '../chunk-WYGXYGJH.js';
|
|
5
|
+
import { openCatalogSource, openLibraryManager, createFullRegistry, openLibrary } from '../chunk-RSYV7XEN.js';
|
|
6
|
+
import { logErr, S, logOk, logInfo, colorRef, logWarn, kindColorPad, kindColor, formatSoftDepSection, bareSoftDepName, formatSoftDepHint, formatRelativeTime, fitWidth, formatSoftDepRemovePreview, formatSoftDepAddPreview } from '../chunk-KMY7HVQ6.js';
|
|
7
7
|
import { LocalSecretsProvider } from '../chunk-6BEGKO2Q.js';
|
|
8
|
-
import {
|
|
9
|
-
import '../chunk-BZMTR5WW.js';
|
|
10
|
-
import '../chunk-UKJMQZV6.js';
|
|
11
|
-
import '../chunk-R7FOF242.js';
|
|
12
|
-
import '../chunk-JXT46QFC.js';
|
|
13
|
-
import { runFlow, resumeFlow } from '../chunk-YXEPZ7LP.js';
|
|
8
|
+
import { runFlow, resumeFlow } from '../chunk-CNSNN7N6.js';
|
|
14
9
|
import '../chunk-4R6DROGN.js';
|
|
15
10
|
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-
|
|
11
|
+
import { runAgentChat, loadSessionById, loadSession, listSessions, setCurrentSession, deleteSession, clearSession, loadAgentManifest, compileComposition, MarkdownStreamer, resolveMixin } from '../chunk-BGIC25VK.js';
|
|
12
|
+
import { buildClaudePluginFiles } from '../chunk-RDYOU6N6.js';
|
|
18
13
|
import '../chunk-X5YPJV4N.js';
|
|
19
14
|
import '../chunk-O7SG5PC2.js';
|
|
20
15
|
import '../chunk-7QBNJTTQ.js';
|
|
@@ -22,38 +17,43 @@ import '../chunk-GTS2FODO.js';
|
|
|
22
17
|
import '../chunk-WQ7DE5UC.js';
|
|
23
18
|
import '../chunk-32NA4TVC.js';
|
|
24
19
|
import '../chunk-W3UDISS2.js';
|
|
25
|
-
import '../chunk-
|
|
26
|
-
import '../chunk-K5SD7FSF.js';
|
|
20
|
+
import '../chunk-HKX5VSWQ.js';
|
|
27
21
|
import '../chunk-ISQWMBKD.js';
|
|
22
|
+
import '../chunk-RRVQAE5D.js';
|
|
28
23
|
import '../chunk-BMQKMOQY.js';
|
|
29
24
|
import '../chunk-GAH4YRCI.js';
|
|
30
|
-
import '../chunk-
|
|
31
|
-
import '../chunk-SUOGVHGJ.js';
|
|
25
|
+
import '../chunk-TNSCHS4I.js';
|
|
32
26
|
import '../chunk-LV2HPH3C.js';
|
|
33
|
-
import '../chunk-
|
|
34
|
-
import '../chunk-
|
|
27
|
+
import '../chunk-DMG6NJH7.js';
|
|
28
|
+
import '../chunk-KEQ4GLVM.js';
|
|
35
29
|
import '../chunk-6E6PKKAD.js';
|
|
36
|
-
import { loadFlow, loadAllFlows } from '../chunk-
|
|
30
|
+
import { loadFlow, loadAllFlows } from '../chunk-4N5XR5DQ.js';
|
|
37
31
|
import '../chunk-DEYYRFQU.js';
|
|
38
32
|
import '../chunk-IFGTRL2I.js';
|
|
39
|
-
import
|
|
40
|
-
import '../chunk-
|
|
41
|
-
import {
|
|
42
|
-
import '../chunk-
|
|
43
|
-
import
|
|
44
|
-
import
|
|
33
|
+
import '../chunk-PK7Q7MC7.js';
|
|
34
|
+
import { AssetManager, NON_DEPLOYABLE_KINDS, MissingManifestError, normalizeRepoUrl, FACTORY_SOURCE_URL } from '../chunk-3CHARYD4.js';
|
|
35
|
+
import { resolveLibraryDir, getStoreManifestsDir, getDefaultValue, isSecretPlaceholder } from '../chunk-FDE7XRQA.js';
|
|
36
|
+
import '../chunk-MZV6WCF3.js';
|
|
37
|
+
import '../chunk-JXT46QFC.js';
|
|
38
|
+
import '../chunk-UKJMQZV6.js';
|
|
39
|
+
import '../chunk-R7FOF242.js';
|
|
40
|
+
import '../chunk-6NR2BEIY.js';
|
|
41
|
+
import '../chunk-CGYEHQOX.js';
|
|
42
|
+
import { readLock, resolveSettings, globalSettingsPath, projectSettingsPath, loadSettings, saveSettings, portableSpawn, portableSpawnSync, WorkspaceYamlEditor, checkAgentSkillConformance } from '../chunk-HY33RMEA.js';
|
|
43
|
+
import { assetSearchDirs, detectDomains } from '../chunk-ZAP2BDHG.js';
|
|
44
|
+
import { factoryAssetRoots } from '../chunk-ZBZQC5R7.js';
|
|
45
|
+
import { globalCacheRoot, sourceCacheKey, getGlobalCacheDir, resolveAgentDir, loadSkWorkspaceConfig, resolveSkWorkspaceConfig, storeManifestSlug } from '../chunk-UQKYT4V6.js';
|
|
46
|
+
import { SKAILE_MANIFEST_FILENAME, decodeSkaileManifest, loadSkPublishManifest, saveSkPublishManifest } from '../chunk-P4VHQA4N.js';
|
|
45
47
|
import { parseFrontmatter } from '../chunk-BQCGFPHW.js';
|
|
46
48
|
import { parseAssetRef, ASSET_KINDS, isValidAssetName, slugifyAssetName, ASSET_NAME_HINT, assetRefToStr } from '../chunk-GEEW6SY2.js';
|
|
47
49
|
import '../chunk-F3HNW354.js';
|
|
48
50
|
import { SUPPORTED_DRIVER_TARGETS } from '../chunk-MENCWIHW.js';
|
|
49
51
|
import { DRIVER_DEFAULTS } from '../chunk-K5GBV4SA.js';
|
|
50
|
-
import { assetSearchDirs, detectDomains } from '../chunk-ZAP2BDHG.js';
|
|
51
52
|
import { openSqlite } from '../chunk-JB35MVBN.js';
|
|
52
53
|
import '../chunk-KTBKW2FI.js';
|
|
53
54
|
import '../chunk-UQ6LFBPZ.js';
|
|
54
|
-
import '../chunk-
|
|
55
|
-
import '../chunk-
|
|
56
|
-
import '../chunk-CGYEHQOX.js';
|
|
55
|
+
import '../chunk-IEX5YV4R.js';
|
|
56
|
+
import { validatePreset } from '../chunk-IRORTHGA.js';
|
|
57
57
|
import '../chunk-NSBPE2FW.js';
|
|
58
58
|
import * as fs12 from 'fs';
|
|
59
59
|
import fs12__default, { readFileSync, existsSync, mkdirSync, writeFileSync, lstatSync, rmSync, readdirSync, statSync } from 'fs';
|
|
@@ -71,8 +71,22 @@ import { createInterface } from 'readline';
|
|
|
71
71
|
import fs6 from 'fs/promises';
|
|
72
72
|
import { parse as parse$1, stringify as stringify$1 } from 'smol-toml';
|
|
73
73
|
import { execSync } from 'child_process';
|
|
74
|
+
import * as readline2 from 'readline/promises';
|
|
74
75
|
import { createTRPCUntypedClient, httpLink, httpSubscriptionLink } from '@trpc/client';
|
|
75
76
|
|
|
77
|
+
function catalogAssetRef(a) {
|
|
78
|
+
return `${a.kind}:@${a.publisher}/${a.name}#${a.version}`;
|
|
79
|
+
}
|
|
80
|
+
function localEntryRef(e) {
|
|
81
|
+
return e.publisher ? `${e.kind}:@${e.publisher}/${e.name}` : e.name;
|
|
82
|
+
}
|
|
83
|
+
function filterCatalogAssets(assets, query) {
|
|
84
|
+
if (!query) return assets;
|
|
85
|
+
const q = query.toLowerCase();
|
|
86
|
+
return assets.filter(
|
|
87
|
+
(a) => a.name.toLowerCase().includes(q) || (a.description?.toLowerCase().includes(q) ?? false) || a.publisher.toLowerCase().includes(q)
|
|
88
|
+
);
|
|
89
|
+
}
|
|
76
90
|
async function runSearch(kind, query, opts) {
|
|
77
91
|
if (kind?.includes(":")) {
|
|
78
92
|
query = kind;
|
|
@@ -89,19 +103,68 @@ async function runSearch(kind, query, opts) {
|
|
|
89
103
|
await searchStore(query, kind, opts, airGapped);
|
|
90
104
|
}
|
|
91
105
|
}
|
|
106
|
+
async function searchIndex(query, kind) {
|
|
107
|
+
const { openLibrary: openLibrary2 } = await import('../open-library-4HMIDK3N.js');
|
|
108
|
+
const library = await openLibrary2();
|
|
109
|
+
try {
|
|
110
|
+
const defs = await library.listAssetDefs(kind ? { kind } : {});
|
|
111
|
+
let entries = defs.map(
|
|
112
|
+
(d) => ({
|
|
113
|
+
name: d.name,
|
|
114
|
+
kind: d.kind,
|
|
115
|
+
description: d.description ?? "",
|
|
116
|
+
source: d.id,
|
|
117
|
+
// Stored publishers may carry the `@` scope sigil (manifest-mode rows);
|
|
118
|
+
// `localEntryRef` re-adds it, so strip here to avoid `@@`.
|
|
119
|
+
publisher: d.publisher ? d.publisher.replace(/^@/, "") : void 0,
|
|
120
|
+
version: d.version,
|
|
121
|
+
requires: [],
|
|
122
|
+
dependencies: [],
|
|
123
|
+
license: d.license,
|
|
124
|
+
category: d.category
|
|
125
|
+
})
|
|
126
|
+
);
|
|
127
|
+
if (query) {
|
|
128
|
+
const q = query.toLowerCase();
|
|
129
|
+
entries = entries.filter(
|
|
130
|
+
(e) => e.name.toLowerCase().includes(q) || e.description.toLowerCase().includes(q)
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
return entries;
|
|
134
|
+
} finally {
|
|
135
|
+
library.close();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function searchFactory(projectDir, query, kind) {
|
|
139
|
+
const prefixes = factoryAssetRoots().map((r) => r.endsWith(path14__default.sep) ? r : r + path14__default.sep);
|
|
140
|
+
const isFactoryPath = (p8) => prefixes.some((fp) => p8 === fp.slice(0, -1) || p8.startsWith(fp));
|
|
141
|
+
try {
|
|
142
|
+
return new AssetManager({ projectDir }).search(query, kind).filter((e) => isFactoryPath(e.source));
|
|
143
|
+
} catch {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function entryDedupKey(e) {
|
|
148
|
+
return `${e.kind}:${e.publisher ? `@${e.publisher}/` : ""}${e.name}`;
|
|
149
|
+
}
|
|
150
|
+
function unionEntries(indexed, factory) {
|
|
151
|
+
const seen = new Set(indexed.map(entryDedupKey));
|
|
152
|
+
return [...indexed, ...factory.filter((e) => !seen.has(entryDedupKey(e)))];
|
|
153
|
+
}
|
|
92
154
|
async function searchLocal(query, kind, opts, showStore, airGapped) {
|
|
93
155
|
const projectDir = path14__default.resolve(opts.projectDir);
|
|
94
|
-
|
|
156
|
+
const factory = searchFactory(projectDir, query, kind);
|
|
157
|
+
let entries = unionEntries(await searchIndex(query, kind), factory);
|
|
95
158
|
if (entries.length === 0 && !query && !kind && !airGapped) {
|
|
96
|
-
const { autoSyncForSearch } = await import('../source-
|
|
159
|
+
const { autoSyncForSearch } = await import('../source-LOAM7IIQ.js');
|
|
97
160
|
if (await autoSyncForSearch(projectDir)) {
|
|
98
|
-
entries =
|
|
161
|
+
entries = unionEntries(await searchIndex(query, kind), factory);
|
|
99
162
|
}
|
|
100
163
|
}
|
|
101
164
|
if (entries.length === 0) {
|
|
102
165
|
if (!showStore) {
|
|
103
166
|
logInfo(
|
|
104
|
-
query ? `No entries matching "${query}".` : "No assets found. Run `skaile source sync` first."
|
|
167
|
+
query ? `No entries matching "${query}".` : kind ? `No "${kind}" assets found in this project's sources.` : "No assets found. Run `skaile source sync` first."
|
|
105
168
|
);
|
|
106
169
|
}
|
|
107
170
|
return;
|
|
@@ -119,7 +182,7 @@ function printLocalEntries(entries) {
|
|
|
119
182
|
byKind.get(e.kind).push(e);
|
|
120
183
|
}
|
|
121
184
|
for (const [k, items] of byKind) {
|
|
122
|
-
const nameW = Math.max(4, ...items.map((e) => e.
|
|
185
|
+
const nameW = Math.max(4, ...items.map((e) => localEntryRef(e).length));
|
|
123
186
|
console.log();
|
|
124
187
|
console.log(
|
|
125
188
|
` ${kindColor(k)} ${S.heading(`${k.toUpperCase()}S`)} ${S.dim(`(${items.length})`)}`
|
|
@@ -127,7 +190,9 @@ function printLocalEntries(entries) {
|
|
|
127
190
|
console.log(` ${S.rule(nameW + 62)}`);
|
|
128
191
|
for (const e of items) {
|
|
129
192
|
const ver = e.version ? S.dim(` v${e.version}`) : "";
|
|
130
|
-
console.log(
|
|
193
|
+
console.log(
|
|
194
|
+
` ${S.cmd(localEntryRef(e).padEnd(nameW))} ${e.description.slice(0, 60)}${ver}`
|
|
195
|
+
);
|
|
131
196
|
}
|
|
132
197
|
}
|
|
133
198
|
console.log(`
|
|
@@ -145,30 +210,33 @@ async function searchStore(query, kind, opts, airGapped) {
|
|
|
145
210
|
logInfo("air-gapped (cache_ttl: 0) \u2014 local sources only");
|
|
146
211
|
return;
|
|
147
212
|
}
|
|
213
|
+
const { openCatalogSource: openCatalogSource2, LocalCatalogDisabledError } = await import('../open-library-4HMIDK3N.js');
|
|
148
214
|
try {
|
|
149
|
-
const
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
153
|
-
if (kind) params.kind = kind;
|
|
154
|
-
const storeRes = await storeFetch2(config, "/api/assets", { params });
|
|
155
|
-
if (storeRes.results.length > 0) {
|
|
215
|
+
const remote = await openCatalogSource2({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
216
|
+
const assets = await remote.listAssets(kind ? { kind } : {});
|
|
217
|
+
const results = filterCatalogAssets(assets, query);
|
|
218
|
+
if (results.length > 0) {
|
|
156
219
|
console.log(`
|
|
157
220
|
${S.heading("Store:")}`);
|
|
158
|
-
for (const asset of
|
|
159
|
-
const ref =
|
|
221
|
+
for (const asset of results) {
|
|
222
|
+
const ref = catalogAssetRef(asset);
|
|
160
223
|
console.log(
|
|
161
|
-
` \u2B21 ${kindColorPad(asset.kind)} ${colorRef(ref).padEnd(
|
|
224
|
+
` \u2B21 ${kindColorPad(asset.kind)} ${colorRef(ref).padEnd(48)} ${S.dim(asset.description?.slice(0, 50) || "")}`
|
|
162
225
|
);
|
|
163
226
|
}
|
|
164
227
|
} else if (opts.store) {
|
|
165
228
|
logInfo("No results in store");
|
|
166
229
|
}
|
|
167
230
|
} catch (e) {
|
|
231
|
+
const local = e instanceof LocalCatalogDisabledError;
|
|
168
232
|
if (opts.store) {
|
|
169
|
-
logErr(
|
|
233
|
+
logErr(
|
|
234
|
+
local ? "remote catalog disabled (catalog.url: local) \u2014 set catalog.url: https://skaile.store to search the store" : `Store search failed: ${e.message}`
|
|
235
|
+
);
|
|
170
236
|
} else {
|
|
171
|
-
logInfo(
|
|
237
|
+
logInfo(
|
|
238
|
+
local ? "remote catalog disabled (catalog.url: local) \u2014 showing local results only" : "store unavailable \u2014 showing local results only (run with --store to see the error)"
|
|
239
|
+
);
|
|
172
240
|
}
|
|
173
241
|
}
|
|
174
242
|
}
|
|
@@ -1006,7 +1074,7 @@ function makeCatalogCommand() {
|
|
|
1006
1074
|
return catalog;
|
|
1007
1075
|
}
|
|
1008
1076
|
async function runLocalCatalogTest(projectDir) {
|
|
1009
|
-
const { resolveCatalogSource } = await import('../open-library-
|
|
1077
|
+
const { resolveCatalogSource } = await import('../open-library-4HMIDK3N.js');
|
|
1010
1078
|
let resolved;
|
|
1011
1079
|
try {
|
|
1012
1080
|
resolved = await resolveCatalogSource({ projectDir });
|
|
@@ -1625,8 +1693,8 @@ async function promptField(field) {
|
|
|
1625
1693
|
function makeConnectorCommand() {
|
|
1626
1694
|
const cmd = new Command("connector").description("Operate on connectors in a workspace");
|
|
1627
1695
|
cmd.command("catalog").description("List all available connector drivers and their dependencies").action(async () => {
|
|
1628
|
-
const { scanDirectory, factoryAssetRoots } = await import('../core/index.js');
|
|
1629
|
-
const entries = scanFactoryConnectors(scanDirectory,
|
|
1696
|
+
const { scanDirectory, factoryAssetRoots: factoryAssetRoots2 } = await import('../core/index.js');
|
|
1697
|
+
const entries = scanFactoryConnectors(scanDirectory, factoryAssetRoots2());
|
|
1630
1698
|
if (entries.length === 0) {
|
|
1631
1699
|
console.log("No connector descriptors found.");
|
|
1632
1700
|
return;
|
|
@@ -1650,14 +1718,14 @@ function makeConnectorCommand() {
|
|
|
1650
1718
|
cmd.command("add <driver>").option("--id <id>", "Connector instance ID (defaults to driver name)").option("--access <level>", "Access level: read-only | read-write", "read-only").option("--no-install", "Skip npm dependency installation").option("--project-dir <path>", "Workspace directory", process.cwd()).description("Add a connector to skaile.yaml and install its npm deps").action(
|
|
1651
1719
|
async (driver, opts) => {
|
|
1652
1720
|
const { installNpmPackages } = await import('../connectors/index.js');
|
|
1653
|
-
const { scanDirectory, factoryAssetRoots, WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
|
|
1721
|
+
const { scanDirectory, factoryAssetRoots: factoryAssetRoots2, WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
|
|
1654
1722
|
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1655
1723
|
const yamlPath = path14__default.join(projectDir, "skaile.yaml");
|
|
1656
1724
|
if (!existsSync(yamlPath)) {
|
|
1657
1725
|
logErr("No skaile.yaml found in current directory. Run 'skaile init' first.");
|
|
1658
1726
|
process.exit(1);
|
|
1659
1727
|
}
|
|
1660
|
-
const entries = scanFactoryConnectors(scanDirectory,
|
|
1728
|
+
const entries = scanFactoryConnectors(scanDirectory, factoryAssetRoots2());
|
|
1661
1729
|
const entry = entries.find((e) => e.name === driver);
|
|
1662
1730
|
if (!entry) {
|
|
1663
1731
|
logErr(
|
|
@@ -1996,7 +2064,7 @@ async function ensureTargetsRegistered(projectDir) {
|
|
|
1996
2064
|
const { resolveSkWorkspaceConfig: resolveSkWorkspaceConfig2 } = await import('../core/index.js');
|
|
1997
2065
|
const config = resolveSkWorkspaceConfig2(projectDir);
|
|
1998
2066
|
if (config.plugins && config.plugins.length > 0) {
|
|
1999
|
-
const { ensurePluginsLoaded } = await import('../plugin-store-
|
|
2067
|
+
const { ensurePluginsLoaded } = await import('../plugin-store-S7OMGI7N.js');
|
|
2000
2068
|
const result = await ensurePluginsLoaded(projectDir, config.plugins, pluginRegistry);
|
|
2001
2069
|
for (const f of result.failed) logWarn(f.error);
|
|
2002
2070
|
}
|
|
@@ -2801,11 +2869,6 @@ function makeIntegrationCommand() {
|
|
|
2801
2869
|
cmd.action(() => cmd.help());
|
|
2802
2870
|
return cmd;
|
|
2803
2871
|
}
|
|
2804
|
-
var NOT_WIRED_MSG_PUBLISH = "`skaile library publish` is scaffolded but not yet wired. Server endpoint `POST /sources/<id>/manifest` lands in a follow-up PR.";
|
|
2805
|
-
function notWired(verb, msg) {
|
|
2806
|
-
logErr(`${msg} (verb: library ${verb})`);
|
|
2807
|
-
process.exit(2);
|
|
2808
|
-
}
|
|
2809
2872
|
function makeLibraryCommand() {
|
|
2810
2873
|
const cmd = new Command("library").description("Manage user authoring libraries (local / git)");
|
|
2811
2874
|
cmd.command("list").description("List all registered libraries").option("--json", "Output as JSON").action(async (opts) => {
|
|
@@ -3181,9 +3244,20 @@ function makeLibraryCommand() {
|
|
|
3181
3244
|
close();
|
|
3182
3245
|
}
|
|
3183
3246
|
});
|
|
3184
|
-
cmd.command("publish <
|
|
3185
|
-
|
|
3186
|
-
|
|
3247
|
+
cmd.command("publish <lib>").description("Push + register the library's manifest atomically (needs git backend)").option("--asset <ref>", "Publish only the single asset matching this ref/name").option("--create-repo", "Provision + link a public github repo if the library has no remote").option("--ref <gitref>", "Git ref to ingest (default: the library branch or main)").option("--dry-run", "Print the plan; push nothing and call no store endpoint").action(
|
|
3248
|
+
async (lib, opts) => {
|
|
3249
|
+
const { runLibraryPublish } = await import('../library-publish-K5IBE44D.js');
|
|
3250
|
+
await runLibraryPublish(lib, opts);
|
|
3251
|
+
}
|
|
3252
|
+
);
|
|
3253
|
+
cmd.command("register <lib>").description("Register the library's manifest without pushing (bytes already on github)").option("--asset <ref>", "Publish only the single asset matching this ref/name").option("--ref <gitref>", "Git ref to ingest (default: the library branch or main)").option("--dry-run", "Print the plan; call no store endpoint").action(async (lib, opts) => {
|
|
3254
|
+
const { runLibraryRegister } = await import('../library-publish-K5IBE44D.js');
|
|
3255
|
+
await runLibraryRegister(lib, opts);
|
|
3256
|
+
});
|
|
3257
|
+
cmd.command("yank <lib>").description("Retract the library's published assets from the store").option("--asset <ref>", "Yank only the single asset matching this ref/name").action(async (lib, opts) => {
|
|
3258
|
+
const { runLibraryYank } = await import('../library-publish-K5IBE44D.js');
|
|
3259
|
+
await runLibraryYank(lib, opts);
|
|
3260
|
+
});
|
|
3187
3261
|
return cmd;
|
|
3188
3262
|
}
|
|
3189
3263
|
async function printPerLibraryStatus(name, asJson) {
|
|
@@ -3712,7 +3786,7 @@ async function previewSoftDepsUnderCursor() {
|
|
|
3712
3786
|
}
|
|
3713
3787
|
async function loadAssets() {
|
|
3714
3788
|
softDepPreviewCache.clear();
|
|
3715
|
-
const { gatherAssetFeeds } = await import('../asset-feeds-
|
|
3789
|
+
const { gatherAssetFeeds } = await import('../asset-feeds-T35ELX2O.js');
|
|
3716
3790
|
const { entries, domains, notes } = await gatherAssetFeeds(am, am.projectDir);
|
|
3717
3791
|
if (notes.length > 0) {
|
|
3718
3792
|
state.message = notes.map((n) => `[${n.feed}] ${n.message}`).join(" \u2022 ");
|
|
@@ -3879,7 +3953,7 @@ function reconcileCollapsedSets(rows) {
|
|
|
3879
3953
|
async function loadSourcesAndLibraries() {
|
|
3880
3954
|
try {
|
|
3881
3955
|
const [{ openLibraryManager: openLibraryManager2 }, { skaileHomeDir }, { getGlobalCacheDir: getGlobalCacheDir2 }] = await Promise.all([
|
|
3882
|
-
import('../open-library-
|
|
3956
|
+
import('../open-library-4HMIDK3N.js'),
|
|
3883
3957
|
import('../library/index.js'),
|
|
3884
3958
|
import('../core/index.js')
|
|
3885
3959
|
]);
|
|
@@ -4748,8 +4822,8 @@ function makeManageCommand() {
|
|
|
4748
4822
|
}
|
|
4749
4823
|
function makeMcpServerCommand() {
|
|
4750
4824
|
return new Command("mcp-server").description("Start skaile workspace MCP server (stdio transport)").option("--project-dir <path>", "Project directory (default: cwd)", process.cwd()).action(async (opts) => {
|
|
4751
|
-
const
|
|
4752
|
-
const projectDir =
|
|
4825
|
+
const path37 = await import('path');
|
|
4826
|
+
const projectDir = path37.default.resolve(opts.projectDir);
|
|
4753
4827
|
const { LogStore, StdoutSink, registerLogStore } = await import('../core/logging.js');
|
|
4754
4828
|
registerLogStore(
|
|
4755
4829
|
new LogStore({
|
|
@@ -4965,7 +5039,7 @@ function action2(fn) {
|
|
|
4965
5039
|
};
|
|
4966
5040
|
}
|
|
4967
5041
|
async function reconcileAndReport(projectDir, plugins) {
|
|
4968
|
-
const { reconcilePlugins } = await import('../plugin-store-
|
|
5042
|
+
const { reconcilePlugins } = await import('../plugin-store-S7OMGI7N.js');
|
|
4969
5043
|
if (plugins.length === 0) {
|
|
4970
5044
|
logInfo("No plugins declared \u2014 nothing to reconcile.");
|
|
4971
5045
|
return;
|
|
@@ -4981,7 +5055,7 @@ async function reconcileAndReport(projectDir, plugins) {
|
|
|
4981
5055
|
async function runInstall2(spec, opts) {
|
|
4982
5056
|
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4983
5057
|
const { WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
|
|
4984
|
-
const { specName } = await import('../plugin-store-
|
|
5058
|
+
const { specName } = await import('../plugin-store-S7OMGI7N.js');
|
|
4985
5059
|
const yamlPath = path14__default.join(projectDir, "skaile.yaml");
|
|
4986
5060
|
const editor = WorkspaceYamlEditor2.load(yamlPath);
|
|
4987
5061
|
const replaced = editor.addPlugin(spec, specName);
|
|
@@ -4993,7 +5067,7 @@ async function runInstall2(spec, opts) {
|
|
|
4993
5067
|
async function runRemove(name, opts) {
|
|
4994
5068
|
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4995
5069
|
const { WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
|
|
4996
|
-
const { specName } = await import('../plugin-store-
|
|
5070
|
+
const { specName } = await import('../plugin-store-S7OMGI7N.js');
|
|
4997
5071
|
const yamlPath = path14__default.join(projectDir, "skaile.yaml");
|
|
4998
5072
|
const editor = WorkspaceYamlEditor2.load(yamlPath);
|
|
4999
5073
|
const removed = editor.removePlugin(name, specName);
|
|
@@ -5021,7 +5095,7 @@ async function runList(opts) {
|
|
|
5021
5095
|
const registry = createPluginRegistry();
|
|
5022
5096
|
if (declared.length > 0) {
|
|
5023
5097
|
try {
|
|
5024
|
-
const { loadPlugins } = await import('../plugin-store-
|
|
5098
|
+
const { loadPlugins } = await import('../plugin-store-S7OMGI7N.js');
|
|
5025
5099
|
const result = await loadPlugins(projectDir, declared, registry);
|
|
5026
5100
|
for (const f of result.failed) logWarn(f.error);
|
|
5027
5101
|
} catch (err) {
|
|
@@ -5055,150 +5129,93 @@ function makePluginCommand() {
|
|
|
5055
5129
|
cmd.action(() => cmd.help());
|
|
5056
5130
|
return cmd;
|
|
5057
5131
|
}
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
async function loadPresetForValidation(resolved) {
|
|
5082
|
-
if (!existsSync(resolved)) {
|
|
5083
|
-
logErr(`File not found: ${resolved}`);
|
|
5084
|
-
process.exit(1);
|
|
5085
|
-
}
|
|
5086
|
-
const content = readFileSync(resolved, "utf-8");
|
|
5087
|
-
const { parsePresetYaml } = await import('../library/index.js');
|
|
5088
|
-
const parseResult = parsePresetYaml(content);
|
|
5089
|
-
if (!parseResult.ok) {
|
|
5090
|
-
logErr("Preset validation failed (parse errors):");
|
|
5091
|
-
for (const err of parseResult.errors) {
|
|
5092
|
-
console.log(` ${S.err("\u2717")} ${err}`);
|
|
5093
|
-
}
|
|
5094
|
-
process.exit(1);
|
|
5095
|
-
}
|
|
5096
|
-
if (!parseResult.preset) {
|
|
5097
|
-
logErr("Preset validation failed: parser returned no manifest");
|
|
5098
|
-
process.exit(1);
|
|
5099
|
-
}
|
|
5100
|
-
return parseResult.preset;
|
|
5101
|
-
}
|
|
5102
|
-
async function reportNestedPresetRefs(preset) {
|
|
5103
|
-
const { detectNestedPresetRefs } = await import('../library/index.js');
|
|
5104
|
-
const nestedRefs = detectNestedPresetRefs(preset);
|
|
5105
|
-
if (nestedRefs.length > 0) {
|
|
5106
|
-
logInfo(`Nested preset refs: ${nestedRefs.length} (depth validated at apply-time)`);
|
|
5107
|
-
}
|
|
5108
|
-
}
|
|
5109
|
-
async function checkPresetCycles(preset, resolved) {
|
|
5110
|
-
const { detectCycles } = await import('../discovery/index.js');
|
|
5111
|
-
const presetRef = path14__default.basename(resolved, ".preset.yaml");
|
|
5112
|
-
const edges = [];
|
|
5132
|
+
|
|
5133
|
+
// cli/src/commands/preset-apply.ts
|
|
5134
|
+
var TOKEN_RE = /\$\{(INPUT|SECRET):([^}]+)\}/g;
|
|
5135
|
+
var NESTED_PRESET_UNSUPPORTED = "nested presets are not supported by `preset apply` yet";
|
|
5136
|
+
function resolvePlaceholderValue(placeholder, providedValue) {
|
|
5137
|
+
if (isSecretPlaceholder(placeholder)) {
|
|
5138
|
+
return { envRef: `env:${placeholder.key}` };
|
|
5139
|
+
}
|
|
5140
|
+
const fallback = getDefaultValue(placeholder);
|
|
5141
|
+
const resolved = providedValue ?? (fallback !== void 0 ? String(fallback) : void 0);
|
|
5142
|
+
if (resolved === void 0) {
|
|
5143
|
+
if (placeholder.required !== false) {
|
|
5144
|
+
throw new Error(`Placeholder "${placeholder.key}" is required but no value was provided`);
|
|
5145
|
+
}
|
|
5146
|
+
return { value: "" };
|
|
5147
|
+
}
|
|
5148
|
+
return { value: resolved };
|
|
5149
|
+
}
|
|
5150
|
+
function presetItemsToWorkspace(preset, values) {
|
|
5151
|
+
const dependencies = [];
|
|
5152
|
+
const connectors = [];
|
|
5153
|
+
const mcpServers = [];
|
|
5154
|
+
const envVarsToSet = /* @__PURE__ */ new Set();
|
|
5113
5155
|
for (const item of preset.items) {
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5156
|
+
const ref = item.ref;
|
|
5157
|
+
if (ref.startsWith("preset:")) throw new Error(NESTED_PRESET_UNSUPPORTED);
|
|
5158
|
+
if (item.id && ref.startsWith("connector:")) {
|
|
5159
|
+
const config = resolveItemConfig(item, preset, values, envVarsToSet);
|
|
5160
|
+
connectors.push({
|
|
5161
|
+
id: item.id,
|
|
5162
|
+
driver: ref.slice("connector:".length),
|
|
5163
|
+
...config
|
|
5164
|
+
});
|
|
5165
|
+
} else if (item.id && ref.startsWith("mcp:")) {
|
|
5166
|
+
const config = resolveItemConfig(item, preset, values, envVarsToSet);
|
|
5167
|
+
mcpServers.push({ id: item.id, ...config });
|
|
5168
|
+
} else {
|
|
5169
|
+
dependencies.push(ref);
|
|
5124
5170
|
}
|
|
5125
|
-
process.exit(1);
|
|
5126
5171
|
}
|
|
5172
|
+
const sources = (preset.sources ?? []).map(
|
|
5173
|
+
(s) => s.pin ? { url: s.url, pin: s.pin } : { url: s.url }
|
|
5174
|
+
);
|
|
5175
|
+
return { dependencies, connectors, mcpServers, sources, envVarsToSet: [...envVarsToSet] };
|
|
5127
5176
|
}
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
const
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5177
|
+
function resolveItemConfig(item, preset, values, envVarsToSet) {
|
|
5178
|
+
const byKey = placeholderIndex(item, preset);
|
|
5179
|
+
const resolve5 = (key) => {
|
|
5180
|
+
const ph = byKey.get(key) ?? { key, type: "text", required: true };
|
|
5181
|
+
return resolvePlaceholderValue(ph, values[key]);
|
|
5182
|
+
};
|
|
5183
|
+
return substituteNode(item.config ?? {}, resolve5, envVarsToSet);
|
|
5184
|
+
}
|
|
5185
|
+
function placeholderIndex(item, preset) {
|
|
5186
|
+
const map = /* @__PURE__ */ new Map();
|
|
5187
|
+
for (const input of preset.inputs ?? []) map.set(input.key, input);
|
|
5188
|
+
for (const ph of item.placeholders ?? []) map.set(ph.key, ph);
|
|
5189
|
+
return map;
|
|
5190
|
+
}
|
|
5191
|
+
function substituteNode(node, resolve5, envVarsToSet) {
|
|
5192
|
+
if (typeof node === "string") return substituteString(node, resolve5, envVarsToSet);
|
|
5193
|
+
if (Array.isArray(node)) return node.map((el) => substituteNode(el, resolve5, envVarsToSet));
|
|
5194
|
+
if (node && typeof node === "object") {
|
|
5195
|
+
const out = {};
|
|
5196
|
+
for (const [k, v] of Object.entries(node)) out[k] = substituteNode(v, resolve5, envVarsToSet);
|
|
5197
|
+
return out;
|
|
5198
|
+
}
|
|
5199
|
+
return node;
|
|
5200
|
+
}
|
|
5201
|
+
function substituteString(value, resolve5, envVarsToSet) {
|
|
5202
|
+
const tokens = [...value.matchAll(TOKEN_RE)];
|
|
5203
|
+
if (tokens.length === 0) return value;
|
|
5204
|
+
const secret = tokens.find(([, ns]) => ns === "SECRET") ?? tokens.find(([, , key]) => "envRef" in resolve5(key));
|
|
5205
|
+
if (secret) {
|
|
5206
|
+
const [full, , key] = secret;
|
|
5207
|
+
if (tokens.length > 1 || full !== value) {
|
|
5208
|
+
throw new Error(
|
|
5209
|
+
`Secret "${key}" must be the only token in its value \u2014 remove the surrounding tokens/text`
|
|
5210
|
+
);
|
|
5136
5211
|
}
|
|
5212
|
+
envVarsToSet.add(key);
|
|
5213
|
+
return `env:${key}`;
|
|
5137
5214
|
}
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
}
|
|
5143
|
-
return true;
|
|
5144
|
-
}
|
|
5145
|
-
function printPresetSummary(preset, placeholderCount, hasWarnings) {
|
|
5146
|
-
console.log();
|
|
5147
|
-
console.log(S.heading(" Preset Validation"));
|
|
5148
|
-
console.log(` ${S.rule(40)}`);
|
|
5149
|
-
console.log(` ${S.label("Name")} ${preset.name}`);
|
|
5150
|
-
console.log(` ${S.label("Version")} ${preset.version ?? "unversioned"}`);
|
|
5151
|
-
console.log(` ${S.label("Items")} ${preset.items.length}`);
|
|
5152
|
-
console.log(` ${S.label("Inputs")} ${preset.inputs?.length ?? 0}`);
|
|
5153
|
-
console.log(` ${S.label("Placeholders")} ${placeholderCount}`);
|
|
5154
|
-
console.log();
|
|
5155
|
-
if (hasWarnings) {
|
|
5156
|
-
logWarn("Validation passed with warnings");
|
|
5157
|
-
} else {
|
|
5158
|
-
logOk("Preset is valid");
|
|
5159
|
-
}
|
|
5160
|
-
}
|
|
5161
|
-
async function runPresetValidate(filePath) {
|
|
5162
|
-
const resolved = path14__default.resolve(filePath);
|
|
5163
|
-
const preset = await loadPresetForValidation(resolved);
|
|
5164
|
-
await reportNestedPresetRefs(preset);
|
|
5165
|
-
await checkPresetCycles(preset, resolved);
|
|
5166
|
-
const allPlaceholders = preset.items.flatMap((item) => item.placeholders ?? []);
|
|
5167
|
-
const hasWarnings = await checkPresetPlaceholders(allPlaceholders);
|
|
5168
|
-
printPresetSummary(preset, allPlaceholders.length, hasWarnings);
|
|
5169
|
-
}
|
|
5170
|
-
function generatePresetTemplate(name) {
|
|
5171
|
-
return `# ${name}.preset.yaml
|
|
5172
|
-
# Polymorphic Preset \u2014 composition + configuration primitive for the asset store.
|
|
5173
|
-
# See: _devlog/specs/2026-05-03-ai-asset-store-v2-design.md \xA7 Presets
|
|
5174
|
-
|
|
5175
|
-
name: "${name}"
|
|
5176
|
-
version: "1.0.0"
|
|
5177
|
-
description: "TODO: describe what this preset configures"
|
|
5178
|
-
|
|
5179
|
-
# Placeholders \u2014 values the user provides at apply-time.
|
|
5180
|
-
# Types: text, multiline, secret, number, boolean, enum, oauth, instance-picker
|
|
5181
|
-
placeholders:
|
|
5182
|
-
- key: EXAMPLE_KEY
|
|
5183
|
-
type: text
|
|
5184
|
-
label: "Example placeholder"
|
|
5185
|
-
required: true
|
|
5186
|
-
# default: "some-value"
|
|
5187
|
-
# hint: "Help text shown to the user"
|
|
5188
|
-
|
|
5189
|
-
# Items \u2014 each becomes a Library Instance when the preset is applied.
|
|
5190
|
-
# Ref types:
|
|
5191
|
-
# - Asset ref (kind:publisher/name@pin) \u2192 creates new Instance
|
|
5192
|
-
# - Library Instance ref (#uuid) \u2192 reuses existing Instance
|
|
5193
|
-
# - Nested Preset ref (preset:path.preset.yaml) \u2192 recursive apply (max depth 3)
|
|
5194
|
-
items:
|
|
5195
|
-
- id: example-item
|
|
5196
|
-
ref: "skill:@skaile/example-skill@^1.0"
|
|
5197
|
-
config:
|
|
5198
|
-
# Use \${INPUT:EXAMPLE_KEY} for placeholder interpolation
|
|
5199
|
-
setting: "\${INPUT:EXAMPLE_KEY}"
|
|
5200
|
-
# credential_ref: "\${SECRET:EXAMPLE_KEY}" # for secret placeholders
|
|
5201
|
-
`;
|
|
5215
|
+
return value.replace(TOKEN_RE, (_m, _ns, key) => {
|
|
5216
|
+
const resolved = resolve5(key);
|
|
5217
|
+
return "envRef" in resolved ? resolved.envRef : resolved.value;
|
|
5218
|
+
});
|
|
5202
5219
|
}
|
|
5203
5220
|
var REF_HINT = "kind:@<publisher>/<name>#<version> (e.g. skill:@skaile/use-exa#1.0.0)";
|
|
5204
5221
|
function isValidAssetRef(ref) {
|
|
@@ -5275,7 +5292,7 @@ async function runRefInstall(ref, opts) {
|
|
|
5275
5292
|
const spinner5 = p6.spinner();
|
|
5276
5293
|
spinner5.start(`Installing ${ref}`);
|
|
5277
5294
|
try {
|
|
5278
|
-
const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-
|
|
5295
|
+
const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-4HMIDK3N.js');
|
|
5279
5296
|
const catalog = await openCatalogSource2({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
5280
5297
|
if (!supportsInstallManifest(catalog)) {
|
|
5281
5298
|
throw new Error(
|
|
@@ -5290,6 +5307,9 @@ async function runRefInstall(ref, opts) {
|
|
|
5290
5307
|
logInfo(`Path: ${S.dim(result.installPath)}`);
|
|
5291
5308
|
logInfo(`Commit: ${S.dim(result.commitSha)}`);
|
|
5292
5309
|
logInfo(`Files: ${S.dim(String(result.fileCount))}`);
|
|
5310
|
+
logInfo(
|
|
5311
|
+
S.dim(`Installed globally (see Path above) \u2014 use \`skaile add ${ref}\` to deploy into this project.`)
|
|
5312
|
+
);
|
|
5293
5313
|
} finally {
|
|
5294
5314
|
library.close();
|
|
5295
5315
|
}
|
|
@@ -5312,7 +5332,7 @@ async function runYamlInstall(opts) {
|
|
|
5312
5332
|
return;
|
|
5313
5333
|
}
|
|
5314
5334
|
try {
|
|
5315
|
-
const { ensureSourcesCloned } = await import('../ensure-sources-
|
|
5335
|
+
const { ensureSourcesCloned } = await import('../ensure-sources-QDVFUIUP.js');
|
|
5316
5336
|
const hydrate = ensureSourcesCloned(projectDir, { quiet: true });
|
|
5317
5337
|
if (hydrate.cloned.length > 0) {
|
|
5318
5338
|
logOk(`Cloned source(s): ${hydrate.cloned.join(", ")}`);
|
|
@@ -5468,48 +5488,669 @@ function makeCleanCommand() {
|
|
|
5468
5488
|
}
|
|
5469
5489
|
});
|
|
5470
5490
|
}
|
|
5471
|
-
function
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
}
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5491
|
+
function buildPresetFromWorkspace(config, name, sources = []) {
|
|
5492
|
+
const items = [];
|
|
5493
|
+
for (const ref of config.dependencies ?? []) {
|
|
5494
|
+
items.push({ ref });
|
|
5495
|
+
}
|
|
5496
|
+
for (const connector of config.connectors ?? []) {
|
|
5497
|
+
const config_ = compact({
|
|
5498
|
+
access: connector.access,
|
|
5499
|
+
auth: connector.auth,
|
|
5500
|
+
options: connector.options,
|
|
5501
|
+
version: connector.version,
|
|
5502
|
+
tags: connector.tags
|
|
5503
|
+
});
|
|
5504
|
+
items.push({
|
|
5505
|
+
id: connector.id,
|
|
5506
|
+
ref: `connector:${connector.driver}`,
|
|
5507
|
+
...config_ ? { config: config_ } : {}
|
|
5508
|
+
});
|
|
5509
|
+
}
|
|
5510
|
+
for (const mcp of config.mcp_servers ?? []) {
|
|
5511
|
+
const config_ = compact({
|
|
5512
|
+
transport: mcp.transport,
|
|
5513
|
+
command: mcp.command,
|
|
5514
|
+
args: mcp.args,
|
|
5515
|
+
env: mcp.env,
|
|
5516
|
+
url: mcp.url,
|
|
5517
|
+
headers: mcp.headers
|
|
5518
|
+
});
|
|
5519
|
+
items.push({
|
|
5520
|
+
id: mcp.id,
|
|
5521
|
+
ref: `mcp:${mcp.id}`,
|
|
5522
|
+
...config_ ? { config: config_ } : {}
|
|
5523
|
+
});
|
|
5524
|
+
}
|
|
5525
|
+
const project = config.name ?? name;
|
|
5526
|
+
return {
|
|
5527
|
+
name,
|
|
5528
|
+
version: "1.0.0",
|
|
5529
|
+
description: `Exported from ${project} workspace`,
|
|
5530
|
+
items,
|
|
5531
|
+
// Never let a credential-bearing source URL reach a shareable preset.
|
|
5532
|
+
...sources.length > 0 ? { sources: sources.map((s) => ({ ...s, url: stripUrlCredentials(s.url) })) } : {}
|
|
5533
|
+
};
|
|
5534
|
+
}
|
|
5535
|
+
function neededSources(config, lock) {
|
|
5536
|
+
const factoryUrl = normalizeRepoUrl(FACTORY_SOURCE_URL);
|
|
5537
|
+
const nonFactory = (config.sources ?? []).filter((s) => normalizeRepoUrl(s.url) !== factoryUrl);
|
|
5538
|
+
if (!lock) return nonFactory;
|
|
5539
|
+
const inClosure = new Set(lock.sources.map((s) => normalizeRepoUrl(s.url)));
|
|
5540
|
+
return nonFactory.filter((s) => inClosure.has(normalizeRepoUrl(s.url)));
|
|
5541
|
+
}
|
|
5542
|
+
function sourcesWithSidecar(sources) {
|
|
5543
|
+
const dir = getStoreManifestsDir();
|
|
5544
|
+
return sources.filter((s) => existsSync(path14.join(dir, `${storeManifestSlug(s.url)}.yaml`))).map((s) => s.url);
|
|
5545
|
+
}
|
|
5546
|
+
function compact(obj) {
|
|
5547
|
+
const out = {};
|
|
5548
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
5549
|
+
if (v !== void 0 && v !== null) out[k] = v;
|
|
5550
|
+
}
|
|
5551
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
5552
|
+
}
|
|
5553
|
+
var SECRET_REFERENCE_PREFIXES = ["env", "forge", "secret", "op", "kp", "oauth", "pat"];
|
|
5554
|
+
var SECRET_REFERENCE_RE = new RegExp(`^(${SECRET_REFERENCE_PREFIXES.join("|")}):`);
|
|
5555
|
+
function isSecretReference(value) {
|
|
5556
|
+
return SECRET_REFERENCE_RE.test(value);
|
|
5557
|
+
}
|
|
5558
|
+
var PLACEHOLDER_RE = /^\$\{(INPUT|SECRET):[^}]+\}$/;
|
|
5559
|
+
var SUSPICIOUS_KEY_RE = /(?:^|[_-])(?:token|password|passwd|secret|apikey|key|dsn|credential|auth|authorization|bearer)(?:[_-]|$)/i;
|
|
5560
|
+
var PROTO_CREDENTIAL_URL_RE = /\w+:\/\/[^/@\s]+:[^/@\s]+@/;
|
|
5561
|
+
function urlHasCredentials(url) {
|
|
5562
|
+
return PROTO_CREDENTIAL_URL_RE.test(url);
|
|
5563
|
+
}
|
|
5564
|
+
function stripUrlCredentials(url) {
|
|
5565
|
+
return url.replace(/^(\w+:\/\/)[^/@]*:[^/@]*@/, "$1");
|
|
5566
|
+
}
|
|
5567
|
+
function isLongEntropic(value) {
|
|
5568
|
+
if (value.length < 20) return false;
|
|
5569
|
+
if (/^\w+:\/\//.test(value) || value.startsWith("/")) return false;
|
|
5570
|
+
const classes = [/[a-z]/, /[A-Z]/, /[0-9]/].filter((re) => re.test(value)).length;
|
|
5571
|
+
return classes >= 2;
|
|
5572
|
+
}
|
|
5573
|
+
function scanInlineSecrets(preset) {
|
|
5574
|
+
const findings = [];
|
|
5575
|
+
for (const item of preset.items) {
|
|
5576
|
+
const itemId = typeof item.id === "string" ? item.id : "";
|
|
5577
|
+
if (item.config) scanNode(item.config, [], false, itemId, findings);
|
|
5578
|
+
}
|
|
5579
|
+
return findings;
|
|
5580
|
+
}
|
|
5581
|
+
function scanNode(node, segments, inCredentialField, itemId, findings) {
|
|
5582
|
+
if (typeof node === "string") {
|
|
5583
|
+
if (isInlineSecret(node, segments.at(-1) ?? "", inCredentialField)) {
|
|
5584
|
+
findings.push({ itemId, path: segments.join("."), maskedValue: maskSecret(node) });
|
|
5498
5585
|
}
|
|
5499
|
-
|
|
5500
|
-
|
|
5586
|
+
return;
|
|
5587
|
+
}
|
|
5588
|
+
if (Array.isArray(node)) {
|
|
5589
|
+
node.forEach(
|
|
5590
|
+
(el, i) => scanNode(el, [...segments, String(i)], inCredentialField, itemId, findings)
|
|
5501
5591
|
);
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5592
|
+
return;
|
|
5593
|
+
}
|
|
5594
|
+
if (node && typeof node === "object") {
|
|
5595
|
+
for (const [k, v] of Object.entries(node)) {
|
|
5596
|
+
const credField = inCredentialField || k === "auth";
|
|
5597
|
+
scanNode(v, [...segments, k], credField, itemId, findings);
|
|
5598
|
+
}
|
|
5599
|
+
}
|
|
5600
|
+
}
|
|
5601
|
+
function isInlineSecret(value, key, inCredentialField) {
|
|
5602
|
+
if (isSecretReference(value) || PLACEHOLDER_RE.test(value)) return false;
|
|
5603
|
+
if (inCredentialField) return true;
|
|
5604
|
+
if (SUSPICIOUS_KEY_RE.test(key)) return true;
|
|
5605
|
+
if (PROTO_CREDENTIAL_URL_RE.test(value)) return true;
|
|
5606
|
+
return isLongEntropic(value);
|
|
5607
|
+
}
|
|
5608
|
+
function maskSecret(value) {
|
|
5609
|
+
const proto = value.match(/^(\w+):\/\/[^/@\s]+:[^/@\s]+@/);
|
|
5610
|
+
if (proto) return `${proto[1]}://\u2026:****@\u2026`;
|
|
5611
|
+
return "****";
|
|
5612
|
+
}
|
|
5613
|
+
function redactSecrets(preset, findings) {
|
|
5614
|
+
const next = structuredClone(preset);
|
|
5615
|
+
const keys = [];
|
|
5616
|
+
const used = /* @__PURE__ */ new Set();
|
|
5617
|
+
for (const finding of findings) {
|
|
5618
|
+
const item = next.items.find((it) => it.id === finding.itemId);
|
|
5619
|
+
if (!item?.config) continue;
|
|
5620
|
+
const base = placeholderKey(finding.itemId, finding.path);
|
|
5621
|
+
let key = base;
|
|
5622
|
+
for (let n = 2; used.has(key); n++) key = `${base}_${n}`;
|
|
5623
|
+
if (!setAtPath(item.config, finding.path.split("."), `\${INPUT:${key}}`)) continue;
|
|
5624
|
+
used.add(key);
|
|
5625
|
+
const placeholder = {
|
|
5626
|
+
key,
|
|
5627
|
+
type: "secret",
|
|
5628
|
+
required: true,
|
|
5629
|
+
prompt: `Secret value for ${finding.itemId}.${finding.path}`
|
|
5511
5630
|
};
|
|
5512
|
-
|
|
5631
|
+
item.placeholders = [...item.placeholders ?? [], placeholder];
|
|
5632
|
+
keys.push(key);
|
|
5633
|
+
}
|
|
5634
|
+
return { preset: next, keys };
|
|
5635
|
+
}
|
|
5636
|
+
function placeholderKey(itemId, path37) {
|
|
5637
|
+
return `${itemId}_${path37}`.replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
5638
|
+
}
|
|
5639
|
+
function setAtPath(root, segments, value) {
|
|
5640
|
+
let node = root;
|
|
5641
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
5642
|
+
if (!node || typeof node !== "object") return false;
|
|
5643
|
+
node = node[segments[i]];
|
|
5644
|
+
}
|
|
5645
|
+
if (!node || typeof node !== "object") return false;
|
|
5646
|
+
node[segments.at(-1)] = value;
|
|
5647
|
+
return true;
|
|
5648
|
+
}
|
|
5649
|
+
var INLINE_SECRETS_HEADER = "# \u26A0\uFE0F CONTAINS INLINE SECRETS \u2014 replace with placeholders before sharing or publishing";
|
|
5650
|
+
function secretHeaderComment(findings) {
|
|
5651
|
+
return findings.length > 0 ? INLINE_SECRETS_HEADER : null;
|
|
5652
|
+
}
|
|
5653
|
+
|
|
5654
|
+
// cli/src/commands/preset-cmd.ts
|
|
5655
|
+
function makePresetCommand() {
|
|
5656
|
+
const cmd = new Command("preset").description("Scaffold and validate preset YAML files");
|
|
5657
|
+
cmd.command("init [name]").description("Scaffold a new .preset.yaml file").option("--dir <path>", "Output directory", process.cwd()).action(async (name, opts) => {
|
|
5658
|
+
const presetName = name ?? "my-preset";
|
|
5659
|
+
const filename = `${presetName}.preset.yaml`;
|
|
5660
|
+
const outPath = path14__default.join(path14__default.resolve(opts.dir), filename);
|
|
5661
|
+
if (existsSync(outPath)) {
|
|
5662
|
+
logErr(`File already exists: ${outPath}`);
|
|
5663
|
+
logInfo("Choose a different name or remove the existing file.");
|
|
5664
|
+
process.exit(1);
|
|
5665
|
+
}
|
|
5666
|
+
const template = generatePresetTemplate(presetName);
|
|
5667
|
+
writeFileSync(outPath, template, "utf-8");
|
|
5668
|
+
logOk(`Created ${S.brand(filename)}`);
|
|
5669
|
+
logInfo(`Path: ${outPath}`);
|
|
5670
|
+
logInfo("Edit the file to define your preset items, then validate with:");
|
|
5671
|
+
logInfo(` skaile preset validate ${filename}`);
|
|
5672
|
+
});
|
|
5673
|
+
cmd.command("validate <path>").description("Validate a preset YAML file (schema + cycles + nesting depth)").action(async (filePath) => {
|
|
5674
|
+
await runPresetValidate(filePath);
|
|
5675
|
+
});
|
|
5676
|
+
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(
|
|
5677
|
+
"--allow-inline-secrets",
|
|
5678
|
+
"Exit 0 even when inline secrets remain unredacted (opt-in; unsafe for CI)"
|
|
5679
|
+
).option("--force", "Overwrite the output file if it already exists").action(async (name, opts) => {
|
|
5680
|
+
await runPresetExport(name, opts);
|
|
5681
|
+
});
|
|
5682
|
+
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(
|
|
5683
|
+
"--input <KEY=VAL>",
|
|
5684
|
+
"Provide a placeholder value (repeatable)",
|
|
5685
|
+
collectInput,
|
|
5686
|
+
[]
|
|
5687
|
+
).option("--yes", "Skip interactive prompts; use defaults where available").option("--no-deploy", "Skip the final `skaile install` step").action(async (filePath, opts) => {
|
|
5688
|
+
await runPresetApply(filePath, opts);
|
|
5689
|
+
});
|
|
5690
|
+
return cmd;
|
|
5691
|
+
}
|
|
5692
|
+
async function runPresetExport(name, opts) {
|
|
5693
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
5694
|
+
const file = loadSkWorkspaceConfig(projectDir);
|
|
5695
|
+
if (!file) {
|
|
5696
|
+
logErr(`No skaile.yaml found in ${projectDir}`);
|
|
5697
|
+
logInfo("Run this from a project directory or pass --project-dir <path>.");
|
|
5698
|
+
process.exit(1);
|
|
5699
|
+
}
|
|
5700
|
+
const presetName = name ?? file.config.name ?? "my-preset";
|
|
5701
|
+
let lock = null;
|
|
5702
|
+
try {
|
|
5703
|
+
lock = readLock(path14__default.join(projectDir, "skaile.lock.yaml"));
|
|
5704
|
+
} catch {
|
|
5705
|
+
lock = null;
|
|
5706
|
+
}
|
|
5707
|
+
const sources = neededSources(file.config, lock);
|
|
5708
|
+
if (lock === null && sources.length > 0) {
|
|
5709
|
+
logInfo("No lock file \u2014 exporting all non-factory sources conservatively.");
|
|
5710
|
+
}
|
|
5711
|
+
const strippedCreds = sources.filter((s) => urlHasCredentials(s.url)).length;
|
|
5712
|
+
if (strippedCreds > 0) {
|
|
5713
|
+
logWarn(
|
|
5714
|
+
`Stripped credentials from ${strippedCreds} source URL(s) \u2014 resolved via git auth on apply.`
|
|
5715
|
+
);
|
|
5716
|
+
}
|
|
5717
|
+
const sidecarSources = sourcesWithSidecar(sources);
|
|
5718
|
+
if (sidecarSources.length > 0) {
|
|
5719
|
+
logWarn(
|
|
5720
|
+
`${sidecarSources.length} captured source(s) rely on a MACHINE-LOCAL sidecar overlay (\`~/.skaile/store/manifests/*\`) \u2014 assets may not resolve on other machines or when this preset is shared, until the sidecar manifest is published: ${sidecarSources.join(", ")}`
|
|
5721
|
+
);
|
|
5722
|
+
}
|
|
5723
|
+
let preset = buildPresetFromWorkspace(file.config, presetName, sources);
|
|
5724
|
+
if (preset.items.length === 0) {
|
|
5725
|
+
logErr("Nothing to export \u2014 skaile.yaml has no dependencies, connectors, or mcp_servers.");
|
|
5726
|
+
process.exit(1);
|
|
5727
|
+
}
|
|
5728
|
+
const result = validatePreset(preset);
|
|
5729
|
+
if (!result.ok) {
|
|
5730
|
+
logErr("Internal error: generated preset failed validation:");
|
|
5731
|
+
for (const err of result.errors) console.error(` ${S.err("\u2717")} ${err.path}: ${err.message}`);
|
|
5732
|
+
process.exit(1);
|
|
5733
|
+
}
|
|
5734
|
+
const findings = scanInlineSecrets(preset);
|
|
5735
|
+
reportFindings(findings);
|
|
5736
|
+
const toRedact = await resolveRedactions(findings, opts.redact === true);
|
|
5737
|
+
if (toRedact.length > 0) preset = redactSecrets(preset, toRedact).preset;
|
|
5738
|
+
const unresolved = scanInlineSecrets(preset);
|
|
5739
|
+
const header = secretHeaderComment(unresolved);
|
|
5740
|
+
const body = stringify(preset);
|
|
5741
|
+
const contents = header ? `${header}
|
|
5742
|
+
${body}` : body;
|
|
5743
|
+
if (opts.out && opts.dir !== process.cwd()) logWarn("--dir is ignored when --out is set.");
|
|
5744
|
+
const outPath = opts.out ? path14__default.resolve(opts.out) : path14__default.join(path14__default.resolve(opts.dir), `${presetName}.preset.yaml`);
|
|
5745
|
+
if (existsSync(outPath) && !opts.force) {
|
|
5746
|
+
logErr(`File already exists: ${outPath}`);
|
|
5747
|
+
logInfo("Pass --force to overwrite, or choose a different --out/--dir.");
|
|
5748
|
+
process.exit(1);
|
|
5749
|
+
}
|
|
5750
|
+
try {
|
|
5751
|
+
writeFileSync(outPath, contents, "utf-8");
|
|
5752
|
+
} catch (e) {
|
|
5753
|
+
logErr(`Failed to write ${outPath}: ${e.message}`);
|
|
5754
|
+
process.exit(1);
|
|
5755
|
+
}
|
|
5756
|
+
logOk(`Exported ${S.brand(path14__default.basename(outPath))}`);
|
|
5757
|
+
logInfo(`Path: ${outPath}`);
|
|
5758
|
+
if (unresolved.length > 0) {
|
|
5759
|
+
console.error(S.err("This file is NOT safe to share."));
|
|
5760
|
+
if (!opts.allowInlineSecrets) {
|
|
5761
|
+
logErr(`${unresolved.length} inline secret(s) left unredacted.`);
|
|
5762
|
+
logInfo(
|
|
5763
|
+
"Re-run with --redact to placeholder them, or --allow-inline-secrets to accept the risk."
|
|
5764
|
+
);
|
|
5765
|
+
process.exit(1);
|
|
5766
|
+
}
|
|
5767
|
+
}
|
|
5768
|
+
}
|
|
5769
|
+
function reportFindings(findings) {
|
|
5770
|
+
if (findings.length === 0) return;
|
|
5771
|
+
console.error(S.err(`\u26A0\uFE0F ${findings.length} potential INLINE secret(s) found`));
|
|
5772
|
+
for (const f of findings) {
|
|
5773
|
+
console.error(` ${S.err("\u2022")} ${f.itemId} ${S.dim(f.path)} ${f.maskedValue}`);
|
|
5774
|
+
}
|
|
5775
|
+
}
|
|
5776
|
+
async function resolveRedactions(findings, redactAll) {
|
|
5777
|
+
if (findings.length === 0) return [];
|
|
5778
|
+
if (redactAll) return findings;
|
|
5779
|
+
if (!process.stdin.isTTY) return [];
|
|
5780
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
|
|
5781
|
+
try {
|
|
5782
|
+
const chosen = [];
|
|
5783
|
+
for (const f of findings) {
|
|
5784
|
+
const answer = await rl.question(`Redact ${f.itemId}.${f.path}? [y/N] `);
|
|
5785
|
+
if (/^y(es)?$/i.test(answer.trim())) chosen.push(f);
|
|
5786
|
+
}
|
|
5787
|
+
return chosen;
|
|
5788
|
+
} finally {
|
|
5789
|
+
rl.close();
|
|
5790
|
+
}
|
|
5791
|
+
}
|
|
5792
|
+
function collectInput(value, acc) {
|
|
5793
|
+
acc.push(value);
|
|
5794
|
+
return acc;
|
|
5795
|
+
}
|
|
5796
|
+
async function runPresetApply(filePath, opts) {
|
|
5797
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
5798
|
+
const file = loadSkWorkspaceConfig(projectDir);
|
|
5799
|
+
if (!file) {
|
|
5800
|
+
logErr("No skaile.yaml \u2014 run `skaile init` first");
|
|
5801
|
+
process.exit(1);
|
|
5802
|
+
}
|
|
5803
|
+
const resolved = path14__default.resolve(filePath);
|
|
5804
|
+
if (!existsSync(resolved)) {
|
|
5805
|
+
logErr(`File not found: ${resolved}`);
|
|
5806
|
+
process.exit(1);
|
|
5807
|
+
}
|
|
5808
|
+
const { parsePresetYaml } = await import('../library/index.js');
|
|
5809
|
+
const parseResult = parsePresetYaml(readFileSync(resolved, "utf-8"));
|
|
5810
|
+
if (!parseResult.ok || !parseResult.preset) {
|
|
5811
|
+
logErr("Preset validation failed:");
|
|
5812
|
+
for (const err of parseResult.errors) console.error(` ${S.err("\u2717")} ${err}`);
|
|
5813
|
+
process.exit(1);
|
|
5814
|
+
}
|
|
5815
|
+
const preset = parseResult.preset;
|
|
5816
|
+
if (preset.items.some((it) => it.ref.startsWith("preset:"))) {
|
|
5817
|
+
logErr(NESTED_PRESET_UNSUPPORTED);
|
|
5818
|
+
logInfo("Remove the nested `preset:` item(s) and re-run.");
|
|
5819
|
+
process.exit(1);
|
|
5820
|
+
}
|
|
5821
|
+
const values = parseInputs(opts.input);
|
|
5822
|
+
await promptMissingInputs(preset.items, preset.inputs, values, opts.yes === true);
|
|
5823
|
+
let items;
|
|
5824
|
+
try {
|
|
5825
|
+
items = presetItemsToWorkspace(preset, values);
|
|
5826
|
+
} catch (err) {
|
|
5827
|
+
logErr(err.message);
|
|
5828
|
+
process.exit(1);
|
|
5829
|
+
}
|
|
5830
|
+
const editor = WorkspaceYamlEditor.load(file.path);
|
|
5831
|
+
const summary = applyItems(editor, file.config, items);
|
|
5832
|
+
const changed = summary.addedSources.length + summary.addedDeps.length + summary.addedConnectors.length + summary.addedMcp.length;
|
|
5833
|
+
if (changed > 0) editor.save();
|
|
5834
|
+
printApplySummary(summary, items.envVarsToSet);
|
|
5835
|
+
if (opts.deploy) {
|
|
5836
|
+
await runPresetInstall(projectDir);
|
|
5837
|
+
} else {
|
|
5838
|
+
logInfo("Skipped deploy (--no-deploy). Run `skaile install` to deploy the new dependencies.");
|
|
5839
|
+
}
|
|
5840
|
+
}
|
|
5841
|
+
function parseInputs(pairs) {
|
|
5842
|
+
const out = {};
|
|
5843
|
+
for (const pair of pairs) {
|
|
5844
|
+
const eq = pair.indexOf("=");
|
|
5845
|
+
if (eq <= 0) {
|
|
5846
|
+
logErr(`Invalid --input "${pair}" \u2014 expected KEY=VALUE.`);
|
|
5847
|
+
process.exit(1);
|
|
5848
|
+
}
|
|
5849
|
+
out[pair.slice(0, eq)] = pair.slice(eq + 1);
|
|
5850
|
+
}
|
|
5851
|
+
return out;
|
|
5852
|
+
}
|
|
5853
|
+
async function promptMissingInputs(presetItems, presetInputs, values, yes) {
|
|
5854
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5855
|
+
const toPrompt = [];
|
|
5856
|
+
const collect = (ph) => {
|
|
5857
|
+
if (seen.has(ph.key) || isSecretPlaceholder(ph)) return;
|
|
5858
|
+
seen.add(ph.key);
|
|
5859
|
+
if (values[ph.key] === void 0) toPrompt.push(ph);
|
|
5860
|
+
};
|
|
5861
|
+
for (const input of presetInputs ?? []) collect(input);
|
|
5862
|
+
for (const item of presetItems) for (const ph of item.placeholders ?? []) collect(ph);
|
|
5863
|
+
if (toPrompt.length === 0 || yes || !process.stdin.isTTY) return;
|
|
5864
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
|
|
5865
|
+
try {
|
|
5866
|
+
for (const ph of toPrompt) {
|
|
5867
|
+
const def = getDefaultValue(ph);
|
|
5868
|
+
const suffix = def !== void 0 ? ` [${String(def)}]` : "";
|
|
5869
|
+
const answer = (await rl.question(`${ph.prompt ?? ph.key}${suffix}: `)).trim();
|
|
5870
|
+
if (answer) values[ph.key] = answer;
|
|
5871
|
+
else if (def !== void 0) values[ph.key] = String(def);
|
|
5872
|
+
}
|
|
5873
|
+
} finally {
|
|
5874
|
+
rl.close();
|
|
5875
|
+
}
|
|
5876
|
+
}
|
|
5877
|
+
function applyItems(editor, config, items) {
|
|
5878
|
+
const s = {
|
|
5879
|
+
addedDeps: [],
|
|
5880
|
+
skippedDeps: [],
|
|
5881
|
+
addedConnectors: [],
|
|
5882
|
+
skippedConnectors: [],
|
|
5883
|
+
unchangedConnectors: [],
|
|
5884
|
+
addedMcp: [],
|
|
5885
|
+
skippedMcp: [],
|
|
5886
|
+
unchangedMcp: [],
|
|
5887
|
+
addedSources: [],
|
|
5888
|
+
skippedSources: [],
|
|
5889
|
+
unchangedSources: []
|
|
5890
|
+
};
|
|
5891
|
+
const existingSourceUrls = new Map(
|
|
5892
|
+
editor.getSources().map((src) => [normalizeRepoUrl(src.url), src])
|
|
5893
|
+
);
|
|
5894
|
+
for (const src of items.sources) {
|
|
5895
|
+
const key = normalizeRepoUrl(src.url);
|
|
5896
|
+
const existing = existingSourceUrls.get(key);
|
|
5897
|
+
if (!existing) {
|
|
5898
|
+
editor.setSource(src);
|
|
5899
|
+
existingSourceUrls.set(key, src);
|
|
5900
|
+
s.addedSources.push(src.url);
|
|
5901
|
+
} else if ((existing.pin ?? void 0) !== (src.pin ?? void 0)) {
|
|
5902
|
+
s.skippedSources.push({ url: src.url, keptPin: existing.pin, presetPin: src.pin });
|
|
5903
|
+
} else {
|
|
5904
|
+
s.unchangedSources.push(src.url);
|
|
5905
|
+
}
|
|
5906
|
+
}
|
|
5907
|
+
for (const ref of items.dependencies) {
|
|
5908
|
+
if (editor.addDependency(ref)) s.addedDeps.push(ref);
|
|
5909
|
+
else s.skippedDeps.push(ref);
|
|
5910
|
+
}
|
|
5911
|
+
const existingConnectors = new Map((config.connectors ?? []).map((c) => [c.id, c]));
|
|
5912
|
+
for (const conn of items.connectors) {
|
|
5913
|
+
const existing = existingConnectors.get(conn.id);
|
|
5914
|
+
if (existing) {
|
|
5915
|
+
(stableEqual(existing, conn) ? s.unchangedConnectors : s.skippedConnectors).push(conn.id);
|
|
5916
|
+
continue;
|
|
5917
|
+
}
|
|
5918
|
+
editor.setConnector(conn);
|
|
5919
|
+
s.addedConnectors.push(conn.id);
|
|
5920
|
+
}
|
|
5921
|
+
const existingMcp = new Map((config.mcp_servers ?? []).map((m) => [m.id, m]));
|
|
5922
|
+
for (const mcp of items.mcpServers) {
|
|
5923
|
+
const existing = existingMcp.get(mcp.id);
|
|
5924
|
+
if (existing) {
|
|
5925
|
+
(stableEqual(existing, mcp) ? s.unchangedMcp : s.skippedMcp).push(mcp.id);
|
|
5926
|
+
continue;
|
|
5927
|
+
}
|
|
5928
|
+
editor.setMcpServer(mcp);
|
|
5929
|
+
s.addedMcp.push(mcp.id);
|
|
5930
|
+
}
|
|
5931
|
+
return s;
|
|
5932
|
+
}
|
|
5933
|
+
function stableEqual(a, b) {
|
|
5934
|
+
return canonicalJson(a) === canonicalJson(b);
|
|
5935
|
+
}
|
|
5936
|
+
function canonicalJson(value) {
|
|
5937
|
+
return JSON.stringify(
|
|
5938
|
+
value,
|
|
5939
|
+
(_k, v) => v && typeof v === "object" && !Array.isArray(v) ? Object.fromEntries(
|
|
5940
|
+
Object.entries(v).sort(([x], [y]) => x.localeCompare(y))
|
|
5941
|
+
) : v
|
|
5942
|
+
);
|
|
5943
|
+
}
|
|
5944
|
+
function printApplySummary(summary, envVarsToSet) {
|
|
5945
|
+
const added = summary.addedSources.length + summary.addedDeps.length + summary.addedConnectors.length + summary.addedMcp.length;
|
|
5946
|
+
if (added === 0) {
|
|
5947
|
+
logInfo("Nothing to apply \u2014 everything was already present.");
|
|
5948
|
+
} else {
|
|
5949
|
+
if (summary.addedSources.length > 0) {
|
|
5950
|
+
logOk(`Registered ${summary.addedSources.length} source(s).`);
|
|
5951
|
+
}
|
|
5952
|
+
logOk(
|
|
5953
|
+
`Applied ${summary.addedDeps.length} dependency(ies), ${summary.addedConnectors.length} connector(s), ${summary.addedMcp.length} mcp server(s).`
|
|
5954
|
+
);
|
|
5955
|
+
}
|
|
5956
|
+
const skipped = [
|
|
5957
|
+
...summary.skippedSources.map(
|
|
5958
|
+
(s) => `source ${s.url} (kept pin '${s.keptPin ?? "none"}', preset had '${s.presetPin ?? "none"}')`
|
|
5959
|
+
),
|
|
5960
|
+
...summary.skippedDeps.map((d) => `dependency ${d} (already present)`),
|
|
5961
|
+
...summary.skippedConnectors.map((c) => `connector ${c} (id exists, differs)`),
|
|
5962
|
+
...summary.skippedMcp.map((m) => `mcp ${m} (id exists, differs)`)
|
|
5963
|
+
];
|
|
5964
|
+
for (const line of skipped) logWarn(`Skipped ${line}`);
|
|
5965
|
+
const unchanged = summary.unchangedConnectors.length + summary.unchangedMcp.length + summary.unchangedSources.length;
|
|
5966
|
+
if (unchanged > 0)
|
|
5967
|
+
logInfo(`${unchanged} source/connector/mcp entry(ies) already matched \u2014 left as-is.`);
|
|
5968
|
+
if (envVarsToSet.length > 0) {
|
|
5969
|
+
logWarn(
|
|
5970
|
+
`This preset references secrets by env var \u2014 provide them before running: ${envVarsToSet.join(", ")}`
|
|
5971
|
+
);
|
|
5972
|
+
logInfo("Add them to .env (gitignored) or export in your shell, e.g. export <VAR>=\u2026");
|
|
5973
|
+
}
|
|
5974
|
+
}
|
|
5975
|
+
async function runPresetInstall(projectDir) {
|
|
5976
|
+
try {
|
|
5977
|
+
const { AssetManager: AssetManager2 } = await import('../asset-manager/index.js');
|
|
5978
|
+
const am2 = new AssetManager2({ projectDir });
|
|
5979
|
+
logInfo("Installing new dependencies\u2026");
|
|
5980
|
+
const result = await am2.install({});
|
|
5981
|
+
for (const d of result.deployed) logOk(d);
|
|
5982
|
+
for (const m of result.missing) logErr(`Missing: ${m}`);
|
|
5983
|
+
await reportInstalledSoftDeps(am2);
|
|
5984
|
+
} catch (err) {
|
|
5985
|
+
logErr(`Install failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
5986
|
+
logInfo("Run `skaile install` to deploy the new dependencies.");
|
|
5987
|
+
}
|
|
5988
|
+
}
|
|
5989
|
+
async function loadPresetForValidation(resolved) {
|
|
5990
|
+
if (!existsSync(resolved)) {
|
|
5991
|
+
logErr(`File not found: ${resolved}`);
|
|
5992
|
+
process.exit(1);
|
|
5993
|
+
}
|
|
5994
|
+
const content = readFileSync(resolved, "utf-8");
|
|
5995
|
+
const { parsePresetYaml } = await import('../library/index.js');
|
|
5996
|
+
const parseResult = parsePresetYaml(content);
|
|
5997
|
+
if (!parseResult.ok) {
|
|
5998
|
+
logErr("Preset validation failed (parse errors):");
|
|
5999
|
+
for (const err of parseResult.errors) {
|
|
6000
|
+
console.log(` ${S.err("\u2717")} ${err}`);
|
|
6001
|
+
}
|
|
6002
|
+
process.exit(1);
|
|
6003
|
+
}
|
|
6004
|
+
if (!parseResult.preset) {
|
|
6005
|
+
logErr("Preset validation failed: parser returned no manifest");
|
|
6006
|
+
process.exit(1);
|
|
6007
|
+
}
|
|
6008
|
+
return parseResult.preset;
|
|
6009
|
+
}
|
|
6010
|
+
async function reportNestedPresetRefs(preset) {
|
|
6011
|
+
const { detectNestedPresetRefs } = await import('../library/index.js');
|
|
6012
|
+
const nestedRefs = detectNestedPresetRefs(preset);
|
|
6013
|
+
if (nestedRefs.length > 0) {
|
|
6014
|
+
logInfo(`Nested preset refs: ${nestedRefs.length} (depth validated at apply-time)`);
|
|
6015
|
+
}
|
|
6016
|
+
}
|
|
6017
|
+
async function checkPresetCycles(preset, resolved) {
|
|
6018
|
+
const { detectCycles } = await import('../discovery/index.js');
|
|
6019
|
+
const presetRef = path14__default.basename(resolved, ".preset.yaml");
|
|
6020
|
+
const edges = [];
|
|
6021
|
+
for (const item of preset.items) {
|
|
6022
|
+
if (item.ref) {
|
|
6023
|
+
edges.push({ from: presetRef, to: item.ref, field: "items[].ref" });
|
|
6024
|
+
}
|
|
6025
|
+
}
|
|
6026
|
+
if (edges.length === 0) return;
|
|
6027
|
+
const cycleResult = detectCycles(edges);
|
|
6028
|
+
if (!cycleResult.acyclic) {
|
|
6029
|
+
logErr("Cycle detected in preset references:");
|
|
6030
|
+
if (cycleResult.cyclePath) {
|
|
6031
|
+
console.log(` ${S.err("\u2717")} ${cycleResult.cyclePath.join(" \u2192 ")}`);
|
|
6032
|
+
}
|
|
6033
|
+
process.exit(1);
|
|
6034
|
+
}
|
|
6035
|
+
}
|
|
6036
|
+
async function checkPresetPlaceholders(allPlaceholders) {
|
|
6037
|
+
if (allPlaceholders.length === 0) return false;
|
|
6038
|
+
const { validatePlaceholder } = await import('../library/index.js');
|
|
6039
|
+
const invalidEntries = [];
|
|
6040
|
+
for (const ph of allPlaceholders) {
|
|
6041
|
+
if (ph.default === void 0) continue;
|
|
6042
|
+
const result = validatePlaceholder(ph, ph.default);
|
|
6043
|
+
if (!result.valid) {
|
|
6044
|
+
invalidEntries.push({ key: ph.key, errors: result.errors });
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6047
|
+
if (invalidEntries.length === 0) return false;
|
|
6048
|
+
logWarn("Placeholder issues:");
|
|
6049
|
+
for (const r of invalidEntries) {
|
|
6050
|
+
console.log(` ${S.warn("!")} ${r.key}: ${r.errors.join(", ")}`);
|
|
6051
|
+
}
|
|
6052
|
+
return true;
|
|
6053
|
+
}
|
|
6054
|
+
function printPresetSummary(preset, placeholderCount, hasWarnings) {
|
|
6055
|
+
console.log();
|
|
6056
|
+
console.log(S.heading(" Preset Validation"));
|
|
6057
|
+
console.log(` ${S.rule(40)}`);
|
|
6058
|
+
console.log(` ${S.label("Name")} ${preset.name}`);
|
|
6059
|
+
console.log(` ${S.label("Version")} ${preset.version ?? "unversioned"}`);
|
|
6060
|
+
console.log(` ${S.label("Items")} ${preset.items.length}`);
|
|
6061
|
+
console.log(` ${S.label("Inputs")} ${preset.inputs?.length ?? 0}`);
|
|
6062
|
+
console.log(` ${S.label("Placeholders")} ${placeholderCount}`);
|
|
6063
|
+
console.log();
|
|
6064
|
+
if (hasWarnings) {
|
|
6065
|
+
logWarn("Validation passed with warnings");
|
|
6066
|
+
} else {
|
|
6067
|
+
logOk("Preset is valid");
|
|
6068
|
+
}
|
|
6069
|
+
}
|
|
6070
|
+
async function runPresetValidate(filePath) {
|
|
6071
|
+
const resolved = path14__default.resolve(filePath);
|
|
6072
|
+
const preset = await loadPresetForValidation(resolved);
|
|
6073
|
+
await reportNestedPresetRefs(preset);
|
|
6074
|
+
await checkPresetCycles(preset, resolved);
|
|
6075
|
+
const allPlaceholders = preset.items.flatMap((item) => item.placeholders ?? []);
|
|
6076
|
+
const hasWarnings = await checkPresetPlaceholders(allPlaceholders);
|
|
6077
|
+
printPresetSummary(preset, allPlaceholders.length, hasWarnings);
|
|
6078
|
+
}
|
|
6079
|
+
function generatePresetTemplate(name) {
|
|
6080
|
+
return `# ${name}.preset.yaml
|
|
6081
|
+
# Polymorphic Preset \u2014 composition + configuration primitive for the asset store.
|
|
6082
|
+
# See: _devlog/specs/2026-05-03-ai-asset-store-v2-design.md \xA7 Presets
|
|
6083
|
+
|
|
6084
|
+
name: "${name}"
|
|
6085
|
+
version: "1.0.0"
|
|
6086
|
+
description: "TODO: describe what this preset configures"
|
|
6087
|
+
|
|
6088
|
+
# Placeholders \u2014 values the user provides at apply-time.
|
|
6089
|
+
# Types: text, multiline, secret, number, boolean, enum, oauth, instance-picker
|
|
6090
|
+
placeholders:
|
|
6091
|
+
- key: EXAMPLE_KEY
|
|
6092
|
+
type: text
|
|
6093
|
+
label: "Example placeholder"
|
|
6094
|
+
required: true
|
|
6095
|
+
# default: "some-value"
|
|
6096
|
+
# hint: "Help text shown to the user"
|
|
6097
|
+
|
|
6098
|
+
# Items \u2014 each becomes a Library Instance when the preset is applied.
|
|
6099
|
+
# Ref types:
|
|
6100
|
+
# - Asset ref (kind:publisher/name@pin) \u2192 creates new Instance
|
|
6101
|
+
# - Library Instance ref (#uuid) \u2192 reuses existing Instance
|
|
6102
|
+
# - Nested Preset ref (preset:path.preset.yaml) \u2192 recursive apply (max depth 3)
|
|
6103
|
+
items:
|
|
6104
|
+
- id: example-item
|
|
6105
|
+
ref: "skill:@skaile/example-skill@^1.0"
|
|
6106
|
+
config:
|
|
6107
|
+
# Use \${INPUT:EXAMPLE_KEY} for placeholder interpolation
|
|
6108
|
+
setting: "\${INPUT:EXAMPLE_KEY}"
|
|
6109
|
+
# credential_ref: "\${SECRET:EXAMPLE_KEY}" # for secret placeholders
|
|
6110
|
+
`;
|
|
6111
|
+
}
|
|
6112
|
+
function makeRebuildCommand() {
|
|
6113
|
+
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) => {
|
|
6114
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
6115
|
+
let agentDir;
|
|
6116
|
+
if (agentArg) {
|
|
6117
|
+
if (agentArg.includes("/") || agentArg.includes("\\")) {
|
|
6118
|
+
agentDir = path14__default.resolve(projectDir, agentArg);
|
|
6119
|
+
} else {
|
|
6120
|
+
const resolved = resolveAgentDir(projectDir);
|
|
6121
|
+
agentDir = resolved ?? path14__default.resolve(projectDir, agentArg);
|
|
6122
|
+
}
|
|
6123
|
+
} else {
|
|
6124
|
+
const resolved = resolveAgentDir(projectDir);
|
|
6125
|
+
if (!resolved) {
|
|
6126
|
+
logErr("No agent found in current project. Specify an agent name or path.");
|
|
6127
|
+
process.exit(1);
|
|
6128
|
+
}
|
|
6129
|
+
agentDir = resolved;
|
|
6130
|
+
}
|
|
6131
|
+
const manifest = await loadAgentManifest(agentDir);
|
|
6132
|
+
if (!manifest) {
|
|
6133
|
+
logErr(`No agent.yaml found in ${agentDir}`);
|
|
6134
|
+
process.exit(1);
|
|
6135
|
+
}
|
|
6136
|
+
if (!manifest.composes || manifest.composes.length === 0) {
|
|
6137
|
+
logInfo("Agent has no composes: items \u2014 nothing to rebuild.");
|
|
6138
|
+
return;
|
|
6139
|
+
}
|
|
6140
|
+
logInfo(
|
|
6141
|
+
`Rebuilding ${manifest.name ?? "agent"} (${manifest.composes.length} composition items)...`
|
|
6142
|
+
);
|
|
6143
|
+
const loadContent = async (ref, kind) => {
|
|
6144
|
+
try {
|
|
6145
|
+
const repos = {};
|
|
6146
|
+
const mixinKind = kind;
|
|
6147
|
+
const resolved = await resolveMixin(ref, mixinKind, agentDir, repos);
|
|
6148
|
+
return resolved?.content ?? null;
|
|
6149
|
+
} catch {
|
|
6150
|
+
return null;
|
|
6151
|
+
}
|
|
6152
|
+
};
|
|
6153
|
+
const result = await compileComposition({
|
|
5513
6154
|
agentDir,
|
|
5514
6155
|
items: manifest.composes,
|
|
5515
6156
|
loadContent
|
|
@@ -5523,6 +6164,21 @@ function makeRebuildCommand() {
|
|
|
5523
6164
|
logInfo(`Written: ${result.manifestPath}`);
|
|
5524
6165
|
});
|
|
5525
6166
|
}
|
|
6167
|
+
|
|
6168
|
+
// cli/src/driver-error.ts
|
|
6169
|
+
function friendlyDriverError(err) {
|
|
6170
|
+
const e = err;
|
|
6171
|
+
if (!e) return null;
|
|
6172
|
+
const isSpawnEnoent = e.code === "ENOENT" && (e.syscall?.startsWith("spawn") === true || /^spawn .*ENOENT/.test(e.message ?? ""));
|
|
6173
|
+
const isConfig = e.category === "config" || e.detail?.category === "config";
|
|
6174
|
+
if (!isSpawnEnoent && !isConfig) return null;
|
|
6175
|
+
const hint = e.hint ?? e.detail?.hint;
|
|
6176
|
+
const base = hint ?? "The configured agent binary is not installed or not on your PATH.";
|
|
6177
|
+
return `${base}
|
|
6178
|
+
Try a different backend with \`--driver claude-sdk\`.`;
|
|
6179
|
+
}
|
|
6180
|
+
|
|
6181
|
+
// cli/src/commands/run.ts
|
|
5526
6182
|
function makeFlowEventHandler() {
|
|
5527
6183
|
const md = new MarkdownStreamer();
|
|
5528
6184
|
const displayed = /* @__PURE__ */ new Set();
|
|
@@ -5608,14 +6264,24 @@ function makeRunCommand() {
|
|
|
5608
6264
|
}
|
|
5609
6265
|
process.exit(1);
|
|
5610
6266
|
}
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
6267
|
+
try {
|
|
6268
|
+
await runAgentChat({
|
|
6269
|
+
projectDir,
|
|
6270
|
+
driver: config.driver,
|
|
6271
|
+
model: config.model,
|
|
6272
|
+
provider: config.provider,
|
|
6273
|
+
message: textPrompt,
|
|
6274
|
+
skill: opts.skill
|
|
6275
|
+
});
|
|
6276
|
+
} catch (err) {
|
|
6277
|
+
const friendly = friendlyDriverError(err);
|
|
6278
|
+
if (friendly) {
|
|
6279
|
+
logErr(friendly);
|
|
6280
|
+
} else {
|
|
6281
|
+
logErr(err instanceof Error ? err.message : String(err));
|
|
6282
|
+
}
|
|
6283
|
+
process.exit(1);
|
|
6284
|
+
}
|
|
5619
6285
|
return;
|
|
5620
6286
|
}
|
|
5621
6287
|
let flow;
|
|
@@ -5634,17 +6300,23 @@ function makeRunCommand() {
|
|
|
5634
6300
|
if (opts.label) console.log(` ${S.label("Label:")} ${opts.label}`);
|
|
5635
6301
|
if (dryRun) console.log(` ${S.warn("(dry run \u2014 no agent will be started)")}`);
|
|
5636
6302
|
console.log();
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
6303
|
+
try {
|
|
6304
|
+
await runFlow({
|
|
6305
|
+
projectDir,
|
|
6306
|
+
flowPath,
|
|
6307
|
+
driver,
|
|
6308
|
+
model,
|
|
6309
|
+
provider,
|
|
6310
|
+
sessionLabel: opts.label,
|
|
6311
|
+
dryRun,
|
|
6312
|
+
onEvent: makeFlowEventHandler(),
|
|
6313
|
+
onLog: (line) => console.log(line)
|
|
6314
|
+
});
|
|
6315
|
+
} catch (err) {
|
|
6316
|
+
const friendly = friendlyDriverError(err);
|
|
6317
|
+
logErr(friendly ?? (err instanceof Error ? err.message : String(err)));
|
|
6318
|
+
process.exit(1);
|
|
6319
|
+
}
|
|
5648
6320
|
});
|
|
5649
6321
|
return cmd;
|
|
5650
6322
|
}
|
|
@@ -5786,12 +6458,12 @@ function makeServeCommand() {
|
|
|
5786
6458
|
);
|
|
5787
6459
|
}
|
|
5788
6460
|
async function ensurePluginsLoadedForServe(projectDir) {
|
|
5789
|
-
const { logInfo: logInfo2, logWarn: logWarn2 } = await import('../helpers-
|
|
6461
|
+
const { logInfo: logInfo2, logWarn: logWarn2 } = await import('../helpers-TF7GCBRQ.js');
|
|
5790
6462
|
try {
|
|
5791
6463
|
const { resolveSkWorkspaceConfig: resolveSkWorkspaceConfig2 } = await import('../core/index.js');
|
|
5792
6464
|
const config = resolveSkWorkspaceConfig2(projectDir);
|
|
5793
6465
|
if (!config.plugins || config.plugins.length === 0) return;
|
|
5794
|
-
const { ensurePluginsLoaded } = await import('../plugin-store-
|
|
6466
|
+
const { ensurePluginsLoaded } = await import('../plugin-store-S7OMGI7N.js');
|
|
5795
6467
|
const { pluginRegistry } = await import('../plugin-registry/index.js');
|
|
5796
6468
|
const result = await ensurePluginsLoaded(projectDir, config.plugins, pluginRegistry);
|
|
5797
6469
|
if (result.loaded.length > 0) {
|
|
@@ -5805,21 +6477,21 @@ async function ensurePluginsLoadedForServe(projectDir) {
|
|
|
5805
6477
|
}
|
|
5806
6478
|
}
|
|
5807
6479
|
async function runCompileTest(opts) {
|
|
5808
|
-
const { logOk: logOk2, logErr: logErr2, logInfo: logInfo2, S: S2 } = await import('../helpers-
|
|
6480
|
+
const { logOk: logOk2, logErr: logErr2, logInfo: logInfo2, S: S2 } = await import('../helpers-TF7GCBRQ.js');
|
|
5809
6481
|
const { tmpdir } = await import('os');
|
|
5810
|
-
const { dirname: dirname4, join:
|
|
6482
|
+
const { dirname: dirname4, join: join6, resolve: resolve5 } = await import('path');
|
|
5811
6483
|
const { fileURLToPath: fileURLToPath2 } = await import('url');
|
|
5812
|
-
const { unlinkSync, existsSync:
|
|
6484
|
+
const { unlinkSync, existsSync: existsSync14 } = await import('fs');
|
|
5813
6485
|
const { spawn } = await import('child_process');
|
|
5814
6486
|
const { portableSpawnSync: portableSpawnSync2 } = await import('../core/index.js');
|
|
5815
|
-
const { MONOREPO_ROOT } = await import('../paths-
|
|
6487
|
+
const { MONOREPO_ROOT } = await import('../paths-P3DWFUPS.js');
|
|
5816
6488
|
if (MONOREPO_ROOT === null) {
|
|
5817
6489
|
logErr2("--compile-test is only available inside the skaile-dev workspace.");
|
|
5818
6490
|
logInfo2("Run it from a checkout of skaile-ai/skaile-dev (the monorepo shell).");
|
|
5819
6491
|
process.exitCode = 2;
|
|
5820
6492
|
return;
|
|
5821
6493
|
}
|
|
5822
|
-
const outfile =
|
|
6494
|
+
const outfile = join6(tmpdir(), `skaile-compile-test-${Date.now()}`);
|
|
5823
6495
|
const __thisFile = fileURLToPath2(import.meta.url);
|
|
5824
6496
|
const entryPoint = resolve5(dirname4(__thisFile), "..", "index.ts");
|
|
5825
6497
|
logInfo2(`Building compiled binary...`);
|
|
@@ -5871,7 +6543,7 @@ async function runCompileTest(opts) {
|
|
|
5871
6543
|
} catch {
|
|
5872
6544
|
}
|
|
5873
6545
|
try {
|
|
5874
|
-
if (
|
|
6546
|
+
if (existsSync14(outfile)) unlinkSync(outfile);
|
|
5875
6547
|
} catch {
|
|
5876
6548
|
}
|
|
5877
6549
|
}
|
|
@@ -6625,96 +7297,37 @@ function makeShowCommand() {
|
|
|
6625
7297
|
}
|
|
6626
7298
|
});
|
|
6627
7299
|
}
|
|
7300
|
+
async function fetchIdentity() {
|
|
7301
|
+
const jwt = await getStoreToken();
|
|
7302
|
+
return storeFetch({ ...getStoreConfig(), jwt }, "/api/v1/me");
|
|
7303
|
+
}
|
|
6628
7304
|
function makeStoreCommand() {
|
|
6629
7305
|
const store = new Command("store").description("Manage the AI Asset Store");
|
|
6630
|
-
store.command("login").description("
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
const
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
resolve5(answer);
|
|
6639
|
-
});
|
|
6640
|
-
});
|
|
6641
|
-
try {
|
|
6642
|
-
const res = await storeFetch(
|
|
6643
|
-
config,
|
|
6644
|
-
"/api/auth/login",
|
|
6645
|
-
{ method: "POST", body: { email: opts.email, password } }
|
|
6646
|
-
);
|
|
6647
|
-
saveStoreTokens(res.jwt, res.refreshToken);
|
|
6648
|
-
logOk(`Logged in as ${S.brand(`@${res.publisher.slug}`)}`);
|
|
6649
|
-
} catch (e) {
|
|
6650
|
-
logErr(e.message);
|
|
6651
|
-
process.exit(1);
|
|
6652
|
-
}
|
|
6653
|
-
} else {
|
|
6654
|
-
const loginUrl = `${config.url}/api/auth/login/github`;
|
|
6655
|
-
console.log(`
|
|
6656
|
-
Opening browser to authenticate...
|
|
6657
|
-
${S.dim(loginUrl)}
|
|
6658
|
-
`);
|
|
6659
|
-
const http = await import('http');
|
|
6660
|
-
const { URL: URL2 } = await import('url');
|
|
6661
|
-
const server = http.createServer((req, res) => {
|
|
6662
|
-
const url = new URL2(req.url ?? "/", "http://localhost");
|
|
6663
|
-
const jwt = url.searchParams.get("token");
|
|
6664
|
-
const refresh = url.searchParams.get("refresh");
|
|
6665
|
-
if (jwt && refresh) {
|
|
6666
|
-
saveStoreTokens(jwt, refresh);
|
|
6667
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
6668
|
-
res.end("<h2>Authenticated! You can close this tab.</h2>");
|
|
6669
|
-
logOk("Authenticated with the store");
|
|
6670
|
-
server.close();
|
|
6671
|
-
} else {
|
|
6672
|
-
res.writeHead(400);
|
|
6673
|
-
res.end("Missing tokens");
|
|
6674
|
-
}
|
|
6675
|
-
});
|
|
6676
|
-
server.listen(0, () => {
|
|
6677
|
-
const port = server.address()?.port;
|
|
6678
|
-
const open = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
6679
|
-
import('child_process').then(({ exec }) => {
|
|
6680
|
-
exec(`${open} "${loginUrl}"`);
|
|
6681
|
-
});
|
|
6682
|
-
console.log(` ${S.dim(`Listening on http://localhost:${port} for callback...`)}`);
|
|
6683
|
-
});
|
|
6684
|
-
setTimeout(() => {
|
|
6685
|
-
logErr("Login timed out");
|
|
6686
|
-
server.close();
|
|
6687
|
-
process.exit(1);
|
|
6688
|
-
}, 12e4);
|
|
7306
|
+
store.command("login").description("Sign in to the store (Keycloak device flow \u2014 approve in your browser)").action(async () => {
|
|
7307
|
+
try {
|
|
7308
|
+
await deviceLogin(loadStoreAuthConfig());
|
|
7309
|
+
const me = await fetchIdentity().catch(() => ({}));
|
|
7310
|
+
logOk(`Signed in${me.username ? ` as ${S.brand(`@${me.username}`)}` : "."}`);
|
|
7311
|
+
} catch (e) {
|
|
7312
|
+
logErr(e.message);
|
|
7313
|
+
process.exit(1);
|
|
6689
7314
|
}
|
|
6690
7315
|
});
|
|
6691
|
-
store.command("logout").description("Sign out of the store").action(
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
try {
|
|
6695
|
-
await storeFetch(config, "/api/auth/logout", {
|
|
6696
|
-
method: "POST",
|
|
6697
|
-
body: { refreshToken: config.refreshToken }
|
|
6698
|
-
});
|
|
6699
|
-
} catch {
|
|
6700
|
-
}
|
|
6701
|
-
}
|
|
6702
|
-
clearStoreTokens();
|
|
6703
|
-
logOk("Logged out");
|
|
7316
|
+
store.command("logout").description("Sign out of the store").action(() => {
|
|
7317
|
+
logout(loadStoreAuthConfig());
|
|
7318
|
+
logOk("Signed out.");
|
|
6704
7319
|
});
|
|
6705
7320
|
store.command("whoami").description("Show current store identity").action(async () => {
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
logErr("Not authenticated. Run: skaile store login");
|
|
7321
|
+
if (!hasStoredAuth(loadStoreAuthConfig())) {
|
|
7322
|
+
logErr("Not signed in. Run: skaile store login");
|
|
6709
7323
|
process.exit(1);
|
|
6710
7324
|
}
|
|
6711
7325
|
try {
|
|
6712
|
-
const me = await
|
|
7326
|
+
const me = await fetchIdentity();
|
|
6713
7327
|
console.log();
|
|
6714
|
-
console.log(` ${S.heading("Publisher")} ${S.brand(`@${me.
|
|
6715
|
-
console.log(` ${S.label("
|
|
6716
|
-
console.log(` ${S.label("
|
|
6717
|
-
console.log(` ${S.label("Verified")} ${me.verified ? S.ok("yes") : S.dim("no")}`);
|
|
7328
|
+
console.log(` ${S.heading("Publisher")} ${S.brand(`@${me.username ?? "?"}`)}`);
|
|
7329
|
+
if (me.githubLogin) console.log(` ${S.label("GitHub")} ${me.githubLogin}`);
|
|
7330
|
+
if (me.roles?.length) console.log(` ${S.label("Roles")} ${me.roles.join(", ")}`);
|
|
6718
7331
|
console.log();
|
|
6719
7332
|
} catch (e) {
|
|
6720
7333
|
logErr(e.message);
|
|
@@ -6752,9 +7365,8 @@ function makeStoreCommand() {
|
|
|
6752
7365
|
process.exit(2);
|
|
6753
7366
|
});
|
|
6754
7367
|
store.command("yank <version>").description("Yank (soft-delete) a published version").option("--asset <ref>", "Asset reference (@publisher/slug)").action(async (version, opts) => {
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
logErr("Not authenticated. Run: skaile store login");
|
|
7368
|
+
if (!isStoreAuthenticated()) {
|
|
7369
|
+
logErr("Not signed in. Run: skaile store login");
|
|
6758
7370
|
process.exit(1);
|
|
6759
7371
|
}
|
|
6760
7372
|
if (!opts.asset) {
|
|
@@ -6768,7 +7380,8 @@ function makeStoreCommand() {
|
|
|
6768
7380
|
process.exit(1);
|
|
6769
7381
|
}
|
|
6770
7382
|
try {
|
|
6771
|
-
await
|
|
7383
|
+
const jwt = await getStoreToken();
|
|
7384
|
+
await storeFetch({ ...getStoreConfig(), jwt }, `/api/assets/${publisher}/${slug}/${version}/yank`, {
|
|
6772
7385
|
method: "PATCH"
|
|
6773
7386
|
});
|
|
6774
7387
|
logOk(`Yanked v${version} of @${publisher}/${slug}`);
|
|
@@ -7448,12 +8061,43 @@ function makeVerifyCommand() {
|
|
|
7448
8061
|
}
|
|
7449
8062
|
});
|
|
7450
8063
|
}
|
|
8064
|
+
function refKindName(ref) {
|
|
8065
|
+
const trimmed = ref.trim();
|
|
8066
|
+
const colon = trimmed.indexOf(":");
|
|
8067
|
+
let kind = colon === -1 ? void 0 : trimmed.slice(0, colon);
|
|
8068
|
+
if (kind === "mcp") kind = "mcp-server";
|
|
8069
|
+
let rest = colon === -1 ? trimmed : trimmed.slice(colon + 1);
|
|
8070
|
+
const hash = rest.indexOf("#");
|
|
8071
|
+
if (hash !== -1) rest = rest.slice(0, hash);
|
|
8072
|
+
if (rest.startsWith("@")) {
|
|
8073
|
+
const slash = rest.indexOf("/");
|
|
8074
|
+
if (slash !== -1) rest = rest.slice(slash + 1);
|
|
8075
|
+
}
|
|
8076
|
+
return { kind, name: rest };
|
|
8077
|
+
}
|
|
8078
|
+
function whyEmptyMessage(ref, declared) {
|
|
8079
|
+
const { kind, name } = refKindName(ref);
|
|
8080
|
+
const isDeclared = declared.some(
|
|
8081
|
+
(d) => d.name === name && (kind === void 0 || d.kind === kind)
|
|
8082
|
+
);
|
|
8083
|
+
if (isDeclared) {
|
|
8084
|
+
return `${ref} not found in lock file. Run \`skaile install\` first.`;
|
|
8085
|
+
}
|
|
8086
|
+
return `${ref} is not a dependency of this project \u2014 nothing in skaile.yaml requires it. Run \`skaile list\` to see declared dependencies.`;
|
|
8087
|
+
}
|
|
7451
8088
|
function makeWhyCommand() {
|
|
7452
8089
|
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) => {
|
|
7453
8090
|
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
7454
8091
|
const chain = am2.why(ref);
|
|
7455
8092
|
if (chain.length === 0) {
|
|
7456
|
-
|
|
8093
|
+
let declared;
|
|
8094
|
+
try {
|
|
8095
|
+
declared = am2.listDeclared();
|
|
8096
|
+
} catch {
|
|
8097
|
+
logErr(`${ref} not found in lock file. Run \`skaile install\` first.`);
|
|
8098
|
+
return;
|
|
8099
|
+
}
|
|
8100
|
+
logErr(whyEmptyMessage(ref, declared));
|
|
7457
8101
|
return;
|
|
7458
8102
|
}
|
|
7459
8103
|
console.log();
|
|
@@ -7599,7 +8243,7 @@ program.command("init [project-dir]").description("Initialize a project director
|
|
|
7599
8243
|
);
|
|
7600
8244
|
async function runInit(projectDir, opts) {
|
|
7601
8245
|
const { mkdirSync: mkdirSync5, writeFileSync: writeFileSync4 } = await import('fs');
|
|
7602
|
-
const { stringify } = await import('yaml');
|
|
8246
|
+
const { stringify: stringify2 } = await import('yaml');
|
|
7603
8247
|
const { DRIVER_TARGETS, SUPPORTED_DRIVER_TARGETS: SUPPORTED_DRIVER_TARGETS2 } = await import('../core/index.js');
|
|
7604
8248
|
const backend = opts.backend;
|
|
7605
8249
|
if (!SUPPORTED_DRIVER_TARGETS2.includes(backend)) {
|
|
@@ -7610,29 +8254,29 @@ async function runInit(projectDir, opts) {
|
|
|
7610
8254
|
const resolved = path14__default.resolve(projectDir ?? ".");
|
|
7611
8255
|
const projectName = path14__default.basename(resolved);
|
|
7612
8256
|
const created = [];
|
|
7613
|
-
const { existsSync:
|
|
7614
|
-
if (!
|
|
8257
|
+
const { existsSync: existsSync14 } = await import('fs');
|
|
8258
|
+
if (!existsSync14(resolved)) {
|
|
7615
8259
|
mkdirSync5(resolved, { recursive: true });
|
|
7616
8260
|
created.push(".");
|
|
7617
8261
|
}
|
|
7618
8262
|
const skaileDir = path14__default.join(resolved, ".skaile");
|
|
7619
|
-
if (!
|
|
8263
|
+
if (!existsSync14(skaileDir)) {
|
|
7620
8264
|
mkdirSync5(path14__default.join(skaileDir, "sessions"), { recursive: true });
|
|
7621
8265
|
created.push(".skaile/");
|
|
7622
8266
|
}
|
|
7623
8267
|
const settingsPath = path14__default.join(skaileDir, "settings.json");
|
|
7624
|
-
if (!
|
|
8268
|
+
if (!existsSync14(settingsPath)) {
|
|
7625
8269
|
writeFileSync4(settingsPath, "{}\n");
|
|
7626
8270
|
created.push(".skaile/settings.json");
|
|
7627
8271
|
}
|
|
7628
8272
|
const wsConfigPath = path14__default.join(resolved, "skaile.yaml");
|
|
7629
|
-
if (!
|
|
7630
|
-
writeFileSync4(wsConfigPath,
|
|
8273
|
+
if (!existsSync14(wsConfigPath)) {
|
|
8274
|
+
writeFileSync4(wsConfigPath, stringify2(buildInitWorkspaceConfig(projectName, backend)));
|
|
7631
8275
|
created.push("skaile.yaml");
|
|
7632
8276
|
}
|
|
7633
8277
|
for (const dir of new Set(Object.values(DRIVER_TARGETS[backend].local))) {
|
|
7634
8278
|
const full = path14__default.join(resolved, dir);
|
|
7635
|
-
if (!
|
|
8279
|
+
if (!existsSync14(full)) {
|
|
7636
8280
|
mkdirSync5(full, { recursive: true });
|
|
7637
8281
|
created.push(`${dir}/`);
|
|
7638
8282
|
}
|
|
@@ -7663,7 +8307,7 @@ function buildInitWorkspaceConfig(projectName, backend) {
|
|
|
7663
8307
|
}
|
|
7664
8308
|
async function initGitScaffold(resolved, created) {
|
|
7665
8309
|
const { execSync: execSync3 } = await import('child_process');
|
|
7666
|
-
const { existsSync:
|
|
8310
|
+
const { existsSync: existsSync14, readFileSync: readFileSync8, writeFileSync: writeFileSync4 } = await import('fs');
|
|
7667
8311
|
const gitignorePath = path14__default.join(resolved, ".gitignore");
|
|
7668
8312
|
const entries = [
|
|
7669
8313
|
"node_modules/",
|
|
@@ -7679,7 +8323,7 @@ async function initGitScaffold(resolved, created) {
|
|
|
7679
8323
|
".env",
|
|
7680
8324
|
".env.local"
|
|
7681
8325
|
];
|
|
7682
|
-
const existing =
|
|
8326
|
+
const existing = existsSync14(gitignorePath) ? readFileSync8(gitignorePath, "utf-8") : "";
|
|
7683
8327
|
const have = new Set(existing.split("\n").map((l) => l.trim()));
|
|
7684
8328
|
const append = entries.filter((e) => !have.has(e));
|
|
7685
8329
|
if (append.length > 0) {
|
|
@@ -7688,7 +8332,7 @@ async function initGitScaffold(resolved, created) {
|
|
|
7688
8332
|
`);
|
|
7689
8333
|
if (!existing) created.push(".gitignore");
|
|
7690
8334
|
}
|
|
7691
|
-
if (!
|
|
8335
|
+
if (!existsSync14(path14__default.join(resolved, ".git"))) {
|
|
7692
8336
|
try {
|
|
7693
8337
|
execSync3("git init", { cwd: resolved, stdio: "pipe" });
|
|
7694
8338
|
created.push(".git/");
|
|
@@ -7718,7 +8362,7 @@ async function bootstrapUserConfig() {
|
|
|
7718
8362
|
}
|
|
7719
8363
|
async function hydrateInitSources(resolved, created) {
|
|
7720
8364
|
try {
|
|
7721
|
-
const { ensureSourcesCloned } = await import('../ensure-sources-
|
|
8365
|
+
const { ensureSourcesCloned } = await import('../ensure-sources-QDVFUIUP.js');
|
|
7722
8366
|
const hydrate = ensureSourcesCloned(resolved, { quiet: true });
|
|
7723
8367
|
for (const n of hydrate.cloned) created.push(`~/.skaile/cache/sources/${n}/`);
|
|
7724
8368
|
if (hydrate.failed.length > 0) {
|
|
@@ -7751,10 +8395,14 @@ function printInitSummary(resolved, projectDir, created) {
|
|
|
7751
8395
|
console.log(
|
|
7752
8396
|
` ${S.dim(`${step}.`)} ${S.cmd("skaile search <query>")} ${S.dim("\u2014 find assets to add")}`
|
|
7753
8397
|
);
|
|
8398
|
+
step++;
|
|
8399
|
+
console.log(
|
|
8400
|
+
` ${S.dim(`${step}.`)} ${S.cmd("skaile preset apply <file>")} ${S.dim("\u2014 apply a saved preset (assets + config) at once")}`
|
|
8401
|
+
);
|
|
7754
8402
|
console.log();
|
|
7755
8403
|
}
|
|
7756
8404
|
program.command("setup").description("Interactive provider setup wizard").action(async () => {
|
|
7757
|
-
const { cmdSetup } = await import('../setup-
|
|
8405
|
+
const { cmdSetup } = await import('../setup-2CCS63L6.js');
|
|
7758
8406
|
await cmdSetup([], { projectDir: process.cwd() });
|
|
7759
8407
|
});
|
|
7760
8408
|
program.addCommand(makeInstallCommand());
|