@vibe-forge/workspace-assets 0.11.0 → 0.11.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.
@@ -467,7 +467,8 @@
467
467
  ]
468
468
  },
469
469
  "options": {
470
- "systemPrompt": "<system-prompt>\nThe project system rules are:\n# review\n\n> 必须检查发布改动的回归风险。\n\n# demo/security\n\n> Use when: 插件安全规则\n> Rule file path: node_modules/@vibe-forge/plugin-demo/rules/security.md\n> Only read this rule file when the task matches the scenario above.\n</system-prompt>\n\n\n<system-prompt>\nThe following skill modules are loaded for the project:\n# research\n\n> Skill description: 检索资料\n> Skill file path: .ai/skills/research/SKILL.md\n> Resolve relative paths in the resource content relative to the directory containing this skill file.\n\n<skill-content>\n先阅读 README.md,再补充结论。\n</skill-content>\n</system-prompt>\n\n\n<system-prompt>\nThe project includes the following entities:\n - architect: 负责拆解方案的实体\n\nWhen solving user problems, you may specify entities through `vibe-forge.StartTasks` as needed and have them coordinate multiple entity types to complete the work; use `GetTaskInfo` and `wait` to track progress.\n</system-prompt>\n\n\n\n\n<system-prompt>\nYou are a professional project execution manager who can skillfully direct other entities to work toward your goal. Expectations:\n\n- Never complete code development work alone\n- You must coordinate other developers to complete tasks\n- You must keep them aligned with the goal and verify that their completion reports meet the requirements\n\nChoose the appropriate workflow based on the user's needs and the actual development goal, and use the workflow identifier to locate and load the corresponding definition.\n- Pass the identifier based on the actual need. This is not a path; use the standard workflow loading capability to resolve it.\n- Decide how to pass parameters based on their descriptions and actual usage scenarios.\nThe project includes the following workflows:\n- Workflow name: release\n - Description: 正式发布流程\n - Identifier: release\n - Parameters:\n - None\n\n- Workflow name: demo/release\n - Description: 插件发布流程\n - Identifier: demo/release\n - Parameters:\n - None\n\n</system-prompt>\n\n\n执行正式发布,并整理变更摘要。",
470
+ "systemPrompt": "<system-prompt>\nThe project system rules are:\n# review\n\n> 必须检查发布改动的回归风险。\n\n# demo/security\n\n> Use when: 插件安全规则\n> Rule file path: node_modules/@vibe-forge/plugin-demo/rules/security.md\n> Only read this rule file when the task matches the scenario above.\n</system-prompt>\n\n\n<system-prompt>\nThe following skill modules are loaded for the project:\n# research\n\n> Skill description: 检索资料\n> Skill file path: .ai/skills/research/SKILL.md\n> Resolve relative paths in the resource content relative to the directory containing this skill file.\n\n<skill-content>\n先阅读 README.md,再补充结论。\n</skill-content>\n</system-prompt>\n\n\n<system-prompt>\nThe project includes the following entities:\n - architect: 负责拆解方案的实体\n\nWhen solving user problems, you may specify entities through `VibeForge.StartTasks` as needed and have them coordinate multiple entity types to complete the work; use `VibeForge.GetTaskInfo` and `wait` to track progress.\n</system-prompt>\n\n\n<system-prompt>\nYou are a professional project execution manager who can skillfully direct other entities to work toward your goal. Expectations:\n\n- Never complete code development work alone\n- You must coordinate other developers to complete tasks\n- You must keep them aligned with the goal and verify that their completion reports meet the requirements\n\nChoose the appropriate workflow based on the user's needs and the actual development goal, and use the workflow identifier to locate and load the corresponding definition.\n- Pass the identifier based on the actual need. This is not a path; use the standard workflow loading capability to resolve it.\n- Decide how to pass parameters based on their descriptions and actual usage scenarios.\nThe project includes the following workflows:\n- Workflow name: release\n - Description: 正式发布流程\n - Identifier: release\n - Parameters:\n - None\n\n- Workflow name: demo/release\n - Description: 插件发布流程\n - Identifier: demo/release\n - Parameters:\n - None\n\n</system-prompt>\n\n\n执行正式发布,并整理变更摘要。",
471
+ "systemPrompt": "<system-prompt>\nThe project system rules are:\n# review\n\n> 必须检查发布改动的回归风险。\n\n# demo/security\n\n> Use when: 插件安全规则\n> Rule file path: node_modules/@vibe-forge/plugin-demo/rules/security.md\n> Only read this rule file when the task matches the scenario above.\n</system-prompt>\n\n\n<system-prompt>\nThe following skill modules are loaded for the project:\n# research\n\n> Skill description: 检索资料\n> Skill file path: .ai/skills/research/SKILL.md\n> Resolve relative paths in the resource content relative to the directory containing this skill file.\n\n<skill-content>\n先阅读 README.md,再补充结论。\n</skill-content>\n</system-prompt>\n\n\n<system-prompt>\nThe project includes the following entities:\n - architect: 负责拆解方案的实体\n\nWhen solving user problems, you may specify entities through `VibeForge.StartTasks` as needed and have them coordinate multiple entity types to complete the work; use `VibeForge.GetTaskInfo` and `wait` to track progress.\n</system-prompt>\n\n\n<system-prompt>\nYou are a professional project execution manager who can skillfully direct other entities to work toward your goal. Expectations:\n\n- Never complete code development work alone\n- You must coordinate other developers to complete tasks\n- You must keep them aligned with the goal and verify that their completion reports meet the requirements\n\nChoose the appropriate workflow based on the user's needs and the actual development goal, and use the workflow identifier to locate and load the corresponding definition.\n- Pass the identifier based on the actual need. This is not a path; use the standard workflow loading capability to resolve it.\n- Decide how to pass parameters based on their descriptions and actual usage scenarios.\nThe project includes the following workflows:\n- Workflow name: release\n - Description: 正式发布流程\n - Identifier: release\n - Parameters:\n - None\n\n- Workflow name: demo/release\n - Description: 插件发布流程\n - Identifier: demo/release\n - Parameters:\n - None\n\n</system-prompt>\n\n\n执行正式发布,并整理变更摘要。",
471
472
  "tools": {
472
473
  "include": [
473
474
  "Edit",
@@ -554,6 +555,12 @@
554
555
  "status": "prompt",
555
556
  "reason": "Mapped into the generated system prompt."
556
557
  },
558
+ {
559
+ "assetId": "skill:workspace:workspace:research:<workspace>/.ai/skills/research/SKILL.md",
560
+ "adapter": "claude-code",
561
+ "status": "native",
562
+ "reason": "Synced into the Claude mock home as a native skill."
563
+ },
557
564
  {
558
565
  "assetId": "skill:workspace:workspace:research:<workspace>/.ai/skills/research/SKILL.md",
559
566
  "adapter": "claude-code",
@@ -68,6 +68,57 @@ describe('resolveWorkspaceAssetBundle', () => {
68
68
  ]))
69
69
  })
