@vibe-forge/workspace-assets 0.9.0 → 0.9.1-alpha.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/__tests__/__snapshots__/workspace-assets-rich.snapshot.json +355 -360
- package/__tests__/adapter-asset-plan.spec.ts +40 -66
- package/__tests__/bundle.spec.ts +44 -168
- package/__tests__/prompt-selection.spec.ts +14 -358
- package/__tests__/snapshot.ts +127 -75
- package/__tests__/test-helpers.ts +0 -11
- package/__tests__/workspace-assets.snapshot.spec.ts +103 -72
- package/package.json +10 -10
- package/src/adapter-asset-plan.ts +174 -0
- package/src/bundle.ts +178 -0
- package/src/document-assets.ts +191 -0
- package/src/helpers.ts +35 -0
- package/src/index.ts +3 -1368
- package/src/internal-types.ts +39 -1
- package/src/plugin-assets.ts +175 -0
- package/src/prompt-selection.ts +151 -0
- package/LICENSE +0 -21
package/__tests__/snapshot.ts
CHANGED
|
@@ -16,16 +16,25 @@ import type {
|
|
|
16
16
|
} from '@vibe-forge/types'
|
|
17
17
|
import { resolveDocumentName, resolveSpecIdentifier } from '@vibe-forge/utils'
|
|
18
18
|
|
|
19
|
+
import { isOpenCodeOverlayAsset } from '#~/internal-types.js'
|
|
20
|
+
|
|
19
21
|
const sortStrings = (values: string[]) => [...values].sort((left, right) => left.localeCompare(right))
|
|
20
22
|
|
|
23
|
+
const isConfigNativePluginAsset = (
|
|
24
|
+
asset: Extract<WorkspaceAsset, { kind: 'nativePlugin' }>
|
|
25
|
+
): asset is Extract<WorkspaceAsset, { kind: 'nativePlugin' }> & {
|
|
26
|
+
payload: {
|
|
27
|
+
name: string
|
|
28
|
+
enabled: boolean
|
|
29
|
+
}
|
|
30
|
+
} => !isOpenCodeOverlayAsset(asset)
|
|
31
|
+
|
|
21
32
|
const sanitizeValue = (
|
|
22
33
|
value: string,
|
|
23
34
|
cwd: string
|
|
24
35
|
) => (
|
|
25
36
|
value
|
|
26
|
-
.replaceAll(`/private${cwd}`, '<workspace>')
|
|
27
37
|
.replaceAll(cwd, '<workspace>')
|
|
28
|
-
.replaceAll(`/private${process.execPath}`, '<node-path>')
|
|
29
38
|
.replaceAll(process.execPath, '<node-path>')
|
|
30
39
|
)
|
|
31
40
|
|
|
@@ -90,73 +99,104 @@ const summarizeDefinition = (
|
|
|
90
99
|
body: definition.body.trim()
|
|
91
100
|
})
|
|
92
101
|
|
|
93
|
-
const
|
|
94
|
-
asset: WorkspaceAsset,
|
|
102
|
+
const summarizeDocumentAsset = (
|
|
103
|
+
asset: Extract<WorkspaceAsset, { kind: 'rule' | 'spec' | 'entity' | 'skill' }>,
|
|
95
104
|
cwd: string
|
|
96
|
-
) => (
|
|
97
|
-
`${asset.kind}:${asset.origin}:${asset.instancePath ?? 'workspace'}:${asset.displayName}:${sanitizeValue(asset.sourcePath, cwd)}`
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
const summarizeBaseAsset = (
|
|
101
|
-
asset: WorkspaceAsset,
|
|
102
|
-
cwd: string,
|
|
103
|
-
assetIdMap?: Map<string, string>
|
|
104
105
|
) => ({
|
|
105
|
-
id:
|
|
106
|
+
id: asset.id,
|
|
106
107
|
kind: asset.kind,
|
|
107
|
-
name: asset.name,
|
|
108
|
-
displayName: asset.displayName,
|
|
109
108
|
origin: asset.origin,
|
|
110
109
|
scope: asset.scope,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
resolvedBy: asset.resolvedBy,
|
|
115
|
-
taskOverlaySource: asset.taskOverlaySource
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
const summarizeDocumentAsset = (
|
|
119
|
-
asset: Extract<WorkspaceAsset, { kind: 'rule' | 'spec' | 'entity' | 'skill' }>,
|
|
120
|
-
cwd: string,
|
|
121
|
-
assetIdMap?: Map<string, string>
|
|
122
|
-
) => ({
|
|
123
|
-
...summarizeBaseAsset(asset, cwd, assetIdMap),
|
|
110
|
+
pluginId: asset.pluginId,
|
|
111
|
+
enabled: asset.enabled,
|
|
112
|
+
targets: sortStrings(asset.targets),
|
|
124
113
|
definition: summarizeDefinition(asset.kind, asset.payload.definition, cwd)
|
|
125
114
|
})
|
|
126
115
|
|
|
127
116
|
const summarizeMcpServer = (
|
|
128
117
|
asset: Extract<WorkspaceAsset, { kind: 'mcpServer' }>,
|
|
129
|
-
cwd: string
|
|
130
|
-
assetIdMap?: Map<string, string>
|
|
118
|
+
cwd: string
|
|
131
119
|
) => ({
|
|
132
|
-
|
|
120
|
+
id: asset.id,
|
|
121
|
+
origin: asset.origin,
|
|
122
|
+
scope: asset.scope,
|
|
123
|
+
pluginId: asset.pluginId,
|
|
124
|
+
enabled: asset.enabled,
|
|
125
|
+
targets: sortStrings(asset.targets),
|
|
126
|
+
name: asset.payload.name,
|
|
133
127
|
config: normalizeValue(asset.payload.config, cwd)
|
|
134
128
|
})
|
|
135
129
|
|
|
136
130
|
const summarizeHookPlugin = (
|
|
137
131
|
asset: Extract<WorkspaceAsset, { kind: 'hookPlugin' }>,
|
|
138
|
-
cwd: string
|
|
139
|
-
assetIdMap?: Map<string, string>
|
|
132
|
+
cwd: string
|
|
140
133
|
) => ({
|
|
141
|
-
|
|
134
|
+
id: asset.id,
|
|
135
|
+
origin: asset.origin,
|
|
136
|
+
scope: asset.scope,
|
|
137
|
+
pluginId: asset.pluginId,
|
|
138
|
+
enabled: asset.enabled,
|
|
139
|
+
targets: sortStrings(asset.targets),
|
|
142
140
|
packageName: asset.payload.packageName,
|
|
143
141
|
config: normalizeValue(asset.payload.config, cwd)
|
|
144
142
|
})
|
|
145
143
|
|
|
146
|
-
const
|
|
147
|
-
asset: Extract<WorkspaceAsset, { kind: '
|
|
148
|
-
cwd: string
|
|
149
|
-
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
144
|
+
const summarizeNativePlugin = (
|
|
145
|
+
asset: Extract<WorkspaceAsset, { kind: 'nativePlugin' }>,
|
|
146
|
+
cwd: string
|
|
147
|
+
) => {
|
|
148
|
+
if (isOpenCodeOverlayAsset(asset)) {
|
|
149
|
+
return {
|
|
150
|
+
id: asset.id,
|
|
151
|
+
kind: asset.kind,
|
|
152
|
+
origin: asset.origin,
|
|
153
|
+
scope: asset.scope,
|
|
154
|
+
pluginId: asset.pluginId,
|
|
155
|
+
enabled: asset.enabled,
|
|
156
|
+
targets: sortStrings(asset.targets),
|
|
157
|
+
entryName: asset.payload.entryName,
|
|
158
|
+
sourcePath: sanitizeValue(asset.payload.sourcePath, cwd),
|
|
159
|
+
targetSubpath: asset.payload.targetSubpath
|
|
160
|
+
}
|
|
161
|
+
}
|
|
155
162
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
163
|
+
return {
|
|
164
|
+
id: asset.id,
|
|
165
|
+
kind: asset.kind,
|
|
166
|
+
origin: asset.origin,
|
|
167
|
+
scope: asset.scope,
|
|
168
|
+
pluginId: asset.pluginId,
|
|
169
|
+
enabled: asset.enabled,
|
|
170
|
+
targets: sortStrings(asset.targets),
|
|
171
|
+
name: isConfigNativePluginAsset(asset) ? asset.payload.name : undefined
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const summarizeOverlayAsset = (
|
|
176
|
+
asset:
|
|
177
|
+
| Extract<WorkspaceAsset, { kind: 'agent' | 'command' | 'mode' }>
|
|
178
|
+
| Extract<WorkspaceAsset, { kind: 'nativePlugin' }>,
|
|
179
|
+
cwd: string
|
|
180
|
+
) => {
|
|
181
|
+
if (!isOpenCodeOverlayAsset(asset)) {
|
|
182
|
+
return summarizeNativePlugin(asset, cwd)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
id: asset.id,
|
|
187
|
+
kind: asset.kind,
|
|
188
|
+
origin: asset.origin,
|
|
189
|
+
scope: asset.scope,
|
|
190
|
+
pluginId: asset.pluginId,
|
|
191
|
+
enabled: asset.enabled,
|
|
192
|
+
targets: sortStrings(asset.targets),
|
|
193
|
+
entryName: asset.payload.entryName,
|
|
194
|
+
sourcePath: sanitizeValue(asset.payload.sourcePath, cwd),
|
|
195
|
+
targetSubpath: asset.payload.targetSubpath
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const summarizeDiagnostics = (diagnostics: AssetDiagnostic[]) => (
|
|
160
200
|
[...diagnostics]
|
|
161
201
|
.sort((left, right) => {
|
|
162
202
|
const assetIdDiff = left.assetId.localeCompare(right.assetId)
|
|
@@ -164,31 +204,29 @@ const summarizeDiagnostics = (
|
|
|
164
204
|
return left.status.localeCompare(right.status)
|
|
165
205
|
})
|
|
166
206
|
.map(diagnostic => ({
|
|
167
|
-
assetId:
|
|
207
|
+
assetId: diagnostic.assetId,
|
|
168
208
|
adapter: diagnostic.adapter,
|
|
169
209
|
status: diagnostic.status,
|
|
170
|
-
reason: diagnostic.reason
|
|
171
|
-
scope: diagnostic.scope,
|
|
172
|
-
packageId: diagnostic.packageId
|
|
210
|
+
reason: diagnostic.reason
|
|
173
211
|
}))
|
|
174
212
|
)
|
|
175
213
|
|
|
176
214
|
const summarizePlan = (
|
|
177
215
|
plan: AdapterAssetPlan,
|
|
178
|
-
cwd: string
|
|
179
|
-
assetIdMap: Map<string, string>
|
|
216
|
+
cwd: string
|
|
180
217
|
) => ({
|
|
181
218
|
adapter: plan.adapter,
|
|
182
219
|
mcpServers: normalizeValue(plan.mcpServers, cwd),
|
|
183
220
|
overlays: [...plan.overlays]
|
|
184
221
|
.sort((left, right) => left.assetId.localeCompare(right.assetId))
|
|
185
222
|
.map(entry => ({
|
|
186
|
-
assetId:
|
|
223
|
+
assetId: entry.assetId,
|
|
187
224
|
kind: entry.kind,
|
|
188
225
|
sourcePath: sanitizeValue(entry.sourcePath, cwd),
|
|
189
226
|
targetPath: entry.targetPath
|
|
190
227
|
})),
|
|
191
|
-
|
|
228
|
+
native: normalizeValue(plan.native, cwd),
|
|
229
|
+
diagnostics: summarizeDiagnostics(plan.diagnostics)
|
|
192
230
|
})
|
|
193
231
|
|
|
194
232
|
const summarizeSelection = (
|
|
@@ -199,8 +237,7 @@ const summarizeSelection = (
|
|
|
199
237
|
mcpServers?: Filter
|
|
200
238
|
promptAssetIds?: string[]
|
|
201
239
|
},
|
|
202
|
-
cwd: string
|
|
203
|
-
assetIdMap: Map<string, string>
|
|
240
|
+
cwd: string
|
|
204
241
|
) => ({
|
|
205
242
|
resolution: {
|
|
206
243
|
rules: resolution.rules.map(rule => summarizeDefinition('rule', rule, cwd)),
|
|
@@ -209,15 +246,13 @@ const summarizeSelection = (
|
|
|
209
246
|
skills: resolution.skills.map(skill => summarizeDefinition('skill', skill, cwd)),
|
|
210
247
|
specs: resolution.specs.map(spec => summarizeDefinition('spec', spec, cwd)),
|
|
211
248
|
targetBody: resolution.targetBody.trim(),
|
|
212
|
-
promptAssetIds: sortStrings(resolution.promptAssetIds
|
|
249
|
+
promptAssetIds: sortStrings(resolution.promptAssetIds)
|
|
213
250
|
},
|
|
214
251
|
options: {
|
|
215
252
|
systemPrompt: options.systemPrompt?.trim(),
|
|
216
253
|
tools: sortFilter(options.tools),
|
|
217
254
|
mcpServers: sortFilter(options.mcpServers),
|
|
218
|
-
promptAssetIds: options.promptAssetIds == null
|
|
219
|
-
? undefined
|
|
220
|
-
: sortStrings(options.promptAssetIds.map(assetId => assetIdMap.get(assetId) ?? assetId))
|
|
255
|
+
promptAssetIds: options.promptAssetIds == null ? undefined : sortStrings(options.promptAssetIds)
|
|
221
256
|
}
|
|
222
257
|
})
|
|
223
258
|
|
|
@@ -236,39 +271,56 @@ export const serializeWorkspaceAssetsSnapshot = (params: {
|
|
|
236
271
|
plans: AdapterAssetPlan[]
|
|
237
272
|
}) => {
|
|
238
273
|
const { bundle, cwd } = params
|
|
239
|
-
const
|
|
274
|
+
const overlayAssets = bundle.assets.filter((
|
|
275
|
+
asset
|
|
276
|
+
): asset is
|
|
277
|
+
| Extract<WorkspaceAsset, { kind: 'agent' | 'command' | 'mode' }>
|
|
278
|
+
| Extract<WorkspaceAsset, { kind: 'nativePlugin' }> => (
|
|
279
|
+
asset.kind === 'agent' ||
|
|
280
|
+
asset.kind === 'command' ||
|
|
281
|
+
asset.kind === 'mode' ||
|
|
282
|
+
(asset.kind === 'nativePlugin' && isOpenCodeOverlayAsset(asset))
|
|
283
|
+
)
|
|
284
|
+
)
|
|
285
|
+
const claudeNativePlugins = bundle.assets.filter((
|
|
286
|
+
asset
|
|
287
|
+
): asset is Extract<WorkspaceAsset, { kind: 'nativePlugin' }> => (
|
|
288
|
+
asset.kind === 'nativePlugin' && !isOpenCodeOverlayAsset(asset)
|
|
289
|
+
))
|
|
240
290
|
|
|
241
291
|
const snapshot = {
|
|
242
292
|
bundle: {
|
|
243
293
|
cwd: '<workspace>',
|
|
244
|
-
|
|
245
|
-
|
|
294
|
+
enabledPlugins: normalizeValue(bundle.enabledPlugins, cwd),
|
|
295
|
+
extraKnownMarketplaces: normalizeValue(bundle.extraKnownMarketplaces, cwd),
|
|
246
296
|
defaultIncludeMcpServers: sortStrings(bundle.defaultIncludeMcpServers),
|
|
247
297
|
defaultExcludeMcpServers: sortStrings(bundle.defaultExcludeMcpServers),
|
|
248
|
-
rules: bundle.rules.map(rule => summarizeDocumentAsset(rule, cwd
|
|
249
|
-
specs: bundle.specs.map(spec => summarizeDocumentAsset(spec, cwd
|
|
250
|
-
entities: bundle.entities.map(entity => summarizeDocumentAsset(entity, cwd
|
|
251
|
-
skills: bundle.skills.map(skill => summarizeDocumentAsset(skill, cwd
|
|
298
|
+
rules: bundle.rules.map(rule => summarizeDocumentAsset(rule, cwd)),
|
|
299
|
+
specs: bundle.specs.map(spec => summarizeDocumentAsset(spec, cwd)),
|
|
300
|
+
entities: bundle.entities.map(entity => summarizeDocumentAsset(entity, cwd)),
|
|
301
|
+
skills: bundle.skills.map(skill => summarizeDocumentAsset(skill, cwd)),
|
|
252
302
|
mcpServers: Object.values(bundle.mcpServers)
|
|
253
303
|
.sort((left, right) => left.payload.name.localeCompare(right.payload.name))
|
|
254
|
-
.map(server => summarizeMcpServer(server, cwd
|
|
304
|
+
.map(server => summarizeMcpServer(server, cwd)),
|
|
255
305
|
hookPlugins: bundle.hookPlugins
|
|
256
306
|
.sort((left, right) => left.id.localeCompare(right.id))
|
|
257
|
-
.map(plugin => summarizeHookPlugin(plugin, cwd
|
|
258
|
-
|
|
307
|
+
.map(plugin => summarizeHookPlugin(plugin, cwd)),
|
|
308
|
+
claudeNativePlugins: claudeNativePlugins
|
|
309
|
+
.sort((left, right) => left.id.localeCompare(right.id))
|
|
310
|
+
.map(asset => summarizeNativePlugin(asset, cwd)),
|
|
311
|
+
opencodeOverlayAssets: overlayAssets
|
|
259
312
|
.sort((left, right) => left.id.localeCompare(right.id))
|
|
260
|
-
.map(asset =>
|
|
313
|
+
.map(asset => summarizeOverlayAsset(asset, cwd))
|
|
261
314
|
},
|
|
262
315
|
selection: summarizeSelection(
|
|
263
316
|
params.selection.resolution,
|
|
264
317
|
params.selection.options,
|
|
265
|
-
cwd
|
|
266
|
-
assetIdMap
|
|
318
|
+
cwd
|
|
267
319
|
),
|
|
268
320
|
plans: Object.fromEntries(
|
|
269
321
|
[...params.plans]
|
|
270
322
|
.sort((left, right) => left.adapter.localeCompare(right.adapter))
|
|
271
|
-
.map(plan => [plan.adapter, summarizePlan(plan, cwd
|
|
323
|
+
.map(plan => [plan.adapter, summarizePlan(plan, cwd)])
|
|
272
324
|
)
|
|
273
325
|
}
|
|
274
326
|
|
|
@@ -17,17 +17,6 @@ export const writeDocument = async (filePath: string, content: string) => {
|
|
|
17
17
|
await writeFile(filePath, content)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export const installPluginPackage = async (
|
|
21
|
-
workspace: string,
|
|
22
|
-
packageName: string,
|
|
23
|
-
files: Record<string, string>
|
|
24
|
-
) => {
|
|
25
|
-
const packageDir = join(workspace, 'node_modules', ...packageName.split('/'))
|
|
26
|
-
await Promise.all(Object.entries(files).map(async ([relativePath, content]) => {
|
|
27
|
-
await writeDocument(join(packageDir, relativePath), content)
|
|
28
|
-
}))
|
|
29
|
-
}
|
|
30
|
-
|
|
31
20
|
afterEach(async () => {
|
|
32
21
|
await Promise.all(tempDirs.splice(0).map(dir => rm(dir, { recursive: true, force: true })))
|
|
33
22
|
})
|
|
@@ -8,7 +8,7 @@ import type { Config } from '@vibe-forge/types'
|
|
|
8
8
|
import { buildAdapterAssetPlan, resolvePromptAssetSelection, resolveWorkspaceAssetBundle } from '#~/index.js'
|
|
9
9
|
|
|
10
10
|
import { serializeWorkspaceAssetsSnapshot } from './snapshot'
|
|
11
|
-
import { createWorkspace,
|
|
11
|
+
import { createWorkspace, writeDocument } from './test-helpers'
|
|
12
12
|
|
|
13
13
|
const resolveSnapshotPath = (name: string) => (
|
|
14
14
|
fileURLToPath(new URL(`./__snapshots__/${name}.snapshot.json`, import.meta.url))
|
|
@@ -19,33 +19,43 @@ describe('workspace assets snapshots', () => {
|
|
|
19
19
|
const workspace = await createWorkspace()
|
|
20
20
|
|
|
21
21
|
const projectConfig: Config = {
|
|
22
|
-
plugins:
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
id: 'demo',
|
|
28
|
-
scope: 'demo'
|
|
22
|
+
plugins: {
|
|
23
|
+
logger: {
|
|
24
|
+
level: 'info'
|
|
29
25
|
}
|
|
30
|
-
|
|
26
|
+
},
|
|
27
|
+
enabledPlugins: {
|
|
28
|
+
logger: true,
|
|
29
|
+
demo: true,
|
|
30
|
+
legacy: false,
|
|
31
|
+
telemetry: true
|
|
32
|
+
},
|
|
31
33
|
mcpServers: {
|
|
32
34
|
docs: {
|
|
33
35
|
command: 'npx',
|
|
34
36
|
args: ['docs-server']
|
|
35
37
|
}
|
|
36
38
|
},
|
|
37
|
-
defaultIncludeMcpServers: ['docs', '
|
|
39
|
+
defaultIncludeMcpServers: ['docs', 'browser'],
|
|
40
|
+
extraKnownMarketplaces: {
|
|
41
|
+
internal: {
|
|
42
|
+
source: {
|
|
43
|
+
source: 'git',
|
|
44
|
+
url: 'https://plugins.internal.example.com'
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
38
48
|
}
|
|
39
49
|
|
|
40
50
|
const userConfig: Config = {
|
|
41
|
-
plugins:
|
|
42
|
-
{
|
|
43
|
-
|
|
44
|
-
options: {
|
|
45
|
-
mode: 'summary'
|
|
46
|
-
}
|
|
51
|
+
plugins: {
|
|
52
|
+
telemetry: {
|
|
53
|
+
mode: 'summary'
|
|
47
54
|
}
|
|
48
|
-
|
|
55
|
+
},
|
|
56
|
+
enabledPlugins: {
|
|
57
|
+
telemetry: true
|
|
58
|
+
},
|
|
49
59
|
mcpServers: {
|
|
50
60
|
notes: {
|
|
51
61
|
command: 'node',
|
|
@@ -55,59 +65,6 @@ describe('workspace assets snapshots', () => {
|
|
|
55
65
|
defaultExcludeMcpServers: ['notes']
|
|
56
66
|
}
|
|
57
67
|
|
|
58
|
-
await installPluginPackage(workspace, '@vibe-forge/plugin-demo', {
|
|
59
|
-
'package.json': JSON.stringify({
|
|
60
|
-
name: '@vibe-forge/plugin-demo',
|
|
61
|
-
version: '1.0.0'
|
|
62
|
-
}, null, 2),
|
|
63
|
-
'hooks.js': 'module.exports = {}\n',
|
|
64
|
-
'rules/security.md': [
|
|
65
|
-
'---',
|
|
66
|
-
'description: 插件安全规则',
|
|
67
|
-
'---',
|
|
68
|
-
'上线前要检查权限与密钥暴露。'
|
|
69
|
-
].join('\n'),
|
|
70
|
-
'specs/release/index.md': [
|
|
71
|
-
'---',
|
|
72
|
-
'description: 插件发布流程',
|
|
73
|
-
'---',
|
|
74
|
-
'插件 release 不应直接替代项目 release。'
|
|
75
|
-
].join('\n'),
|
|
76
|
-
'skills/audit/SKILL.md': [
|
|
77
|
-
'---',
|
|
78
|
-
'description: 审计输出',
|
|
79
|
-
'---',
|
|
80
|
-
'检查最终输出是否覆盖风险项。'
|
|
81
|
-
].join('\n'),
|
|
82
|
-
'mcp/browser.json': JSON.stringify(
|
|
83
|
-
{
|
|
84
|
-
name: 'browser',
|
|
85
|
-
command: 'npx',
|
|
86
|
-
args: ['browser-mcp']
|
|
87
|
-
},
|
|
88
|
-
null,
|
|
89
|
-
2
|
|
90
|
-
),
|
|
91
|
-
'opencode/agents/release-helper.md': '# release-helper\n',
|
|
92
|
-
'opencode/commands/review.md': '# review\n',
|
|
93
|
-
'opencode/modes/strict.md': '# strict\n',
|
|
94
|
-
'opencode/plugins/demo-plugin.js': 'export default {}\n'
|
|
95
|
-
})
|
|
96
|
-
await installPluginPackage(workspace, '@vibe-forge/plugin-logger', {
|
|
97
|
-
'package.json': JSON.stringify({
|
|
98
|
-
name: '@vibe-forge/plugin-logger',
|
|
99
|
-
version: '1.0.0'
|
|
100
|
-
}, null, 2),
|
|
101
|
-
'hooks.js': 'module.exports = {}\n'
|
|
102
|
-
})
|
|
103
|
-
await installPluginPackage(workspace, '@vibe-forge/plugin-telemetry', {
|
|
104
|
-
'package.json': JSON.stringify({
|
|
105
|
-
name: '@vibe-forge/plugin-telemetry',
|
|
106
|
-
version: '1.0.0'
|
|
107
|
-
}, null, 2),
|
|
108
|
-
'hooks.js': 'module.exports = {}\n'
|
|
109
|
-
})
|
|
110
|
-
|
|
111
68
|
await writeDocument(
|
|
112
69
|
join(workspace, '.ai/rules/review.md'),
|
|
113
70
|
[
|
|
@@ -118,6 +75,25 @@ describe('workspace assets snapshots', () => {
|
|
|
118
75
|
'必须检查发布改动的回归风险。'
|
|
119
76
|
].join('\n')
|
|
120
77
|
)
|
|
78
|
+
await writeDocument(
|
|
79
|
+
join(workspace, '.ai/plugins/demo/rules/review.md'),
|
|
80
|
+
[
|
|
81
|
+
'---',
|
|
82
|
+
'description: 插件评审规则',
|
|
83
|
+
'always: true',
|
|
84
|
+
'---',
|
|
85
|
+
'这是插件内的 review 规则,不应覆盖项目规则。'
|
|
86
|
+
].join('\n')
|
|
87
|
+
)
|
|
88
|
+
await writeDocument(
|
|
89
|
+
join(workspace, '.ai/plugins/demo/rules/security.md'),
|
|
90
|
+
[
|
|
91
|
+
'---',
|
|
92
|
+
'description: 插件安全规则',
|
|
93
|
+
'---',
|
|
94
|
+
'上线前要检查权限与密钥暴露。'
|
|
95
|
+
].join('\n')
|
|
96
|
+
)
|
|
121
97
|
await writeDocument(
|
|
122
98
|
join(workspace, '.ai/specs/release/index.md'),
|
|
123
99
|
[
|
|
@@ -130,9 +106,9 @@ describe('workspace assets snapshots', () => {
|
|
|
130
106
|
'mcpServers:',
|
|
131
107
|
' include:',
|
|
132
108
|
' - docs',
|
|
133
|
-
' -
|
|
109
|
+
' - browser',
|
|
134
110
|
' exclude:',
|
|
135
|
-
' -
|
|
111
|
+
' - browser',
|
|
136
112
|
'tools:',
|
|
137
113
|
' include:',
|
|
138
114
|
' - Read',
|
|
@@ -141,6 +117,15 @@ describe('workspace assets snapshots', () => {
|
|
|
141
117
|
'执行正式发布,并整理变更摘要。'
|
|
142
118
|
].join('\n')
|
|
143
119
|
)
|
|
120
|
+
await writeDocument(
|
|
121
|
+
join(workspace, '.ai/plugins/demo/specs/release/index.md'),
|
|
122
|
+
[
|
|
123
|
+
'---',
|
|
124
|
+
'description: 插件发布流程',
|
|
125
|
+
'---',
|
|
126
|
+
'插件 release 不应覆盖项目 release。'
|
|
127
|
+
].join('\n')
|
|
128
|
+
)
|
|
144
129
|
await writeDocument(
|
|
145
130
|
join(workspace, '.ai/entities/architect/README.md'),
|
|
146
131
|
[
|
|
@@ -159,6 +144,52 @@ describe('workspace assets snapshots', () => {
|
|
|
159
144
|
'先阅读 README.md,再补充结论。'
|
|
160
145
|
].join('\n')
|
|
161
146
|
)
|
|
147
|
+
await writeDocument(
|
|
148
|
+
join(workspace, '.ai/plugins/demo/skills/research/SKILL.md'),
|
|
149
|
+
[
|
|
150
|
+
'---',
|
|
151
|
+
'description: 插件 research',
|
|
152
|
+
'---',
|
|
153
|
+
'插件 research 不应覆盖项目 skill。'
|
|
154
|
+
].join('\n')
|
|
155
|
+
)
|
|
156
|
+
await writeDocument(
|
|
157
|
+
join(workspace, '.ai/plugins/demo/skills/audit/SKILL.md'),
|
|
158
|
+
[
|
|
159
|
+
'---',
|
|
160
|
+
'description: 审计输出',
|
|
161
|
+
'---',
|
|
162
|
+
'检查最终输出是否覆盖风险项。'
|
|
163
|
+
].join('\n')
|
|
164
|
+
)
|
|
165
|
+
await writeDocument(
|
|
166
|
+
join(workspace, '.ai/plugins/demo/mcp/browser.json'),
|
|
167
|
+
JSON.stringify(
|
|
168
|
+
{
|
|
169
|
+
name: 'browser',
|
|
170
|
+
command: 'npx',
|
|
171
|
+
args: ['browser-mcp']
|
|
172
|
+
},
|
|
173
|
+
null,
|
|
174
|
+
2
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
await writeDocument(
|
|
178
|
+
join(workspace, '.ai/plugins/demo/opencode/plugins/demo-plugin.js'),
|
|
179
|
+
'export default {};\n'
|
|
180
|
+
)
|
|
181
|
+
await writeDocument(
|
|
182
|
+
join(workspace, '.ai/plugins/demo/opencode/agents/release-helper.md'),
|
|
183
|
+
'# release-helper\n'
|
|
184
|
+
)
|
|
185
|
+
await writeDocument(
|
|
186
|
+
join(workspace, '.ai/plugins/demo/opencode/commands/review.md'),
|
|
187
|
+
'# review\n'
|
|
188
|
+
)
|
|
189
|
+
await writeDocument(
|
|
190
|
+
join(workspace, '.ai/plugins/demo/opencode/modes/strict.md'),
|
|
191
|
+
'# strict\n'
|
|
192
|
+
)
|
|
162
193
|
|
|
163
194
|
const bundle = await resolveWorkspaceAssetBundle({
|
|
164
195
|
cwd: workspace,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-forge/workspace-assets",
|
|
3
|
-
"version": "0.9.0",
|
|
3
|
+
"version": "0.9.1-alpha.0",
|
|
4
4
|
"description": "Workspace asset resolution and adapter asset planning for Vibe Forge",
|
|
5
5
|
"imports": {
|
|
6
6
|
"#~/*.js": {
|
|
@@ -25,18 +25,18 @@
|
|
|
25
25
|
},
|
|
26
26
|
"./package.json": "./package.json"
|
|
27
27
|
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"test": "pnpm -C ../.. exec vitest run --workspace vitest.workspace.ts --project bundler packages/workspace-assets/__tests__"
|
|
30
|
+
},
|
|
28
31
|
"dependencies": {
|
|
32
|
+
"@vibe-forge/config": "workspace:^",
|
|
33
|
+
"@vibe-forge/definition-loader": "workspace:^",
|
|
34
|
+
"@vibe-forge/types": "workspace:^",
|
|
35
|
+
"@vibe-forge/utils": "workspace:^",
|
|
29
36
|
"fast-glob": "^3.3.3",
|
|
30
|
-
"
|
|
31
|
-
"js-yaml": "^4.1.1",
|
|
32
|
-
"@vibe-forge/types": "^0.9.0",
|
|
33
|
-
"@vibe-forge/utils": "^0.9.0",
|
|
34
|
-
"@vibe-forge/config": "^0.9.0"
|
|
37
|
+
"js-yaml": "^4.1.1"
|
|
35
38
|
},
|
|
36
39
|
"devDependencies": {
|
|
37
40
|
"@types/js-yaml": "^4.0.9"
|
|
38
|
-
},
|
|
39
|
-
"scripts": {
|
|
40
|
-
"test": "pnpm -C ../.. exec vitest run --workspace vitest.workspace.ts --project bundler packages/workspace-assets/__tests__"
|
|
41
41
|
}
|
|
42
|
-
}
|
|
42
|
+
}
|