@vibe-forge/workspace-assets 3.2.0 → 3.2.2-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 +1 -1
- package/__tests__/adapter-asset-plan.spec.ts +0 -58
- package/__tests__/bundle.spec.ts +0 -238
- package/__tests__/prompt-builders.spec.ts +30 -3
- package/__tests__/skill-dependencies-cli.spec.ts +59 -252
- package/package.json +4 -4
- package/src/bundle-internal.ts +51 -4
- package/src/configured-skills.ts +5 -1
- package/src/plugin-skill-dependencies.ts +1 -0
- package/src/prompt-builders.ts +4 -2
- package/src/selection-internal.ts +9 -2
- package/src/skill-dependencies.ts +10 -108
- package/src/task-tool-guidance.ts +19 -6
- package/src/workspace-prompt.ts +4 -2
- package/src/skills-cli-dependency-helpers.ts +0 -94
- package/src/skills-cli-dependency.ts +0 -125
|
@@ -467,7 +467,7 @@
|
|
|
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 start child runtime sessions with `vf run --input-format stream-json --output-format stream-json` and a `session.start` protocol envelope as needed; use `session.status`, `session.events`, and `wait` to track progress.\nAgent runtime guide:\n- Use unified CLI protocol mode, `vf run --input-format stream-json --output-format stream-json`, to start a child runtime session when the work should run in a separate entity or continue independently from the current turn.\n- Send typed runtime protocol envelopes such as `session.start`, `session.message`, `session.status`, `session.events`, `session.submit`, and `session.stop`; do not treat dedicated
|
|
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 start child runtime sessions with `vf run --input-format stream-json --output-format stream-json` and a `session.start` protocol envelope as needed; use `session.status`, `session.events`, and `wait` to track progress.\nAgent runtime guide:\n- Use unified CLI protocol mode, `vf run --input-format stream-json --output-format stream-json`, to start a child runtime session when the work should run in a separate entity or continue independently from the current turn.\n- Send typed runtime protocol envelopes such as `session.start`, `session.message`, `session.status`, `session.events`, `session.submit`, and `session.stop`; do not treat dedicated agent subcommands as the standard integration surface.\n- Ordinary new sessions stay session-scoped. A room is created or discovered only when a unified CLI runtime protocol start command launches a child runtime session from a server-managed host session and the server projects runtime store metadata/events.\n- Do not use MCP task tools, dedicated agent subcommands, legacy StartTasks, hand-written DB edits, or ad-hoc TS scripts as the task consumer surface. Use CLI protocol mode and the runtime protocol/store for start, status, events, follow-up messages, input submission, and cancellation.\n- Server-managed host sessions inject the current adapter, model, effort, and permission mode as runtime protocol defaults. Omit these fields to inherit the host selection, or set them explicitly only when a child task must use a different runtime profile.\n- Copyable JSONL example; write one `session.start` line per child task, and use multiple lines for multiple subtasks:\n```bash\ncat <<'JSONL' | vf run --input-format stream-json --output-format stream-json\n{\"commandId\":\"start-planner\",\"type\":\"session.start\",\"payload\":{\"title\":\"Plan Agent Room UI fix\",\"message\":\"Plan the frontend changes and tests for the Agent Room UI fix.\",\"entity\":\"dev-planner\",\"background\":true},\"title\":\"Plan Agent Room UI fix\",\"message\":\"Plan the frontend changes and tests for the Agent Room UI fix.\",\"entity\":\"dev-planner\",\"background\":true}\n{\"commandId\":\"start-reviewer\",\"type\":\"session.start\",\"payload\":{\"title\":\"Review Agent Room UI fix\",\"message\":\"Review the implemented Agent Room UI fix for regressions and missing tests.\",\"entity\":\"dev-reviewer\",\"background\":true},\"title\":\"Review Agent Room UI fix\",\"message\":\"Review the implemented Agent Room UI fix for regressions and missing tests.\",\"entity\":\"dev-reviewer\",\"background\":true}\nJSONL\n```\n- Keep `payload.title`, `payload.message`, `payload.entity`, and `payload.background: true` explicit in each start envelope. The mirrored top-level fields make the JSONL executable by the current runtime protocol reader.\n- Include a short `title` when the task prompt is long; it becomes the child session title and room run label. Put any room or workspace context in the title and initial message.\n- Read the returned `sessionId` and use it for follow-up protocol commands. Read the latest runtime snapshot from the runtime store or a `session.status` protocol command, and read progress from runtime events or a `session.events` protocol command.\n- Use a follow/read-events workflow when you need to watch progress instead of repeatedly restarting work.\n- Use a `session.message` protocol command to give an existing session another instruction. Running sessions continue immediately; completed or failed sessions resume the same conversation when the runtime allows resume.\n- When the chat UI sends a `[ROOM_TASK_MESSAGE] ... [/ROOM_TASK_MESSAGE]` block, treat it as a runtime relay envelope instead of ordinary prose. Parse the `sessionId` or legacy `taskId`, `message`, and optional `mode` / `request` fields. If the envelope indicates `mode: interaction`, or runtime status shows `waiting_input` / pending input, use a `session.submit` protocol command. Otherwise use `session.message`. Do not reply inline instead of routing the relay.\n- Use `session.submit` only when a runtime session is waiting for an explicit input or approval request. Do not use it for ordinary follow-up instructions.\n- Use a `session.stop` protocol command for graceful cancellation and set `mode` to `force` only when stop cannot recover the session.\n- Compatibility aliases such as dedicated agent start/status/events/send/submit/stop subcommands may exist for debugging or legacy scripts, but they are not the primary guidance for new agent workflows.\n- When a session is still making progress, use `wait` between checks and inspect status/events instead of starting a replacement session.\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
471
|
"tools": {
|
|
472
472
|
"include": [
|
|
473
473
|
"Edit",
|
|
@@ -280,64 +280,6 @@ describe('buildAdapterAssetPlan', () => {
|
|
|
280
280
|
]))
|
|
281
281
|
})
|
|
282
282
|
|
|
283
|
-
it('keeps explicit skills CLI dependencies ahead of preselected home-bridged skills in overlays', async () => {
|
|
284
|
-
const workspace = await createWorkspace()
|
|
285
|
-
const realHome = process.env.__VF_PROJECT_REAL_HOME__
|
|
286
|
-
const tempInstallDir = join(workspace, '.tmp-install-skills-cli-foo')
|
|
287
|
-
const installedSkillDir = join(tempInstallDir, '.agents', 'skills', 'foo')
|
|
288
|
-
await writeDocument(
|
|
289
|
-
join(installedSkillDir, 'SKILL.md'),
|
|
290
|
-
'---\nname: foo\ndescription: Registry foo\n---\nUse the registry definition.\n'
|
|
291
|
-
)
|
|
292
|
-
skillsCliMocks.installSkillsCliSkillToTemp.mockResolvedValue({
|
|
293
|
-
tempDir: tempInstallDir,
|
|
294
|
-
installedSkill: {
|
|
295
|
-
dirName: 'foo',
|
|
296
|
-
name: 'foo',
|
|
297
|
-
sourcePath: installedSkillDir
|
|
298
|
-
}
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
await writeDocument(
|
|
302
|
-
join(realHome!, '.agents/skills/foo/SKILL.md'),
|
|
303
|
-
'---\ndescription: Home foo\n---\nUse the home definition.\n'
|
|
304
|
-
)
|
|
305
|
-
await writeDocument(
|
|
306
|
-
join(workspace, '.ai/skills/app-builder/SKILL.md'),
|
|
307
|
-
[
|
|
308
|
-
'---',
|
|
309
|
-
'name: app-builder',
|
|
310
|
-
'description: Build apps',
|
|
311
|
-
'dependencies:',
|
|
312
|
-
' - anthropics/skills@foo',
|
|
313
|
-
'---',
|
|
314
|
-
'Build the app.'
|
|
315
|
-
].join('\n')
|
|
316
|
-
)
|
|
317
|
-
|
|
318
|
-
const bundle = await resolveWorkspaceAssetBundle({
|
|
319
|
-
cwd: workspace,
|
|
320
|
-
configs: [undefined, undefined],
|
|
321
|
-
useDefaultVibeForgeMcpServer: false
|
|
322
|
-
})
|
|
323
|
-
const plan = await buildAdapterAssetPlan({
|
|
324
|
-
adapter: 'opencode',
|
|
325
|
-
bundle,
|
|
326
|
-
options: {
|
|
327
|
-
skills: {
|
|
328
|
-
include: ['foo', 'app-builder']
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
})
|
|
332
|
-
|
|
333
|
-
const fooOverlays = plan.overlays.filter(entry => entry.kind === 'skill' && entry.targetPath === 'skills/foo')
|
|
334
|
-
expect(fooOverlays).toHaveLength(1)
|
|
335
|
-
expect(fooOverlays[0]?.sourcePath).toContain(
|
|
336
|
-
'/.ai/caches/skill-dependencies/skills-cli/skills/latest/default/anthropics/skills/latest/foo'
|
|
337
|
-
)
|
|
338
|
-
expect(fooOverlays[0]?.sourcePath).not.toBe(join(realHome!, '.agents/skills/foo'))
|
|
339
|
-
})
|
|
340
|
-
|
|
341
283
|
it('prunes excluded skill dependency subtrees from selected native overlays', async () => {
|
|
342
284
|
const workspace = await createWorkspace()
|
|
343
285
|
|
package/__tests__/bundle.spec.ts
CHANGED
|
@@ -386,79 +386,6 @@ describe('resolveWorkspaceAssetBundle', () => {
|
|
|
386
386
|
}))
|
|
387
387
|
})
|
|
388
388
|
|
|
389
|
-
it('installs selected missing skill dependencies from the skills CLI cache', async () => {
|
|
390
|
-
const workspace = await createWorkspace()
|
|
391
|
-
const realHome = process.env.__VF_PROJECT_REAL_HOME__
|
|
392
|
-
const tempInstallDir = join(workspace, '.tmp-install-skills-cli')
|
|
393
|
-
const installedSkillDir = join(tempInstallDir, '.agents', 'skills', 'frontend-design')
|
|
394
|
-
await writeDocument(
|
|
395
|
-
join(installedSkillDir, 'SKILL.md'),
|
|
396
|
-
'---\nname: frontend-design\ndescription: UI design guidance\n---\nUse strong visual hierarchy.\n'
|
|
397
|
-
)
|
|
398
|
-
skillsCliMocks.installSkillsCliSkillToTemp.mockResolvedValue({
|
|
399
|
-
tempDir: tempInstallDir,
|
|
400
|
-
installedSkill: {
|
|
401
|
-
dirName: 'frontend-design',
|
|
402
|
-
name: 'frontend-design',
|
|
403
|
-
sourcePath: installedSkillDir
|
|
404
|
-
}
|
|
405
|
-
})
|
|
406
|
-
|
|
407
|
-
await writeDocument(
|
|
408
|
-
join(realHome!, '.agents/skills/frontend-design/SKILL.md'),
|
|
409
|
-
'---\ndescription: home frontend design\n---\nUse the home definition.'
|
|
410
|
-
)
|
|
411
|
-
await writeDocument(
|
|
412
|
-
join(workspace, '.ai/skills/app-builder/SKILL.md'),
|
|
413
|
-
[
|
|
414
|
-
'---',
|
|
415
|
-
'name: app-builder',
|
|
416
|
-
'description: Build apps',
|
|
417
|
-
'dependencies:',
|
|
418
|
-
' - anthropics/skills@frontend-design',
|
|
419
|
-
'---',
|
|
420
|
-
'Build the app.'
|
|
421
|
-
].join('\n')
|
|
422
|
-
)
|
|
423
|
-
|
|
424
|
-
const bundle = await resolveWorkspaceAssetBundle({
|
|
425
|
-
cwd: workspace,
|
|
426
|
-
configs: [undefined, undefined],
|
|
427
|
-
useDefaultVibeForgeMcpServer: false
|
|
428
|
-
})
|
|
429
|
-
|
|
430
|
-
expect(bundle.skills.map(asset => asset.name).sort()).toEqual(['app-builder', 'frontend-design'])
|
|
431
|
-
expect(bundle.skills.find(asset => asset.name === 'frontend-design')).toEqual(expect.objectContaining({
|
|
432
|
-
resolvedBy: 'home-bridge',
|
|
433
|
-
sourcePath: join(realHome!, '.agents/skills/frontend-design/SKILL.md')
|
|
434
|
-
}))
|
|
435
|
-
|
|
436
|
-
await buildAdapterAssetPlan({
|
|
437
|
-
adapter: 'opencode',
|
|
438
|
-
bundle,
|
|
439
|
-
options: {
|
|
440
|
-
skills: {
|
|
441
|
-
include: ['app-builder']
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
})
|
|
445
|
-
|
|
446
|
-
const dependency = bundle.skills.find(asset => asset.name === 'frontend-design')
|
|
447
|
-
expect(bundle.skills.map(asset => asset.name).sort()).toEqual(['app-builder', 'frontend-design'])
|
|
448
|
-
expect(dependency?.sourcePath).toContain(
|
|
449
|
-
'/.ai/caches/skill-dependencies/skills-cli/skills/latest/default/anthropics/skills/latest/frontend-design/'
|
|
450
|
-
)
|
|
451
|
-
expect(bundle.skills.find(asset => (
|
|
452
|
-
asset.name === 'frontend-design' && asset.resolvedBy === 'home-bridge'
|
|
453
|
-
))).toBeUndefined()
|
|
454
|
-
expect(skillsCliMocks.findSkillsCli).not.toHaveBeenCalled()
|
|
455
|
-
expect(skillsCliMocks.installSkillsCliSkillToTemp).toHaveBeenCalledWith({
|
|
456
|
-
config: undefined,
|
|
457
|
-
skill: 'frontend-design',
|
|
458
|
-
source: 'anthropics/skills'
|
|
459
|
-
})
|
|
460
|
-
})
|
|
461
|
-
|
|
462
389
|
it('installs configured project skills before bundle resolution and rewrites renamed skill names', async () => {
|
|
463
390
|
const workspace = await createWorkspace()
|
|
464
391
|
const tempInstallDir = join(workspace, '.tmp-configured-install')
|
|
@@ -564,171 +491,6 @@ describe('resolveWorkspaceAssetBundle', () => {
|
|
|
564
491
|
)
|
|
565
492
|
})
|
|
566
493
|
|
|
567
|
-
it('installs skill dependencies into the primary workspace shared cache', async () => {
|
|
568
|
-
const primary = await createWorkspace()
|
|
569
|
-
const worktree = await createWorkspace()
|
|
570
|
-
const previousPrimaryWorkspace = process.env.__VF_PROJECT_PRIMARY_WORKSPACE_FOLDER__
|
|
571
|
-
const tempInstallDir = join(worktree, '.tmp-install-skills-cli')
|
|
572
|
-
const installedSkillDir = join(tempInstallDir, '.agents', 'skills', 'frontend-design')
|
|
573
|
-
await writeDocument(
|
|
574
|
-
join(installedSkillDir, 'SKILL.md'),
|
|
575
|
-
'---\nname: frontend-design\ndescription: UI design guidance\n---\nUse primary cache.\n'
|
|
576
|
-
)
|
|
577
|
-
skillsCliMocks.installSkillsCliSkillToTemp.mockResolvedValue({
|
|
578
|
-
tempDir: tempInstallDir,
|
|
579
|
-
installedSkill: {
|
|
580
|
-
dirName: 'frontend-design',
|
|
581
|
-
name: 'frontend-design',
|
|
582
|
-
sourcePath: installedSkillDir
|
|
583
|
-
}
|
|
584
|
-
})
|
|
585
|
-
|
|
586
|
-
try {
|
|
587
|
-
process.env.__VF_PROJECT_PRIMARY_WORKSPACE_FOLDER__ = primary
|
|
588
|
-
await writeDocument(
|
|
589
|
-
join(worktree, '.ai/skills/app-builder/SKILL.md'),
|
|
590
|
-
[
|
|
591
|
-
'---',
|
|
592
|
-
'name: app-builder',
|
|
593
|
-
'description: Build apps',
|
|
594
|
-
'dependencies:',
|
|
595
|
-
' - anthropics/skills@frontend-design',
|
|
596
|
-
'---',
|
|
597
|
-
'Build the app.'
|
|
598
|
-
].join('\n')
|
|
599
|
-
)
|
|
600
|
-
|
|
601
|
-
const bundle = await resolveWorkspaceAssetBundle({
|
|
602
|
-
cwd: worktree,
|
|
603
|
-
configs: [undefined, undefined],
|
|
604
|
-
useDefaultVibeForgeMcpServer: false
|
|
605
|
-
})
|
|
606
|
-
|
|
607
|
-
await buildAdapterAssetPlan({
|
|
608
|
-
adapter: 'opencode',
|
|
609
|
-
bundle,
|
|
610
|
-
options: {
|
|
611
|
-
skills: {
|
|
612
|
-
include: ['app-builder']
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
})
|
|
616
|
-
|
|
617
|
-
const dependency = bundle.skills.find(asset => asset.name === 'frontend-design')
|
|
618
|
-
expect(dependency?.sourcePath).toContain(join(
|
|
619
|
-
primary,
|
|
620
|
-
'.ai/caches/skill-dependencies/skills-cli/skills/latest/default/anthropics/skills/latest/frontend-design/'
|
|
621
|
-
))
|
|
622
|
-
expect(dependency?.sourcePath).not.toContain(join(worktree, '.ai/caches'))
|
|
623
|
-
} finally {
|
|
624
|
-
if (previousPrimaryWorkspace == null) {
|
|
625
|
-
delete process.env.__VF_PROJECT_PRIMARY_WORKSPACE_FOLDER__
|
|
626
|
-
} else {
|
|
627
|
-
process.env.__VF_PROJECT_PRIMARY_WORKSPACE_FOLDER__ = previousPrimaryWorkspace
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
})
|
|
631
|
-
|
|
632
|
-
it('reuses complete skill dependency caches without deleting or downloading them again', async () => {
|
|
633
|
-
const workspace = await createWorkspace()
|
|
634
|
-
|
|
635
|
-
const cachedSkillPath = join(
|
|
636
|
-
workspace,
|
|
637
|
-
'.ai/caches/skill-dependencies/skills-cli/skills/latest/default/anthropics/skills/latest/frontend-design/SKILL.md'
|
|
638
|
-
)
|
|
639
|
-
await writeDocument(
|
|
640
|
-
cachedSkillPath,
|
|
641
|
-
'---\nname: frontend-design\ndescription: Cached UI guidance\n---\nUse the cached copy.\n'
|
|
642
|
-
)
|
|
643
|
-
await writeDocument(
|
|
644
|
-
join(workspace, '.ai/skills/app-builder/SKILL.md'),
|
|
645
|
-
[
|
|
646
|
-
'---',
|
|
647
|
-
'name: app-builder',
|
|
648
|
-
'description: Build apps',
|
|
649
|
-
'dependencies:',
|
|
650
|
-
' - anthropics/skills@frontend-design',
|
|
651
|
-
'---',
|
|
652
|
-
'Build the app.'
|
|
653
|
-
].join('\n')
|
|
654
|
-
)
|
|
655
|
-
|
|
656
|
-
const bundle = await resolveWorkspaceAssetBundle({
|
|
657
|
-
cwd: workspace,
|
|
658
|
-
configs: [undefined, undefined],
|
|
659
|
-
useDefaultVibeForgeMcpServer: false
|
|
660
|
-
})
|
|
661
|
-
|
|
662
|
-
await buildAdapterAssetPlan({
|
|
663
|
-
adapter: 'opencode',
|
|
664
|
-
bundle,
|
|
665
|
-
options: {
|
|
666
|
-
skills: {
|
|
667
|
-
include: ['app-builder']
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
})
|
|
671
|
-
|
|
672
|
-
expect(skillsCliMocks.findSkillsCli).not.toHaveBeenCalled()
|
|
673
|
-
expect(skillsCliMocks.installSkillsCliSkillToTemp).not.toHaveBeenCalled()
|
|
674
|
-
expect(await readFile(cachedSkillPath, 'utf8')).toContain('Use the cached copy.')
|
|
675
|
-
expect(bundle.skills.map(asset => asset.name).sort()).toEqual(['app-builder', 'frontend-design'])
|
|
676
|
-
})
|
|
677
|
-
|
|
678
|
-
it('parses registry/source/version dependency specs and forwards them to the skills CLI installer', async () => {
|
|
679
|
-
const workspace = await createWorkspace()
|
|
680
|
-
const tempInstallDir = join(workspace, '.tmp-install-skills-cli')
|
|
681
|
-
const installedSkillDir = join(tempInstallDir, '.agents', 'skills', 'frontend-design')
|
|
682
|
-
await writeDocument(
|
|
683
|
-
join(installedSkillDir, 'SKILL.md'),
|
|
684
|
-
'---\nname: frontend-design\ndescription: UI design guidance\n---\nUse internal design tokens.\n'
|
|
685
|
-
)
|
|
686
|
-
skillsCliMocks.installSkillsCliSkillToTemp.mockResolvedValue({
|
|
687
|
-
tempDir: tempInstallDir,
|
|
688
|
-
installedSkill: {
|
|
689
|
-
dirName: 'frontend-design',
|
|
690
|
-
name: 'frontend-design',
|
|
691
|
-
sourcePath: installedSkillDir
|
|
692
|
-
}
|
|
693
|
-
})
|
|
694
|
-
|
|
695
|
-
await writeDocument(
|
|
696
|
-
join(workspace, '.ai/skills/app-builder/SKILL.md'),
|
|
697
|
-
[
|
|
698
|
-
'---',
|
|
699
|
-
'name: app-builder',
|
|
700
|
-
'description: Build apps',
|
|
701
|
-
'dependencies:',
|
|
702
|
-
' - https://registry.example.com@example-source/default/public@frontend-design@1.0.3',
|
|
703
|
-
'---',
|
|
704
|
-
'Build the app.'
|
|
705
|
-
].join('\n')
|
|
706
|
-
)
|
|
707
|
-
|
|
708
|
-
const bundle = await resolveWorkspaceAssetBundle({
|
|
709
|
-
cwd: workspace,
|
|
710
|
-
configs: [undefined, undefined],
|
|
711
|
-
useDefaultVibeForgeMcpServer: false
|
|
712
|
-
})
|
|
713
|
-
|
|
714
|
-
await buildAdapterAssetPlan({
|
|
715
|
-
adapter: 'opencode',
|
|
716
|
-
bundle,
|
|
717
|
-
options: {
|
|
718
|
-
skills: {
|
|
719
|
-
include: ['app-builder']
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
})
|
|
723
|
-
|
|
724
|
-
expect(skillsCliMocks.installSkillsCliSkillToTemp).toHaveBeenCalledWith({
|
|
725
|
-
registry: 'https://registry.example.com',
|
|
726
|
-
skill: 'frontend-design',
|
|
727
|
-
source: 'example-source/default/public',
|
|
728
|
-
version: '1.0.3'
|
|
729
|
-
})
|
|
730
|
-
})
|
|
731
|
-
|
|
732
494
|
it('loads workspace entities from the env-configured entities dir', async () => {
|
|
733
495
|
const workspace = await createWorkspace()
|
|
734
496
|
const previousEntitiesDir = process.env.__VF_PROJECT_AI_ENTITIES_DIR__
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { join } from 'node:path'
|
|
2
|
+
import process from 'node:process'
|
|
2
3
|
|
|
3
|
-
import { describe, expect, it } from 'vitest'
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
4
5
|
|
|
5
6
|
import {
|
|
6
7
|
generateEntitiesRoutePrompt,
|
|
@@ -11,6 +12,16 @@ import {
|
|
|
11
12
|
} from '#~/prompt-builders.js'
|
|
12
13
|
import { generateWorkspaceRoutePrompt } from '#~/workspace-prompt.js'
|
|
13
14
|
|
|
15
|
+
const originalCliResumeCommandPrefix = process.env.__VF_CLI_RESUME_COMMAND_PREFIX__
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
if (originalCliResumeCommandPrefix == null) {
|
|
19
|
+
delete process.env.__VF_CLI_RESUME_COMMAND_PREFIX__
|
|
20
|
+
} else {
|
|
21
|
+
process.env.__VF_CLI_RESUME_COMMAND_PREFIX__ = originalCliResumeCommandPrefix
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
14
25
|
describe('workspace asset prompt builders', () => {
|
|
15
26
|
it('builds skill prompts with stable names, descriptions, and relative paths', () => {
|
|
16
27
|
const cwd = '/tmp/project'
|
|
@@ -184,10 +195,10 @@ describe('workspace asset prompt builders', () => {
|
|
|
184
195
|
expect(prompt).toContain('"background":true')
|
|
185
196
|
expect(prompt).toContain('write one `session.start` line per child task')
|
|
186
197
|
expect(prompt).toContain('typed runtime protocol envelopes')
|
|
187
|
-
expect(prompt).toContain('do not treat dedicated
|
|
198
|
+
expect(prompt).toContain('do not treat dedicated agent subcommands as the standard integration surface')
|
|
188
199
|
expect(prompt).toContain('Read the returned `sessionId`')
|
|
189
200
|
expect(prompt).toContain('Ordinary new sessions stay session-scoped')
|
|
190
|
-
expect(prompt).toContain('Do not use MCP task tools,
|
|
201
|
+
expect(prompt).toContain('Do not use MCP task tools, dedicated agent subcommands, legacy StartTasks')
|
|
191
202
|
expect(prompt).toContain('hand-written DB edits')
|
|
192
203
|
expect(prompt).toContain('ad-hoc TS scripts')
|
|
193
204
|
expect(prompt).toContain('server-managed host session')
|
|
@@ -237,6 +248,22 @@ describe('workspace asset prompt builders', () => {
|
|
|
237
248
|
expect(prompt).not.toContain('VibeForge.StartTasks')
|
|
238
249
|
})
|
|
239
250
|
|
|
251
|
+
it('uses forwarded cli names in managed task guidance', () => {
|
|
252
|
+
process.env.__VF_CLI_RESUME_COMMAND_PREFIX__ = 'dyai'
|
|
253
|
+
|
|
254
|
+
const prompt = generateEntitiesRoutePrompt([
|
|
255
|
+
{
|
|
256
|
+
path: '/tmp/project/.ai/entities/reviewer/README.md',
|
|
257
|
+
body: '负责代码审查',
|
|
258
|
+
attributes: {}
|
|
259
|
+
}
|
|
260
|
+
])
|
|
261
|
+
|
|
262
|
+
expect(prompt).toContain('`dyai run --input-format stream-json --output-format stream-json`')
|
|
263
|
+
expect(prompt).toContain("cat <<'JSONL' | dyai run --input-format stream-json --output-format stream-json")
|
|
264
|
+
expect(prompt).not.toContain('`vf run --input-format stream-json --output-format stream-json`')
|
|
265
|
+
})
|
|
266
|
+
|
|
240
267
|
it('builds skill route prompts without preloading content', () => {
|
|
241
268
|
const cwd = '/tmp/project'
|
|
242
269
|
|