70
70
 
71
+ it('loads workspace assets from the env-configured ai base dir', async () => {
72
+ const workspace = await createWorkspace()
73
+ const previousBaseDir = process.env.__VF_PROJECT_AI_BASE_DIR__
74
+
75
+ try {
76
+ process.env.__VF_PROJECT_AI_BASE_DIR__ = '.vf'
77
+ await writeDocument(join(workspace, '.vf/rules/review.md'), '---\ndescription: 评审规则\n---\n必须检查风险')
78
+ await writeDocument(join(workspace, '.vf/skills/research/SKILL.md'), '---\ndescription: 检索资料\n---\n阅读 README.md')
79
+
80
+ const bundle = await resolveWorkspaceAssetBundle({
81
+ cwd: workspace,
82
+ configs: [undefined, undefined],
83
+ useDefaultVibeForgeMcpServer: false
84
+ })
85
+
86
+ expect(bundle.rules.map(asset => asset.displayName)).toEqual(['review'])
87
+ expect(bundle.skills.map(asset => asset.displayName)).toEqual(['research'])
88
+ } finally {
89
+ if (previousBaseDir == null) {
90
+ delete process.env.__VF_PROJECT_AI_BASE_DIR__
91
+ } else {
92
+ process.env.__VF_PROJECT_AI_BASE_DIR__ = previousBaseDir
93
+ }
94
+ }
95
+ })
96
+
97
+ it('loads workspace entities from the env-configured entities dir', async () => {
98
+ const workspace = await createWorkspace()
99
+ const previousEntitiesDir = process.env.__VF_PROJECT_AI_ENTITIES_DIR__
100
+
101
+ try {
102
+ process.env.__VF_PROJECT_AI_ENTITIES_DIR__ = 'agents'
103
+ await writeDocument(join(workspace, '.ai/agents/reviewer/README.md'), '---\ndescription: 负责代码评审\n---\n检查风险')
104
+
105
+ const bundle = await resolveWorkspaceAssetBundle({
106
+ cwd: workspace,
107
+ configs: [undefined, undefined],
108
+ useDefaultVibeForgeMcpServer: false
109
+ })
110
+
111
+ expect(bundle.entities.map(asset => asset.displayName)).toEqual(['reviewer'])
112
+ expect(bundle.entities[0]?.sourcePath).toContain('/.ai/agents/reviewer/README.md')
113
+ } finally {
114
+ if (previousEntitiesDir == null) {
115
+ delete process.env.__VF_PROJECT_AI_ENTITIES_DIR__
116
+ } else {
117
+ process.env.__VF_PROJECT_AI_ENTITIES_DIR__ = previousEntitiesDir
118
+ }
119
+ }
120
+ })
121
+
71
122
  it('auto-loads managed Claude plugins from .ai/plugins as directory plugins', async () => {
72
123
  const workspace = await createWorkspace()
73
124
 
@@ -129,8 +180,8 @@ describe('resolveWorkspaceAssetBundle', () => {
129
180
  useDefaultVibeForgeMcpServer: true
130
181
  })
131
182
 
132
- expect(enabledBundle.mcpServers).toHaveProperty('vibe-forge')
133
- expect(enabledBundle.mcpServers['vibe-forge']?.payload.config).toEqual(expect.objectContaining({
183
+ expect(enabledBundle.mcpServers).toHaveProperty('VibeForge')
184
+ expect(enabledBundle.mcpServers.VibeForge?.payload.config).toEqual(expect.objectContaining({
134
185
  command: process.execPath,
135
186
  args: [expect.stringMatching(/packages\/mcp\/cli\.js$/)]
136
187
  }))
@@ -141,7 +192,7 @@ describe('resolveWorkspaceAssetBundle', () => {
141
192
  useDefaultVibeForgeMcpServer: false
142
193
  })
143
194
 
144
- expect(disabledBundle.mcpServers).not.toHaveProperty('vibe-forge')
195
+ expect(disabledBundle.mcpServers).not.toHaveProperty('VibeForge')
145
196
  })
146
197
 
147
198
  it('skips disabled plugin instances and lets disabled child overrides suppress default child activation', async () => {
@@ -173,8 +173,8 @@ describe('workspace asset prompt builders', () => {
173
173
  ])
174
174
 
175
175
  expect(prompt).toContain('reviewer: 负责代码审查')
176
- expect(prompt).toContain('`vibe-forge.StartTasks`')
177
- expect(prompt).toContain('`GetTaskInfo`')
176
+ expect(prompt).toContain('`VibeForge.StartTasks`')
177
+ expect(prompt).toContain('`VibeForge.GetTaskInfo`')
178
178
  expect(prompt).toContain('`wait`')
179
179
  expect(prompt).not.toContain('run-tasks')
180
180
  expect(prompt).not.toContain('需要关注变更风险')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-forge/workspace-assets",
3
- "version": "0.11.0",
3
+ "version": "0.11.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": "^0.11.1",
32
33
  "@vibe-forge/definition-core": "^0.11.0",
33
- "@vibe-forge/config": "^0.11.0",
34
- "@vibe-forge/types": "^0.11.0",
35
- "@vibe-forge/utils": "^0.11.0"
34
+ "@vibe-forge/types": "^0.11.2",
35
+ "@vibe-forge/utils": "^0.11.2"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/js-yaml": "^4.0.9"
@@ -9,7 +9,7 @@ import {
9
9
  resolveDefaultVibeForgeMcpServerConfig
10
10
  } from '@vibe-forge/config'
11
11
  import type { Config, Definition, Entity, PluginConfig, WorkspaceAsset, WorkspaceAssetKind } from '@vibe-forge/types'
12
- import { resolveRelativePath } from '@vibe-forge/utils'
12
+ import { resolveProjectAiBaseDir, resolveProjectAiEntitiesDir, resolveRelativePath } from '@vibe-forge/utils'
13
13
  import { listManagedPluginInstalls, toManagedPluginConfig } from '@vibe-forge/utils/managed-plugin'
14
14
  import {
15
15
  flattenPluginInstances,
@@ -217,13 +217,15 @@ const createOpenCodeOverlayAsset = <TKind extends OpenCodeOverlayKind>(params: {
217
217
  } as OpenCodeOverlayAsset<TKind>)
218
218
 
219
219
  const scanWorkspaceDocuments = async (cwd: string) => {
220
+ const aiBaseDir = resolveProjectAiBaseDir(cwd, process.env)
221
+ const entitiesDir = resolveProjectAiEntitiesDir(cwd, process.env)
220
222
  const [rulePaths, skillPaths, specPaths, entityDocPaths, entityJsonPaths, mcpPaths] = await Promise.all([
221
- glob(['.ai/rules/*.md'], { cwd, absolute: true }),
222
- glob(['.ai/skills/*/SKILL.md'], { cwd, absolute: true }),
223
- glob(['.ai/specs/*.md', '.ai/specs/*/index.md'], { cwd, absolute: true }),
224
- glob(['.ai/entities/*.md', '.ai/entities/*/README.md'], { cwd, absolute: true }),
225
- glob(['.ai/entities/*/index.json'], { cwd, absolute: true }),
226
- glob(['.ai/mcp/*.json', '.ai/mcp/*.yaml', '.ai/mcp/*.yml'], { cwd, absolute: true })
223
+ glob(['rules/*.md'], { cwd: aiBaseDir, absolute: true }),
224
+ glob(['skills/*/SKILL.md'], { cwd: aiBaseDir, absolute: true }),
225
+ glob(['specs/*.md', 'specs/*/index.md'], { cwd: aiBaseDir, absolute: true }),
226
+ glob(['*.md', '*/README.md'], { cwd: entitiesDir, absolute: true }),
227
+ glob(['*/index.json'], { cwd: entitiesDir, absolute: true }),
228
+ glob(['mcp/*.json', 'mcp/*.yaml', 'mcp/*.yml'], { cwd: aiBaseDir, absolute: true })
227
229
  ])
228
230
 
229
231
  return {
@@ -441,7 +443,7 @@ export async function collectWorkspaceAssets(params: {
441
443
  name: DEFAULT_VIBE_FORGE_MCP_SERVER_NAME,
442
444
  config: defaultVibeForgeMcpServer,
443
445
  origin: 'workspace',
444
- sourcePath: resolve(params.cwd, '.ai')
446
+ sourcePath: resolveProjectAiBaseDir(params.cwd, process.env)
445
447
  }))
446
448
  }
447
449
  }
@@ -5,7 +5,7 @@ import {
5
5
  resolveSpecIdentifier
6
6
  } from '@vibe-forge/definition-core'
7
7
  import type { Definition, Entity, Rule, Skill, Spec } from '@vibe-forge/types'
8
- import { resolvePromptPath } from '@vibe-forge/utils'
8
+ import { CANONICAL_VIBE_FORGE_MCP_SERVER_NAME, resolvePromptPath } from '@vibe-forge/utils'
9
9
 
10
10
  const toMarkdownBlockquote = (content: string) => (
11
11
  content
@@ -178,7 +178,7 @@ export const generateEntitiesRoutePrompt = (entities: Definition<Entity>[]) => {
178
178
  })
179
179
  .join('')
180
180
  }\n` +
181
- 'When solving user problems, you may specify entities through `vibe-forge.StartTasks` as needed and have them coordinate multiple entity types to complete the work; use `GetTaskInfo` and `wait` to track progress.\n' +
181
+ `When solving user problems, you may specify entities through \`${CANONICAL_VIBE_FORGE_MCP_SERVER_NAME}.StartTasks\` as needed and have them coordinate multiple entity types to complete the work; use \`${CANONICAL_VIBE_FORGE_MCP_SERVER_NAME}.GetTaskInfo\` and \`wait\` to track progress.\n` +
182
182
  '</system-prompt>\n'
183
183
  )
184
184
  }