@vibe-forge/workspace-assets 3.2.2-alpha.0 → 3.2.2-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/bundle.spec.ts +10 -65
- package/__tests__/skill-dependencies-cli.spec.ts +31 -0
- package/package.json +4 -4
- package/src/bundle-internal.ts +15 -9
- package/src/bundle.ts +1 -0
- package/src/configured-skills.ts +24 -30
- package/src/prompt-selection.ts +3 -3
- package/src/selection-internal.ts +36 -3
package/__tests__/bundle.spec.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { join } from 'node:path'
|
|
3
3
|
import process from 'node:process'
|
|
4
4
|
|
|
5
|
-
import { readFile } from 'node:fs/promises'
|
|
6
5
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
7
6
|
|
|
8
7
|
const skillsCliMocks = vi.hoisted(() => ({
|
|
@@ -27,6 +26,7 @@ import { createWorkspace, installPluginPackage, writeDocument } from './test-hel
|
|
|
27
26
|
|
|
28
27
|
afterEach(() => {
|
|
29
28
|
vi.clearAllMocks()
|
|
29
|
+
vi.restoreAllMocks()
|
|
30
30
|
vi.unstubAllGlobals()
|
|
31
31
|
})
|
|
32
32
|
|
|
@@ -291,7 +291,7 @@ describe('resolveWorkspaceAssetBundle', () => {
|
|
|
291
291
|
|
|
292
292
|
expect(bundle.skills).toEqual([])
|
|
293
293
|
expect(warnSpy).toHaveBeenCalledWith(
|
|
294
|
-
expect.stringContaining('Ignoring invalid
|
|
294
|
+
expect.stringContaining('Ignoring invalid skillsMeta.homeBridge root "./team-skills"')
|
|
295
295
|
)
|
|
296
296
|
} finally {
|
|
297
297
|
warnSpy.mockRestore()
|
|
@@ -386,22 +386,9 @@ describe('resolveWorkspaceAssetBundle', () => {
|
|
|
386
386
|
}))
|
|
387
387
|
})
|
|
388
388
|
|
|
389
|
-
it('
|
|
389
|
+
it('does not install configured project skills during bundle resolution and warns when requested', async () => {
|
|
390
390
|
const workspace = await createWorkspace()
|
|
391
|
-
const
|
|
392
|
-
const installedSkillDir = join(tempInstallDir, '.agents', 'skills', 'design-review')
|
|
393
|
-
await writeDocument(
|
|
394
|
-
join(installedSkillDir, 'SKILL.md'),
|
|
395
|
-
'---\nname: design-review\ndescription: Review design work\n---\nReview the UI implementation.\n'
|
|
396
|
-
)
|
|
397
|
-
skillsCliMocks.installSkillsCliSkillToTemp.mockResolvedValue({
|
|
398
|
-
tempDir: tempInstallDir,
|
|
399
|
-
installedSkill: {
|
|
400
|
-
dirName: 'design-review',
|
|
401
|
-
name: 'design-review',
|
|
402
|
-
sourcePath: installedSkillDir
|
|
403
|
-
}
|
|
404
|
-
})
|
|
391
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
|
|
405
392
|
|
|
406
393
|
const bundle = await resolveWorkspaceAssetBundle({
|
|
407
394
|
cwd: workspace,
|
|
@@ -414,22 +401,16 @@ describe('resolveWorkspaceAssetBundle', () => {
|
|
|
414
401
|
}
|
|
415
402
|
]
|
|
416
403
|
}, undefined],
|
|
417
|
-
|
|
404
|
+
warnMissingConfiguredSkills: true,
|
|
418
405
|
useDefaultVibeForgeMcpServer: false
|
|
419
406
|
})
|
|
420
407
|
|
|
421
|
-
expect(bundle.skills.map(asset => asset.name)).toContain('internal-review')
|
|
422
|
-
expect(skillsCliMocks.installSkillsCliSkillToTemp).
|
|
423
|
-
|
|
424
|
-
skill: 'design-review',
|
|
425
|
-
source: 'example-source/default/public'
|
|
426
|
-
})
|
|
427
|
-
await expect(readFile(join(workspace, '.ai/skills/internal-review/SKILL.md'), 'utf8')).resolves.toContain(
|
|
428
|
-
'name: internal-review'
|
|
429
|
-
)
|
|
408
|
+
expect(bundle.skills.map(asset => asset.name)).not.toContain('internal-review')
|
|
409
|
+
expect(skillsCliMocks.installSkillsCliSkillToTemp).not.toHaveBeenCalled()
|
|
410
|
+
expect(warn).toHaveBeenCalledWith(expect.stringContaining('Declared skills are not installed: internal-review'))
|
|
430
411
|
})
|
|
431
412
|
|
|
432
|
-
it('
|
|
413
|
+
it('loads installed configured skills without attempting runtime updates', async () => {
|
|
433
414
|
const workspace = await createWorkspace()
|
|
434
415
|
await writeDocument(
|
|
435
416
|
join(workspace, '.ai/skills/internal-review/SKILL.md'),
|
|
@@ -447,48 +428,12 @@ describe('resolveWorkspaceAssetBundle', () => {
|
|
|
447
428
|
}
|
|
448
429
|
]
|
|
449
430
|
}, undefined],
|
|
450
|
-
|
|
431
|
+
warnMissingConfiguredSkills: true,
|
|
451
432
|
useDefaultVibeForgeMcpServer: false
|
|
452
433
|
})
|
|
453
434
|
|
|
454
435
|
expect(skippedBundle.skills.map(asset => asset.name)).toContain('internal-review')
|
|
455
436
|
expect(skillsCliMocks.installSkillsCliSkillToTemp).not.toHaveBeenCalled()
|
|
456
|
-
|
|
457
|
-
const tempInstallDir = join(workspace, '.tmp-configured-update')
|
|
458
|
-
const installedSkillDir = join(tempInstallDir, '.agents', 'skills', 'design-review')
|
|
459
|
-
await writeDocument(
|
|
460
|
-
join(installedSkillDir, 'SKILL.md'),
|
|
461
|
-
'---\nname: design-review\ndescription: Updated skill\n---\nUpdated content.\n'
|
|
462
|
-
)
|
|
463
|
-
skillsCliMocks.installSkillsCliSkillToTemp.mockResolvedValueOnce({
|
|
464
|
-
tempDir: tempInstallDir,
|
|
465
|
-
installedSkill: {
|
|
466
|
-
dirName: 'design-review',
|
|
467
|
-
name: 'design-review',
|
|
468
|
-
sourcePath: installedSkillDir
|
|
469
|
-
}
|
|
470
|
-
})
|
|
471
|
-
|
|
472
|
-
await resolveWorkspaceAssetBundle({
|
|
473
|
-
cwd: workspace,
|
|
474
|
-
configs: [{
|
|
475
|
-
skills: [
|
|
476
|
-
{
|
|
477
|
-
name: 'design-review',
|
|
478
|
-
source: 'example-source/default/public',
|
|
479
|
-
rename: 'internal-review'
|
|
480
|
-
}
|
|
481
|
-
]
|
|
482
|
-
}, undefined],
|
|
483
|
-
syncConfiguredSkills: true,
|
|
484
|
-
updateConfiguredSkills: true,
|
|
485
|
-
useDefaultVibeForgeMcpServer: false
|
|
486
|
-
})
|
|
487
|
-
|
|
488
|
-
expect(skillsCliMocks.installSkillsCliSkillToTemp).toHaveBeenCalledTimes(1)
|
|
489
|
-
await expect(readFile(join(workspace, '.ai/skills/internal-review/SKILL.md'), 'utf8')).resolves.toContain(
|
|
490
|
-
'Updated content.'
|
|
491
|
-
)
|
|
492
437
|
})
|
|
493
438
|
|
|
494
439
|
it('loads workspace entities from the env-configured entities dir', async () => {
|
|
@@ -64,6 +64,37 @@ describe('materialized skill dependency resolution', () => {
|
|
|
64
64
|
expect(mocks.installSkillsCliSkillToTemp).not.toHaveBeenCalled()
|
|
65
65
|
})
|
|
66
66
|
|
|
67
|
+
it('prompts install command when an explicitly selected configured skill is missing', async () => {
|
|
68
|
+
const workspace = await createWorkspace()
|
|
69
|
+
const bundle = await resolveWorkspaceAssetBundle({
|
|
70
|
+
cwd: workspace,
|
|
71
|
+
configs: [{
|
|
72
|
+
skills: [
|
|
73
|
+
{
|
|
74
|
+
name: 'design-review',
|
|
75
|
+
source: 'example-source/default/public',
|
|
76
|
+
rename: 'internal-review'
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}, undefined],
|
|
80
|
+
useDefaultVibeForgeMcpServer: false
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
await expect(buildAdapterAssetPlan({
|
|
84
|
+
adapter: 'opencode',
|
|
85
|
+
bundle,
|
|
86
|
+
options: {
|
|
87
|
+
skills: {
|
|
88
|
+
include: ['internal-review']
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
})).rejects.toThrow('Run `vf skills install internal-review` or `vf skills install`')
|
|
92
|
+
|
|
93
|
+
expect(mocks.findSkillsCli).not.toHaveBeenCalled()
|
|
94
|
+
expect(mocks.installSkillsCliRefToTemp).not.toHaveBeenCalled()
|
|
95
|
+
expect(mocks.installSkillsCliSkillToTemp).not.toHaveBeenCalled()
|
|
96
|
+
})
|
|
97
|
+
|
|
67
98
|
it('uses project-materialized dependencies from .ai/skills', async () => {
|
|
68
99
|
const workspace = await createWorkspace()
|
|
69
100
|
await writeDocument(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-forge/workspace-assets",
|
|
3
|
-
"version": "3.2.2-alpha.
|
|
3
|
+
"version": "3.2.2-alpha.2",
|
|
4
4
|
"description": "Workspace asset resolution and adapter asset planning for Vibe Forge",
|
|
5
5
|
"imports": {
|
|
6
6
|
"#~/*.js": {
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"fast-glob": "^3.3.3",
|
|
30
30
|
"front-matter": "^4.0.2",
|
|
31
31
|
"js-yaml": "^4.1.1",
|
|
32
|
-
"@vibe-forge/config": "3.2.3-alpha.
|
|
33
|
-
"@vibe-forge/types": "3.2.3-alpha.0",
|
|
32
|
+
"@vibe-forge/config": "3.2.3-alpha.2",
|
|
34
33
|
"@vibe-forge/definition-core": "3.2.0",
|
|
35
|
-
"@vibe-forge/
|
|
34
|
+
"@vibe-forge/types": "3.2.3-alpha.1",
|
|
35
|
+
"@vibe-forge/utils": "3.2.3-alpha.2"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/js-yaml": "^4.0.9"
|
package/src/bundle-internal.ts
CHANGED
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
} from '@vibe-forge/config'
|
|
11
11
|
import type { Config, Definition, Entity, PluginConfig, WorkspaceAsset, WorkspaceAssetKind } from '@vibe-forge/types'
|
|
12
12
|
import {
|
|
13
|
-
isObjectSkillsConfig,
|
|
14
13
|
readProjectSkillsLockfile,
|
|
15
14
|
resolveProjectAiBaseDir,
|
|
16
15
|
resolveProjectAiEntitiesDir,
|
|
17
|
-
resolveRelativePath
|
|
16
|
+
resolveRelativePath,
|
|
17
|
+
resolveSkillsHomeBridge
|
|
18
18
|
} from '@vibe-forge/utils'
|
|
19
19
|
import { listManagedPluginInstalls, toManagedPluginConfig } from '@vibe-forge/utils/managed-plugin'
|
|
20
20
|
import {
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
resolveSkillIdentifier,
|
|
35
35
|
resolveSpecIdentifier
|
|
36
36
|
} from '@vibe-forge/definition-core'
|
|
37
|
-
import {
|
|
37
|
+
import { warnMissingConfiguredProjectSkills } from './configured-skills'
|
|
38
38
|
import { HOME_BRIDGE_RESOLVED_BY } from './home-bridge'
|
|
39
39
|
import { PLUGIN_SKILL_DEPENDENCY_RESOLVED_BY } from './plugin-skill-dependencies'
|
|
40
40
|
import { resolveConfiguredWorkspaceAssets } from './workspaces'
|
|
@@ -154,15 +154,15 @@ const resolveRealHomeDir = (env: NodeJS.ProcessEnv) => {
|
|
|
154
154
|
|
|
155
155
|
const warnInvalidHomeSkillRoot = (root: string) => {
|
|
156
156
|
console.warn(
|
|
157
|
-
`[vibe-forge] Ignoring invalid
|
|
157
|
+
`[vibe-forge] Ignoring invalid skillsMeta.homeBridge root "${root}". ` +
|
|
158
158
|
'Use an absolute path or a path starting with "~".'
|
|
159
159
|
)
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
const resolveHomeBridgeConfig = (configs: [Config?, Config?]) => {
|
|
163
163
|
const [config, userConfig] = configs
|
|
164
|
-
const projectHomeBridge =
|
|
165
|
-
const userHomeBridge =
|
|
164
|
+
const projectHomeBridge = resolveSkillsHomeBridge(config)
|
|
165
|
+
const userHomeBridge = resolveSkillsHomeBridge(userConfig)
|
|
166
166
|
|
|
167
167
|
return {
|
|
168
168
|
enabled: userHomeBridge?.enabled ?? projectHomeBridge?.enabled ?? true,
|
|
@@ -571,6 +571,7 @@ export async function collectWorkspaceAssets(params: {
|
|
|
571
571
|
syncConfiguredSkills?: boolean
|
|
572
572
|
updateConfiguredSkills?: boolean
|
|
573
573
|
useDefaultVibeForgeMcpServer?: boolean
|
|
574
|
+
warnMissingConfiguredSkills?: boolean
|
|
574
575
|
}): Promise<{
|
|
575
576
|
assets: WorkspaceAsset[]
|
|
576
577
|
configs: [Config?, Config?]
|
|
@@ -588,10 +589,15 @@ export async function collectWorkspaceAssets(params: {
|
|
|
588
589
|
workspaces: Array<Extract<WorkspaceAsset, { kind: 'workspace' }>>
|
|
589
590
|
}> {
|
|
590
591
|
const [config, userConfig] = params.configs ?? await loadWorkspaceConfig(params.cwd)
|
|
591
|
-
if (params.syncConfiguredSkills === true) {
|
|
592
|
-
|
|
592
|
+
if (params.syncConfiguredSkills === true || params.updateConfiguredSkills === true) {
|
|
593
|
+
console.warn(
|
|
594
|
+
'[vibe-forge] Runtime skill install/update is disabled. ' +
|
|
595
|
+
'Run `vf skills install` or `vf skills update` before starting the session.'
|
|
596
|
+
)
|
|
597
|
+
}
|
|
598
|
+
if (params.warnMissingConfiguredSkills === true) {
|
|
599
|
+
await warnMissingConfiguredProjectSkills({
|
|
593
600
|
configs: [config, userConfig],
|
|
594
|
-
updateInstalledSkills: params.updateConfiguredSkills,
|
|
595
601
|
workspaceFolder: params.cwd
|
|
596
602
|
})
|
|
597
603
|
}
|
package/src/bundle.ts
CHANGED
|
@@ -11,6 +11,7 @@ export async function resolveWorkspaceAssetBundle(params: {
|
|
|
11
11
|
syncConfiguredSkills?: boolean
|
|
12
12
|
updateConfiguredSkills?: boolean
|
|
13
13
|
useDefaultVibeForgeMcpServer?: boolean
|
|
14
|
+
warnMissingConfiguredSkills?: boolean
|
|
14
15
|
}): Promise<WorkspaceAssetBundle> {
|
|
15
16
|
const collected = await collectWorkspaceAssets(params)
|
|
16
17
|
|
package/src/configured-skills.ts
CHANGED
|
@@ -3,15 +3,13 @@ import process from 'node:process'
|
|
|
3
3
|
|
|
4
4
|
import type { Config, ConfiguredSkillInstallConfig } from '@vibe-forge/types'
|
|
5
5
|
import {
|
|
6
|
-
installProjectSkill,
|
|
7
6
|
normalizeProjectSkillInstall,
|
|
8
7
|
resolveConfiguredSkillInstalls as resolveDeclaredConfiguredSkillInstalls,
|
|
9
|
-
resolveProjectAiPath
|
|
10
|
-
resolveSkillsRegistry
|
|
8
|
+
resolveProjectAiPath
|
|
11
9
|
} from '@vibe-forge/utils'
|
|
12
10
|
import type { NormalizedProjectSkillInstall } from '@vibe-forge/utils'
|
|
13
11
|
|
|
14
|
-
const
|
|
12
|
+
export const resolveConfiguredProjectSkillInstalls = (configs: [Config?, Config?]) => (
|
|
15
13
|
[
|
|
16
14
|
...resolveDeclaredConfiguredSkillInstalls(configs[0]?.skills),
|
|
17
15
|
...resolveDeclaredConfiguredSkillInstalls(configs[1]?.skills)
|
|
@@ -29,7 +27,7 @@ const pathExists = async (targetPath: string) => {
|
|
|
29
27
|
}
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
const
|
|
30
|
+
export const ensureUniqueConfiguredSkillTargets = (skills: NormalizedProjectSkillInstall[]) => {
|
|
33
31
|
const seen = new Map<string, string>()
|
|
34
32
|
|
|
35
33
|
for (const skill of skills) {
|
|
@@ -43,22 +41,18 @@ const ensureUniqueTargets = (skills: NormalizedProjectSkillInstall[]) => {
|
|
|
43
41
|
}
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
export const
|
|
44
|
+
export const findMissingConfiguredProjectSkills = async (params: {
|
|
47
45
|
configs: [Config?, Config?]
|
|
48
|
-
updateInstalledSkills?: boolean
|
|
49
46
|
workspaceFolder: string
|
|
50
47
|
}) => {
|
|
51
|
-
const
|
|
52
|
-
resolveSkillsRegistry(params.configs[0]?.skills)
|
|
53
|
-
const installs = resolveConfiguredSkillInstalls(params.configs)
|
|
48
|
+
const installs = resolveConfiguredProjectSkillInstalls(params.configs)
|
|
54
49
|
if (installs.length === 0) {
|
|
55
50
|
return []
|
|
56
51
|
}
|
|
57
52
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const ensured: Array<{ dirName: string; skillPath: string }> = []
|
|
53
|
+
ensureUniqueConfiguredSkillTargets(installs)
|
|
61
54
|
|
|
55
|
+
const missing: NormalizedProjectSkillInstall[] = []
|
|
62
56
|
for (const skill of installs) {
|
|
63
57
|
const skillPath = resolveProjectAiPath(
|
|
64
58
|
params.workspaceFolder,
|
|
@@ -67,23 +61,23 @@ export const ensureConfiguredProjectSkills = async (params: {
|
|
|
67
61
|
skill.targetDirName,
|
|
68
62
|
'SKILL.md'
|
|
69
63
|
)
|
|
70
|
-
if (
|
|
71
|
-
ensured.push({
|
|
72
|
-
dirName: skill.targetDirName,
|
|
73
|
-
skillPath
|
|
74
|
-
})
|
|
75
|
-
continue
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
ensured.push(
|
|
79
|
-
await installProjectSkill({
|
|
80
|
-
force: true,
|
|
81
|
-
registry: defaultRegistry,
|
|
82
|
-
skill,
|
|
83
|
-
workspaceFolder: params.workspaceFolder
|
|
84
|
-
})
|
|
85
|
-
)
|
|
64
|
+
if (!await pathExists(skillPath)) missing.push(skill)
|
|
86
65
|
}
|
|
87
66
|
|
|
88
|
-
return
|
|
67
|
+
return missing
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const warnMissingConfiguredProjectSkills = async (params: {
|
|
71
|
+
configs: [Config?, Config?]
|
|
72
|
+
workspaceFolder: string
|
|
73
|
+
}) => {
|
|
74
|
+
const missing = await findMissingConfiguredProjectSkills(params)
|
|
75
|
+
if (missing.length === 0) return []
|
|
76
|
+
|
|
77
|
+
const names = missing.map(skill => skill.targetName).join(', ')
|
|
78
|
+
console.warn(
|
|
79
|
+
`[vibe-forge] Declared skills are not installed: ${names}. ` +
|
|
80
|
+
'Run `vf skills install` to install all declared skills, or `vf skills install <name>` for one skill.'
|
|
81
|
+
)
|
|
82
|
+
return missing
|
|
89
83
|
}
|
package/src/prompt-selection.ts
CHANGED
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
resolveEntityInheritance,
|
|
30
30
|
resolveExcludedSkillRefs,
|
|
31
31
|
resolveIncludedSkillRefs,
|
|
32
|
-
|
|
32
|
+
resolveNamedSkillAssets,
|
|
33
33
|
resolvePluginOverlay,
|
|
34
34
|
resolveRuleSelection,
|
|
35
35
|
resolveSelectedSkillAssetsWithDependencies,
|
|
@@ -158,10 +158,10 @@ export async function resolvePromptAssetSelection(params: {
|
|
|
158
158
|
const includedAssets = skillSelection == null
|
|
159
159
|
? []
|
|
160
160
|
: includedRefs != null
|
|
161
|
-
? (includedRefs.length > 0 ?
|
|
161
|
+
? (includedRefs.length > 0 ? resolveNamedSkillAssets(effectiveBundle, includedRefs, targetInstancePath) : [])
|
|
162
162
|
: effectiveBundle.skills
|
|
163
163
|
const excludedIds = new Set(
|
|
164
|
-
|
|
164
|
+
resolveNamedSkillAssets(effectiveBundle, excludedRefs, targetInstancePath).map(asset => asset.id)
|
|
165
165
|
)
|
|
166
166
|
|
|
167
167
|
const expandedTargetSkills = await expandSkillAssetDependenciesWithRemoteResolution({
|
|
@@ -15,7 +15,7 @@ import type {
|
|
|
15
15
|
WorkspaceMcpSelection,
|
|
16
16
|
WorkspaceSkillSelection
|
|
17
17
|
} from '@vibe-forge/types'
|
|
18
|
-
import { normalizePath } from '@vibe-forge/utils'
|
|
18
|
+
import { matchesDeclaredSkillSelector, normalizePath } from '@vibe-forge/utils'
|
|
19
19
|
import { mergePluginConfigs, normalizePluginConfig } from '@vibe-forge/utils/plugin-resolver'
|
|
20
20
|
import { glob } from 'fast-glob'
|
|
21
21
|
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
isRemoteRuleReference,
|
|
27
27
|
parseScopedReference
|
|
28
28
|
} from '@vibe-forge/definition-core'
|
|
29
|
+
import { resolveConfiguredProjectSkillInstalls } from './configured-skills'
|
|
29
30
|
import { PLUGIN_SKILL_DEPENDENCY_RESOLVED_BY } from './plugin-skill-dependencies'
|
|
30
31
|
import { expandSkillAssetDependencies, expandSkillAssetDependenciesWithRemoteResolution } from './skill-dependencies'
|
|
31
32
|
|
|
@@ -516,6 +517,38 @@ export const resolveExcludedSkillRefs = (selection: string[] | SkillSelection |
|
|
|
516
517
|
return selection.type === 'exclude' ? selection.list : undefined
|
|
517
518
|
}
|
|
518
519
|
|
|
520
|
+
const createMissingConfiguredSkillMessage = (
|
|
521
|
+
bundle: WorkspaceAssetBundle,
|
|
522
|
+
refs: string[] | undefined
|
|
523
|
+
) => {
|
|
524
|
+
const configs = bundle.configs ?? [undefined, undefined]
|
|
525
|
+
const declared = resolveConfiguredProjectSkillInstalls(configs)
|
|
526
|
+
|
|
527
|
+
for (const ref of refs ?? []) {
|
|
528
|
+
const match = declared.find(skill => matchesDeclaredSkillSelector(ref, skill))
|
|
529
|
+
if (match == null) continue
|
|
530
|
+
|
|
531
|
+
return `Skill ${ref} is declared in config but is not installed. ` +
|
|
532
|
+
`Run \`vf skills install ${match.targetName}\` or \`vf skills install\` before selecting it.`
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
return undefined
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
export const resolveNamedSkillAssets = (
|
|
539
|
+
bundle: WorkspaceAssetBundle,
|
|
540
|
+
refs: string[] | undefined,
|
|
541
|
+
currentInstancePath?: string
|
|
542
|
+
) => {
|
|
543
|
+
try {
|
|
544
|
+
return resolveNamedAssets(bundle.skills, refs, currentInstancePath)
|
|
545
|
+
} catch (error) {
|
|
546
|
+
const message = createMissingConfiguredSkillMessage(bundle, refs)
|
|
547
|
+
if (message != null) throw new Error(message)
|
|
548
|
+
throw error
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
519
552
|
export const resolveSelectedSkillAssets = (
|
|
520
553
|
assets: Array<Extract<WorkspaceAsset, { kind: 'skill' }>>,
|
|
521
554
|
selection?: WorkspaceSkillSelection
|
|
@@ -540,10 +573,10 @@ export const resolveSelectedSkillAssetsWithDependencies = async (
|
|
|
540
573
|
): Promise<Array<Extract<WorkspaceAsset, { kind: 'skill' }>>> => {
|
|
541
574
|
const rootAssets = bundle.skills.filter(asset => !isPluginSkillDependencyAsset(asset))
|
|
542
575
|
const included = selection?.include != null && selection.include.length > 0
|
|
543
|
-
?
|
|
576
|
+
? resolveNamedSkillAssets(bundle, selection.include)
|
|
544
577
|
: rootAssets
|
|
545
578
|
const excluded = new Set(
|
|
546
|
-
|
|
579
|
+
resolveNamedSkillAssets(bundle, selection?.exclude).map(asset => asset.id)
|
|
547
580
|
)
|
|
548
581
|
return await expandSkillAssetDependenciesWithRemoteResolution({
|
|
549
582
|
allAssets: bundle.assets,
|