更新资源管理器和命令逻辑:新增角色创建和生成相关功能,优化资源加载流程,支持用户自定义资源的发现与合并,同时增强错误处理和描述提取逻辑,提升系统的灵活性和用户体验。

This commit is contained in:
sean
2025-06-10 23:58:29 +08:00
parent 95b5a4d570
commit 192eb2a0df
19 changed files with 3596 additions and 45 deletions

View File

@ -0,0 +1,220 @@
const ResourceManager = require('../../../lib/core/resource/resourceManager')
const fs = require('fs-extra')
const path = require('path')
const os = require('os')
describe('ResourceManager - 用户资源发现', () => {
let resourceManager
let tempDir
let mockPackageRoot
beforeEach(async () => {
// 创建临时测试目录
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'promptx-test-'))
mockPackageRoot = tempDir
// 模拟用户资源目录结构
await fs.ensureDir(path.join(tempDir, '.promptx', 'resource', 'domain'))
resourceManager = new ResourceManager()
// Mock packageProtocol module
jest.doMock('../../../lib/core/resource/protocols/PackageProtocol', () => {
return class MockPackageProtocol {
async getPackageRoot() {
return mockPackageRoot
}
}
})
})
afterEach(async () => {
// 清理临时目录
await fs.remove(tempDir)
jest.restoreAllMocks()
})
describe('discoverUserResources', () => {
it('应该返回空对象当用户资源目录不存在时', async () => {
// 删除用户资源目录
await fs.remove(path.join(tempDir, '.promptx'))
const result = await resourceManager.discoverUserResources()
expect(result).toEqual({})
})
it('应该发现用户创建的角色文件', async () => {
// 创建测试角色文件
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'test-sales-analyst')
await fs.ensureDir(roleDir)
const roleContent = `<role>
<personality>
# 销售数据分析师思维模式
## 核心思维特征
- **数据敏感性思维**:善于从数字中发现故事和趋势模式
</personality>
<principle>
# 销售数据分析师行为原则
## 核心工作原则
- **数据驱动决策**:所有分析建议必须有可靠数据支撑
</principle>
<knowledge>
# 销售数据分析专业知识体系
## 数据处理技能
- **数据清洗方法**:缺失值处理、异常值识别
</knowledge>
</role>`
await fs.writeFile(path.join(roleDir, 'test-sales-analyst.role.md'), roleContent)
const result = await resourceManager.discoverUserResources()
expect(result).toHaveProperty('role')
expect(result.role).toHaveProperty('test-sales-analyst')
expect(result.role['test-sales-analyst']).toMatchObject({
file: expect.stringContaining('test-sales-analyst.role.md'),
name: expect.stringContaining('销售数据分析师'),
source: 'user-generated',
format: 'dpml',
type: 'role'
})
})
it('应该支持多种资源类型发现', async () => {
// 创建角色和相关资源
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'test-role')
await fs.ensureDir(roleDir)
await fs.ensureDir(path.join(roleDir, 'thought'))
await fs.ensureDir(path.join(roleDir, 'execution'))
// 创建角色文件
await fs.writeFile(path.join(roleDir, 'test-role.role.md'), '<role><personality>Test</personality><principle>Test</principle><knowledge>Test</knowledge></role>')
// 创建思维文件
await fs.writeFile(path.join(roleDir, 'thought', 'test.thought.md'), '<thought><exploration>Test exploration</exploration><reasoning>Test reasoning</reasoning></thought>')
// 创建执行文件
await fs.writeFile(path.join(roleDir, 'execution', 'test.execution.md'), '<execution><constraint>Test constraint</constraint></execution>')
const result = await resourceManager.discoverUserResources()
expect(result).toHaveProperty('role')
expect(result).toHaveProperty('thought')
expect(result).toHaveProperty('execution')
expect(result.role).toHaveProperty('test-role')
expect(result.thought).toHaveProperty('test')
expect(result.execution).toHaveProperty('test')
})
it('应该处理DPML格式错误的文件', async () => {
// 创建格式错误的角色文件
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'invalid-role')
await fs.ensureDir(roleDir)
const invalidContent = `这不是有效的DPML格式`
await fs.writeFile(path.join(roleDir, 'invalid-role.role.md'), invalidContent)
const result = await resourceManager.discoverUserResources()
// 应该跳过格式错误的文件,但不应该抛出错误
expect(result.role || {}).not.toHaveProperty('invalid-role')
})
it('应该跨平台正确处理路径', async () => {
// 在不同平台上创建角色文件
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'cross-platform-role')
await fs.ensureDir(roleDir)
const roleContent = '<role><personality>Test</personality><principle>Test</principle><knowledge>Test</knowledge></role>'
await fs.writeFile(path.join(roleDir, 'cross-platform-role.role.md'), roleContent)
const result = await resourceManager.discoverUserResources()
expect(result.role).toHaveProperty('cross-platform-role')
// 验证文件路径使用正确的分隔符
const roleInfo = result.role['cross-platform-role']
expect(roleInfo.file).toBe(path.normalize(roleInfo.file))
})
})
describe('loadUnifiedRegistry', () => {
it('应该合并系统资源和用户资源', async () => {
// 模拟系统资源
const mockSystemResources = {
role: {
'assistant': {
file: '@package://prompt/domain/assistant/assistant.role.md',
name: '🙋 智能助手',
source: 'system',
format: 'dpml',
type: 'role'
}
}
}
// Mock fs.readJSON for system registry
jest.spyOn(fs, 'readJSON')
.mockImplementation((filePath) => {
if (filePath.includes('resource.registry.json')) {
return Promise.resolve(mockSystemResources)
}
return Promise.resolve({})
})
// 创建用户资源
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'user-role')
await fs.ensureDir(roleDir)
await fs.writeFile(
path.join(roleDir, 'user-role.role.md'),
'<role><personality>User</personality><principle>User</principle><knowledge>User</knowledge></role>'
)
const result = await resourceManager.loadUnifiedRegistry()
expect(result.role).toHaveProperty('assistant') // 系统资源
expect(result.role).toHaveProperty('user-role') // 用户资源
})
it('应该让用户资源覆盖同名系统资源', async () => {
// 模拟系统资源
const mockSystemResources = {
role: {
'assistant': {
file: '@package://prompt/domain/assistant/assistant.role.md',
name: '🙋 智能助手',
source: 'system',
format: 'dpml',
type: 'role'
}
}
}
// Mock fs.readJSON for system registry
jest.spyOn(fs, 'readJSON')
.mockImplementation((filePath) => {
if (filePath.includes('resource.registry.json')) {
return Promise.resolve(mockSystemResources)
}
return Promise.resolve({})
})
// 创建同名的用户资源
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'assistant')
await fs.ensureDir(roleDir)
await fs.writeFile(
path.join(roleDir, 'assistant.role.md'),
'<role><personality># 自定义助手\n用户定制的助手</personality><principle>Custom</principle><knowledge>Custom</knowledge></role>'
)
const result = await resourceManager.loadUnifiedRegistry()
expect(result.role.assistant.source).toBe('user-generated')
expect(result.role.assistant.name).toContain('自定义助手')
})
})
})