重构:更新前端开发者角色文档,移除冗余的执行策略,新增微信小程序专项开发部分;更新资源注册表,统一时间戳格式,移除不再使用的资源注册逻辑,优化工具定义获取方式,提升代码可读性和维护性。

This commit is contained in:
sean
2025-06-13 22:57:17 +08:00
parent ac74f37f6c
commit 714c01c4f4
18 changed files with 550 additions and 1117 deletions

View File

@ -46,7 +46,7 @@ class ResourceData {
/**
* 从文件路径和协议推断创建ResourceData
* @param {string} filePath - 文件路径
* @param {string} filePath - 文件路径仅用于提取ID不保存
* @param {string} source - 资源来源
* @param {string} protocol - 资源协议
* @param {string} reference - 资源引用
@ -64,7 +64,6 @@ class ResourceData {
description: ResourceData._generateDefaultDescription(fileName, protocol),
reference,
metadata: {
filePath,
inferredFromFile: true
}
})
@ -189,6 +188,23 @@ class ResourceData {
}
}
/**
* 动态获取文件路径
* 通过解析 reference 动态计算实际的文件路径
* @returns {Promise<string>} 文件路径
*/
async getFilePath() {
const ProtocolResolver = require('./ProtocolResolver')
const resolver = new ProtocolResolver()
try {
const resolvedPath = await resolver.resolve(this.reference)
return resolvedPath
} catch (error) {
throw new Error(`无法解析资源路径 ${this.reference}: ${error.message}`)
}
}
/**
* 克隆资源数据
* @returns {ResourceData} 克隆的实例

View File

@ -84,50 +84,7 @@ class DiscoveryManager {
}
/**
* 发现资源并直接注册到指定注册表(新的简化方法
* @param {ResourceRegistry} registry - 目标注册表
* @returns {Promise<void>}
*/
async discoverAndDirectRegister(registry) {
logger.info(`[DiscoveryManager] 🚀 开始直接注册,发现器数量: ${this.discoveries.length}`)
// 按优先级顺序直接注册,让高优先级的覆盖低优先级的
for (const discovery of this.discoveries) {
try {
logger.debug(`[DiscoveryManager] 🔍 处理发现器: ${discovery.source} (优先级: ${discovery.priority})`)
if (typeof discovery.discoverRegistry === 'function') {
// 使用新的discoverRegistry方法
const discoveredRegistry = await discovery.discoverRegistry()
if (discoveredRegistry instanceof Map) {
logger.debug(`[DiscoveryManager] ✅ ${discovery.source} 发现 ${discoveredRegistry.size} 个资源`)
for (const [resourceId, reference] of discoveredRegistry) {
registry.register(resourceId, reference) // 直接注册,自动覆盖
}
}
} else {
// 向后兼容使用discover()方法
const resources = await discovery.discover()
if (Array.isArray(resources)) {
logger.debug(`[DiscoveryManager] ✅ ${discovery.source} 发现 ${resources.length} 个资源 (兼容模式)`)
resources.forEach(resource => {
if (resource.id && resource.reference) {
registry.register(resource.id, resource.reference) // 直接注册
}
})
}
}
} catch (error) {
logger.warn(`[DiscoveryManager] ❌ ${discovery.source} direct registration failed: ${error.message}`)
// 单个发现器失败不影响其他发现器
}
}
logger.info(`[DiscoveryManager] 🎯 注册完成,注册表总资源数: ${registry.size}`)
}
/**
* 发现并合并所有注册表(新架构方法)
* 发现并合并所有注册表RegistryData架构
* @returns {Promise<Map>} 合并后的资源注册表 Map<resourceId, reference>
*/
async discoverRegistries() {

View File

@ -201,18 +201,17 @@ class PackageDiscovery extends BaseDiscovery {
if (await fs.pathExists(roleFile)) {
const reference = `@package://prompt/domain/${item}/${item}.role.md`
const resourceData = new ResourceData({
id: item,
source: 'package',
protocol: 'role',
name: ResourceData._generateDefaultName(item, 'role'),
description: ResourceData._generateDefaultDescription(item, 'role'),
reference: reference,
metadata: {
filePath: roleFile,
scannedAt: new Date().toISOString()
}
})
const resourceData = new ResourceData({
id: item,
source: 'package',
protocol: 'role',
name: ResourceData._generateDefaultName(item, 'role'),
description: ResourceData._generateDefaultDescription(item, 'role'),
reference: reference,
metadata: {
scannedAt: new Date().toISOString()
}
})
registryData.addResource(resourceData)
}
@ -232,7 +231,6 @@ class PackageDiscovery extends BaseDiscovery {
description: ResourceData._generateDefaultDescription(item, 'thought'),
reference: reference,
metadata: {
filePath: thoughtFile,
scannedAt: new Date().toISOString()
}
})
@ -258,7 +256,6 @@ class PackageDiscovery extends BaseDiscovery {
description: ResourceData._generateDefaultDescription(execId, 'execution'),
reference: reference,
metadata: {
filePath: path.join(executionDir, execFile),
scannedAt: new Date().toISOString()
}
})
@ -304,7 +301,6 @@ class PackageDiscovery extends BaseDiscovery {
description: ResourceData._generateDefaultDescription(id, protocol),
reference: reference,
metadata: {
filePath: path.join(itemPath, file),
scannedAt: new Date().toISOString()
}
})
@ -328,7 +324,6 @@ class PackageDiscovery extends BaseDiscovery {
description: ResourceData._generateDefaultDescription(id, protocol),
reference: reference,
metadata: {
filePath: path.join(coreDir, item),
scannedAt: new Date().toISOString()
}
})
@ -557,26 +552,52 @@ class PackageDiscovery extends BaseDiscovery {
* @returns {Promise<string|null>} 包根目录路径或null
*/
async _findDevelopmentRoot() {
// 策略1检查当前工作目录
const cwd = process.cwd()
const hasPackageJson = await fs.pathExists(path.join(cwd, 'package.json'))
const hasPromptDir = await fs.pathExists(path.join(cwd, 'prompt'))
if (!hasPackageJson || !hasPromptDir) {
return null
if (await this._isValidDevelopmentRoot(cwd)) {
return fs.realpathSync(cwd)
}
try {
const packageJson = await fs.readJSON(path.join(cwd, 'package.json'))
if (packageJson.name === 'dpml-prompt') {
return fs.realpathSync(cwd) // 解析符号链接
// 策略2检查启动脚本的目录适用于通过脚本启动的情况
const scriptDir = path.dirname(process.argv[1])
let searchDir = scriptDir
// 向上查找最多5级目录
for (let i = 0; i < 5; i++) {
if (await this._isValidDevelopmentRoot(searchDir)) {
return fs.realpathSync(searchDir)
}
} catch (error) {
// Ignore JSON parsing errors
const parentDir = path.dirname(searchDir)
if (parentDir === searchDir) break // 已到根目录
searchDir = parentDir
}
return null
}
/**
* 检查目录是否为有效的开发环境根目录
* @param {string} dir - 要检查的目录
* @returns {Promise<boolean>} 是否为有效的开发根目录
* @private
*/
async _isValidDevelopmentRoot(dir) {
const hasPackageJson = await fs.pathExists(path.join(dir, 'package.json'))
const hasPromptDir = await fs.pathExists(path.join(dir, 'prompt'))
if (!hasPackageJson || !hasPromptDir) {
return false
}
try {
const packageJson = await fs.readJSON(path.join(dir, 'package.json'))
return packageJson.name === 'dpml-prompt'
} catch (error) {
return false
}
}
/**
* 查找已安装包的根目录
* @returns {Promise<string|null>} 包根目录路径或null

View File

@ -374,7 +374,6 @@ class ProjectDiscovery extends BaseDiscovery {
description: ResourceData._generateDefaultDescription(item, 'role'),
reference: reference,
metadata: {
filePath: roleFile,
scannedAt: new Date().toISOString()
}
})
@ -399,7 +398,6 @@ class ProjectDiscovery extends BaseDiscovery {
description: ResourceData._generateDefaultDescription(thoughtId, 'thought'),
reference: reference,
metadata: {
filePath: path.join(thoughtDir, thoughtFile),
scannedAt: new Date().toISOString()
}
})
@ -426,7 +424,6 @@ class ProjectDiscovery extends BaseDiscovery {
description: ResourceData._generateDefaultDescription(execId, 'execution'),
reference: reference,
metadata: {
filePath: path.join(executionDir, execFile),
scannedAt: new Date().toISOString()
}
})
@ -453,7 +450,6 @@ class ProjectDiscovery extends BaseDiscovery {
description: ResourceData._generateDefaultDescription(knowledgeId, 'knowledge'),
reference: reference,
metadata: {
filePath: path.join(knowledgeDir, knowledgeFile),
scannedAt: new Date().toISOString()
}
})

View File

@ -10,7 +10,6 @@ const ResourceManager = require('./resourceManager')
// 核心组件
const ResourceProtocolParser = require('./resourceProtocolParser')
const ResourceRegistry = require('./resourceRegistry')
// 数据类型
const {
@ -58,7 +57,6 @@ module.exports = {
// 核心组件
ResourceProtocolParser,
ResourceRegistry,
// 数据类型
LoadingSemantics,

View File

@ -44,59 +44,37 @@ class ExecutionProtocol extends ResourceProtocol {
}
/**
* 解析资源路径
* 解析执行协议
* @param {string} executionPath - 执行路径,如 'best-practice'
* @param {Object} queryParams - 查询参数(暂未使用)
* @returns {Promise<string>} 执行文件内容
*/
async resolvePath (resourcePath, queryParams) {
const executionId = resourcePath.trim()
const fullResourceId = `execution:${executionId}`
// 优先使用统一注册表管理器
if (this.registryManager) {
const reference = this.registryManager.registry.get(fullResourceId)
if (!reference) {
const availableExecutions = this.registryManager.registry.keys()
.filter(id => id.startsWith('execution:'))
.map(id => id.replace('execution:', ''))
throw new Error(`执行模式 "${executionId}" 未在注册表中找到。可用执行模式:${availableExecutions.join(', ')}`)
async resolve(executionPath, queryParams = {}) {
try {
// 构建可能的资源ID格式
const fullResourceId = `execution:${executionPath}`
// 从RegistryData查找资源
let resourceData = this.registryManager.registryData.findResourceById(executionPath, 'execution')
if (!resourceData) {
// 如果没找到,尝试其他格式
resourceData = this.registryManager.registryData.findResourceById(fullResourceId)
}
if (!resourceData) {
const availableExecutions = this.registryManager.registryData.getResourcesByProtocol('execution')
.map(r => r.id).join(', ')
throw new Error(`执行模式 '${executionPath}' 未找到。可用执行模式: ${availableExecutions}`)
}
let resolvedPath = reference
// 处理 @package:// 前缀
if (resolvedPath.startsWith('@package://')) {
const PackageProtocol = require('./PackageProtocol')
const packageProtocol = new PackageProtocol()
const relativePath = resolvedPath.replace('@package://', '')
resolvedPath = await packageProtocol.resolvePath(relativePath)
} else if (resolvedPath.startsWith('@project://')) {
// 处理 @project:// 前缀,转换为绝对路径
const relativePath = resolvedPath.replace('@project://', '')
resolvedPath = path.join(process.cwd(), relativePath)
}
return resolvedPath
// 通过ResourceManager加载实际内容
const result = await this.registryManager.loadResourceByProtocol(resourceData.reference)
return result
} catch (error) {
throw new Error(`ExecutionProtocol.resolve failed: ${error.message}`)
}
// 向后兼容使用旧的registry
if (!this.registry[executionId]) {
throw new Error(`执行模式 "${executionId}" 未在注册表中找到`)
}
let resolvedPath = this.registry[executionId]
// 处理 @package:// 前缀
if (resolvedPath.startsWith('@package://')) {
const PackageProtocol = require('./PackageProtocol')
const packageProtocol = new PackageProtocol()
const relativePath = resolvedPath.replace('@package://', '')
resolvedPath = await packageProtocol.resolvePath(relativePath)
} else if (resolvedPath.startsWith('@project://')) {
// 处理 @project:// 前缀,转换为绝对路径
const relativePath = resolvedPath.replace('@project://', '')
resolvedPath = path.join(process.cwd(), relativePath)
}
return resolvedPath
}
/**

View File

@ -43,59 +43,37 @@ class KnowledgeProtocol extends ResourceProtocol {
}
/**
* 解析资源路径
* 解析知识协议
* @param {string} knowledgePath - 知识路径,如 'scrum'
* @param {Object} queryParams - 查询参数(暂未使用)
* @returns {Promise<string>} 知识文件内容
*/
async resolvePath (resourcePath, queryParams) {
const knowledgeId = resourcePath.trim()
const fullResourceId = `knowledge:${knowledgeId}`
// 优先使用统一注册表管理器
if (this.registryManager) {
const reference = this.registryManager.registry.get(fullResourceId)
if (!reference) {
const availableKnowledge = this.registryManager.registry.keys()
.filter(id => id.startsWith('knowledge:'))
.map(id => id.replace('knowledge:', ''))
throw new Error(`知识资源 "${knowledgeId}" 未在注册表中找到。可用知识资源:${availableKnowledge.join(', ')}`)
async resolve(knowledgePath, queryParams = {}) {
try {
// 构建可能的资源ID格式
const fullResourceId = `knowledge:${knowledgePath}`
// 从RegistryData查找资源
let resourceData = this.registryManager.registryData.findResourceById(knowledgePath, 'knowledge')
if (!resourceData) {
// 如果没找到,尝试其他格式
resourceData = this.registryManager.registryData.findResourceById(fullResourceId)
}
if (!resourceData) {
const availableKnowledge = this.registryManager.registryData.getResourcesByProtocol('knowledge')
.map(r => r.id).join(', ')
throw new Error(`知识模块 '${knowledgePath}' 未找到。可用知识模块: ${availableKnowledge}`)
}
let resolvedPath = reference
// 处理 @package:// 前缀
if (resolvedPath.startsWith('@package://')) {
const PackageProtocol = require('./PackageProtocol')
const packageProtocol = new PackageProtocol()
const relativePath = resolvedPath.replace('@package://', '')
resolvedPath = await packageProtocol.resolvePath(relativePath)
} else if (resolvedPath.startsWith('@project://')) {
// 处理 @project:// 前缀,转换为绝对路径
const relativePath = resolvedPath.replace('@project://', '')
resolvedPath = path.join(process.cwd(), relativePath)
}
return resolvedPath
// 通过ResourceManager加载实际内容
const result = await this.registryManager.loadResourceByProtocol(resourceData.reference)
return result
} catch (error) {
throw new Error(`KnowledgeProtocol.resolve failed: ${error.message}`)
}
// 向后兼容使用旧的registry
if (!this.registry[knowledgeId]) {
throw new Error(`知识资源 "${knowledgeId}" 未在注册表中找到`)
}
let resolvedPath = this.registry[knowledgeId]
// 处理 @package:// 前缀
if (resolvedPath.startsWith('@package://')) {
const PackageProtocol = require('./PackageProtocol')
const packageProtocol = new PackageProtocol()
const relativePath = resolvedPath.replace('@package://', '')
resolvedPath = await packageProtocol.resolvePath(relativePath)
} else if (resolvedPath.startsWith('@project://')) {
// 处理 @project:// 前缀,转换为绝对路径
const relativePath = resolvedPath.replace('@project://', '')
resolvedPath = path.join(process.cwd(), relativePath)
}
return resolvedPath
}
/**

View File

@ -45,56 +45,38 @@ class RoleProtocol extends ResourceProtocol {
}
/**
* 解析资源路径
* 解析角色协议
* @param {string} rolePath - 角色路径,如 'java-developer'
* @param {Object} queryParams - 查询参数(暂未使用)
* @returns {Promise<string>} 角色文件内容
*/
async resolvePath (resourcePath, queryParams) {
const roleId = resourcePath.trim()
const fullResourceId = `role:${roleId}`
// 优先使用统一注册表管理器
if (this.registryManager) {
const reference = this.registryManager.registry.get(fullResourceId)
if (!reference) {
const availableRoles = this.registryManager.registry.keys()
.filter(id => id.startsWith('role:'))
.map(id => id.replace('role:', ''))
throw new Error(`角色 "${roleId}" 未在注册表中找到。可用角色:${availableRoles.join(', ')}`)
async resolve(rolePath, queryParams = {}) {
try {
// 构建可能的资源ID格式
const fullResourceId = `role:${rolePath}`
const shortResourceId = rolePath
// 从RegistryData查找资源
let resourceData = this.registryManager.registryData.findResourceById(rolePath, 'role')
if (!resourceData) {
// 如果没找到,尝试其他格式
resourceData = this.registryManager.registryData.findResourceById(fullResourceId)
}
let resolvedPath = reference
// 处理 @package:// 前缀
if (resolvedPath.startsWith('@package://')) {
const PackageProtocol = require('./PackageProtocol')
const packageProtocol = new PackageProtocol()
const relativePath = resolvedPath.replace('@package://', '')
resolvedPath = await packageProtocol.resolvePath(relativePath)
} else if (resolvedPath.startsWith('@project://')) {
// 处理 @project:// 前缀,转换为绝对路径
const relativePath = resolvedPath.replace('@project://', '')
resolvedPath = path.join(process.cwd(), relativePath)
if (!resourceData) {
const availableRoles = this.registryManager.registryData.getResourcesByProtocol('role')
.map(r => r.id).join(', ')
throw new Error(`角色 '${rolePath}' 未找到。可用角色: ${availableRoles}`)
}
return resolvedPath
// 通过ResourceManager加载实际内容
const result = await this.registryManager.loadResourceByProtocol(resourceData.reference)
return result
} catch (error) {
throw new Error(`RoleProtocol.resolve failed: ${error.message}`)
}
// 向后兼容使用旧的registry
if (!this.registry[roleId]) {
throw new Error(`角色 "${roleId}" 未在注册表中找到。可用角色:${Object.keys(this.registry).join(', ')}`)
}
const roleInfo = this.registry[roleId]
let resolvedPath = typeof roleInfo === 'string' ? roleInfo : roleInfo.file
// 处理 @package:// 前缀
if (resolvedPath.startsWith('@package://')) {
const PackageProtocol = require('./PackageProtocol')
const packageProtocol = new PackageProtocol()
const relativePath = resolvedPath.replace('@package://', '')
resolvedPath = await packageProtocol.resolvePath(relativePath)
}
return resolvedPath
}
/**

View File

@ -43,59 +43,37 @@ class ThoughtProtocol extends ResourceProtocol {
}
/**
* 解析资源路径
* 解析思维协议
* @param {string} thoughtPath - 思维路径,如 'remember'
* @param {Object} queryParams - 查询参数(暂未使用)
* @returns {Promise<string>} 思维文件内容
*/
async resolvePath (resourcePath, queryParams) {
const thoughtId = resourcePath.trim()
const fullResourceId = `thought:${thoughtId}`
// 优先使用统一注册表管理器
if (this.registryManager) {
const reference = this.registryManager.registry.get(fullResourceId)
if (!reference) {
const availableThoughts = this.registryManager.registry.keys()
.filter(id => id.startsWith('thought:'))
.map(id => id.replace('thought:', ''))
throw new Error(`思维模式 "${thoughtId}" 未在注册表中找到。可用思维模式:${availableThoughts.join(', ')}`)
async resolve(thoughtPath, queryParams = {}) {
try {
// 构建可能的资源ID格式
const fullResourceId = `thought:${thoughtPath}`
// 从RegistryData查找资源
let resourceData = this.registryManager.registryData.findResourceById(thoughtPath, 'thought')
if (!resourceData) {
// 如果没找到,尝试其他格式
resourceData = this.registryManager.registryData.findResourceById(fullResourceId)
}
if (!resourceData) {
const availableThoughts = this.registryManager.registryData.getResourcesByProtocol('thought')
.map(r => r.id).join(', ')
throw new Error(`思维模式 '${thoughtPath}' 未找到。可用思维模式: ${availableThoughts}`)
}
let resolvedPath = reference
// 处理 @package:// 前缀
if (resolvedPath.startsWith('@package://')) {
const PackageProtocol = require('./PackageProtocol')
const packageProtocol = new PackageProtocol()
const relativePath = resolvedPath.replace('@package://', '')
resolvedPath = await packageProtocol.resolvePath(relativePath)
} else if (resolvedPath.startsWith('@project://')) {
// 处理 @project:// 前缀,转换为绝对路径
const relativePath = resolvedPath.replace('@project://', '')
resolvedPath = path.join(process.cwd(), relativePath)
}
return resolvedPath
// 通过ResourceManager加载实际内容
const result = await this.registryManager.loadResourceByProtocol(resourceData.reference)
return result
} catch (error) {
throw new Error(`ThoughtProtocol.resolve failed: ${error.message}`)
}
// 向后兼容使用旧的registry
if (!this.registry[thoughtId]) {
throw new Error(`思维模式 "${thoughtId}" 未在注册表中找到`)
}
let resolvedPath = this.registry[thoughtId]
// 处理 @package:// 前缀
if (resolvedPath.startsWith('@package://')) {
const PackageProtocol = require('./PackageProtocol')
const packageProtocol = new PackageProtocol()
const relativePath = resolvedPath.replace('@package://', '')
resolvedPath = await packageProtocol.resolvePath(relativePath)
} else if (resolvedPath.startsWith('@project://')) {
// 处理 @project:// 前缀,转换为绝对路径
const relativePath = resolvedPath.replace('@project://', '')
resolvedPath = path.join(process.cwd(), relativePath)
}
return resolvedPath
}
/**

View File

@ -1,5 +1,4 @@
const fs = require('fs')
const ResourceRegistry = require('./resourceRegistry')
const RegistryData = require('./RegistryData')
const ResourceProtocolParser = require('./resourceProtocolParser')
const DiscoveryManager = require('./discovery/DiscoveryManager')
@ -15,12 +14,15 @@ const KnowledgeProtocol = require('./protocols/KnowledgeProtocol')
class ResourceManager {
constructor() {
// 使用新的RegistryData替代旧的ResourceRegistry
this.registry = new ResourceRegistry() // 保持向后兼容
this.registryData = RegistryData.createEmpty('merged', null) // 新的v2.0注册表
// 新架构:统一的资源注册表
this.registryData = RegistryData.createEmpty('merged', null)
// 协议解析器
this.protocolParser = new ResourceProtocolParser()
this.parser = new ResourceProtocolParser() // 向后兼容别名
this.discoveryManager = new DiscoveryManager() // 新发现管理器
// 资源发现管理器
this.discoveryManager = new DiscoveryManager()
// 初始化协议处理器
this.protocols = new Map()
@ -47,8 +49,7 @@ class ResourceManager {
*/
async initializeWithNewArchitecture() {
try {
// 1. 清空现有注册表(支持重新初始化)
this.registry.clear()
// 1. 清空现有注册表
this.registryData.clear()
// 2. 清除发现器缓存
@ -56,16 +57,13 @@ class ResourceManager {
this.discoveryManager.clearCache()
}
// 3. 直接发现并注册资源到旧的ResourceRegistry保持向后兼容
await this.discoveryManager.discoverAndDirectRegister(this.registry)
// 4. 同时填充新的RegistryData
// 3. 填充新的RegistryData
await this.populateRegistryData()
// 5. 为逻辑协议设置注册表引用
// 4. 为逻辑协议设置注册表引用
this.setupLogicalProtocols()
// 6. 设置初始化状态
// 5. 设置初始化状态
this.initialized = true
// 初始化完成,不输出日志避免干扰用户界面
@ -155,13 +153,16 @@ class ResourceManager {
async loadResource(resourceId) {
try {
// 不再每次刷新资源,依赖初始化时的资源发现
// 确保ResourceManager已初始化
if (!this.initialized) {
await this.initializeWithNewArchitecture()
}
// 处理@!开头的DPML格式如 @!role://java-developer
if (resourceId.startsWith('@!')) {
const parsed = this.protocolParser.parse(resourceId)
// 从新的RegistryData查找资源
// 从RegistryData查找资源
const resourceData = this.registryData.findResourceById(parsed.path, parsed.protocol)
if (!resourceData) {
throw new Error(`Resource not found: ${parsed.protocol}:${parsed.path}`)
@ -179,7 +180,6 @@ class ResourceManager {
}
// 处理传统格式(如 role:java-developer
// 先尝试从新的RegistryData查找
let reference = null
// 如果包含协议前缀(如 thought:remember
@ -197,11 +197,6 @@ class ResourceManager {
}
}
// 如果新的RegistryData中没找到回退到旧的registry
if (!reference) {
reference = this.registry.get(resourceId)
}
if (!reference) {
throw new Error(`Resource not found: ${resourceId}`)
}
@ -216,34 +211,40 @@ class ResourceManager {
reference
}
} catch (error) {
logger.debug(`ResourceManager.loadResource failed for ${resourceId}: ${error.message}`)
return {
success: false,
error: error,
message: error.message
error: error, // 返回完整的Error对象而不是message字符串
resourceId
}
}
}
/**
* 统一协议解析入口点 - 按照架构文档设计
* 解析协议引用并返回相关信息
*/
async resolveProtocolReference(reference) {
// 1. 使用ResourceProtocolParser解析DPML语法
const parsed = this.parser.parse(reference)
// 2. 获取对应的协议处理器
const protocol = this.protocols.get(parsed.protocol)
if (!protocol) {
throw new Error(`不支持的协议: ${parsed.protocol}`)
try {
const parsed = this.protocolParser.parse(reference)
return {
success: true,
protocol: parsed.protocol,
path: parsed.path,
queryParams: parsed.queryParams,
reference
}
} catch (error) {
return {
success: false,
error: error.message,
reference
}
}
// 3. 委托给协议处理器解析
return await protocol.resolve(parsed.path, parsed.queryParams)
}
/**
* 获取所有已注册的协议
* @returns {Array<string>} 协议名称列表
* 获取所有可用的协议列表
*/
getAvailableProtocols() {
return Array.from(this.protocols.keys())
@ -251,8 +252,6 @@ class ResourceManager {
/**
* 检查是否支持指定协议
* @param {string} protocol - 协议名称
* @returns {boolean} 是否支持
*/
supportsProtocol(protocol) {
return this.protocols.has(protocol)
@ -272,77 +271,49 @@ class ResourceManager {
return this._initialized || false
}
// 向后兼容方法
/**
* 解析资源URL向后兼容接口
* 返回格式:{success: boolean, content?: string, error?: Error}
*/
async resolve(resourceUrl) {
try {
// 不再每次刷新资源,依赖初始化时的资源发现
// Handle old format: role:java-backend-developer or @package://...
if (resourceUrl.startsWith('@')) {
// Parse the reference to check if it's a custom protocol
const parsed = this.protocolParser.parse(resourceUrl)
// Check if it's a basic protocol that can be handled directly
const basicProtocols = ['package', 'project', 'file']
if (basicProtocols.includes(parsed.protocol)) {
// Direct protocol format - use protocol resolution
const content = await this.loadResourceByProtocol(resourceUrl)
return {
success: true,
content,
path: resourceUrl,
reference: resourceUrl
}
} else {
// Custom protocol - extract resource ID and use ResourceRegistry
const resourceId = `${parsed.protocol}:${parsed.path}`
return await this.loadResource(resourceId)
}
} else {
// Legacy format: treat as resource ID
return await this.loadResource(resourceUrl)
}
} catch (error) {
return {
success: false,
error: error,
message: error.message
}
return await this.loadResource(resourceUrl)
}
/**
* 获取注册表统计信息
*/
getStats() {
return {
totalResources: this.registryData.size,
protocols: this.getAvailableProtocols(),
initialized: this.initialized
}
}
/**
* 无状态资源刷新(推荐方法
* 每次都重新发现并注册资源,无需维护初始化状态
* 刷新资源(重新发现并注册
*/
async refreshResources() {
try {
// 1. 清空当前注册表
this.registry.clear()
// 1. 标记为未初始化
this.initialized = false
// 2. 清除发现器缓存
// 2. 清空注册表
this.registryData.clear()
// 3. 清除发现器缓存
if (this.discoveryManager && typeof this.discoveryManager.clearCache === 'function') {
this.discoveryManager.clearCache()
}
// 3. 重新发现并直接注册
await this.discoveryManager.discoverAndDirectRegister(this.registry)
// 4. 重新初始化
await this.initializeWithNewArchitecture()
// 4. 更新协议引用
this.setupLogicalProtocols()
// 无状态设计不设置initialized标志
} catch (error) {
logger.warn(`ResourceManager resource refresh failed: ${error.message}`)
// 失败时保持注册表为空状态,下次调用时重试
}
}
/**
* 强制重新初始化资源发现(清除缓存)
* 用于解决新创建角色无法被发现的问题
* @deprecated 推荐使用 refreshResources() 方法
*/
}
module.exports = ResourceManager

View File

@ -1,163 +0,0 @@
const logger = require('../../utils/logger')
/**
* 资源注册表
* 新架构中用于存储动态发现的资源映射关系
*/
class ResourceRegistry {
constructor() {
this.index = new Map()
}
/**
* 注册资源
* @param {string} id - 资源ID (如 'role:java-developer')
* @param {string} reference - 资源引用 (如 '@package://prompt/domain/java-developer/java-developer.role.md')
*/
register(id, reference) {
this.index.set(id, reference)
}
/**
* 获取资源引用
* @param {string} resourceId - 资源ID
* @returns {string|undefined} 资源引用
*/
get(resourceId) {
return this.index.get(resourceId)
}
/**
* 检查资源是否存在
* @param {string} resourceId - 资源ID
* @returns {boolean} 是否存在
*/
has(resourceId) {
return this.index.has(resourceId)
}
/**
* 获取注册表大小
* @returns {number} 注册的资源数量
*/
get size() {
return this.index.size
}
/**
* 清空注册表
*/
clear() {
this.index.clear()
}
/**
* 获取所有资源ID
* @returns {Array<string>} 资源ID列表
*/
keys() {
return Array.from(this.index.keys())
}
/**
* 获取所有资源条目
* @returns {Array<[string, string]>} [resourceId, reference] 对的数组
*/
entries() {
return Array.from(this.index.entries())
}
/**
* 打印所有注册的资源(调试用)
* @param {string} title - 可选标题
*/
printAll(title = '注册表资源清单') {
logger.info(`\n📋 ${title}`)
logger.info('='.repeat(50))
if (this.size === 0) {
logger.info('🔍 注册表为空')
return
}
logger.info(`📊 总计: ${this.size} 个资源\n`)
// 按协议分组显示
const groupedResources = this.groupByProtocol()
for (const [protocol, resources] of Object.entries(groupedResources)) {
logger.info(`🔖 ${protocol.toUpperCase()} 协议 (${resources.length}个):`)
resources.forEach(({ id, reference }) => {
const resourceName = id.split(':')[1] || id
logger.info(`${resourceName}`)
logger.info(` └─ ${reference}`)
})
logger.info('')
}
}
/**
* 按协议分组资源
* @returns {Object} 分组后的资源,格式:{ protocol: [{ id, reference }, ...] }
*/
groupByProtocol() {
const groups = {}
for (const [id, reference] of this.entries()) {
const protocol = id.includes(':') ? id.split(':')[0] : 'other'
if (!groups[protocol]) {
groups[protocol] = []
}
groups[protocol].push({ id, reference })
}
return groups
}
/**
* 获取资源统计信息
* @returns {Object} 统计信息
*/
getStats() {
const groups = this.groupByProtocol()
const stats = {
total: this.size,
byProtocol: {}
}
for (const [protocol, resources] of Object.entries(groups)) {
stats.byProtocol[protocol] = resources.length
}
return stats
}
/**
* 搜索资源
* @param {string} searchTerm - 搜索词
* @returns {Array<[string, string]>} 匹配的资源
*/
search(searchTerm) {
const term = searchTerm.toLowerCase()
return this.entries().filter(([id, reference]) =>
id.toLowerCase().includes(term) ||
reference.toLowerCase().includes(term)
)
}
/**
* 以JSON格式导出注册表
* @returns {Object} 注册表数据
*/
toJSON() {
return {
size: this.size,
resources: Object.fromEntries(this.entries()),
stats: this.getStats()
}
}
}
module.exports = ResourceRegistry