@vibe-forge/workspace-assets 2.0.0 → 2.0.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__/__snapshots__/workspace-assets-rich.snapshot.json +56 -1
- package/__tests__/adapter-asset-plan.spec.ts +218 -6
- package/__tests__/bundle.spec.ts +602 -2
- package/__tests__/prompt-builders.spec.ts +39 -0
- package/__tests__/prompt-selection.spec.ts +307 -0
- package/__tests__/snapshot.ts +1 -0
- package/__tests__/test-helpers.ts +9 -0
- package/__tests__/workspace-assets.snapshot.spec.ts +2 -2
- package/package.json +4 -4
- package/src/adapter-asset-plan.ts +42 -66
- package/src/asset-source.ts +13 -0
- package/src/bundle-internal.ts +226 -21
- package/src/bundle.ts +2 -0
- package/src/home-bridge.ts +1 -0
- package/src/index.ts +3 -0
- package/src/prompt-builders.ts +4 -0
- package/src/prompt-selection.ts +44 -19
- package/src/selection-internal.ts +335 -1
- package/src/skill-dependencies.ts +361 -0
- package/src/skill-registry.ts +329 -0
- package/src/task-tool-guidance.ts +15 -0
- package/src/workspace-config.ts +132 -0
- package/src/workspace-prompt.ts +33 -0
- package/src/workspaces.ts +188 -0
- package/vibe-forge-workspace-assets-2.0.2.tgz +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
/* eslint-disable max-lines -- adapter asset plan scenarios share setup helpers and assertions */
|
|
1
2
|
import { join } from 'node:path'
|
|
2
3
|
|
|
3
|
-
import { describe, expect, it } from 'vitest'
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
4
5
|
|
|
5
6
|
import { buildAdapterAssetPlan, resolvePromptAssetSelection, resolveWorkspaceAssetBundle } from '#~/index.js'
|
|
6
7
|
|
|
@@ -78,7 +79,7 @@ describe('buildAdapterAssetPlan', () => {
|
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
})
|
|
81
|
-
const plan = buildAdapterAssetPlan({
|
|
82
|
+
const plan = await buildAdapterAssetPlan({
|
|
82
83
|
adapter: 'codex',
|
|
83
84
|
bundle,
|
|
84
85
|
options: {
|
|
@@ -150,7 +151,7 @@ describe('buildAdapterAssetPlan', () => {
|
|
|
150
151
|
}, undefined],
|
|
151
152
|
useDefaultVibeForgeMcpServer: false
|
|
152
153
|
})
|
|
153
|
-
const plan = buildAdapterAssetPlan({
|
|
154
|
+
const plan = await buildAdapterAssetPlan({
|
|
154
155
|
adapter: 'opencode',
|
|
155
156
|
bundle,
|
|
156
157
|
options: {
|
|
@@ -180,6 +181,217 @@ describe('buildAdapterAssetPlan', () => {
|
|
|
180
181
|
]))
|
|
181
182
|
})
|
|
182
183
|
|
|
184
|
+
it('labels home-bridged skill diagnostics with source=home', async () => {
|
|
185
|
+
const workspace = await createWorkspace()
|
|
186
|
+
const realHome = process.env.__VF_PROJECT_REAL_HOME__
|
|
187
|
+
|
|
188
|
+
await writeDocument(
|
|
189
|
+
join(realHome!, '.agents/skills/research/SKILL.md'),
|
|
190
|
+
'---\ndescription: 检索资料\n---\n阅读 README.md'
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
const bundle = await resolveWorkspaceAssetBundle({
|
|
194
|
+
cwd: workspace,
|
|
195
|
+
configs: [undefined, undefined],
|
|
196
|
+
useDefaultVibeForgeMcpServer: false
|
|
197
|
+
})
|
|
198
|
+
const researchSkillId = bundle.skills.find(asset => asset.name === 'research')?.id
|
|
199
|
+
|
|
200
|
+
const plan = await buildAdapterAssetPlan({
|
|
201
|
+
adapter: 'opencode',
|
|
202
|
+
bundle,
|
|
203
|
+
options: {
|
|
204
|
+
skills: {
|
|
205
|
+
include: ['research']
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
expect(plan.diagnostics).toEqual(expect.arrayContaining([
|
|
211
|
+
expect.objectContaining({
|
|
212
|
+
assetId: researchSkillId,
|
|
213
|
+
adapter: 'opencode',
|
|
214
|
+
status: 'native',
|
|
215
|
+
source: 'home'
|
|
216
|
+
})
|
|
217
|
+
]))
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
it('includes transitive skill dependencies in selected native overlays', async () => {
|
|
221
|
+
const workspace = await createWorkspace()
|
|
222
|
+
|
|
223
|
+
await writeDocument(
|
|
224
|
+
join(workspace, '.ai/skills/app-builder/SKILL.md'),
|
|
225
|
+
[
|
|
226
|
+
'---',
|
|
227
|
+
'name: app-builder',
|
|
228
|
+
'description: Build apps',
|
|
229
|
+
'dependencies:',
|
|
230
|
+
' - frontend-design',
|
|
231
|
+
'---',
|
|
232
|
+
'Build the app.'
|
|
233
|
+
].join('\n')
|
|
234
|
+
)
|
|
235
|
+
await writeDocument(
|
|
236
|
+
join(workspace, '.ai/skills/frontend-design/SKILL.md'),
|
|
237
|
+
'---\nname: frontend-design\ndescription: UI design guidance\n---\nDesign the UI.'
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
const bundle = await resolveWorkspaceAssetBundle({
|
|
241
|
+
cwd: workspace,
|
|
242
|
+
configs: [undefined, undefined],
|
|
243
|
+
useDefaultVibeForgeMcpServer: false
|
|
244
|
+
})
|
|
245
|
+
const plan = await buildAdapterAssetPlan({
|
|
246
|
+
adapter: 'opencode',
|
|
247
|
+
bundle,
|
|
248
|
+
options: {
|
|
249
|
+
skills: {
|
|
250
|
+
include: ['app-builder']
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
expect(plan.overlays).toEqual(expect.arrayContaining([
|
|
256
|
+
expect.objectContaining({
|
|
257
|
+
kind: 'skill',
|
|
258
|
+
targetPath: 'skills/app-builder'
|
|
259
|
+
}),
|
|
260
|
+
expect.objectContaining({
|
|
261
|
+
kind: 'skill',
|
|
262
|
+
targetPath: 'skills/frontend-design'
|
|
263
|
+
})
|
|
264
|
+
]))
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
it('keeps explicit registry dependencies ahead of preselected home-bridged skills in overlays', async () => {
|
|
268
|
+
const workspace = await createWorkspace()
|
|
269
|
+
const realHome = process.env.__VF_PROJECT_REAL_HOME__
|
|
270
|
+
const fetchMock = vi.fn(async (url: string) => {
|
|
271
|
+
if (url === 'https://registry.example.test/api/search?q=foo&limit=10') {
|
|
272
|
+
return new Response(JSON.stringify({
|
|
273
|
+
skills: [{
|
|
274
|
+
id: 'anthropics/skills/foo',
|
|
275
|
+
skillId: 'foo',
|
|
276
|
+
name: 'foo',
|
|
277
|
+
source: 'anthropics/skills'
|
|
278
|
+
}]
|
|
279
|
+
}))
|
|
280
|
+
}
|
|
281
|
+
if (url === 'https://registry.example.test/api/download/anthropics/skills/foo') {
|
|
282
|
+
return new Response(JSON.stringify({
|
|
283
|
+
files: [{
|
|
284
|
+
path: 'SKILL.md',
|
|
285
|
+
contents: '---\nname: foo\ndescription: Registry foo\n---\nUse the registry definition.\n'
|
|
286
|
+
}]
|
|
287
|
+
}))
|
|
288
|
+
}
|
|
289
|
+
return new Response('not found', { status: 404 })
|
|
290
|
+
})
|
|
291
|
+
vi.stubGlobal('fetch', fetchMock)
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
await writeDocument(
|
|
295
|
+
join(realHome!, '.agents/skills/foo/SKILL.md'),
|
|
296
|
+
'---\ndescription: Home foo\n---\nUse the home definition.\n'
|
|
297
|
+
)
|
|
298
|
+
await writeDocument(
|
|
299
|
+
join(workspace, '.ai/skills/app-builder/SKILL.md'),
|
|
300
|
+
[
|
|
301
|
+
'---',
|
|
302
|
+
'name: app-builder',
|
|
303
|
+
'description: Build apps',
|
|
304
|
+
'dependencies:',
|
|
305
|
+
' - anthropics/skills@foo',
|
|
306
|
+
'---',
|
|
307
|
+
'Build the app.'
|
|
308
|
+
].join('\n')
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
const bundle = await resolveWorkspaceAssetBundle({
|
|
312
|
+
cwd: workspace,
|
|
313
|
+
configs: [{
|
|
314
|
+
skills: {
|
|
315
|
+
registry: 'https://registry.example.test'
|
|
316
|
+
}
|
|
317
|
+
}, undefined],
|
|
318
|
+
useDefaultVibeForgeMcpServer: false
|
|
319
|
+
})
|
|
320
|
+
const plan = await buildAdapterAssetPlan({
|
|
321
|
+
adapter: 'opencode',
|
|
322
|
+
bundle,
|
|
323
|
+
options: {
|
|
324
|
+
skills: {
|
|
325
|
+
include: ['foo', 'app-builder']
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
const fooOverlays = plan.overlays.filter(entry => entry.kind === 'skill' && entry.targetPath === 'skills/foo')
|
|
331
|
+
expect(fooOverlays).toHaveLength(1)
|
|
332
|
+
expect(fooOverlays[0]?.sourcePath).toContain('/.ai/caches/skill-dependencies/registry.example.test/')
|
|
333
|
+
expect(fooOverlays[0]?.sourcePath).not.toBe(join(realHome!, '.agents/skills/foo'))
|
|
334
|
+
} finally {
|
|
335
|
+
vi.unstubAllGlobals()
|
|
336
|
+
}
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
it('prunes excluded skill dependency subtrees from selected native overlays', async () => {
|
|
340
|
+
const workspace = await createWorkspace()
|
|
341
|
+
|
|
342
|
+
await writeDocument(
|
|
343
|
+
join(workspace, '.ai/skills/app-builder/SKILL.md'),
|
|
344
|
+
[
|
|
345
|
+
'---',
|
|
346
|
+
'name: app-builder',
|
|
347
|
+
'description: Build apps',
|
|
348
|
+
'dependencies:',
|
|
349
|
+
' - frontend-design',
|
|
350
|
+
'---',
|
|
351
|
+
'Build the app.'
|
|
352
|
+
].join('\n')
|
|
353
|
+
)
|
|
354
|
+
await writeDocument(
|
|
355
|
+
join(workspace, '.ai/skills/frontend-design/SKILL.md'),
|
|
356
|
+
[
|
|
357
|
+
'---',
|
|
358
|
+
'name: frontend-design',
|
|
359
|
+
'description: UI design guidance',
|
|
360
|
+
'dependencies:',
|
|
361
|
+
' - color-system',
|
|
362
|
+
'---',
|
|
363
|
+
'Design the UI.'
|
|
364
|
+
].join('\n')
|
|
365
|
+
)
|
|
366
|
+
await writeDocument(
|
|
367
|
+
join(workspace, '.ai/skills/color-system/SKILL.md'),
|
|
368
|
+
'---\nname: color-system\ndescription: Color guidance\n---\nPick accessible colors.'
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
const bundle = await resolveWorkspaceAssetBundle({
|
|
372
|
+
cwd: workspace,
|
|
373
|
+
configs: [undefined, undefined],
|
|
374
|
+
useDefaultVibeForgeMcpServer: false
|
|
375
|
+
})
|
|
376
|
+
const plan = await buildAdapterAssetPlan({
|
|
377
|
+
adapter: 'opencode',
|
|
378
|
+
bundle,
|
|
379
|
+
options: {
|
|
380
|
+
skills: {
|
|
381
|
+
include: ['app-builder'],
|
|
382
|
+
exclude: ['frontend-design']
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
expect(plan.overlays).toEqual([
|
|
388
|
+
expect.objectContaining({
|
|
389
|
+
kind: 'skill',
|
|
390
|
+
targetPath: 'skills/app-builder'
|
|
391
|
+
})
|
|
392
|
+
])
|
|
393
|
+
})
|
|
394
|
+
|
|
183
395
|
it('builds copilot native skill overlays and translated runtime diagnostics', async () => {
|
|
184
396
|
const workspace = await createWorkspace()
|
|
185
397
|
|
|
@@ -246,7 +458,7 @@ describe('buildAdapterAssetPlan', () => {
|
|
|
246
458
|
}
|
|
247
459
|
}
|
|
248
460
|
})
|
|
249
|
-
const plan = buildAdapterAssetPlan({
|
|
461
|
+
const plan = await buildAdapterAssetPlan({
|
|
250
462
|
adapter: 'copilot',
|
|
251
463
|
bundle,
|
|
252
464
|
options: {
|
|
@@ -346,7 +558,7 @@ describe('buildAdapterAssetPlan', () => {
|
|
|
346
558
|
const loggerHookPluginId = bundle.hookPlugins.find(asset => asset.packageId === '@vibe-forge/plugin-logger')?.id
|
|
347
559
|
const demoCommandId = bundle.opencodeOverlayAssets.find(asset => asset.kind === 'command')?.id
|
|
348
560
|
|
|
349
|
-
const plan = buildAdapterAssetPlan({
|
|
561
|
+
const plan = await buildAdapterAssetPlan({
|
|
350
562
|
adapter: 'kimi',
|
|
351
563
|
bundle,
|
|
352
564
|
options: {
|
|
@@ -400,7 +612,7 @@ describe('buildAdapterAssetPlan', () => {
|
|
|
400
612
|
})
|
|
401
613
|
const loggerHookPluginId = bundle.hookPlugins.find(asset => asset.packageId === '@vibe-forge/plugin-logger')?.id
|
|
402
614
|
|
|
403
|
-
const plan = buildAdapterAssetPlan({
|
|
615
|
+
const plan = await buildAdapterAssetPlan({
|
|
404
616
|
adapter: 'gemini',
|
|
405
617
|
bundle,
|
|
406
618
|
options: {}
|