refactor: 系统性移除DACP架构 - 简化框架专注@tool协议
🗑️ 核心清理 - 完全移除DACP服务架构和HTTP模式 - 删除DACPCommand、DACPConfigManager等核心组件 - 清理所有DACP相关文件、测试和文档 - 从CLI移除dacp命令,精简为6大核心锦囊 📁 删除内容 Core: - src/dacp/ - 整个DACP服务目录 - src/lib/core/pouch/commands/DACPCommand.js - src/lib/utils/DACPConfigManager.js Tests: - src/tests/commands/DACPCommand.unit.test.js - src/tests/integration/dacp-integration.test.js - src/tests/e2e/dacp-*-e2e.test.js - src/tests/unit/DACPConfigManager.unit.test.js Scripts & Docs: - scripts/test-*dacp*.js - docs/dacp-*.md - prompt/core/dacp-*.execution.md 🔧 代码清理 CLI: - src/bin/promptx.js: 移除dacp命令和--with-dacp选项 - 帮助信息更新:7大命令→6大核心命令 Core: - src/lib/core/pouch/PouchCLI.js: 移除dacp命令注册 - src/lib/core/pouch/commands/index.js: 清理DACPCommand引用 MCP: - src/lib/mcp/toolDefinitions.js: 移除promptx_dacp工具定义 - src/lib/commands/MCPServerCommand.js: 清理所有DACP方法和引用 - src/lib/commands/MCPStreamableHttpCommand.js: 移除DACP参数映射 Registry: - src/package.registry.json: 自动更新,移除2个DACP execution资源 - package.json: 移除dacp相关npm脚本 📊 架构简化结果 - 资源总数:63个 → 61个 (移除2个DACP execution) - CLI命令:7个 → 6大核心锦囊 - 代码复杂度显著降低,专注核心功能 ✅ 验证通过 - @tool://calculator 计算功能正常: 6 × 7 = 42 - @tool://send-email 邮件工具正常 - MCP Server启动正常 - 所有锦囊命令工作正常 🎯 新架构重点 1. 角色系统 - AI专业能力激活 2. 记忆系统 - 知识学习和回忆 3. @tool协议 - JavaScript工具执行 4. MCP集成 - AI应用连接 💡 技术收益 - 移除HTTP服务复杂度 - 统一@tool协议标准 - 简化维护和扩展 - 提升性能和稳定性 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -66,35 +66,6 @@ program
|
||||
await cli.execute('remember', args)
|
||||
})
|
||||
|
||||
// DACP命令
|
||||
program
|
||||
.command('dacp <service_id> <action> [parameters]')
|
||||
.description('🚀 dacp锦囊 - 调用DACP专业服务,让AI角色拥有执行能力')
|
||||
.action(async (service_id, action, parameters, options) => {
|
||||
try {
|
||||
// 解析参数(如果是JSON字符串)
|
||||
let parsedParams = {};
|
||||
if (parameters) {
|
||||
try {
|
||||
parsedParams = JSON.parse(parameters);
|
||||
} catch (error) {
|
||||
console.error('❌ 参数解析错误,请提供有效的JSON格式');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const args = {
|
||||
service_id,
|
||||
action,
|
||||
parameters: parsedParams
|
||||
};
|
||||
|
||||
await cli.execute('dacp', args);
|
||||
} catch (error) {
|
||||
console.error(`❌ DACP命令执行失败: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
|
||||
// Tool命令
|
||||
program
|
||||
@ -143,7 +114,6 @@ program
|
||||
.option('--host <address>', '绑定地址 (仅http/sse传输)', 'localhost')
|
||||
.option('--cors', '启用CORS (仅http/sse传输)', false)
|
||||
.option('--debug', '启用调试模式', false)
|
||||
.option('--with-dacp', '(已废弃,静默忽略)', false)
|
||||
.action(async (options) => {
|
||||
try {
|
||||
// 设置调试模式
|
||||
@ -154,7 +124,6 @@ program
|
||||
// 根据传输类型选择命令
|
||||
if (options.transport === 'stdio') {
|
||||
const mcpServer = new MCPServerCommand();
|
||||
// 🔧 DACP现为Mock模式,静默忽略用户的withDacp配置
|
||||
await mcpServer.execute();
|
||||
} else if (options.transport === 'http' || options.transport === 'sse') {
|
||||
const mcpHttpServer = new MCPStreamableHttpCommand();
|
||||
@ -188,14 +157,14 @@ program.addHelpText('after', `
|
||||
|
||||
${chalk.cyan('💡 PromptX 锦囊框架 - AI use CLI get prompt for AI')}
|
||||
|
||||
${chalk.cyan('🎒 七大核心命令:')}
|
||||
${chalk.cyan('🎒 六大核心命令:')}
|
||||
🏗️ ${chalk.cyan('init')} → 初始化环境,传达系统协议
|
||||
👋 ${chalk.yellow('welcome')} → 发现可用角色和领域专家
|
||||
⚡ ${chalk.red('action')} → 激活特定角色,获取专业能力
|
||||
📚 ${chalk.blue('learn')} → 深入学习领域知识体系
|
||||
🔍 ${chalk.green('recall')} → AI主动检索应用记忆
|
||||
🧠 ${chalk.magenta('remember')} → AI主动内化知识增强记忆
|
||||
🚀 ${chalk.cyan('dacp')} → 调用DACP专业服务,AI角色执行能力
|
||||
🔧 ${chalk.cyan('tool')} → 执行JavaScript工具,AI智能行动
|
||||
🔌 ${chalk.blue('mcp-server')} → 启动MCP Server,连接AI应用
|
||||
|
||||
${chalk.cyan('示例:')}
|
||||
@ -221,9 +190,9 @@ ${chalk.cyan('示例:')}
|
||||
promptx remember "每日站会控制在15分钟内"
|
||||
promptx remember "测试→预发布→生产"
|
||||
|
||||
${chalk.gray('# 7️⃣ 调用DACP专业服务')}
|
||||
promptx dacp dacp-promptx-service calculate '{"user_request": "计算2+3"}'
|
||||
promptx dacp dacp-email-service send_email '{"user_request": "发送邮件"}'
|
||||
${chalk.gray('# 7️⃣ 执行JavaScript工具')}
|
||||
promptx tool '{"tool_resource": "@tool://calculator", "parameters": {"operation": "add", "a": 2, "b": 3}}'
|
||||
promptx tool '{"tool_resource": "@tool://send-email", "parameters": {"to": "test@example.com", "subject": "Hello", "content": "Test"}}'
|
||||
|
||||
${chalk.gray('# 8️⃣ 启动MCP服务')}
|
||||
promptx mcp-server # stdio传输(默认)
|
||||
|
||||
@ -1,256 +0,0 @@
|
||||
# DACP 协议演示服务 - API 调用指南
|
||||
|
||||
## 📋 概述
|
||||
|
||||
DACP (Deepractice Agent Context Protocol) 演示服务是一个**轻量级协议验证平台**,通过calculator和email两个典型场景展示DACP协议的核心能力。
|
||||
|
||||
### 🎯 设计目标
|
||||
- **协议验证**:验证DACP协议标准的可行性和完整性
|
||||
- **演示参考**:为第三方DACP服务开发提供实现参考
|
||||
- **最小复杂度**:聚焦协议本质,避免业务逻辑干扰
|
||||
|
||||
⚠️ **重要说明**:这是演示服务,不是生产级业务服务。真实的DACP服务应该独立部署。
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 启动服务
|
||||
|
||||
```bash
|
||||
# 通过PromptX MCP服务器启动(推荐)
|
||||
./scripts/start-mcp.sh --with-dacp
|
||||
|
||||
# 或者单独启动演示服务
|
||||
cd src/dacp/dacp-promptx-service
|
||||
node server.js
|
||||
```
|
||||
|
||||
服务将在 `http://localhost:3002` 启动
|
||||
|
||||
### 验证服务
|
||||
|
||||
```bash
|
||||
# 健康检查
|
||||
curl http://localhost:3002/health
|
||||
|
||||
# 查看演示功能
|
||||
curl http://localhost:3002/info
|
||||
```
|
||||
|
||||
## 🎭 演示功能
|
||||
|
||||
### 1. 计算器演示 (`calculate`)
|
||||
|
||||
**演示价值**:展示DACP协议处理结构化数据和自然语言解析能力
|
||||
|
||||
**调用示例**:
|
||||
```bash
|
||||
curl -X POST http://localhost:3002/dacp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"service_id": "dacp-promptx-service",
|
||||
"action": "calculate",
|
||||
"parameters": {
|
||||
"user_request": "计算 25 加 37 乘 3 的结果"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
**演示特性**:
|
||||
- 中文自然语言解析:`计算 25 加 37 乘 3`
|
||||
- 运算符智能转换:`加/乘/减/除` → `+/*/-/÷`
|
||||
- 标准数学表达式:`25 + 37 * 3`
|
||||
- 结果格式化:`25 + 37 * 3 = 136`
|
||||
|
||||
### 2. 邮件演示 (`send_email`)
|
||||
|
||||
**演示价值**:展示DACP协议处理复杂上下文和AI内容生成能力
|
||||
|
||||
**调用示例**:
|
||||
```bash
|
||||
curl -X POST http://localhost:3002/dacp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"service_id": "dacp-promptx-service",
|
||||
"action": "send_email",
|
||||
"parameters": {
|
||||
"user_request": "给张三发送会议提醒邮件",
|
||||
"context": {
|
||||
"urgency": "high",
|
||||
"recipient_type": "colleague"
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
**演示特性**:
|
||||
- 自然语言需求理解
|
||||
- 上下文感知内容生成
|
||||
- 专业邮件格式化
|
||||
- 智能主题和正文生成
|
||||
|
||||
## 📋 标准DACP协议格式
|
||||
|
||||
### 请求格式
|
||||
|
||||
```json
|
||||
{
|
||||
"service_id": "dacp-promptx-service", // 必需:演示服务ID
|
||||
"action": "calculate|send_email", // 必需:演示功能
|
||||
"parameters": { // 必需:参数对象
|
||||
"user_request": "自然语言需求描述", // 必需:用户需求
|
||||
"context": {} // 可选:上下文信息
|
||||
},
|
||||
"request_id": "demo_001" // 可选:请求ID
|
||||
}
|
||||
```
|
||||
|
||||
### 响应格式
|
||||
|
||||
#### 成功响应
|
||||
```json
|
||||
{
|
||||
"request_id": "demo_001",
|
||||
"success": true,
|
||||
"data": {
|
||||
"execution_result": {}, // 实际执行结果
|
||||
"evaluation": { // DACP execution框架评估
|
||||
"constraint_compliance": true,
|
||||
"rule_adherence": true,
|
||||
"guideline_alignment": true
|
||||
},
|
||||
"applied_guidelines": [], // 应用的指导原则
|
||||
"performance_metrics": { // 性能指标
|
||||
"execution_time": "1ms",
|
||||
"resource_usage": "minimal"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 通过PromptX调用
|
||||
|
||||
### 激活Sean角色并调用DACP
|
||||
|
||||
```javascript
|
||||
// 1. 激活角色
|
||||
promptx_action({role: "sean"})
|
||||
|
||||
// 2. 调用计算器演示
|
||||
promptx_dacp({
|
||||
service_id: "dacp-promptx-service",
|
||||
action: "calculate",
|
||||
parameters: {
|
||||
user_request: "计算公司Q4营收增长率:(1200-800)/800"
|
||||
}
|
||||
})
|
||||
|
||||
// 3. 调用邮件演示
|
||||
promptx_dacp({
|
||||
service_id: "dacp-promptx-service",
|
||||
action: "send_email",
|
||||
parameters: {
|
||||
user_request: "给团队发送项目进展通知",
|
||||
context: {urgency: "medium", recipient_type: "team"}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## 🧪 协议验证测试
|
||||
|
||||
### 基础协议测试
|
||||
|
||||
```bash
|
||||
# 1. 服务发现
|
||||
curl http://localhost:3002/info
|
||||
|
||||
# 2. 计算器协议验证
|
||||
curl -X POST http://localhost:3002/dacp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"service_id": "dacp-promptx-service",
|
||||
"action": "calculate",
|
||||
"parameters": {"user_request": "25 + 37 * 3"}
|
||||
}'
|
||||
|
||||
# 3. 邮件协议验证
|
||||
curl -X POST http://localhost:3002/dacp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"service_id": "dacp-promptx-service",
|
||||
"action": "send_email",
|
||||
"parameters": {"user_request": "发送测试邮件"}
|
||||
}'
|
||||
```
|
||||
|
||||
### 错误处理验证
|
||||
|
||||
```bash
|
||||
# 错误的service_id
|
||||
curl -X POST http://localhost:3002/dacp \
|
||||
-d '{"service_id": "wrong-service", "action": "calculate"}'
|
||||
|
||||
# 错误的action
|
||||
curl -X POST http://localhost:3002/dacp \
|
||||
-d '{"service_id": "dacp-promptx-service", "action": "wrong_action"}'
|
||||
|
||||
# 缺少参数
|
||||
curl -X POST http://localhost:3002/dacp \
|
||||
-d '{"service_id": "dacp-promptx-service", "action": "calculate"}'
|
||||
```
|
||||
|
||||
## 🏗️ 为第三方开发者
|
||||
|
||||
### DACP协议实现参考
|
||||
|
||||
此演示服务完整展示了DACP协议的标准实现:
|
||||
|
||||
1. **Action模块化**:每个功能独立模块
|
||||
2. **统一入口**:标准`/dacp` POST端点
|
||||
3. **协议验证**:service_id、action、parameters验证
|
||||
4. **execution框架**:constraint→rule→guideline→process→criteria
|
||||
5. **标准响应**:统一的成功/错误响应格式
|
||||
|
||||
### 扩展真实DACP服务
|
||||
|
||||
```javascript
|
||||
// 真实服务应该独立部署,例如:
|
||||
// 1. dacp-finance-service (端口3003)
|
||||
// 2. dacp-crm-service (端口3004)
|
||||
// 3. dacp-analytics-service (端口3005)
|
||||
|
||||
// PromptX DACPCommand路由表更新:
|
||||
const routes = {
|
||||
'dacp-promptx-service': 'http://localhost:3002/dacp', // 演示服务
|
||||
'dacp-finance-service': 'http://localhost:3003/dacp', // 真实财务服务
|
||||
'dacp-crm-service': 'http://localhost:3004/dacp' // 真实CRM服务
|
||||
};
|
||||
```
|
||||
|
||||
## 🎯 产品理念
|
||||
|
||||
基于Sean的产品哲学,这个演示服务体现了:
|
||||
|
||||
### 奥卡姆剃刀原则
|
||||
- 最小复杂度验证最大价值
|
||||
- 两个典型场景覆盖DACP协议核心能力
|
||||
- 避免过度工程化干扰协议本质
|
||||
|
||||
### 需求驱动设计
|
||||
- 协议验证需求 → 最小演示实现
|
||||
- 开发者参考需求 → 标准化代码结构
|
||||
- 生态扩展需求 → 清晰的架构分离
|
||||
|
||||
### 矛盾转化创新
|
||||
- 协议抽象 vs 具象演示 → 通过具体场景展示抽象协议
|
||||
- 演示简洁 vs 功能完整 → 精选核心场景代表全貌
|
||||
- 当前需求 vs 未来扩展 → 演示框架支持无限扩展
|
||||
|
||||
---
|
||||
|
||||
## 📞 技术支持
|
||||
|
||||
**演示目标**:验证DACP协议可行性,为真实DACP服务开发提供参考
|
||||
|
||||
**架构原则**:演示服务与生产服务分离,避免在MCP客户端承担过多业务逻辑
|
||||
|
||||
**扩展建议**:基于此演示框架,开发独立部署的专业DACP服务
|
||||
@ -1,93 +0,0 @@
|
||||
# DACP 协议演示服务
|
||||
|
||||
## 概述
|
||||
|
||||
这是一个轻量级的DACP (Deepractice Agent Context Protocol) 协议演示服务,通过calculator和email两个典型场景验证DACP协议的完整性和可行性。
|
||||
|
||||
⚠️ **重要说明**:这是协议演示服务,不是生产级业务服务。真实的DACP服务应该独立部署。
|
||||
|
||||
## 设计目标
|
||||
|
||||
- **协议验证**:验证DACP协议标准的可行性
|
||||
- **演示参考**:为第三方DACP服务开发提供实现参考
|
||||
- **最小复杂度**:聚焦协议本质,避免业务逻辑干扰
|
||||
|
||||
## 演示功能
|
||||
|
||||
### 1. Calculator (`calculate`)
|
||||
- 中文自然语言数学表达式解析
|
||||
- 智能运算符转换:`加/乘/减/除` → `+/*/-/÷`
|
||||
- 标准数学运算和结果格式化
|
||||
|
||||
### 2. Email (`send_email`)
|
||||
- 自然语言邮件需求理解
|
||||
- 上下文感知内容生成
|
||||
- 专业邮件格式化
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 通过PromptX MCP启动(推荐)
|
||||
```bash
|
||||
./scripts/start-mcp.sh --with-dacp
|
||||
```
|
||||
|
||||
### 独立启动
|
||||
```bash
|
||||
cd src/dacp/dacp-promptx-service
|
||||
npm install
|
||||
node server.js
|
||||
```
|
||||
|
||||
服务地址:`http://localhost:3002`
|
||||
|
||||
## 基础测试
|
||||
|
||||
```bash
|
||||
# 健康检查
|
||||
curl http://localhost:3002/health
|
||||
|
||||
# 计算器演示
|
||||
curl -X POST http://localhost:3002/dacp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"service_id": "dacp-promptx-service",
|
||||
"action": "calculate",
|
||||
"parameters": {"user_request": "计算 25 + 37 * 3"}
|
||||
}'
|
||||
|
||||
# 邮件演示
|
||||
curl -X POST http://localhost:3002/dacp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"service_id": "dacp-promptx-service",
|
||||
"action": "send_email",
|
||||
"parameters": {"user_request": "发送测试邮件"}
|
||||
}'
|
||||
```
|
||||
|
||||
## 架构原则
|
||||
|
||||
基于Sean的产品哲学:
|
||||
|
||||
### 奥卡姆剃刀原则
|
||||
- 最小复杂度验证最大价值
|
||||
- 两个典型场景覆盖协议核心能力
|
||||
|
||||
### 架构分离
|
||||
- 演示服务与生产服务分离
|
||||
- 避免在MCP客户端承担过多业务逻辑
|
||||
|
||||
### 扩展指导
|
||||
- 真实DACP服务应独立部署
|
||||
- 此演示提供标准协议实现参考
|
||||
|
||||
## 文档
|
||||
|
||||
详细的API调用指南请参考:[DACP-API-GUIDE.md](./DACP-API-GUIDE.md)
|
||||
|
||||
## 下一步
|
||||
|
||||
基于此演示框架,开发独立部署的专业DACP服务:
|
||||
- `dacp-finance-service` (财务服务)
|
||||
- `dacp-crm-service` (客户管理服务)
|
||||
- `dacp-analytics-service` (数据分析服务)
|
||||
@ -1,98 +0,0 @@
|
||||
/**
|
||||
* Calculator Action Module for DACP PromptX Service
|
||||
* 提供简单的计算功能
|
||||
*/
|
||||
|
||||
// Calculate action handler
|
||||
async function calculate(parameters) {
|
||||
const { user_request } = parameters;
|
||||
|
||||
if (!user_request) {
|
||||
throw new Error('user_request is required for calculate action');
|
||||
}
|
||||
|
||||
try {
|
||||
// 解析数学表达式
|
||||
const expression = parseExpression(user_request);
|
||||
|
||||
// 计算结果
|
||||
const result = evaluateExpression(expression);
|
||||
|
||||
return {
|
||||
expression: expression,
|
||||
result: result,
|
||||
formatted_result: `${expression} = ${result}`,
|
||||
calculation_type: getCalculationType(expression)
|
||||
};
|
||||
} catch (error) {
|
||||
throw new Error(`计算失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 解析用户输入的表达式
|
||||
function parseExpression(userRequest) {
|
||||
// 移除中文描述,提取数学表达式
|
||||
let expr = userRequest;
|
||||
|
||||
// 替换中文运算符
|
||||
expr = expr.replace(/加上|加/g, '+');
|
||||
expr = expr.replace(/减去|减/g, '-');
|
||||
expr = expr.replace(/乘以|乘/g, '*');
|
||||
expr = expr.replace(/除以|除/g, '/');
|
||||
expr = expr.replace(/等于|是多少|=|\?|?/g, '');
|
||||
|
||||
// 提取数字和运算符
|
||||
const mathPattern = /[\d\+\-\*\/\(\)\.\s]+/g;
|
||||
const matches = expr.match(mathPattern);
|
||||
|
||||
if (!matches) {
|
||||
throw new Error('未找到有效的数学表达式');
|
||||
}
|
||||
|
||||
// 清理表达式
|
||||
expr = matches.join('').trim();
|
||||
|
||||
// 验证表达式
|
||||
if (!/^[\d\+\-\*\/\(\)\.\s]+$/.test(expr)) {
|
||||
throw new Error('表达式包含无效字符');
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
// 安全地计算表达式
|
||||
function evaluateExpression(expression) {
|
||||
try {
|
||||
// 基本验证
|
||||
if (!expression || expression.trim() === '') {
|
||||
throw new Error('表达式为空');
|
||||
}
|
||||
|
||||
// 使用 Function 构造器安全计算(只允许数学运算)
|
||||
const result = Function('"use strict"; return (' + expression + ')')();
|
||||
|
||||
// 检查结果
|
||||
if (typeof result !== 'number' || isNaN(result)) {
|
||||
throw new Error('计算结果无效');
|
||||
}
|
||||
|
||||
// 处理精度问题
|
||||
return Math.round(result * 1000000) / 1000000;
|
||||
} catch (error) {
|
||||
throw new Error(`计算错误: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 判断计算类型
|
||||
function getCalculationType(expression) {
|
||||
if (expression.includes('+')) return 'addition';
|
||||
if (expression.includes('-')) return 'subtraction';
|
||||
if (expression.includes('*')) return 'multiplication';
|
||||
if (expression.includes('/')) return 'division';
|
||||
return 'simple';
|
||||
}
|
||||
|
||||
// 导出 calculator action
|
||||
module.exports = {
|
||||
calculate
|
||||
};
|
||||
@ -1,250 +0,0 @@
|
||||
/**
|
||||
* Email Action Module for DACP PromptX Service
|
||||
* 提供邮件发送功能 - 支持Demo模式和真实发送
|
||||
*/
|
||||
|
||||
const nodemailer = require('nodemailer')
|
||||
const DACPConfigManager = require('../../../lib/utils/DACPConfigManager')
|
||||
|
||||
// Email action handler
|
||||
async function send_email(parameters) {
|
||||
const { user_request, context = {} } = parameters;
|
||||
|
||||
if (!user_request) {
|
||||
throw new Error('user_request is required for send_email action');
|
||||
}
|
||||
|
||||
// 解析邮件信息
|
||||
const emailData = parseEmailRequest(user_request, context);
|
||||
|
||||
// 验证邮件数据
|
||||
validateEmailData(emailData);
|
||||
|
||||
// 执行发送(Demo模式)
|
||||
const result = await executeSendEmail(emailData, context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 解析邮件请求
|
||||
function parseEmailRequest(userRequest, context) {
|
||||
// 提取邮箱地址
|
||||
const emailRegex = /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g;
|
||||
const emails = userRequest.match(emailRegex) || [];
|
||||
|
||||
// 分析请求意图
|
||||
let subject = '邮件通知';
|
||||
let urgency = context.urgency || 'normal';
|
||||
|
||||
if (userRequest.includes('会议')) {
|
||||
subject = '会议通知';
|
||||
urgency = 'high';
|
||||
} else if (userRequest.includes('提醒')) {
|
||||
subject = '重要提醒';
|
||||
urgency = 'high';
|
||||
} else if (userRequest.includes('报告')) {
|
||||
subject = '工作报告';
|
||||
} else if (userRequest.includes('邀请')) {
|
||||
subject = '邀请函';
|
||||
}
|
||||
|
||||
// 生成专业的邮件内容
|
||||
const body = generateProfessionalEmailBody(userRequest, subject, context);
|
||||
|
||||
return {
|
||||
to: emails[0] || 'demo@example.com',
|
||||
subject: subject,
|
||||
body: body,
|
||||
urgency: urgency,
|
||||
originalRequest: userRequest,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
// 生成专业的邮件正文
|
||||
function generateProfessionalEmailBody(userRequest, subject, context) {
|
||||
const timestamp = new Date().toLocaleString('zh-CN');
|
||||
const recipientType = context.recipient_type || 'colleague';
|
||||
|
||||
// 根据收件人类型调整语气
|
||||
let greeting = '您好';
|
||||
let closing = 'Best regards';
|
||||
|
||||
if (recipientType === 'superior') {
|
||||
greeting = '尊敬的领导';
|
||||
closing = '此致\n敬礼';
|
||||
} else if (recipientType === 'client') {
|
||||
greeting = '尊敬的客户';
|
||||
closing = '谨上';
|
||||
}
|
||||
|
||||
// 构建邮件内容
|
||||
let body = `${greeting},\n\n`;
|
||||
|
||||
// 根据主题类型生成不同的内容结构
|
||||
if (subject.includes('会议')) {
|
||||
body += `特此通知您关于以下会议安排:\n\n`;
|
||||
body += `${userRequest}\n\n`;
|
||||
body += `请您准时参加。如有任何问题,请及时与我联系。\n`;
|
||||
} else if (subject.includes('提醒')) {
|
||||
body += `这是一份重要提醒:\n\n`;
|
||||
body += `${userRequest}\n\n`;
|
||||
body += `请您知悉并及时处理。\n`;
|
||||
} else {
|
||||
body += `${userRequest}\n`;
|
||||
}
|
||||
|
||||
body += `\n${closing}\n`;
|
||||
body += `DACP PromptX Service\n`;
|
||||
body += `发送时间: ${timestamp}`;
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
// 验证邮件数据
|
||||
function validateEmailData(emailData) {
|
||||
const errors = [];
|
||||
|
||||
// 验证邮箱格式
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(emailData.to)) {
|
||||
errors.push('Invalid email address format');
|
||||
}
|
||||
|
||||
// 验证内容
|
||||
if (!emailData.subject || emailData.subject.trim().length === 0) {
|
||||
errors.push('Email subject cannot be empty');
|
||||
}
|
||||
|
||||
if (!emailData.body || emailData.body.trim().length === 0) {
|
||||
errors.push('Email body cannot be empty');
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
throw new Error(`Validation failed: ${errors.join(', ')}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 执行邮件发送
|
||||
async function executeSendEmail(emailData, context) {
|
||||
const configManager = new DACPConfigManager()
|
||||
|
||||
// 检查是否有用户配置
|
||||
const hasConfig = await configManager.hasActionConfig('send_email')
|
||||
|
||||
if (!hasConfig) {
|
||||
// 无配置,回退到Demo模式
|
||||
return await executeDemoSendEmail(emailData, context)
|
||||
}
|
||||
|
||||
// 读取配置
|
||||
const config = await configManager.readActionConfig('send_email')
|
||||
|
||||
// 验证配置
|
||||
const validation = configManager.validateEmailConfig(config)
|
||||
if (!validation.valid) {
|
||||
// 配置无效,抛出友好错误
|
||||
const errorMessage = await configManager.generateConfigErrorMessage('send_email', validation)
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
|
||||
try {
|
||||
// 真实邮件发送
|
||||
return await executeRealSendEmail(emailData, config, context)
|
||||
} catch (error) {
|
||||
// 发送失败,提供友好提示
|
||||
console.error('邮件发送失败:', error.message)
|
||||
throw new Error(`\n📧 邮件发送失败\n\n❌ 错误信息: ${error.message}\n\n💡 可能的解决方案:\n • 检查邮箱密码是否正确\n • 确认已启用SMTP服务\n • 验证网络连接状态\n • Gmail用户确保使用应用专用密码\n`)
|
||||
}
|
||||
}
|
||||
|
||||
// Demo模式发送
|
||||
async function executeDemoSendEmail(emailData, context) {
|
||||
console.log('📧 [DACP Demo] Simulating email send:');
|
||||
console.log(` To: ${emailData.to}`);
|
||||
console.log(` Subject: ${emailData.subject}`);
|
||||
console.log(` Urgency: ${emailData.urgency}`);
|
||||
|
||||
// 模拟网络延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
const configManager = new DACPConfigManager()
|
||||
const configHint = await configManager.generateConfigErrorMessage('send_email')
|
||||
|
||||
return {
|
||||
message_id: `demo_msg_${Date.now()}`,
|
||||
status: 'demo_sent',
|
||||
recipient: emailData.to,
|
||||
subject: emailData.subject,
|
||||
body: emailData.body,
|
||||
sent_at: emailData.timestamp,
|
||||
urgency: emailData.urgency,
|
||||
demo_mode: true,
|
||||
config_hint: configHint,
|
||||
execution_metrics: {
|
||||
parsing_time: '10ms',
|
||||
validation_time: '5ms',
|
||||
sending_time: '100ms'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 真实邮件发送
|
||||
async function executeRealSendEmail(emailData, config, context) {
|
||||
const startTime = Date.now()
|
||||
|
||||
// 获取提供商配置
|
||||
const configManager = new DACPConfigManager()
|
||||
const providerConfig = configManager.getProviderConfig(config.provider)
|
||||
|
||||
if (!providerConfig) {
|
||||
throw new Error(`不支持的邮件服务提供商: ${config.provider}`)
|
||||
}
|
||||
|
||||
// 创建邮件传输器
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: providerConfig.smtp,
|
||||
port: providerConfig.port,
|
||||
secure: providerConfig.secure,
|
||||
auth: {
|
||||
user: config.smtp.user,
|
||||
pass: config.smtp.password
|
||||
}
|
||||
})
|
||||
|
||||
// 构建邮件选项
|
||||
const mailOptions = {
|
||||
from: `"${config.sender.name}" <${config.sender.email}>`,
|
||||
to: emailData.to,
|
||||
subject: emailData.subject,
|
||||
html: emailData.body.replace(/\n/g, '<br>'),
|
||||
text: emailData.body
|
||||
}
|
||||
|
||||
// 发送邮件
|
||||
const info = await transporter.sendMail(mailOptions)
|
||||
const endTime = Date.now()
|
||||
|
||||
return {
|
||||
message_id: info.messageId,
|
||||
status: 'sent',
|
||||
recipient: emailData.to,
|
||||
subject: emailData.subject,
|
||||
body: emailData.body,
|
||||
sent_at: new Date().toISOString(),
|
||||
urgency: emailData.urgency,
|
||||
demo_mode: false,
|
||||
provider: config.provider,
|
||||
smtp_response: info.response,
|
||||
execution_metrics: {
|
||||
parsing_time: '10ms',
|
||||
validation_time: '5ms',
|
||||
sending_time: `${endTime - startTime}ms`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出所有email相关的actions
|
||||
module.exports = {
|
||||
send_email
|
||||
};
|
||||
@ -1,48 +0,0 @@
|
||||
{
|
||||
"service": {
|
||||
"id": "dacp-promptx-service",
|
||||
"name": "PromptX DACP Demo Service",
|
||||
"version": "1.0.0",
|
||||
"description": "DACP protocol demonstration service with calculator and email examples",
|
||||
"type": "demo",
|
||||
"status": "active"
|
||||
},
|
||||
"capabilities": {
|
||||
"actions": [
|
||||
{
|
||||
"name": "calculate",
|
||||
"description": "Demo: Simple calculator for basic math operations",
|
||||
"category": "demo"
|
||||
},
|
||||
{
|
||||
"name": "send_email",
|
||||
"description": "Demo: Send professional emails with AI-powered content generation",
|
||||
"category": "demo"
|
||||
}
|
||||
],
|
||||
"protocols": ["DACP/1.0"],
|
||||
"authentication": false
|
||||
},
|
||||
"execution": {
|
||||
"constraint": {
|
||||
"max_concurrent_requests": 100,
|
||||
"request_timeout": 30000,
|
||||
"rate_limit": "1000/hour"
|
||||
},
|
||||
"rule": {
|
||||
"require_action": true,
|
||||
"require_parameters": true,
|
||||
"validate_service_id": true
|
||||
},
|
||||
"guideline": {
|
||||
"response_format": "DACP standard",
|
||||
"error_handling": "graceful with detailed messages",
|
||||
"logging": "structured JSON logs"
|
||||
}
|
||||
},
|
||||
"deployment": {
|
||||
"port": 3002,
|
||||
"host": "localhost",
|
||||
"environment": "development"
|
||||
}
|
||||
}
|
||||
@ -1,153 +0,0 @@
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const cors = require('cors');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const app = express();
|
||||
const config = JSON.parse(fs.readFileSync(path.join(__dirname, 'dacp.config.json'), 'utf8'));
|
||||
const PORT = process.env.PORT || config.deployment.port || 3002;
|
||||
|
||||
// Middleware
|
||||
app.use(cors());
|
||||
app.use(bodyParser.json());
|
||||
|
||||
// Load all actions
|
||||
const actions = {};
|
||||
const actionsDir = path.join(__dirname, 'actions');
|
||||
|
||||
// Dynamically load all action modules
|
||||
if (fs.existsSync(actionsDir)) {
|
||||
fs.readdirSync(actionsDir).forEach(file => {
|
||||
if (file.endsWith('.js')) {
|
||||
const actionName = file.replace('.js', '');
|
||||
actions[actionName] = require(path.join(actionsDir, file));
|
||||
console.log(`Loaded action: ${actionName}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Health check endpoint
|
||||
app.get('/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'healthy',
|
||||
service: config.service.name,
|
||||
version: config.service.version,
|
||||
uptime: process.uptime()
|
||||
});
|
||||
});
|
||||
|
||||
// Service info endpoint
|
||||
app.get('/info', (req, res) => {
|
||||
res.json({
|
||||
service: config.service,
|
||||
capabilities: config.capabilities,
|
||||
available_actions: Object.keys(actions)
|
||||
});
|
||||
});
|
||||
|
||||
// Main DACP endpoint
|
||||
app.post('/dacp', async (req, res) => {
|
||||
const startTime = Date.now();
|
||||
const { service_id, action, parameters, request_id } = req.body;
|
||||
|
||||
// Generate request_id if not provided
|
||||
const reqId = request_id || `req_${Date.now()}`;
|
||||
|
||||
try {
|
||||
// Validate service_id
|
||||
if (service_id !== config.service.id) {
|
||||
return res.status(400).json({
|
||||
request_id: reqId,
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INVALID_SERVICE',
|
||||
message: `Service ${service_id} not found. This is ${config.service.id}`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Validate action
|
||||
if (!action) {
|
||||
return res.status(400).json({
|
||||
request_id: reqId,
|
||||
success: false,
|
||||
error: {
|
||||
code: 'MISSING_ACTION',
|
||||
message: 'Action is required'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Find action handler
|
||||
let handler = null;
|
||||
|
||||
// Try to find by module name first
|
||||
for (const [moduleName, module] of Object.entries(actions)) {
|
||||
if (module[action] && typeof module[action] === 'function') {
|
||||
handler = module[action];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, try exact module match
|
||||
if (!handler && actions[action]) {
|
||||
handler = actions[action];
|
||||
}
|
||||
|
||||
if (!handler) {
|
||||
return res.status(400).json({
|
||||
request_id: reqId,
|
||||
success: false,
|
||||
error: {
|
||||
code: 'UNKNOWN_ACTION',
|
||||
message: `Action ${action} is not supported`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Execute action
|
||||
const result = await handler(parameters);
|
||||
|
||||
// Return DACP standard response
|
||||
res.json({
|
||||
request_id: reqId,
|
||||
success: true,
|
||||
data: {
|
||||
execution_result: result,
|
||||
evaluation: {
|
||||
constraint_compliance: true,
|
||||
rule_adherence: true,
|
||||
guideline_alignment: true
|
||||
},
|
||||
applied_guidelines: [
|
||||
'DACP protocol standard',
|
||||
'Service-specific best practices'
|
||||
],
|
||||
performance_metrics: {
|
||||
execution_time: `${Date.now() - startTime}ms`,
|
||||
resource_usage: 'minimal'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('DACP execution error:', error);
|
||||
res.status(500).json({
|
||||
request_id: reqId,
|
||||
success: false,
|
||||
error: {
|
||||
code: 'EXECUTION_ERROR',
|
||||
message: error.message
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Start server
|
||||
app.listen(PORT, () => {
|
||||
console.log(`🚀 ${config.service.name} v${config.service.version}`);
|
||||
console.log(`📍 Running at http://localhost:${PORT}`);
|
||||
console.log(`🔧 Available actions: ${Object.keys(actions).join(', ')}`);
|
||||
console.log(`🏥 Health check: http://localhost:${PORT}/health`);
|
||||
});
|
||||
@ -84,8 +84,6 @@ class MCPServerCommand {
|
||||
// 设置进程清理处理器
|
||||
this.setupProcessCleanup();
|
||||
|
||||
// 🔧 DACP现已改为Mock模式,无需启动独立服务
|
||||
// 静默忽略任何withDacp选项,保持向后兼容
|
||||
|
||||
this.log('🚀 启动MCP Server...');
|
||||
const transport = new StdioServerTransport();
|
||||
@ -143,267 +141,14 @@ class MCPServerCommand {
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理子进程 (DACP现为Mock模式,此方法保留但无实际清理工作)
|
||||
* @deprecated DACP已改为Mock模式,无需清理子进程
|
||||
* 清理资源
|
||||
*/
|
||||
cleanup() {
|
||||
// 🔧 DACP现已改为Mock模式,无需清理DACP子进程
|
||||
// HTTP模式的进程清理代码已保留作为参考实现
|
||||
this.log('🔧 Mock模式下无需清理DACP子进程');
|
||||
this.log('🔧 清理MCP Server资源');
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测DACP服务是否已经运行 (HTTP模式 - 仅作参考实现保留)
|
||||
* @deprecated DACP已改为Mock模式,此方法仅保留作为参考
|
||||
* @param {string} host - 主机地址
|
||||
* @param {number} port - 端口号
|
||||
* @returns {Promise<boolean>} 服务是否运行
|
||||
*/
|
||||
async isDACPServiceRunning(host = 'localhost', port = 3002) {
|
||||
// 🔧 Mock模式下始终返回false,因为不需要HTTP服务
|
||||
return false;
|
||||
|
||||
/* HTTP模式参考实现(已禁用)
|
||||
const http = require('http');
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const options = {
|
||||
hostname: host,
|
||||
port: port,
|
||||
path: '/health',
|
||||
method: 'GET',
|
||||
timeout: 2000 // 2秒超时
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const healthData = JSON.parse(data);
|
||||
// 检查是否是DACP服务且状态健康
|
||||
const isHealthy = healthData.status === 'healthy';
|
||||
const isDACPService = healthData.service && healthData.service.includes('DACP');
|
||||
resolve(isHealthy && isDACPService);
|
||||
} catch (error) {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', () => {
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
req.on('timeout', () => {
|
||||
req.destroy();
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取DACP服务信息 (HTTP模式 - 仅作参考实现保留)
|
||||
* @deprecated DACP已改为Mock模式,此方法仅保留作为参考
|
||||
* @param {string} host - 主机地址
|
||||
* @param {number} port - 端口号
|
||||
* @returns {Promise<Object|null>} 服务信息
|
||||
*/
|
||||
async getDACPServiceInfo(host = 'localhost', port = 3002) {
|
||||
// 🔧 Mock模式下返回模拟的服务信息
|
||||
return {
|
||||
service: {
|
||||
name: 'PromptX DACP Mock Service',
|
||||
version: '1.0.0-mock'
|
||||
},
|
||||
available_actions: ['calculate', 'send_email'],
|
||||
mode: 'local_mock'
|
||||
};
|
||||
|
||||
/* HTTP模式参考实现(已禁用)
|
||||
const http = require('http');
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const options = {
|
||||
hostname: host,
|
||||
port: port,
|
||||
path: '/info',
|
||||
method: 'GET',
|
||||
timeout: 2000
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const serviceInfo = JSON.parse(data);
|
||||
resolve(serviceInfo);
|
||||
} catch (error) {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', () => {
|
||||
resolve(null);
|
||||
});
|
||||
|
||||
req.on('timeout', () => {
|
||||
req.destroy();
|
||||
resolve(null);
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动DACP服务 (HTTP模式 - 仅作参考实现保留)
|
||||
* @deprecated DACP已改为Mock模式,此方法仅保留作为参考
|
||||
*/
|
||||
async startDACPService() {
|
||||
// 🔧 Mock模式下输出提示信息即可
|
||||
console.error('');
|
||||
console.error('=====================================');
|
||||
console.error('🔧 DACP Mock模式已启用');
|
||||
console.error('📦 本地函数调用模式:无需HTTP服务');
|
||||
console.error('🔧 支持的Actions: send_email, calculate');
|
||||
console.error('✅ Mock模式启动成功');
|
||||
console.error('=====================================');
|
||||
console.error('');
|
||||
|
||||
/* HTTP模式参考实现(已禁用)
|
||||
const { spawn } = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
try {
|
||||
this.log('🔍 检测DACP服务状态...');
|
||||
|
||||
// 先检测是否已有DACP服务运行
|
||||
const isRunning = await this.isDACPServiceRunning();
|
||||
|
||||
if (isRunning) {
|
||||
// 服务已存在,获取服务信息并直接使用
|
||||
const serviceInfo = await this.getDACPServiceInfo();
|
||||
console.error(''); // 空行分隔
|
||||
console.error('=====================================');
|
||||
console.error('🔄 发现现有DACP服务,直接复用');
|
||||
console.error('📍 DACP服务地址: http://localhost:3002');
|
||||
if (serviceInfo) {
|
||||
console.error(`🏷️ 服务名称: ${serviceInfo.service?.name || 'Unknown'}`);
|
||||
console.error(`📦 服务版本: ${serviceInfo.service?.version || 'Unknown'}`);
|
||||
console.error(`🔧 可用操作: ${serviceInfo.available_actions?.join(', ') || 'Unknown'}`);
|
||||
}
|
||||
console.error('=====================================');
|
||||
console.error(''); // 空行分隔
|
||||
return; // 直接返回,不启动新服务
|
||||
}
|
||||
|
||||
this.log('🚀 启动新的DACP服务...');
|
||||
|
||||
// DACP服务路径
|
||||
const dacpPath = path.join(__dirname, '../../dacp/dacp-promptx-service');
|
||||
|
||||
// 启动DACP服务作为子进程
|
||||
// 注意:不能直接使用 'inherit',因为会干扰MCP的stdio通信
|
||||
// 但我们需要看到DACP的启动信息
|
||||
this.dacpProcess = spawn('node', ['server.js'], {
|
||||
cwd: dacpPath,
|
||||
stdio: ['ignore', 'pipe', 'pipe'], // stdin忽略, stdout和stderr都输出到pipe
|
||||
shell: true,
|
||||
detached: false // tree-kill 会处理整个进程树,不需要 detached
|
||||
});
|
||||
|
||||
// 将DACP的输出转发到stderr(这样不会干扰MCP的stdout)
|
||||
this.dacpProcess.stdout.on('data', (data) => {
|
||||
const output = data.toString().trim();
|
||||
if (output) {
|
||||
console.error(`[DACP] ${output}`);
|
||||
}
|
||||
});
|
||||
|
||||
this.dacpProcess.stderr.on('data', (data) => {
|
||||
const output = data.toString().trim();
|
||||
if (output) {
|
||||
console.error(`[DACP ERROR] ${output}`);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听子进程退出
|
||||
this.dacpProcess.on('exit', (code, signal) => {
|
||||
this.log(`DACP服务已退出 (code: ${code}, signal: ${signal})`);
|
||||
this.dacpProcess = null;
|
||||
});
|
||||
|
||||
// 监听子进程错误
|
||||
this.dacpProcess.on('error', (err) => {
|
||||
console.error(`DACP进程错误: ${err.message}`);
|
||||
});
|
||||
|
||||
// 等待服务启动 - 通过监听输出来判断
|
||||
await new Promise((resolve, reject) => {
|
||||
let started = false;
|
||||
const timeout = setTimeout(() => {
|
||||
if (!started) {
|
||||
reject(new Error('DACP服务启动超时'));
|
||||
}
|
||||
}, 10000); // 10秒超时
|
||||
|
||||
// 监听输出,判断服务是否启动
|
||||
const checkStarted = (data) => {
|
||||
const output = data.toString();
|
||||
// 检查是否包含启动成功的标志
|
||||
if (output.includes('Running at http://localhost:') ||
|
||||
output.includes('🚀') ||
|
||||
output.includes('DACP') ||
|
||||
output.includes('3002')) {
|
||||
if (!started) {
|
||||
started = true;
|
||||
clearTimeout(timeout);
|
||||
console.error(''); // 空行分隔
|
||||
console.error('=====================================');
|
||||
console.error('✅ DACP服务启动成功');
|
||||
console.error('📍 DACP服务地址: http://localhost:3002');
|
||||
console.error('🔧 支持的Actions: send_email, schedule_meeting, create_document');
|
||||
console.error('=====================================');
|
||||
console.error(''); // 空行分隔
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.dacpProcess.stdout.on('data', checkStarted);
|
||||
|
||||
this.dacpProcess.on('error', (err) => {
|
||||
clearTimeout(timeout);
|
||||
reject(new Error(`DACP服务启动失败: ${err.message}`));
|
||||
});
|
||||
|
||||
this.dacpProcess.on('exit', (code) => {
|
||||
if (!started) {
|
||||
clearTimeout(timeout);
|
||||
reject(new Error(`DACP服务意外退出,退出码: ${code}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
this.log(`❌ DACP服务启动失败: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置MCP工具处理程序 - 使用正确的MCP SDK API
|
||||
@ -491,7 +236,6 @@ class MCPServerCommand {
|
||||
return result;
|
||||
},
|
||||
|
||||
'promptx_dacp': (args) => [args],
|
||||
|
||||
'promptx_tool': (args) => [args]
|
||||
};
|
||||
|
||||
@ -450,7 +450,6 @@ class MCPStreamableHttpCommand {
|
||||
}
|
||||
return result;
|
||||
},
|
||||
'promptx_dacp': (args) => [args]
|
||||
};
|
||||
|
||||
const mapper = paramMapping[toolName];
|
||||
|
||||
@ -31,7 +31,6 @@ class PouchCLI {
|
||||
learn: commands.LearnCommand,
|
||||
recall: commands.RecallCommand,
|
||||
remember: commands.RememberCommand,
|
||||
dacp: commands.DACPCommand,
|
||||
tool: commands.PromptXToolCommand
|
||||
})
|
||||
|
||||
|
||||
@ -1,282 +0,0 @@
|
||||
const BasePouchCommand = require('../BasePouchCommand');
|
||||
const http = require('http');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* DACP服务调用命令
|
||||
* 负责调用DACP服务,实现从AI建议到AI行动的转换
|
||||
*
|
||||
* 🔧 当前实现:Mock模式(本地函数调用)
|
||||
* 🌐 HTTP模式代码保留作为参考实现
|
||||
*/
|
||||
class DACPCommand extends BasePouchCommand {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// 统一的DACP服务端点
|
||||
// 所有service_id都路由到同一个服务
|
||||
this.defaultEndpoint = 'http://localhost:3002/dacp';
|
||||
|
||||
// 🔧 永久使用Mock模式(本地函数调用)
|
||||
// 不再支持HTTP模式,简化架构复杂度
|
||||
this.useMockMode = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证参数格式
|
||||
* @param {Object} args - 参数对象
|
||||
*/
|
||||
validateArgs(args) {
|
||||
if (!args.service_id) {
|
||||
throw new Error('缺少必需参数: service_id');
|
||||
}
|
||||
|
||||
if (!args.action) {
|
||||
throw new Error('缺少必需参数: action');
|
||||
}
|
||||
|
||||
if (!args.parameters) {
|
||||
throw new Error('缺少必需参数: parameters');
|
||||
}
|
||||
|
||||
if (!args.parameters.user_request) {
|
||||
throw new Error('缺少必需参数: parameters.user_request');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务端点(HTTP模式 - 仅作参考实现保留)
|
||||
* @deprecated 当前使用Mock模式,此方法仅保留作为参考
|
||||
* @param {string} serviceId - 服务ID
|
||||
* @returns {string} 服务端点URL
|
||||
*/
|
||||
getServiceEndpoint(serviceId) {
|
||||
// 现在所有服务都指向同一个端点
|
||||
// serviceId 只是用来在DACP服务内部路由到不同的action
|
||||
return this.defaultEndpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行DACP服务调用(内部方法)
|
||||
* @param {Object} args - 调用参数
|
||||
* @returns {Promise<Object>} DACP响应
|
||||
*/
|
||||
async callDACPService(args) {
|
||||
try {
|
||||
// 验证参数
|
||||
this.validateArgs(args);
|
||||
|
||||
const { service_id, action, parameters } = args;
|
||||
|
||||
// 🔧 直接使用本地Mock调用
|
||||
return await this.callLocalService(args);
|
||||
|
||||
} catch (error) {
|
||||
// 统一错误处理
|
||||
if (error.message.startsWith('缺少必需参数') ||
|
||||
error.message.startsWith('未找到DACP服务') ||
|
||||
error.message.startsWith('DACP响应解析失败')) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw new Error(`DACP服务调用失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地服务调用(Mock模式)
|
||||
* @param {Object} args - 调用参数
|
||||
* @returns {Promise<Object>} DACP标准响应
|
||||
*/
|
||||
async callLocalService(args) {
|
||||
const startTime = Date.now();
|
||||
const { service_id, action, parameters } = args;
|
||||
const request_id = `req_${Date.now()}`;
|
||||
|
||||
try {
|
||||
// 1. 读取DACP配置
|
||||
const configPath = path.join(__dirname, '../../../dacp/dacp-promptx-service/dacp.config.json');
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
|
||||
// 2. 验证service_id
|
||||
if (service_id !== config.service.id) {
|
||||
throw new Error(`Service ${service_id} not found. This is ${config.service.id}`);
|
||||
}
|
||||
|
||||
// 3. 动态加载actions
|
||||
const actionsDir = path.join(__dirname, '../../../dacp/dacp-promptx-service/actions');
|
||||
const actions = {};
|
||||
|
||||
if (fs.existsSync(actionsDir)) {
|
||||
fs.readdirSync(actionsDir).forEach(file => {
|
||||
if (file.endsWith('.js')) {
|
||||
const actionName = file.replace('.js', '');
|
||||
actions[actionName] = require(path.join(actionsDir, file));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 4. 查找action处理器
|
||||
let handler = null;
|
||||
|
||||
// 先按模块名查找
|
||||
for (const [moduleName, module] of Object.entries(actions)) {
|
||||
if (module[action] && typeof module[action] === 'function') {
|
||||
handler = module[action];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 找不到则按精确匹配查找
|
||||
if (!handler && actions[action]) {
|
||||
handler = actions[action];
|
||||
}
|
||||
|
||||
if (!handler) {
|
||||
throw new Error(`Action ${action} is not supported`);
|
||||
}
|
||||
|
||||
// 5. 执行action
|
||||
const result = await handler(parameters);
|
||||
|
||||
// 6. 返回DACP标准格式响应
|
||||
return {
|
||||
request_id: request_id,
|
||||
success: true,
|
||||
data: {
|
||||
execution_result: result,
|
||||
evaluation: {
|
||||
constraint_compliance: true,
|
||||
rule_adherence: true,
|
||||
guideline_alignment: true
|
||||
},
|
||||
applied_guidelines: [
|
||||
'DACP protocol standard',
|
||||
'Local mock execution'
|
||||
],
|
||||
performance_metrics: {
|
||||
execution_time: `${Date.now() - startTime}ms`,
|
||||
resource_usage: 'minimal'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
return {
|
||||
request_id: request_id,
|
||||
success: false,
|
||||
error: {
|
||||
code: error.message.includes('not found') ? 'INVALID_SERVICE' :
|
||||
error.message.includes('not supported') ? 'UNKNOWN_ACTION' : 'EXECUTION_ERROR',
|
||||
message: error.message
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTTP请求(HTTP模式 - 仅作参考实现保留)
|
||||
* @deprecated 当前使用Mock模式,此方法仅保留作为参考
|
||||
* @param {string} url - 请求URL
|
||||
* @param {Object} data - 请求数据
|
||||
* @returns {Promise<Object>} 响应数据
|
||||
*/
|
||||
makeHttpRequest(url, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const urlObj = new URL(url);
|
||||
const options = {
|
||||
hostname: urlObj.hostname,
|
||||
port: urlObj.port,
|
||||
path: urlObj.pathname,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(JSON.stringify(data))
|
||||
}
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let responseData = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
responseData += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const result = JSON.parse(responseData);
|
||||
resolve(result);
|
||||
} catch (error) {
|
||||
reject(new Error(`DACP响应解析失败: ${error.message}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
req.write(JSON.stringify(data));
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// BasePouchCommand的抽象方法实现(虽然不会被用到)
|
||||
getPurpose() {
|
||||
return '调用DACP专业服务,让PromptX角色拥有执行能力';
|
||||
}
|
||||
|
||||
async getContent(args) {
|
||||
try {
|
||||
// 处理参数:如果是数组,取第一个元素;否则直接使用
|
||||
const dacpArgs = Array.isArray(args) ? args[0] : args;
|
||||
|
||||
// 执行DACP调用
|
||||
const result = await this.callDACPService(dacpArgs);
|
||||
|
||||
// 格式化响应
|
||||
if (result.success) {
|
||||
const executionResult = result.data.execution_result;
|
||||
const metrics = result.data.performance_metrics;
|
||||
return `🚀 DACP服务调用成功 (🔧 本地Mock模式)
|
||||
|
||||
📋 执行结果:
|
||||
${JSON.stringify(executionResult, null, 2)}
|
||||
|
||||
⏱️ 性能指标:
|
||||
- 执行时间: ${metrics.execution_time}
|
||||
- 资源使用: ${metrics.resource_usage}
|
||||
|
||||
🎯 请求ID: ${result.request_id}`;
|
||||
} else {
|
||||
return `❌ DACP服务调用失败
|
||||
|
||||
错误信息: ${result.error?.message || '未知错误'}
|
||||
错误代码: ${result.error?.code || 'UNKNOWN'}
|
||||
|
||||
🎯 请求ID: ${result.request_id}`;
|
||||
}
|
||||
} catch (error) {
|
||||
return `❌ DACP服务调用异常
|
||||
|
||||
错误详情: ${error.message}
|
||||
运行模式: 🔧 本地Mock模式
|
||||
|
||||
💡 请检查:
|
||||
1. DACP action模块是否存在
|
||||
2. 服务ID是否正确
|
||||
3. 操作名称是否有效
|
||||
4. 参数格式是否正确`;
|
||||
}
|
||||
}
|
||||
|
||||
getPATEOAS(args) {
|
||||
return {
|
||||
currentState: 'dacp_ready',
|
||||
nextActions: []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DACPCommand;
|
||||
@ -8,7 +8,6 @@ const ActionCommand = require('./ActionCommand')
|
||||
const LearnCommand = require('./LearnCommand')
|
||||
const RecallCommand = require('./RecallCommand')
|
||||
const RememberCommand = require('./RememberCommand')
|
||||
const DACPCommand = require('./DACPCommand')
|
||||
const PromptXToolCommand = require('../../../commands/PromptXToolCommand')
|
||||
|
||||
module.exports = {
|
||||
@ -18,6 +17,5 @@ module.exports = {
|
||||
LearnCommand,
|
||||
RecallCommand,
|
||||
RememberCommand,
|
||||
DACPCommand,
|
||||
PromptXToolCommand
|
||||
}
|
||||
|
||||
@ -111,46 +111,6 @@ const TOOL_DEFINITIONS = [
|
||||
tags: z.string().optional().describe('自定义标签,用空格分隔,可选')
|
||||
})
|
||||
},
|
||||
{
|
||||
name: 'promptx_dacp',
|
||||
description: '🚀 [DACP专业服务工具] 专业执行工具 - 需要明确知道如何使用特定DACP服务时调用。工具存在但需要专业知识才能正确使用,不建议在不了解服务配置和参数的情况下尝试。',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
service_id: {
|
||||
type: 'string',
|
||||
description: 'DACP服务ID,如:dacp-email-service'
|
||||
},
|
||||
action: {
|
||||
type: 'string',
|
||||
description: '具体操作,如:send_email'
|
||||
},
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
user_request: {
|
||||
type: 'string',
|
||||
description: '用户自然语言需求'
|
||||
},
|
||||
context: {
|
||||
type: 'object',
|
||||
description: '上下文信息'
|
||||
}
|
||||
},
|
||||
required: ['user_request']
|
||||
}
|
||||
},
|
||||
required: ['service_id', 'action', 'parameters']
|
||||
},
|
||||
zodSchema: z.object({
|
||||
service_id: z.string().describe('DACP服务ID,如:dacp-email-service'),
|
||||
action: z.string().describe('具体操作,如:send_email'),
|
||||
parameters: z.object({
|
||||
user_request: z.string().describe('用户自然语言需求'),
|
||||
context: z.object({}).optional().describe('上下文信息')
|
||||
})
|
||||
})
|
||||
},
|
||||
{
|
||||
name: 'promptx_tool',
|
||||
description: '🔧 [工具执行器] 执行通过@tool协议声明的JavaScript工具 - 支持角色配置中定义的专业工具能力,如@tool://calculator数学计算、@tool://send-email邮件发送等。提供安全沙箱执行、参数验证、错误处理和性能监控。',
|
||||
|
||||
@ -1,360 +0,0 @@
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
const { getDirectoryService } = require('./DirectoryService')
|
||||
|
||||
/**
|
||||
* DACP配置管理器
|
||||
* 支持项目级配置优先,用户级配置回退的分层配置策略
|
||||
* 配置优先级:项目级(.promptx/dacp/) > 用户级(~/.promptx/dacp/)
|
||||
*/
|
||||
class DACPConfigManager {
|
||||
constructor() {
|
||||
this.userHome = os.homedir()
|
||||
this.userDacpConfigDir = path.join(this.userHome, '.promptx', 'dacp')
|
||||
this.directoryService = getDirectoryService()
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保用户级DACP配置目录存在
|
||||
*/
|
||||
async ensureUserConfigDir() {
|
||||
await fs.ensureDir(this.userDacpConfigDir)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目级DACP配置目录路径
|
||||
* @returns {Promise<string|null>} 项目级配置目录路径或null
|
||||
*/
|
||||
async getProjectConfigDir() {
|
||||
try {
|
||||
const promptxDir = await this.directoryService.getPromptXDirectory()
|
||||
return path.join(promptxDir, 'dacp')
|
||||
} catch (error) {
|
||||
console.warn('获取项目级配置目录失败:', error.message)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保项目级DACP配置目录存在
|
||||
* @returns {Promise<string|null>} 项目级配置目录路径或null
|
||||
*/
|
||||
async ensureProjectConfigDir() {
|
||||
const projectConfigDir = await this.getProjectConfigDir()
|
||||
if (projectConfigDir) {
|
||||
await fs.ensureDir(projectConfigDir)
|
||||
return projectConfigDir
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定action的用户级配置文件路径
|
||||
* @param {string} action - action名称,如 'send_email'
|
||||
* @returns {string} 用户级配置文件完整路径
|
||||
*/
|
||||
getUserConfigPath(action) {
|
||||
return path.join(this.userDacpConfigDir, `${action}.json`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定action的项目级配置文件路径
|
||||
* @param {string} action - action名称,如 'send_email'
|
||||
* @returns {Promise<string|null>} 项目级配置文件完整路径或null
|
||||
*/
|
||||
async getProjectConfigPath(action) {
|
||||
const projectConfigDir = await this.getProjectConfigDir()
|
||||
if (projectConfigDir) {
|
||||
return path.join(projectConfigDir, `${action}.json`)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定action的配置文件路径(用户级,向后兼容)
|
||||
* @param {string} action - action名称,如 'send_email'
|
||||
* @returns {string} 配置文件完整路径
|
||||
* @deprecated 使用getUserConfigPath或getProjectConfigPath
|
||||
*/
|
||||
getConfigPath(action) {
|
||||
return this.getUserConfigPath(action)
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取项目级action配置
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<Object|null>} 配置对象或null
|
||||
*/
|
||||
async readProjectActionConfig(action) {
|
||||
try {
|
||||
const projectConfigPath = await this.getProjectConfigPath(action)
|
||||
if (projectConfigPath && await fs.pathExists(projectConfigPath)) {
|
||||
const config = await fs.readJson(projectConfigPath)
|
||||
console.log(`📁 使用项目级DACP配置: ${action}`)
|
||||
return config
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`读取项目级DACP配置失败 ${action}:`, error.message)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取用户级action配置
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<Object|null>} 配置对象或null
|
||||
*/
|
||||
async readUserActionConfig(action) {
|
||||
const userConfigPath = this.getUserConfigPath(action)
|
||||
|
||||
try {
|
||||
if (await fs.pathExists(userConfigPath)) {
|
||||
const config = await fs.readJson(userConfigPath)
|
||||
console.log(`🏠 使用用户级DACP配置: ${action}`)
|
||||
return config
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`读取用户级DACP配置失败 ${action}:`, error.message)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取action配置(项目级优先,用户级回退)
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<Object|null>} 配置对象或null
|
||||
*/
|
||||
async readActionConfig(action) {
|
||||
// 优先级:项目级 > 用户级
|
||||
const projectConfig = await this.readProjectActionConfig(action)
|
||||
if (projectConfig) {
|
||||
return projectConfig
|
||||
}
|
||||
|
||||
return await this.readUserActionConfig(action)
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入用户级action配置
|
||||
* @param {string} action - action名称
|
||||
* @param {Object} config - 配置对象
|
||||
*/
|
||||
async writeUserActionConfig(action, config) {
|
||||
await this.ensureUserConfigDir()
|
||||
const configPath = this.getUserConfigPath(action)
|
||||
await fs.writeJson(configPath, config, { spaces: 2 })
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入项目级action配置
|
||||
* @param {string} action - action名称
|
||||
* @param {Object} config - 配置对象
|
||||
*/
|
||||
async writeProjectActionConfig(action, config) {
|
||||
const projectConfigDir = await this.ensureProjectConfigDir()
|
||||
if (projectConfigDir) {
|
||||
const configPath = path.join(projectConfigDir, `${action}.json`)
|
||||
await fs.writeJson(configPath, config, { spaces: 2 })
|
||||
} else {
|
||||
throw new Error('无法获取项目目录,写入项目级配置失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入action配置(向后兼容,写入用户级)
|
||||
* @param {string} action - action名称
|
||||
* @param {Object} config - 配置对象
|
||||
* @deprecated 使用writeUserActionConfig或writeProjectActionConfig
|
||||
*/
|
||||
async writeActionConfig(action, config) {
|
||||
return await this.writeUserActionConfig(action, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查项目级action配置是否存在
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async hasProjectActionConfig(action) {
|
||||
try {
|
||||
const projectConfigPath = await this.getProjectConfigPath(action)
|
||||
if (!projectConfigPath) {
|
||||
return false
|
||||
}
|
||||
return await fs.pathExists(projectConfigPath)
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户级action配置是否存在
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async hasUserActionConfig(action) {
|
||||
const userConfigPath = this.getUserConfigPath(action)
|
||||
return await fs.pathExists(userConfigPath)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查action配置是否存在(项目级或用户级)
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async hasActionConfig(action) {
|
||||
const hasProject = await this.hasProjectActionConfig(action)
|
||||
if (hasProject) {
|
||||
return true
|
||||
}
|
||||
return await this.hasUserActionConfig(action)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证邮件配置
|
||||
* @param {Object} config - 邮件配置对象
|
||||
* @returns {Object} 验证结果 {valid: boolean, errors: string[]}
|
||||
*/
|
||||
validateEmailConfig(config) {
|
||||
const errors = []
|
||||
|
||||
if (!config) {
|
||||
errors.push('配置对象不能为空')
|
||||
return { valid: false, errors }
|
||||
}
|
||||
|
||||
// 验证provider
|
||||
if (!config.provider) {
|
||||
errors.push('缺少邮件服务提供商(provider)配置')
|
||||
}
|
||||
|
||||
// 验证SMTP配置
|
||||
if (!config.smtp) {
|
||||
errors.push('缺少SMTP配置')
|
||||
} else {
|
||||
if (!config.smtp.user) {
|
||||
errors.push('缺少SMTP用户名(smtp.user)')
|
||||
}
|
||||
if (!config.smtp.password) {
|
||||
errors.push('缺少SMTP密码(smtp.password)')
|
||||
}
|
||||
}
|
||||
|
||||
// 验证发件人配置
|
||||
if (!config.sender) {
|
||||
errors.push('缺少发件人配置(sender)')
|
||||
} else {
|
||||
if (!config.sender.email) {
|
||||
errors.push('缺少发件人邮箱(sender.email)')
|
||||
}
|
||||
if (!config.sender.name) {
|
||||
errors.push('缺少发件人姓名(sender.name)')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
valid: errors.length === 0,
|
||||
errors
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取邮件服务提供商配置
|
||||
* @param {string} provider - 提供商名称
|
||||
* @returns {Object} 提供商配置
|
||||
*/
|
||||
getProviderConfig(provider) {
|
||||
const providers = {
|
||||
gmail: {
|
||||
smtp: 'smtp.gmail.com',
|
||||
port: 587,
|
||||
secure: false,
|
||||
requireAuth: true
|
||||
},
|
||||
outlook: {
|
||||
smtp: 'smtp-mail.outlook.com',
|
||||
port: 587,
|
||||
secure: false,
|
||||
requireAuth: true
|
||||
},
|
||||
qq: {
|
||||
smtp: 'smtp.qq.com',
|
||||
port: 465,
|
||||
secure: true,
|
||||
requireAuth: true
|
||||
},
|
||||
'163': {
|
||||
smtp: 'smtp.163.com',
|
||||
port: 465,
|
||||
secure: true,
|
||||
requireAuth: true
|
||||
},
|
||||
'126': {
|
||||
smtp: 'smtp.126.com',
|
||||
port: 465,
|
||||
secure: true,
|
||||
requireAuth: true
|
||||
}
|
||||
}
|
||||
|
||||
return providers[provider] || null
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成配置错误提示信息
|
||||
* @param {string} action - action名称
|
||||
* @param {Object} validation - 验证结果
|
||||
* @returns {Promise<string>} 错误提示信息
|
||||
*/
|
||||
async generateConfigErrorMessage(action, validation = null) {
|
||||
const userConfigPath = this.getUserConfigPath(action)
|
||||
const projectConfigPath = await this.getProjectConfigPath(action)
|
||||
|
||||
let message = `\n📧 DACP邮件服务配置缺失\n\n`
|
||||
|
||||
if (!validation) {
|
||||
// 配置文件不存在
|
||||
message += `❌ 未找到配置文件\n\n`
|
||||
message += `🔍 查找路径:\n`
|
||||
if (projectConfigPath) {
|
||||
message += ` 项目级: ${projectConfigPath} (优先)\n`
|
||||
}
|
||||
message += ` 用户级: ${userConfigPath} (回退)\n\n`
|
||||
message += `📝 推荐创建项目级配置文件,内容如下:\n\n`
|
||||
message += `{\n`
|
||||
message += ` "provider": "gmail",\n`
|
||||
message += ` "smtp": {\n`
|
||||
message += ` "user": "your-email@gmail.com",\n`
|
||||
message += ` "password": "your-app-password"\n`
|
||||
message += ` },\n`
|
||||
message += ` "sender": {\n`
|
||||
message += ` "name": "Your Name",\n`
|
||||
message += ` "email": "your-email@gmail.com"\n`
|
||||
message += ` }\n`
|
||||
message += `}\n\n`
|
||||
message += `💡 支持的邮件服务商: gmail, outlook, qq, 163, 126\n\n`
|
||||
message += `🏗️ 配置优先级: 项目级(.promptx/dacp/) > 用户级(~/.promptx/dacp/)\n\n`
|
||||
message += `🔐 Gmail用户需要使用应用专用密码:\n`
|
||||
message += ` 1. 进入 Google 账户设置\n`
|
||||
message += ` 2. 启用两步验证\n`
|
||||
message += ` 3. 生成应用专用密码\n`
|
||||
message += ` 4. 使用生成的密码替换上面的 "your-app-password"\n`
|
||||
} else {
|
||||
// 配置不完整
|
||||
const configLocation = await this.hasProjectActionConfig(action) ?
|
||||
(projectConfigPath ? `项目级: ${projectConfigPath}` : '项目级配置') :
|
||||
`用户级: ${userConfigPath}`
|
||||
message += `❌ 配置文件存在但不完整: ${configLocation}\n\n`
|
||||
message += `缺少以下配置项:\n`
|
||||
validation.errors.forEach(error => {
|
||||
message += ` • ${error}\n`
|
||||
})
|
||||
message += `\n请检查并完善配置文件。\n`
|
||||
}
|
||||
|
||||
return message
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DACPConfigManager
|
||||
@ -4,9 +4,9 @@
|
||||
"metadata": {
|
||||
"version": "2.0.0",
|
||||
"description": "package 级资源注册表",
|
||||
"createdAt": "2025-06-28T06:05:40.997Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.006Z",
|
||||
"resourceCount": 63
|
||||
"createdAt": "2025-06-28T06:22:37.206Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.216Z",
|
||||
"resourceCount": 61
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
@ -17,9 +17,9 @@
|
||||
"description": "专业角色,提供特定领域的专业能力",
|
||||
"reference": "@package://prompt/domain/assistant/assistant.role.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.000Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.000Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.000Z"
|
||||
"createdAt": "2025-06-28T06:22:37.211Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.211Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.211Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -30,9 +30,9 @@
|
||||
"description": "专业角色,提供特定领域的专业能力",
|
||||
"reference": "@package://prompt/domain/frontend-developer/frontend-developer.role.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.000Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.000Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.000Z"
|
||||
"createdAt": "2025-06-28T06:22:37.211Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.211Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.211Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -43,9 +43,9 @@
|
||||
"description": "专业角色,提供特定领域的专业能力",
|
||||
"reference": "@package://prompt/domain/java-backend-developer/java-backend-developer.role.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.000Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.000Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.000Z"
|
||||
"createdAt": "2025-06-28T06:22:37.211Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.211Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.211Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -56,9 +56,9 @@
|
||||
"description": "专业角色,提供特定领域的专业能力",
|
||||
"reference": "@package://prompt/domain/noface/noface.role.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.000Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.000Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.000Z"
|
||||
"createdAt": "2025-06-28T06:22:37.211Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.211Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.211Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -69,9 +69,9 @@
|
||||
"description": "专业角色,提供特定领域的专业能力",
|
||||
"reference": "@package://prompt/domain/nuwa/nuwa.role.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.000Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.000Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.000Z"
|
||||
"createdAt": "2025-06-28T06:22:37.211Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.211Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.211Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -82,9 +82,9 @@
|
||||
"description": "专业角色,提供特定领域的专业能力",
|
||||
"reference": "@package://prompt/domain/product-manager/product-manager.role.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.000Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.000Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.000Z"
|
||||
"createdAt": "2025-06-28T06:22:37.211Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.211Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.211Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -95,9 +95,9 @@
|
||||
"description": "专业角色,提供特定领域的专业能力",
|
||||
"reference": "@package://prompt/domain/sean/sean.role.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.000Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.000Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.000Z"
|
||||
"createdAt": "2025-06-28T06:22:37.211Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.211Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.211Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -108,35 +108,9 @@
|
||||
"description": "专业角色,提供特定领域的专业能力",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/xiaohongshu-marketer.role.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.000Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.000Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "dacp-email-sending",
|
||||
"source": "package",
|
||||
"protocol": "execution",
|
||||
"name": "Dacp Email Sending 执行模式",
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/core/dacp-email-sending.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "dacp-service-calling",
|
||||
"source": "package",
|
||||
"protocol": "execution",
|
||||
"name": "Dacp Service Calling 执行模式",
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/core/dacp-service-calling.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.211Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.211Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.211Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -147,9 +121,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/assistant/execution/assistant.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -160,9 +134,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/java-backend-developer/execution/code-quality.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -173,9 +147,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/frontend-developer/execution/frontend-developer.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -186,9 +160,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/frontend-developer/execution/technical-architecture.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -199,9 +173,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/frontend-developer/execution/user-experience.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -212,9 +186,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/frontend-developer/execution/wechat-miniprogram-development.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -225,9 +199,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/java-backend-developer/execution/database-design.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -238,9 +212,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/java-backend-developer/execution/java-backend-developer.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -251,9 +225,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/java-backend-developer/execution/spring-ecosystem.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -264,9 +238,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/java-backend-developer/execution/system-architecture.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -277,9 +251,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/noface/execution/adaptive-learning.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -290,9 +264,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/noface/execution/content-preservation.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -303,9 +277,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/nuwa/execution/dpml-authoring.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -316,9 +290,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/nuwa/execution/role-design-patterns.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -329,9 +303,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/nuwa/execution/role-generation.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -342,9 +316,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/nuwa/execution/visualization-enhancement.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -355,9 +329,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/product-manager/execution/market-analysis.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -368,9 +342,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/product-manager/execution/product-manager.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -381,9 +355,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/product-manager/execution/user-research.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -394,9 +368,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/sean/execution/contradiction-analysis.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -407,9 +381,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/sean/execution/contradiction-management-methodology.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -420,9 +394,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/sean/execution/sean-decision-framework.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -433,9 +407,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/sean/execution/template-adherence.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -446,9 +420,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/execution/brand-marketing.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -459,9 +433,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/execution/community-building.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -472,9 +446,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/execution/content-creation.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -485,9 +459,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/execution/content-optimization.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -498,9 +472,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/execution/data-analytics.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -511,9 +485,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/execution/ecommerce-conversion.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -524,9 +498,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/execution/performance-optimization.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -537,9 +511,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/execution/platform-compliance.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -550,9 +524,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/execution/team-collaboration.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -563,9 +537,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/execution/user-operation.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -576,9 +550,9 @@
|
||||
"description": "执行模式,定义具体的行为模式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/execution/xiaohongshu-marketer.execution.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.001Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.001Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.001Z"
|
||||
"createdAt": "2025-06-28T06:22:37.212Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.212Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.212Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -589,9 +563,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/core/_deprecated/recall_v1.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.002Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -602,9 +576,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/core/_deprecated/remember_v1.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -615,9 +589,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/core/recall-xml.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -628,9 +602,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/core/recall.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -641,9 +615,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/core/remember-xml.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -654,9 +628,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/core/remember.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -667,9 +641,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/domain/assistant/thought/assistant.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -680,9 +654,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/domain/frontend-developer/thought/frontend-developer.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -693,9 +667,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/domain/java-backend-developer/thought/java-backend-developer.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -706,9 +680,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/domain/nuwa/thought/role-creation.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -719,9 +693,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/domain/product-manager/thought/product-manager.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -732,9 +706,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/domain/sean/thought/contradiction-methodology.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -745,9 +719,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/domain/sean/thought/sean.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -758,9 +732,9 @@
|
||||
"description": "思维模式,指导AI的思考方式",
|
||||
"reference": "@package://prompt/domain/xiaohongshu-marketer/thought/xiaohongshu-marketer.thought.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.003Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.003Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.003Z"
|
||||
"createdAt": "2025-06-28T06:22:37.213Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.213Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.213Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -771,9 +745,9 @@
|
||||
"description": "知识库,提供专业知识和信息",
|
||||
"reference": "@package://prompt/domain/sean/knowledge/contradiction-methodology.knowledge.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.004Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.004Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.004Z"
|
||||
"createdAt": "2025-06-28T06:22:37.214Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.214Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.214Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -784,9 +758,9 @@
|
||||
"description": "知识库,提供专业知识和信息",
|
||||
"reference": "@package://prompt/domain/sean/knowledge/product-philosophy.knowledge.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.004Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.004Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.004Z"
|
||||
"createdAt": "2025-06-28T06:22:37.214Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.214Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.214Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -797,9 +771,9 @@
|
||||
"description": "知识库,提供专业知识和信息",
|
||||
"reference": "@package://prompt/domain/sean/knowledge/promptx-evolution.knowledge.md",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.004Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.004Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.004Z"
|
||||
"createdAt": "2025-06-28T06:22:37.214Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.214Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.214Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -810,9 +784,9 @@
|
||||
"description": "tool类型的资源",
|
||||
"reference": "@package://prompt/tool/calculator.tool.js",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.004Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.004Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.004Z"
|
||||
"createdAt": "2025-06-28T06:22:37.215Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.215Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.215Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -823,23 +797,23 @@
|
||||
"description": "tool类型的资源",
|
||||
"reference": "@package://prompt/tool/send-email.tool.js",
|
||||
"metadata": {
|
||||
"createdAt": "2025-06-28T06:05:41.005Z",
|
||||
"updatedAt": "2025-06-28T06:05:41.005Z",
|
||||
"scannedAt": "2025-06-28T06:05:41.005Z"
|
||||
"createdAt": "2025-06-28T06:22:37.216Z",
|
||||
"updatedAt": "2025-06-28T06:22:37.216Z",
|
||||
"scannedAt": "2025-06-28T06:22:37.216Z"
|
||||
}
|
||||
}
|
||||
],
|
||||
"stats": {
|
||||
"totalResources": 63,
|
||||
"totalResources": 61,
|
||||
"byProtocol": {
|
||||
"role": 8,
|
||||
"execution": 36,
|
||||
"execution": 34,
|
||||
"thought": 14,
|
||||
"knowledge": 3,
|
||||
"tool": 2
|
||||
},
|
||||
"bySource": {
|
||||
"package": 63
|
||||
"package": 61
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,268 +0,0 @@
|
||||
const DACPCommand = require('../../lib/core/pouch/commands/DACPCommand');
|
||||
|
||||
// Mock fetch
|
||||
global.fetch = jest.fn();
|
||||
|
||||
describe('DACPCommand', () => {
|
||||
let dacpCommand;
|
||||
|
||||
beforeEach(() => {
|
||||
dacpCommand = new DACPCommand();
|
||||
fetch.mockClear();
|
||||
});
|
||||
|
||||
describe('协议参数解析', () => {
|
||||
test('应该正确解析必需参数', () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '给张三发个邮件',
|
||||
context: { urgency: 'high' }
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => dacpCommand.validateArgs(args)).not.toThrow();
|
||||
});
|
||||
|
||||
test('应该拒绝缺少service_id的请求', () => {
|
||||
const args = {
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '给张三发个邮件'
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => dacpCommand.validateArgs(args))
|
||||
.toThrow('缺少必需参数: service_id');
|
||||
});
|
||||
|
||||
test('应该拒绝缺少action的请求', () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
parameters: {
|
||||
user_request: '给张三发个邮件'
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => dacpCommand.validateArgs(args))
|
||||
.toThrow('缺少必需参数: action');
|
||||
});
|
||||
|
||||
test('应该拒绝缺少parameters的请求', () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email'
|
||||
};
|
||||
|
||||
expect(() => dacpCommand.validateArgs(args))
|
||||
.toThrow('缺少必需参数: parameters');
|
||||
});
|
||||
|
||||
test('应该拒绝缺少user_request的请求', () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
context: { urgency: 'high' }
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => dacpCommand.validateArgs(args))
|
||||
.toThrow('缺少必需参数: parameters.user_request');
|
||||
});
|
||||
|
||||
test('应该允许可选的context参数', () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '给张三发个邮件'
|
||||
// context 是可选的
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => dacpCommand.validateArgs(args)).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('服务路由', () => {
|
||||
test('应该正确路由到已知服务', () => {
|
||||
expect(dacpCommand.getServiceEndpoint('dacp-email-service'))
|
||||
.toBe('http://localhost:3001/dacp');
|
||||
});
|
||||
|
||||
test('应该返回null对于未知服务', () => {
|
||||
expect(dacpCommand.getServiceEndpoint('unknown-service'))
|
||||
.toBeNull();
|
||||
});
|
||||
|
||||
test('应该支持多个服务路由', () => {
|
||||
expect(dacpCommand.getServiceEndpoint('dacp-calendar-service'))
|
||||
.toBe('http://localhost:3002/dacp');
|
||||
expect(dacpCommand.getServiceEndpoint('dacp-document-service'))
|
||||
.toBe('http://localhost:3003/dacp');
|
||||
});
|
||||
});
|
||||
|
||||
describe('DACP协议转发', () => {
|
||||
test('应该构造正确的DACP请求格式', async () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '给张三发个会议提醒邮件',
|
||||
context: { urgency: 'high' }
|
||||
}
|
||||
};
|
||||
|
||||
const mockResponse = {
|
||||
request_id: 'req_123',
|
||||
success: true,
|
||||
data: { execution_result: { status: 'sent' } }
|
||||
};
|
||||
|
||||
fetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => mockResponse
|
||||
});
|
||||
|
||||
const result = await dacpCommand.execute(args);
|
||||
|
||||
// 验证fetch调用参数
|
||||
expect(fetch).toHaveBeenCalledWith('http://localhost:3001/dacp', expect.objectContaining({
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
}));
|
||||
|
||||
// 单独验证body格式
|
||||
const requestBody = JSON.parse(fetch.mock.calls[0][1].body);
|
||||
expect(requestBody).toEqual({
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '给张三发个会议提醒邮件',
|
||||
context: { urgency: 'high' }
|
||||
},
|
||||
request_id: expect.stringMatching(/^req_\d+$/)
|
||||
});
|
||||
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
|
||||
test('应该自动生成request_id', async () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '测试邮件'
|
||||
}
|
||||
};
|
||||
|
||||
fetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({ success: true })
|
||||
});
|
||||
|
||||
await dacpCommand.execute(args);
|
||||
|
||||
const requestBody = JSON.parse(fetch.mock.calls[0][1].body);
|
||||
expect(requestBody.request_id).toMatch(/^req_\d+$/);
|
||||
});
|
||||
|
||||
test('应该处理网络错误', async () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '测试邮件'
|
||||
}
|
||||
};
|
||||
|
||||
fetch.mockRejectedValueOnce(new Error('网络连接失败'));
|
||||
|
||||
await expect(dacpCommand.execute(args))
|
||||
.rejects.toThrow('DACP服务调用失败: 网络连接失败');
|
||||
});
|
||||
|
||||
test('应该处理未知服务错误', async () => {
|
||||
const args = {
|
||||
service_id: 'unknown-service',
|
||||
action: 'some_action',
|
||||
parameters: {
|
||||
user_request: '测试请求'
|
||||
}
|
||||
};
|
||||
|
||||
await expect(dacpCommand.execute(args))
|
||||
.rejects.toThrow('未找到DACP服务: unknown-service');
|
||||
});
|
||||
|
||||
test('应该处理HTTP错误响应', async () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '测试邮件'
|
||||
}
|
||||
};
|
||||
|
||||
fetch.mockResolvedValueOnce({
|
||||
ok: false,
|
||||
status: 500,
|
||||
statusText: 'Internal Server Error',
|
||||
json: async () => ({
|
||||
success: false,
|
||||
error: { code: 'DACP_SERVICE_ERROR', message: '服务内部错误' }
|
||||
})
|
||||
});
|
||||
|
||||
const result = await dacpCommand.execute(args);
|
||||
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
error: { code: 'DACP_SERVICE_ERROR', message: '服务内部错误' }
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('错误处理', () => {
|
||||
test('应该返回标准错误格式', async () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '测试邮件'
|
||||
}
|
||||
};
|
||||
|
||||
fetch.mockRejectedValueOnce(new Error('Connection refused'));
|
||||
|
||||
try {
|
||||
await dacpCommand.execute(args);
|
||||
} catch (error) {
|
||||
expect(error.message).toBe('DACP服务调用失败: Connection refused');
|
||||
}
|
||||
});
|
||||
|
||||
test('应该处理JSON解析错误', async () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '测试邮件'
|
||||
}
|
||||
};
|
||||
|
||||
fetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => {
|
||||
throw new Error('Invalid JSON');
|
||||
}
|
||||
});
|
||||
|
||||
await expect(dacpCommand.execute(args))
|
||||
.rejects.toThrow('DACP响应解析失败: Invalid JSON');
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,77 +0,0 @@
|
||||
const DACPCommand = require('../../lib/core/pouch/commands/DACPCommand');
|
||||
|
||||
describe('DACP Calculator E2E Tests', () => {
|
||||
let dacpCommand;
|
||||
|
||||
beforeEach(() => {
|
||||
dacpCommand = new DACPCommand();
|
||||
});
|
||||
|
||||
test('should successfully calculate simple math expression', async () => {
|
||||
const result = await dacpCommand.execute({
|
||||
service_id: 'dacp-promptx-service',
|
||||
action: 'calculate',
|
||||
parameters: {
|
||||
user_request: '2加3等于多少'
|
||||
}
|
||||
});
|
||||
|
||||
// 验证DACP协议响应格式
|
||||
expect(result).toHaveProperty('request_id');
|
||||
expect(result).toHaveProperty('success', true);
|
||||
expect(result).toHaveProperty('data');
|
||||
|
||||
// 验证计算结果
|
||||
expect(result.data.execution_result).toMatchObject({
|
||||
expression: '2+3',
|
||||
result: 5,
|
||||
formatted_result: '2+3 = 5',
|
||||
calculation_type: 'addition'
|
||||
});
|
||||
});
|
||||
|
||||
test('should handle complex calculations', async () => {
|
||||
const result = await dacpCommand.execute({
|
||||
service_id: 'dacp-promptx-service',
|
||||
action: 'calculate',
|
||||
parameters: {
|
||||
user_request: '(10 + 5) * 2 - 8 / 4'
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.execution_result).toMatchObject({
|
||||
expression: '(10 + 5) * 2 - 8 / 4',
|
||||
result: 28,
|
||||
formatted_result: '(10 + 5) * 2 - 8 / 4 = 28'
|
||||
});
|
||||
});
|
||||
|
||||
test('should handle Chinese operators', async () => {
|
||||
const result = await dacpCommand.execute({
|
||||
service_id: 'dacp-promptx-service',
|
||||
action: 'calculate',
|
||||
parameters: {
|
||||
user_request: '100减去25再乘以2'
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
// 修正:计算器把它解析为 100-25*2 = 100-50 = 50
|
||||
expect(result.data.execution_result.result).toBe(50);
|
||||
});
|
||||
|
||||
test('should handle calculation errors gracefully', async () => {
|
||||
const result = await dacpCommand.execute({
|
||||
service_id: 'dacp-promptx-service',
|
||||
action: 'calculate',
|
||||
parameters: {
|
||||
user_request: '无效的表达式'
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result).toHaveProperty('error');
|
||||
expect(result.error.code).toBe('EXECUTION_ERROR');
|
||||
});
|
||||
});
|
||||
@ -1,122 +0,0 @@
|
||||
const PouchCLI = require('../../lib/core/pouch/PouchCLI');
|
||||
|
||||
describe('DACP Email Service E2E Tests', () => {
|
||||
let pouchCLI;
|
||||
|
||||
beforeEach(async () => {
|
||||
pouchCLI = new PouchCLI();
|
||||
await pouchCLI.initialize();
|
||||
});
|
||||
|
||||
test('应该能够调用真实的DACP邮件服务', async () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '给产品团队发送PromptX项目进展更新',
|
||||
context: {
|
||||
project: 'PromptX',
|
||||
urgency: 'medium',
|
||||
recipient_type: 'internal'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await pouchCLI.execute('dacp', args);
|
||||
|
||||
// 验证DACP响应格式
|
||||
expect(result).toHaveProperty('request_id');
|
||||
expect(result).toHaveProperty('success');
|
||||
|
||||
if (result.success) {
|
||||
expect(result).toHaveProperty('data');
|
||||
expect(result.data).toHaveProperty('execution_result');
|
||||
expect(result.data).toHaveProperty('evaluation');
|
||||
expect(result.data).toHaveProperty('applied_guidelines');
|
||||
expect(result.data).toHaveProperty('performance_metrics');
|
||||
|
||||
// 验证execution_result格式
|
||||
const { execution_result } = result.data;
|
||||
expect(execution_result).toHaveProperty('message_id');
|
||||
expect(execution_result).toHaveProperty('status');
|
||||
expect(execution_result).toHaveProperty('recipients');
|
||||
expect(execution_result).toHaveProperty('subject');
|
||||
expect(execution_result).toHaveProperty('body');
|
||||
|
||||
console.log('✅ DACP邮件服务调用成功:');
|
||||
console.log(` 📧 消息ID: ${execution_result.message_id}`);
|
||||
console.log(` 📬 状态: ${execution_result.status}`);
|
||||
console.log(` 📝 主题: ${execution_result.subject}`);
|
||||
console.log(` ⚡ 响应时间: ${result.data.performance_metrics.response_time}`);
|
||||
} else {
|
||||
console.log('❌ DACP邮件服务返回错误:', result.error);
|
||||
// 对于E2E测试,我们可能期望服务可用,所以这里可以fail
|
||||
// 但也可以选择跳过测试如果服务不可用
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
// 如果是连接错误,说明DACP邮件服务没有运行,跳过测试
|
||||
if (error.message.includes('fetch failed') ||
|
||||
error.message.includes('Connection refused') ||
|
||||
error.message.includes('ECONNREFUSED')) {
|
||||
console.log('⚠️ DACP邮件服务未运行,跳过E2E测试');
|
||||
console.log(' 启动服务命令: cd src/dacp/dacp-email-service && npm start');
|
||||
return; // 跳过测试而不是失败
|
||||
}
|
||||
|
||||
// 其他错误应该被报告
|
||||
throw error;
|
||||
}
|
||||
}, 10000); // 10秒超时
|
||||
|
||||
test('应该正确处理用户自然语言需求', async () => {
|
||||
const testCases = [
|
||||
{
|
||||
description: '会议提醒邮件',
|
||||
request: '给张三发个明天产品评审会议的提醒邮件',
|
||||
context: { urgency: 'high', recipient_type: 'internal' }
|
||||
},
|
||||
{
|
||||
description: '客户沟通邮件',
|
||||
request: '向客户汇报项目进展,包含最新的功能更新',
|
||||
context: { recipient_type: 'client', project: 'PromptX' }
|
||||
},
|
||||
{
|
||||
description: '团队通知邮件',
|
||||
request: '通知团队今晚系统维护,请提前保存工作',
|
||||
context: { urgency: 'high', recipient_type: 'internal' }
|
||||
}
|
||||
];
|
||||
|
||||
for (const testCase of testCases) {
|
||||
try {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: testCase.request,
|
||||
context: testCase.context
|
||||
}
|
||||
};
|
||||
|
||||
const result = await pouchCLI.execute('dacp', args);
|
||||
|
||||
if (result.success) {
|
||||
console.log(`✅ ${testCase.description} - 成功处理`);
|
||||
console.log(` 🎯 主题: ${result.data.execution_result.subject}`);
|
||||
console.log(` 📋 应用指导: ${result.data.applied_guidelines.join(', ')}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
if (error.message.includes('fetch failed') ||
|
||||
error.message.includes('Connection refused') ||
|
||||
error.message.includes('ECONNREFUSED')) {
|
||||
console.log(`⚠️ 跳过测试用例: ${testCase.description} (服务未运行)`);
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}, 15000); // 15秒超时
|
||||
});
|
||||
@ -1,141 +0,0 @@
|
||||
const PouchCLI = require('../../lib/core/pouch/PouchCLI');
|
||||
|
||||
// Mock fetch for DACP service calls
|
||||
global.fetch = jest.fn();
|
||||
|
||||
describe('DACP Integration Tests', () => {
|
||||
let pouchCLI;
|
||||
|
||||
beforeEach(async () => {
|
||||
pouchCLI = new PouchCLI();
|
||||
await pouchCLI.initialize();
|
||||
fetch.mockClear();
|
||||
});
|
||||
|
||||
test('应该能够通过PouchCLI调用DACP命令', async () => {
|
||||
const mockDACPResponse = {
|
||||
request_id: 'req_123',
|
||||
success: true,
|
||||
data: {
|
||||
execution_result: {
|
||||
message_id: 'msg_456',
|
||||
status: 'sent',
|
||||
recipients: ['demo@example.com'],
|
||||
subject: '会议通知',
|
||||
body: '您好,\n\n给张三发个会议提醒邮件\n\n此邮件由DACP邮件服务自动生成。'
|
||||
},
|
||||
evaluation: {
|
||||
criteria_met: true,
|
||||
quality_score: 95
|
||||
},
|
||||
applied_guidelines: [
|
||||
'HTML格式提升阅读体验',
|
||||
'专业邮件签名'
|
||||
],
|
||||
performance_metrics: {
|
||||
response_time: '150ms',
|
||||
delivery_rate: 100
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => mockDACPResponse
|
||||
});
|
||||
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '给张三发个会议提醒邮件',
|
||||
context: { urgency: 'high' }
|
||||
}
|
||||
};
|
||||
|
||||
const result = await pouchCLI.execute('dacp', args);
|
||||
|
||||
// 验证DACP服务被正确调用
|
||||
expect(fetch).toHaveBeenCalledWith('http://localhost:3001/dacp', expect.objectContaining({
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
}));
|
||||
|
||||
// 验证请求体格式
|
||||
const requestBody = JSON.parse(fetch.mock.calls[0][1].body);
|
||||
expect(requestBody).toEqual({
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '给张三发个会议提醒邮件',
|
||||
context: { urgency: 'high' }
|
||||
},
|
||||
request_id: expect.stringMatching(/^req_\d+$/)
|
||||
});
|
||||
|
||||
// 验证返回结果
|
||||
expect(result).toEqual(mockDACPResponse);
|
||||
});
|
||||
|
||||
test('应该正确处理DACP服务不可用的情况', async () => {
|
||||
fetch.mockRejectedValueOnce(new Error('Connection refused'));
|
||||
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
action: 'send_email',
|
||||
parameters: {
|
||||
user_request: '测试邮件'
|
||||
}
|
||||
};
|
||||
|
||||
await expect(pouchCLI.execute('dacp', args))
|
||||
.rejects.toThrow('DACP服务调用失败: Connection refused');
|
||||
});
|
||||
|
||||
test('应该正确处理未知DACP服务的情况', async () => {
|
||||
const args = {
|
||||
service_id: 'unknown-service',
|
||||
action: 'some_action',
|
||||
parameters: {
|
||||
user_request: '测试请求'
|
||||
}
|
||||
};
|
||||
|
||||
await expect(pouchCLI.execute('dacp', args))
|
||||
.rejects.toThrow('未找到DACP服务: unknown-service');
|
||||
});
|
||||
|
||||
test('应该正确处理参数验证错误', async () => {
|
||||
const args = {
|
||||
service_id: 'dacp-email-service',
|
||||
// 缺少action参数
|
||||
parameters: {
|
||||
user_request: '测试邮件'
|
||||
}
|
||||
};
|
||||
|
||||
await expect(pouchCLI.execute('dacp', args))
|
||||
.rejects.toThrow('缺少必需参数: action');
|
||||
});
|
||||
|
||||
test('应该支持多个DACP服务路由', async () => {
|
||||
const mockResponse = { success: true };
|
||||
fetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => mockResponse
|
||||
});
|
||||
|
||||
// 测试日程服务路由
|
||||
const args = {
|
||||
service_id: 'dacp-calendar-service',
|
||||
action: 'create_meeting',
|
||||
parameters: {
|
||||
user_request: '创建明天的会议'
|
||||
}
|
||||
};
|
||||
|
||||
await pouchCLI.execute('dacp', args);
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith('http://localhost:3002/dacp', expect.any(Object));
|
||||
});
|
||||
});
|
||||
@ -1,226 +0,0 @@
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
const DACPConfigManager = require('../../lib/utils/DACPConfigManager')
|
||||
|
||||
// Mock DirectoryService
|
||||
jest.mock('../../lib/utils/DirectoryService', () => ({
|
||||
getDirectoryService: () => ({
|
||||
getPromptXDirectory: jest.fn()
|
||||
})
|
||||
}))
|
||||
|
||||
const { getDirectoryService } = require('../../lib/utils/DirectoryService')
|
||||
|
||||
describe('DACPConfigManager - 项目级配置优先', () => {
|
||||
let configManager
|
||||
let mockDirectoryService
|
||||
let tempDir
|
||||
let userConfigDir
|
||||
let projectConfigDir
|
||||
|
||||
beforeEach(async () => {
|
||||
// 创建临时测试目录
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'dacp-config-test-'))
|
||||
userConfigDir = path.join(tempDir, 'user', '.promptx', 'dacp')
|
||||
projectConfigDir = path.join(tempDir, 'project', '.promptx', 'dacp')
|
||||
|
||||
// 确保目录存在
|
||||
await fs.ensureDir(userConfigDir)
|
||||
await fs.ensureDir(projectConfigDir)
|
||||
|
||||
// Mock DirectoryService
|
||||
mockDirectoryService = getDirectoryService()
|
||||
mockDirectoryService.getPromptXDirectory.mockResolvedValue(path.join(tempDir, 'project', '.promptx'))
|
||||
|
||||
// 创建配置管理器
|
||||
configManager = new DACPConfigManager()
|
||||
|
||||
// Mock用户目录
|
||||
configManager.userDacpConfigDir = userConfigDir
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
// 清理临时目录
|
||||
await fs.remove(tempDir)
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('配置读取优先级', () => {
|
||||
test('应该优先读取项目级配置', async () => {
|
||||
const projectConfig = {
|
||||
provider: 'gmail',
|
||||
smtp: { user: 'project@gmail.com', password: 'project-pass' },
|
||||
sender: { name: 'Project User', email: 'project@gmail.com' }
|
||||
}
|
||||
|
||||
const userConfig = {
|
||||
provider: 'outlook',
|
||||
smtp: { user: 'user@outlook.com', password: 'user-pass' },
|
||||
sender: { name: 'User Name', email: 'user@outlook.com' }
|
||||
}
|
||||
|
||||
// 写入两个配置文件
|
||||
await fs.writeJson(path.join(projectConfigDir, 'send_email.json'), projectConfig)
|
||||
await fs.writeJson(path.join(userConfigDir, 'send_email.json'), userConfig)
|
||||
|
||||
const result = await configManager.readActionConfig('send_email')
|
||||
|
||||
expect(result).toEqual(projectConfig)
|
||||
expect(result.smtp.user).toBe('project@gmail.com')
|
||||
})
|
||||
|
||||
test('项目级配置不存在时应该回退到用户级配置', async () => {
|
||||
const userConfig = {
|
||||
provider: 'outlook',
|
||||
smtp: { user: 'user@outlook.com', password: 'user-pass' },
|
||||
sender: { name: 'User Name', email: 'user@outlook.com' }
|
||||
}
|
||||
|
||||
// 只写入用户级配置
|
||||
await fs.writeJson(path.join(userConfigDir, 'send_email.json'), userConfig)
|
||||
|
||||
const result = await configManager.readActionConfig('send_email')
|
||||
|
||||
expect(result).toEqual(userConfig)
|
||||
expect(result.smtp.user).toBe('user@outlook.com')
|
||||
})
|
||||
|
||||
test('两个配置都不存在时应该返回null', async () => {
|
||||
const result = await configManager.readActionConfig('send_email')
|
||||
expect(result).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('配置存在性检查', () => {
|
||||
test('hasActionConfig应该检查项目级和用户级配置', async () => {
|
||||
// 无配置时
|
||||
expect(await configManager.hasActionConfig('send_email')).toBe(false)
|
||||
|
||||
// 仅用户级配置时
|
||||
await fs.writeJson(path.join(userConfigDir, 'send_email.json'), {})
|
||||
expect(await configManager.hasActionConfig('send_email')).toBe(true)
|
||||
|
||||
// 同时存在项目级配置时
|
||||
await fs.writeJson(path.join(projectConfigDir, 'send_email.json'), {})
|
||||
expect(await configManager.hasActionConfig('send_email')).toBe(true)
|
||||
})
|
||||
|
||||
test('hasProjectActionConfig应该正确检查项目级配置', async () => {
|
||||
expect(await configManager.hasProjectActionConfig('send_email')).toBe(false)
|
||||
|
||||
await fs.writeJson(path.join(projectConfigDir, 'send_email.json'), {})
|
||||
expect(await configManager.hasProjectActionConfig('send_email')).toBe(true)
|
||||
})
|
||||
|
||||
test('hasUserActionConfig应该正确检查用户级配置', async () => {
|
||||
expect(await configManager.hasUserActionConfig('send_email')).toBe(false)
|
||||
|
||||
await fs.writeJson(path.join(userConfigDir, 'send_email.json'), {})
|
||||
expect(await configManager.hasUserActionConfig('send_email')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('配置写入', () => {
|
||||
test('writeProjectActionConfig应该写入项目级配置', async () => {
|
||||
const config = {
|
||||
provider: 'gmail',
|
||||
smtp: { user: 'test@gmail.com', password: 'test-pass' },
|
||||
sender: { name: 'Test User', email: 'test@gmail.com' }
|
||||
}
|
||||
|
||||
await configManager.writeProjectActionConfig('send_email', config)
|
||||
|
||||
const projectConfigPath = path.join(projectConfigDir, 'send_email.json')
|
||||
expect(await fs.pathExists(projectConfigPath)).toBe(true)
|
||||
|
||||
const savedConfig = await fs.readJson(projectConfigPath)
|
||||
expect(savedConfig).toEqual(config)
|
||||
})
|
||||
|
||||
test('writeUserActionConfig应该写入用户级配置', async () => {
|
||||
const config = {
|
||||
provider: 'outlook',
|
||||
smtp: { user: 'test@outlook.com', password: 'test-pass' },
|
||||
sender: { name: 'Test User', email: 'test@outlook.com' }
|
||||
}
|
||||
|
||||
await configManager.writeUserActionConfig('send_email', config)
|
||||
|
||||
const userConfigPath = path.join(userConfigDir, 'send_email.json')
|
||||
expect(await fs.pathExists(userConfigPath)).toBe(true)
|
||||
|
||||
const savedConfig = await fs.readJson(userConfigPath)
|
||||
expect(savedConfig).toEqual(config)
|
||||
})
|
||||
})
|
||||
|
||||
describe('向后兼容性', () => {
|
||||
test('原有API方法应该保持兼容', async () => {
|
||||
const config = {
|
||||
provider: 'gmail',
|
||||
smtp: { user: 'legacy@gmail.com', password: 'legacy-pass' },
|
||||
sender: { name: 'Legacy User', email: 'legacy@gmail.com' }
|
||||
}
|
||||
|
||||
// writeActionConfig应该写入用户级配置
|
||||
await configManager.writeActionConfig('send_email', config)
|
||||
|
||||
const userConfigPath = path.join(userConfigDir, 'send_email.json')
|
||||
expect(await fs.pathExists(userConfigPath)).toBe(true)
|
||||
|
||||
// getConfigPath应该返回用户级路径
|
||||
expect(configManager.getConfigPath('send_email')).toBe(userConfigPath)
|
||||
})
|
||||
})
|
||||
|
||||
describe('错误处理', () => {
|
||||
test('DirectoryService失败时应该优雅降级', async () => {
|
||||
// Mock DirectoryService抛出错误
|
||||
mockDirectoryService.getPromptXDirectory.mockRejectedValue(new Error('项目目录不存在'))
|
||||
|
||||
const userConfig = {
|
||||
provider: 'gmail',
|
||||
smtp: { user: 'user@gmail.com', password: 'user-pass' },
|
||||
sender: { name: 'User', email: 'user@gmail.com' }
|
||||
}
|
||||
|
||||
await fs.writeJson(path.join(userConfigDir, 'send_email.json'), userConfig)
|
||||
|
||||
// 应该能够回退到用户级配置
|
||||
const result = await configManager.readActionConfig('send_email')
|
||||
expect(result).toEqual(userConfig)
|
||||
})
|
||||
|
||||
test('项目目录不可写时writeProjectActionConfig应该抛出错误', async () => {
|
||||
mockDirectoryService.getPromptXDirectory.mockRejectedValue(new Error('无法获取项目目录'))
|
||||
|
||||
const config = { provider: 'gmail' }
|
||||
|
||||
await expect(configManager.writeProjectActionConfig('send_email', config))
|
||||
.rejects.toThrow('无法获取项目目录,写入项目级配置失败')
|
||||
})
|
||||
})
|
||||
|
||||
describe('配置错误提示信息', () => {
|
||||
test('应该生成包含项目级和用户级路径的错误信息', async () => {
|
||||
const errorMessage = await configManager.generateConfigErrorMessage('send_email')
|
||||
|
||||
expect(errorMessage).toContain('DACP邮件服务配置缺失')
|
||||
expect(errorMessage).toContain('项目级:')
|
||||
expect(errorMessage).toContain('用户级:')
|
||||
expect(errorMessage).toContain('配置优先级: 项目级(.promptx/dacp/) > 用户级(~/.promptx/dacp/)')
|
||||
})
|
||||
|
||||
test('应该正确标识当前使用的配置级别', async () => {
|
||||
const validation = { valid: false, errors: ['缺少SMTP配置'] }
|
||||
|
||||
// 创建项目级配置
|
||||
await fs.writeJson(path.join(projectConfigDir, 'send_email.json'), {})
|
||||
|
||||
const errorMessage = await configManager.generateConfigErrorMessage('send_email', validation)
|
||||
expect(errorMessage).toContain('项目级:')
|
||||
expect(errorMessage).toContain('缺少以下配置项')
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user