@vibe-forge/workspace-assets 3.0.0 → 3.1.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.
@@ -394,7 +394,7 @@ describe('buildAdapterAssetPlan', () => {
394
394
  ])
395
395
  })
396
396
 
397
- it('builds copilot native skill overlays and translated runtime diagnostics', async () => {
397
+ it('builds copilot native skill overlays and native hook diagnostics', async () => {
398
398
  const workspace = await createWorkspace()
399
399
 
400
400
  await installPluginPackage(workspace, '@vibe-forge/plugin-logger', {
@@ -489,7 +489,7 @@ describe('buildAdapterAssetPlan', () => {
489
489
  expect.objectContaining({
490
490
  assetId: loggerHookPluginId,
491
491
  adapter: 'copilot',
492
- status: 'translated'
492
+ status: 'native'
493
493
  }),
494
494
  expect.objectContaining({
495
495
  assetId: docsMcpId,
@@ -113,6 +113,141 @@ describe('skills CLI dependency resolution', () => {
113
113
  })
114
114
  })
115
115
 
116
+ it('blocks missing dependency installs when auto downloads are disabled', async () => {
117
+ const workspace = await createWorkspace()
118
+
119
+ await writeDocument(
120
+ join(workspace, '.ai/skills/app-builder/SKILL.md'),
121
+ [
122
+ '---',
123
+ 'name: app-builder',
124
+ 'description: Build apps',
125
+ 'dependencies:',
126
+ ' - name: frontend-design',
127
+ ' source: anthropics/skills',
128
+ ' registry: https://dependency-registry.example.test',
129
+ '---',
130
+ 'Build the app.'
131
+ ].join('\n')
132
+ )
133
+
134
+ const bundle = await resolveWorkspaceAssetBundle({
135
+ cwd: workspace,
136
+ configs: [{
137
+ skills: {
138
+ autoDownloadDependencies: false
139
+ }
140
+ }, undefined],
141
+ useDefaultVibeForgeMcpServer: false
142
+ })
143
+
144
+ await expect(buildAdapterAssetPlan({
145
+ adapter: 'opencode',
146
+ bundle,
147
+ options: {
148
+ skills: {
149
+ include: ['app-builder']
150
+ }
151
+ }
152
+ })).rejects.toThrow('Skill dependency automatic downloads are disabled; cache not found')
153
+
154
+ expect(mocks.findSkillsCli).not.toHaveBeenCalled()
155
+ expect(mocks.installSkillsCliRefToTemp).not.toHaveBeenCalled()
156
+ expect(mocks.installSkillsCliSkillToTemp).not.toHaveBeenCalled()
157
+ expect(bundle.skills.map(asset => asset.name)).toEqual(['app-builder'])
158
+ })
159
+
160
+ it('blocks bare-name dependency searches when auto downloads are disabled', async () => {
161
+ const workspace = await createWorkspace()
162
+
163
+ await writeDocument(
164
+ join(workspace, '.ai/skills/app-builder/SKILL.md'),
165
+ [
166
+ '---',
167
+ 'name: app-builder',
168
+ 'description: Build apps',
169
+ 'dependencies:',
170
+ ' - frontend-design',
171
+ '---',
172
+ 'Build the app.'
173
+ ].join('\n')
174
+ )
175
+
176
+ const bundle = await resolveWorkspaceAssetBundle({
177
+ cwd: workspace,
178
+ configs: [{
179
+ skills: {
180
+ autoDownloadDependencies: false
181
+ }
182
+ }, undefined],
183
+ useDefaultVibeForgeMcpServer: false
184
+ })
185
+
186
+ await expect(buildAdapterAssetPlan({
187
+ adapter: 'opencode',
188
+ bundle,
189
+ options: {
190
+ skills: {
191
+ include: ['app-builder']
192
+ }
193
+ }
194
+ })).rejects.toThrow(
195
+ 'Skill dependency automatic downloads are disabled; cannot resolve frontend-design without a source'
196
+ )
197
+
198
+ expect(mocks.findSkillsCli).not.toHaveBeenCalled()
199
+ expect(mocks.installSkillsCliRefToTemp).not.toHaveBeenCalled()
200
+ expect(mocks.installSkillsCliSkillToTemp).not.toHaveBeenCalled()
201
+ })
202
+
203
+ it('reuses source-qualified dependency caches when auto downloads are disabled', async () => {
204
+ const workspace = await createWorkspace()
205
+ await writeDocument(
206
+ join(
207
+ workspace,
208
+ '.ai/caches/skill-dependencies/skills-cli/skills/latest/default/anthropics/skills/latest/frontend-design/SKILL.md'
209
+ ),
210
+ '---\nname: frontend-design\ndescription: Cached UI guidance\n---\nUse the cached dependency.\n'
211
+ )
212
+ await writeDocument(
213
+ join(workspace, '.ai/skills/app-builder/SKILL.md'),
214
+ [
215
+ '---',
216
+ 'name: app-builder',
217
+ 'description: Build apps',
218
+ 'dependencies:',
219
+ ' - anthropics/skills@frontend-design',
220
+ '---',
221
+ 'Build the app.'
222
+ ].join('\n')
223
+ )
224
+
225
+ const bundle = await resolveWorkspaceAssetBundle({
226
+ cwd: workspace,
227
+ configs: [{
228
+ skills: {
229
+ autoDownloadDependencies: false
230
+ }
231
+ }, undefined],
232
+ useDefaultVibeForgeMcpServer: false
233
+ })
234
+
235
+ await buildAdapterAssetPlan({
236
+ adapter: 'opencode',
237
+ bundle,
238
+ options: {
239
+ skills: {
240
+ include: ['app-builder']
241
+ }
242
+ }
243
+ })
244
+
245
+ expect(mocks.findSkillsCli).not.toHaveBeenCalled()
246
+ expect(mocks.installSkillsCliRefToTemp).not.toHaveBeenCalled()
247
+ expect(mocks.installSkillsCliSkillToTemp).not.toHaveBeenCalled()
248
+ expect(bundle.skills.map(asset => asset.name).sort()).toEqual(['app-builder', 'frontend-design'])
249
+ })
250
+
116
251
  it('parses registry and version from dependency specs', async () => {
117
252
  const workspace = await createWorkspace()
118
253
  const installedSkillDir = join(installWorkspace, '.agents', 'skills', 'frontend-design')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-forge/workspace-assets",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
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/types": "3.0.0",
33
- "@vibe-forge/definition-core": "3.0.0",
34
- "@vibe-forge/utils": "3.0.0",
35
- "@vibe-forge/config": "3.0.0"
32
+ "@vibe-forge/types": "3.1.0",
33
+ "@vibe-forge/config": "3.1.0",
34
+ "@vibe-forge/utils": "3.1.0",
35
+ "@vibe-forge/definition-core": "3.1.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/js-yaml": "^4.0.9"
@@ -78,7 +78,7 @@ export async function buildAdapterAssetPlan(params: {
78
78
  params.bundle.hookPlugins.forEach((asset) => {
79
79
  pushDiagnostic(asset, {
80
80
  adapter: params.adapter,
81
- status: params.adapter === 'copilot' ? 'translated' : 'native',
81
+ status: 'native',
82
82
  reason: params.adapter === 'claude-code'
83
83
  ? 'Mapped into the Claude Code native hooks bridge.'
84
84
  : params.adapter === 'codex'
@@ -86,7 +86,7 @@ export async function buildAdapterAssetPlan(params: {
86
86
  : params.adapter === 'gemini'
87
87
  ? 'Mapped into the Gemini native hooks bridge.'
88
88
  : params.adapter === 'copilot'
89
- ? 'Handled by the Vibe Forge task hook bridge.'
89
+ ? 'Mapped into the Copilot CLI native hooks bridge.'
90
90
  : params.adapter === 'kimi'
91
91
  ? 'Mapped into the Kimi native hooks bridge.'
92
92
  : 'Mapped into the OpenCode native hooks bridge.'
@@ -14,17 +14,33 @@ import {
14
14
  withInstallLock
15
15
  } from './skills-cli-dependency-helpers'
16
16
 
17
+ const resolveAutoDownloadDependenciesEnabled = (
18
+ projectConfig: Config | undefined,
19
+ userConfig: Config | undefined
20
+ ) => userConfig?.skills?.autoDownloadDependencies ?? projectConfig?.skills?.autoDownloadDependencies ?? true
21
+
17
22
  export const installSkillsCliDependency = async (params: {
18
23
  cwd: string
19
24
  configs: [Config?, Config?]
20
25
  dependency: NormalizedSkillDependency
21
26
  }) => {
22
- const resolvedTarget = params.dependency.source != null
23
- ? {
24
- skill: params.dependency.name,
25
- source: params.dependency.source
27
+ const [projectConfig, userConfig] = params.configs
28
+ const autoDownloadDependenciesEnabled = resolveAutoDownloadDependenciesEnabled(projectConfig, userConfig)
29
+ const resolvedTarget = await (async () => {
30
+ if (params.dependency.source != null) {
31
+ return {
32
+ skill: params.dependency.name,
33
+ source: params.dependency.source
34
+ }
35
+ }
36
+
37
+ if (!autoDownloadDependenciesEnabled) {
38
+ throw new Error(
39
+ `Skill dependency automatic downloads are disabled; cannot resolve ${params.dependency.ref} without a source`
40
+ )
26
41
  }
27
- : await (async () => {
42
+
43
+ return await (async () => {
28
44
  const searchResults = await findSkillsCli({
29
45
  registry: params.dependency.registry,
30
46
  query: params.dependency.name
@@ -40,6 +56,7 @@ export const installSkillsCliDependency = async (params: {
40
56
  source: selected.source
41
57
  }
42
58
  })()
59
+ })()
43
60
 
44
61
  const installDir = buildInstallDir({
45
62
  cwd: params.cwd,
@@ -58,6 +75,10 @@ export const installSkillsCliDependency = async (params: {
58
75
  }
59
76
  }
60
77
 
78
+ if (!autoDownloadDependenciesEnabled) {
79
+ throw new Error(`Skill dependency automatic downloads are disabled; cache not found for ${params.dependency.ref}`)
80
+ }
81
+
61
82
  const tempInstallDir = `${installDir}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`
62
83
  await rm(tempInstallDir, { recursive: true, force: true })
63
84
  await mkdir(tempInstallDir, { recursive: true })