@vibe-forge/workspace-assets 3.4.0-rc.1 → 3.4.0-rc.3
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
CHANGED
|
@@ -23,6 +23,7 @@ vi.mock('@vibe-forge/utils/skills-cli', async () => {
|
|
|
23
23
|
})
|
|
24
24
|
|
|
25
25
|
import { resolveWorkspaceAssetBundle } from '#~/index.js'
|
|
26
|
+
import { resolveProjectSkillsStorePath, writeProjectSkillsLockfile } from '@vibe-forge/utils'
|
|
26
27
|
|
|
27
28
|
import { createWorkspace, installPluginPackage, writeDocument } from './test-helpers'
|
|
28
29
|
|
|
@@ -579,6 +580,57 @@ describe('resolveWorkspaceAssetBundle', () => {
|
|
|
579
580
|
expect(skillsCliMocks.installSkillsCliSkillToTemp).not.toHaveBeenCalled()
|
|
580
581
|
})
|
|
581
582
|
|
|
583
|
+
it('loads lockfile-managed configured skills from the real home project store', async () => {
|
|
584
|
+
const workspace = await createWorkspace()
|
|
585
|
+
const storeHash = 'sha256-home-store'
|
|
586
|
+
const installDir = resolveProjectSkillsStorePath(
|
|
587
|
+
{
|
|
588
|
+
storeHash,
|
|
589
|
+
workspaceFolder: workspace
|
|
590
|
+
},
|
|
591
|
+
'skills',
|
|
592
|
+
'internal-review'
|
|
593
|
+
)
|
|
594
|
+
await writeDocument(
|
|
595
|
+
join(installDir, 'SKILL.md'),
|
|
596
|
+
'---\nname: internal-review\ndescription: Existing skill\n---\nExisting content.\n'
|
|
597
|
+
)
|
|
598
|
+
await writeProjectSkillsLockfile(workspace, {
|
|
599
|
+
version: 1,
|
|
600
|
+
storeHash,
|
|
601
|
+
skills: {
|
|
602
|
+
'internal-review': {
|
|
603
|
+
hash: 'sha256:test',
|
|
604
|
+
installedAt: '2026-05-19T00:00:00.000Z',
|
|
605
|
+
installPath: 'skills/internal-review',
|
|
606
|
+
name: 'internal-review',
|
|
607
|
+
requested: true,
|
|
608
|
+
source: 'example-source/default/public'
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
})
|
|
612
|
+
|
|
613
|
+
const bundle = await resolveWorkspaceAssetBundle({
|
|
614
|
+
cwd: workspace,
|
|
615
|
+
configs: [{
|
|
616
|
+
skills: [
|
|
617
|
+
{
|
|
618
|
+
name: 'design-review',
|
|
619
|
+
source: 'example-source/default/public',
|
|
620
|
+
rename: 'internal-review'
|
|
621
|
+
}
|
|
622
|
+
]
|
|
623
|
+
}, undefined],
|
|
624
|
+
warnMissingConfiguredSkills: true,
|
|
625
|
+
useDefaultVibeForgeMcpServer: false
|
|
626
|
+
})
|
|
627
|
+
|
|
628
|
+
expect(bundle.skills.find(asset => asset.name === 'internal-review')).toEqual(expect.objectContaining({
|
|
629
|
+
sourcePath: join(installDir, 'SKILL.md')
|
|
630
|
+
}))
|
|
631
|
+
expect(skillsCliMocks.installSkillsCliSkillToTemp).not.toHaveBeenCalled()
|
|
632
|
+
})
|
|
633
|
+
|
|
582
634
|
it('loads workspace entities from the env-configured entities dir', async () => {
|
|
583
635
|
const workspace = await createWorkspace()
|
|
584
636
|
const previousEntitiesDir = process.env.__VF_PROJECT_AI_ENTITIES_DIR__
|
|
@@ -19,6 +19,8 @@ vi.mock('@vibe-forge/utils/skills-cli', async () => {
|
|
|
19
19
|
}
|
|
20
20
|
})
|
|
21
21
|
|
|
22
|
+
import { resolveProjectSkillsStorePath } from '@vibe-forge/utils'
|
|
23
|
+
|
|
22
24
|
import { buildAdapterAssetPlan, resolveWorkspaceAssetBundle } from '#~/index.js'
|
|
23
25
|
|
|
24
26
|
import { createWorkspace, installPluginPackage, writeDocument } from './test-helpers'
|
|
@@ -136,8 +138,9 @@ describe('materialized skill dependency resolution', () => {
|
|
|
136
138
|
expect(mocks.findSkillsCli).not.toHaveBeenCalled()
|
|
137
139
|
})
|
|
138
140
|
|
|
139
|
-
it('loads plugin dependencies from
|
|
141
|
+
it('loads plugin dependencies from the home project store through the lockfile', async () => {
|
|
140
142
|
const workspace = await createWorkspace()
|
|
143
|
+
const storeHash = 'sha256-store'
|
|
141
144
|
await installPluginPackage(workspace, '@vibe-forge/plugin-review', {
|
|
142
145
|
'package.json': JSON.stringify({ name: '@vibe-forge/plugin-review', version: '1.0.0' }, null, 2),
|
|
143
146
|
'skills/review-helper/SKILL.md': [
|
|
@@ -151,20 +154,27 @@ describe('materialized skill dependency resolution', () => {
|
|
|
151
154
|
].join('\n')
|
|
152
155
|
})
|
|
153
156
|
await writeDocument(
|
|
154
|
-
join(
|
|
157
|
+
join(
|
|
158
|
+
resolveProjectSkillsStorePath({
|
|
159
|
+
storeHash,
|
|
160
|
+
workspaceFolder: workspace
|
|
161
|
+
}, 'skills', '.plugins', 'review', 'shared-runtime'),
|
|
162
|
+
'SKILL.md'
|
|
163
|
+
),
|
|
155
164
|
'---\nname: shared-runtime\ndescription: Shared runtime\n---\nShared plugin dependency.\n'
|
|
156
165
|
)
|
|
157
166
|
await writeDocument(
|
|
158
167
|
join(workspace, '.ai/skills.lock.yaml'),
|
|
159
168
|
[
|
|
160
169
|
'version: 1',
|
|
170
|
+
`storeHash: ${storeHash}`,
|
|
161
171
|
'pluginSkills:',
|
|
162
172
|
' review/shared-runtime:',
|
|
163
173
|
' name: shared-runtime',
|
|
164
174
|
' requested: false',
|
|
165
175
|
' pluginInstance: review',
|
|
166
176
|
' pluginInstancePath: "0"',
|
|
167
|
-
' installPath:
|
|
177
|
+
' installPath: skills/.plugins/review/shared-runtime',
|
|
168
178
|
' dependencyOf:',
|
|
169
179
|
' - plugin:review/review-helper',
|
|
170
180
|
' source: vendor/shared-skills',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-forge/workspace-assets",
|
|
3
|
-
"version": "3.4.0-rc.
|
|
3
|
+
"version": "3.4.0-rc.3",
|
|
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.4.0-rc.
|
|
33
|
-
"@vibe-forge/definition-core": "3.4.0-rc.
|
|
34
|
-
"@vibe-forge/
|
|
35
|
-
"@vibe-forge/
|
|
32
|
+
"@vibe-forge/config": "3.4.0-rc.3",
|
|
33
|
+
"@vibe-forge/definition-core": "3.4.0-rc.3",
|
|
34
|
+
"@vibe-forge/types": "3.4.0-rc.3",
|
|
35
|
+
"@vibe-forge/utils": "3.4.0-rc.3"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/js-yaml": "^4.0.9"
|
package/src/bundle-internal.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
readProjectSkillsLockfile,
|
|
14
14
|
resolveProjectAiBaseDir,
|
|
15
15
|
resolveProjectAiEntitiesDir,
|
|
16
|
+
resolveProjectSkillInstallDir,
|
|
16
17
|
resolveRelativePath,
|
|
17
18
|
resolveSkillsHomeBridge
|
|
18
19
|
} from '@vibe-forge/utils'
|
|
@@ -500,7 +501,14 @@ const scanProjectSkillLockfileDocuments = async (cwd: string) => {
|
|
|
500
501
|
const lockfile = await readProjectSkillsLockfile(cwd)
|
|
501
502
|
const skillPaths: string[] = []
|
|
502
503
|
for (const entry of Object.values(lockfile.skills ?? {})) {
|
|
503
|
-
const skillPath = resolve(
|
|
504
|
+
const skillPath = resolve(
|
|
505
|
+
resolveProjectSkillInstallDir({
|
|
506
|
+
installPath: entry.installPath,
|
|
507
|
+
storeHash: entry.storeHash ?? lockfile.storeHash,
|
|
508
|
+
workspaceFolder: cwd
|
|
509
|
+
}),
|
|
510
|
+
'SKILL.md'
|
|
511
|
+
)
|
|
504
512
|
if (await pathExists(skillPath)) {
|
|
505
513
|
skillPaths.push(skillPath)
|
|
506
514
|
}
|
|
@@ -522,7 +530,14 @@ const scanPluginDependencySkillDocuments = async (
|
|
|
522
530
|
))
|
|
523
531
|
if (instance == null) continue
|
|
524
532
|
|
|
525
|
-
const skillPath = resolve(
|
|
533
|
+
const skillPath = resolve(
|
|
534
|
+
resolveProjectSkillInstallDir({
|
|
535
|
+
installPath: entry.installPath,
|
|
536
|
+
storeHash: entry.storeHash ?? lockfile.storeHash,
|
|
537
|
+
workspaceFolder: cwd
|
|
538
|
+
}),
|
|
539
|
+
'SKILL.md'
|
|
540
|
+
)
|
|
526
541
|
if (await pathExists(skillPath)) {
|
|
527
542
|
documents.push({
|
|
528
543
|
instance,
|
package/src/configured-skills.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable max-lines -- configured skill resolution keeps matching, warnings, and CLI sync policy together. */
|
|
2
2
|
import { access } from 'node:fs/promises'
|
|
3
|
-
import {
|
|
3
|
+
import { join } from 'node:path'
|
|
4
4
|
import process from 'node:process'
|
|
5
5
|
|
|
6
6
|
import type {
|
|
@@ -16,9 +16,10 @@ import {
|
|
|
16
16
|
readProjectSkillsLockfile,
|
|
17
17
|
resolveConfiguredSkillInstalls as resolveDeclaredConfiguredSkillInstalls,
|
|
18
18
|
resolveProjectAiPath,
|
|
19
|
+
resolveProjectSkillInstallDir,
|
|
19
20
|
toSkillSlug
|
|
20
21
|
} from '@vibe-forge/utils'
|
|
21
|
-
import type { NormalizedProjectSkillInstall, ProjectSkillLockEntry } from '@vibe-forge/utils'
|
|
22
|
+
import type { NormalizedProjectSkillInstall, ProjectSkillLockEntry, ProjectSkillsLockfile } from '@vibe-forge/utils'
|
|
22
23
|
|
|
23
24
|
interface NormalizedConfiguredSkillCollection {
|
|
24
25
|
include?: ConfiguredSkillCollectionConfig['include']
|
|
@@ -106,33 +107,42 @@ const lockEntryMatchesCollection = (
|
|
|
106
107
|
(collection.version == null || entry.version === collection.version)
|
|
107
108
|
)
|
|
108
109
|
|
|
109
|
-
const resolveLockEntrySkillPath = (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
const resolveLockEntrySkillPath = (
|
|
111
|
+
workspaceFolder: string,
|
|
112
|
+
lockfile: Pick<ProjectSkillsLockfile, 'storeHash'>,
|
|
113
|
+
entry: ProjectSkillLockEntry
|
|
114
|
+
) =>
|
|
115
|
+
join(
|
|
116
|
+
resolveProjectSkillInstallDir({
|
|
117
|
+
installPath: entry.installPath,
|
|
118
|
+
storeHash: entry.storeHash ?? lockfile.storeHash,
|
|
119
|
+
workspaceFolder
|
|
120
|
+
}),
|
|
121
|
+
'SKILL.md'
|
|
122
|
+
)
|
|
115
123
|
|
|
116
124
|
const hasInstalledCollectionLockEntry = async (params: {
|
|
117
125
|
collection: NormalizedConfiguredSkillCollection
|
|
118
|
-
|
|
126
|
+
lockfile: ProjectSkillsLockfile
|
|
119
127
|
workspaceFolder: string
|
|
120
128
|
}) => {
|
|
121
|
-
for (const entry of Object.values(params.
|
|
129
|
+
for (const entry of Object.values(params.lockfile.skills ?? {})) {
|
|
122
130
|
if (!lockEntryMatchesCollection(entry, params.collection)) continue
|
|
123
|
-
if (await pathExists(resolveLockEntrySkillPath(params.workspaceFolder, entry))) return true
|
|
131
|
+
if (await pathExists(resolveLockEntrySkillPath(params.workspaceFolder, params.lockfile, entry))) return true
|
|
124
132
|
}
|
|
125
133
|
|
|
126
134
|
return false
|
|
127
135
|
}
|
|
128
136
|
|
|
129
137
|
const hasInstalledSkillTarget = async (params: {
|
|
130
|
-
|
|
138
|
+
lockfile: ProjectSkillsLockfile
|
|
131
139
|
targetDirName: string
|
|
132
140
|
workspaceFolder: string
|
|
133
141
|
}) => {
|
|
134
|
-
const entry = params.
|
|
135
|
-
if (entry != null && await pathExists(resolveLockEntrySkillPath(params.workspaceFolder, entry)))
|
|
142
|
+
const entry = params.lockfile.skills?.[params.targetDirName]
|
|
143
|
+
if (entry != null && await pathExists(resolveLockEntrySkillPath(params.workspaceFolder, params.lockfile, entry))) {
|
|
144
|
+
return true
|
|
145
|
+
}
|
|
136
146
|
|
|
137
147
|
const skillPath = resolveProjectAiPath(
|
|
138
148
|
params.workspaceFolder,
|
|
@@ -174,7 +184,7 @@ export const findMissingConfiguredProjectSkills = async (params: {
|
|
|
174
184
|
for (const skill of installs) {
|
|
175
185
|
if (
|
|
176
186
|
!await hasInstalledSkillTarget({
|
|
177
|
-
|
|
187
|
+
lockfile,
|
|
178
188
|
targetDirName: skill.targetDirName,
|
|
179
189
|
workspaceFolder: params.workspaceFolder
|
|
180
190
|
})
|
|
@@ -214,7 +224,7 @@ export const findMissingConfiguredProjectSkillCollections = async (params: {
|
|
|
214
224
|
if (
|
|
215
225
|
!await hasInstalledCollectionLockEntry({
|
|
216
226
|
collection,
|
|
217
|
-
|
|
227
|
+
lockfile,
|
|
218
228
|
workspaceFolder: params.workspaceFolder
|
|
219
229
|
})
|
|
220
230
|
) {
|
|
@@ -229,7 +239,7 @@ export const findMissingConfiguredProjectSkillCollections = async (params: {
|
|
|
229
239
|
if (target == null) continue
|
|
230
240
|
if (
|
|
231
241
|
!await hasInstalledSkillTarget({
|
|
232
|
-
|
|
242
|
+
lockfile,
|
|
233
243
|
targetDirName: target.targetDirName,
|
|
234
244
|
workspaceFolder: params.workspaceFolder
|
|
235
245
|
})
|