🎯 PromptX v0.0.1 完整实现 - 五大锦囊命令、AI记忆系统、角色系统、PATEOAS状态机、DPML协议全部完成
This commit is contained in:
@ -1,31 +0,0 @@
|
||||
const chalk = require('chalk');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
/**
|
||||
* promptx hello 命令
|
||||
* 系统入口 - AI助手接待用户并展示可用角色
|
||||
*/
|
||||
async function helloCommand(options) {
|
||||
try {
|
||||
logger.step('PromptX Hello - 系统初始化中...');
|
||||
|
||||
// TODO: 实现在任务 2.1 中
|
||||
console.log(chalk.cyan(`
|
||||
🎯 PromptX 系统入口
|
||||
|
||||
${chalk.yellow('功能:')} AI助手接待用户并展示可用角色
|
||||
${chalk.yellow('状态:')} 待实现 (任务 2.1)
|
||||
|
||||
${chalk.green('下一步:')}
|
||||
请执行任务 2.1 来实现完整的 hello 命令功能
|
||||
`));
|
||||
|
||||
logger.info('Hello命令框架已就绪,等待具体实现');
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Hello命令执行失败:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = helloCommand;
|
||||
@ -1,185 +0,0 @@
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const chalk = require('chalk');
|
||||
|
||||
/**
|
||||
* promptx init 命令
|
||||
* 在用户项目中初始化PromptX集成
|
||||
*/
|
||||
async function init(options = {}) {
|
||||
console.log(chalk.blue.bold('🚀 初始化 PromptX 项目集成...\n'));
|
||||
|
||||
try {
|
||||
const projectRoot = process.cwd();
|
||||
const promptxDir = path.join(projectRoot, '.promptx');
|
||||
const memoryDir = path.join(promptxDir, 'memory');
|
||||
|
||||
// 检查是否已经初始化
|
||||
try {
|
||||
await fs.access(promptxDir);
|
||||
console.log(chalk.yellow('⚠️ 项目已经初始化过 PromptX 集成'));
|
||||
console.log(chalk.gray(` .promptx 目录已存在: ${promptxDir}`));
|
||||
|
||||
if (!options.force) {
|
||||
console.log(chalk.gray(' 使用 --force 参数强制重新初始化'));
|
||||
return;
|
||||
}
|
||||
console.log(chalk.blue('🔄 强制重新初始化...'));
|
||||
} catch (error) {
|
||||
// 目录不存在,继续初始化
|
||||
}
|
||||
|
||||
// 创建 .promptx 目录
|
||||
await fs.mkdir(promptxDir, { recursive: true });
|
||||
console.log(chalk.green('✅ 创建 .promptx 目录'));
|
||||
|
||||
// 创建 .promptx/memory 目录
|
||||
await fs.mkdir(memoryDir, { recursive: true });
|
||||
console.log(chalk.green('✅ 创建 memory 目录'));
|
||||
|
||||
// 创建基础记忆文件
|
||||
const memoryFiles = [
|
||||
{
|
||||
name: 'declarative.md',
|
||||
content: `# 声明式记忆
|
||||
|
||||
## 项目重要信息
|
||||
- 项目初始化时间: ${new Date().toISOString()}
|
||||
- PromptX 集成状态: ✅ 已完成
|
||||
|
||||
## 使用说明
|
||||
在这里记录项目的重要决策、配置信息和关键知识点。
|
||||
|
||||
### 示例条目
|
||||
**时间**: 2024-01-01T00:00:00.000Z
|
||||
**重要性**: 8/10
|
||||
**内容**: 项目使用 PromptX 进行 AI 助手集成
|
||||
**有效期**: 长期
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'episodic.md',
|
||||
content: `# 情景记忆
|
||||
|
||||
## 项目历程记录
|
||||
记录项目开发过程中的重要事件和里程碑。
|
||||
|
||||
### 项目初始化
|
||||
- **时间**: ${new Date().toISOString()}
|
||||
- **事件**: PromptX 集成初始化完成
|
||||
- **详情**: 使用 \`promptx init\` 命令完成项目集成设置
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'procedural.md',
|
||||
content: `# 程序记忆
|
||||
|
||||
## 项目工作流程
|
||||
|
||||
### PromptX 使用流程
|
||||
1. **学习阶段**: \`promptx learn <resource>\`
|
||||
2. **记忆保存**: \`promptx remember <content>\`
|
||||
3. **记忆检索**: \`promptx recall\`
|
||||
4. **助手切换**: \`promptx hello\`
|
||||
|
||||
### 项目开发流程
|
||||
在这里记录项目特有的开发流程和最佳实践。
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'semantic.md',
|
||||
content: `# 语义记忆
|
||||
|
||||
## 项目知识图谱
|
||||
|
||||
### PromptX 协议体系
|
||||
- **@project://**: 指向当前项目根目录
|
||||
- **@memory://**: 指向项目记忆系统
|
||||
- **@package://**: 指向 PromptX 包资源
|
||||
- **@prompt://**: 指向提示词资源
|
||||
|
||||
### 项目特定概念
|
||||
在这里定义项目中的重要概念和术语。
|
||||
`
|
||||
}
|
||||
];
|
||||
|
||||
for (const file of memoryFiles) {
|
||||
const filePath = path.join(memoryDir, file.name);
|
||||
await fs.writeFile(filePath, file.content, 'utf8');
|
||||
console.log(chalk.green(`✅ 创建记忆文件: ${file.name}`));
|
||||
}
|
||||
|
||||
// 创建 .promptx/config.json 配置文件
|
||||
const config = {
|
||||
version: "0.0.1",
|
||||
initialized: new Date().toISOString(),
|
||||
settings: {
|
||||
memoryPath: "memory",
|
||||
defaultRole: null,
|
||||
autoRemember: false
|
||||
},
|
||||
protocols: {
|
||||
project: {
|
||||
root: ".",
|
||||
identifiers: [".promptx", "package.json", ".git"]
|
||||
},
|
||||
memory: {
|
||||
types: ["declarative", "episodic", "procedural", "semantic"]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const configPath = path.join(promptxDir, 'config.json');
|
||||
await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf8');
|
||||
console.log(chalk.green('✅ 创建配置文件: config.json'));
|
||||
|
||||
// 创建 .gitignore (如果需要)
|
||||
const gitignorePath = path.join(projectRoot, '.gitignore');
|
||||
try {
|
||||
let gitignoreContent = '';
|
||||
try {
|
||||
gitignoreContent = await fs.readFile(gitignorePath, 'utf8');
|
||||
} catch (error) {
|
||||
// .gitignore 不存在
|
||||
}
|
||||
|
||||
if (!gitignoreContent.includes('.promptx')) {
|
||||
const appendContent = gitignoreContent.length > 0 ? '\n# PromptX\n.promptx/config.json\n' : '# PromptX\n.promptx/config.json\n';
|
||||
await fs.appendFile(gitignorePath, appendContent, 'utf8');
|
||||
console.log(chalk.green('✅ 更新 .gitignore 文件'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(chalk.yellow('⚠️ 无法更新 .gitignore 文件'));
|
||||
}
|
||||
|
||||
// 完成提示
|
||||
console.log(chalk.green.bold('\n🎉 PromptX 项目集成初始化完成!\n'));
|
||||
|
||||
console.log(chalk.blue('📁 创建的文件结构:'));
|
||||
console.log(chalk.gray(' .promptx/'));
|
||||
console.log(chalk.gray(' ├── config.json'));
|
||||
console.log(chalk.gray(' └── memory/'));
|
||||
console.log(chalk.gray(' ├── declarative.md'));
|
||||
console.log(chalk.gray(' ├── episodic.md'));
|
||||
console.log(chalk.gray(' ├── procedural.md'));
|
||||
console.log(chalk.gray(' └── semantic.md'));
|
||||
|
||||
console.log(chalk.blue('\n🚀 可用的协议:'));
|
||||
console.log(chalk.gray(' @project:// - 访问项目文件'));
|
||||
console.log(chalk.gray(' @memory:// - 访问项目记忆'));
|
||||
console.log(chalk.gray(' @prompt:// - 访问提示词资源'));
|
||||
|
||||
console.log(chalk.blue('\n🎯 下一步:'));
|
||||
console.log(chalk.gray(' 1. 使用 promptx hello 选择 AI 角色'));
|
||||
console.log(chalk.gray(' 2. 使用 promptx learn 学习项目知识'));
|
||||
console.log(chalk.gray(' 3. 使用 promptx remember 保存重要信息'));
|
||||
console.log(chalk.gray(' 4. 使用 promptx recall 检索记忆内容'));
|
||||
|
||||
} catch (error) {
|
||||
console.error(chalk.red('❌ 初始化失败:'), error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = init;
|
||||
@ -1,35 +0,0 @@
|
||||
const chalk = require('chalk');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
/**
|
||||
* promptx learn 命令
|
||||
* 学习命令 - AI获取和理解提示词内容
|
||||
*/
|
||||
async function learnCommand(resource, options) {
|
||||
try {
|
||||
logger.step(`学习资源: ${resource}`);
|
||||
|
||||
// TODO: 实现在任务 2.2 中
|
||||
console.log(chalk.blue(`
|
||||
📚 PromptX Learn 命令
|
||||
|
||||
${chalk.yellow('资源:')} ${resource}
|
||||
${chalk.yellow('格式:')} ${options.format}
|
||||
${chalk.yellow('状态:')} 待实现 (任务 2.2)
|
||||
|
||||
${chalk.green('计划功能:')}
|
||||
- 支持打包参数 (protocols, core, domain)
|
||||
- 支持具体文件路径
|
||||
- 替代现有 node promptx.js 功能
|
||||
- 向后兼容现有AI bootstrap流程
|
||||
`));
|
||||
|
||||
logger.info('Learn命令框架已就绪,等待具体实现');
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Learn命令执行失败:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = learnCommand;
|
||||
@ -1,36 +0,0 @@
|
||||
const chalk = require('chalk');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
/**
|
||||
* promptx recall 命令
|
||||
* 记忆检索 - AI回忆和检索记忆内容
|
||||
*/
|
||||
async function recallCommand(options) {
|
||||
try {
|
||||
logger.step('检索记忆内容...');
|
||||
|
||||
// TODO: 实现在任务 2.3 中
|
||||
console.log(chalk.green(`
|
||||
🔍 PromptX Recall 命令
|
||||
|
||||
${chalk.yellow('选项:')}
|
||||
- 最近记忆: ${options.recent || false}
|
||||
- 重要记忆: ${options.important || false}
|
||||
- 限制数量: ${options.limit}
|
||||
${chalk.yellow('状态:')} 待实现 (任务 2.3)
|
||||
|
||||
${chalk.green('计划功能:')}
|
||||
- 读取 .memory/declarative.md 文件
|
||||
- 基础筛选功能 (--recent, --important)
|
||||
- 为未来高级记忆体系打基础
|
||||
`));
|
||||
|
||||
logger.info('Recall命令框架已就绪,等待具体实现');
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Recall命令执行失败:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = recallCommand;
|
||||
@ -1,36 +0,0 @@
|
||||
const chalk = require('chalk');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
/**
|
||||
* promptx remember 命令
|
||||
* 记忆保存 - AI保存重要信息和经验
|
||||
*/
|
||||
async function rememberCommand(content, options) {
|
||||
try {
|
||||
logger.step('保存记忆中...');
|
||||
|
||||
// TODO: 实现在任务 2.4 中
|
||||
console.log(chalk.magenta(`
|
||||
🧠 PromptX Remember 命令
|
||||
|
||||
${chalk.yellow('内容:')} ${content}
|
||||
${chalk.yellow('评分:')} ${options.score}
|
||||
${chalk.yellow('有效期:')} ${options.duration}
|
||||
${chalk.yellow('状态:')} 待实现 (任务 2.4)
|
||||
|
||||
${chalk.green('计划功能:')}
|
||||
- 写入 .memory/declarative.md 文件
|
||||
- 结构化参数设计 (--score, --duration)
|
||||
- 替代复杂标签系统
|
||||
- 支持智能默认值
|
||||
`));
|
||||
|
||||
logger.info('Remember命令框架已就绪,等待具体实现');
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Remember命令执行失败:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = rememberCommand;
|
||||
57
src/lib/core/pouch/.promptx.json
Normal file
57
src/lib/core/pouch/.promptx.json
Normal file
@ -0,0 +1,57 @@
|
||||
{
|
||||
"version": "0.0.1",
|
||||
"initialized": "2025-05-31T06:15:39.372Z",
|
||||
"defaultFormat": "human",
|
||||
"stateHistory": [
|
||||
{
|
||||
"from": "initial",
|
||||
"to": "init",
|
||||
"timestamp": "2025-05-31T06:15:39.370Z",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"from": "init",
|
||||
"to": "hello",
|
||||
"timestamp": "2025-05-31T06:15:39.373Z",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"from": "hello",
|
||||
"command": "init",
|
||||
"timestamp": "2025-05-31T06:16:28.040Z",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"from": "initialized",
|
||||
"command": "hello",
|
||||
"timestamp": "2025-05-31T06:16:28.042Z",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"from": "discovering",
|
||||
"command": "action",
|
||||
"timestamp": "2025-05-31T06:16:28.042Z",
|
||||
"args": [
|
||||
"copywriter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"from": "activated-copywriter",
|
||||
"command": "learn",
|
||||
"timestamp": "2025-05-31T06:16:28.046Z",
|
||||
"args": [
|
||||
"scrum"
|
||||
]
|
||||
},
|
||||
{
|
||||
"from": "learned-scrum",
|
||||
"command": "recall",
|
||||
"timestamp": "2025-05-31T06:16:28.047Z",
|
||||
"args": [
|
||||
"test"
|
||||
]
|
||||
}
|
||||
],
|
||||
"currentState": "recalled-test",
|
||||
"lastUpdated": "2025-05-31T06:16:28.047Z"
|
||||
}
|
||||
120
src/lib/core/pouch/BasePouchCommand.js
Normal file
120
src/lib/core/pouch/BasePouchCommand.js
Normal file
@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 基础锦囊命令抽象类
|
||||
* 所有锦囊命令都需要继承此类
|
||||
*/
|
||||
class BasePouchCommand {
|
||||
constructor() {
|
||||
this.context = {
|
||||
currentPouch: '',
|
||||
history: [],
|
||||
userProfile: {},
|
||||
sessionData: {},
|
||||
domainContext: {}
|
||||
};
|
||||
this.outputFormat = 'human';
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行锦囊命令
|
||||
* @param {Array} args - 命令参数
|
||||
* @returns {Promise<PouchOutput>} 锦囊输出
|
||||
*/
|
||||
async execute(args = []) {
|
||||
const purpose = this.getPurpose();
|
||||
const content = await this.getContent(args);
|
||||
const pateoas = this.getPATEOAS(args);
|
||||
|
||||
return this.formatOutput(purpose, content, pateoas);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置状态上下文
|
||||
* @param {StateContext} context - 状态上下文
|
||||
*/
|
||||
setContext(context) {
|
||||
this.context = { ...this.context, ...context };
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置输出格式
|
||||
* @param {'human'|'json'} format - 输出格式
|
||||
*/
|
||||
setOutputFormat(format) {
|
||||
this.outputFormat = format;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取锦囊目的说明(子类必须实现)
|
||||
* @returns {string} 目的说明
|
||||
*/
|
||||
getPurpose() {
|
||||
throw new Error('子类必须实现 getPurpose 方法');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取锦囊内容(子类必须实现)
|
||||
* @param {Array} args - 命令参数
|
||||
* @returns {Promise<string>} 锦囊内容
|
||||
*/
|
||||
async getContent(args) {
|
||||
throw new Error('子类必须实现 getContent 方法');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取PATEOAS导航信息(子类必须实现)
|
||||
* @param {Array} args - 命令参数
|
||||
* @returns {PATEOASNavigation} PATEOAS导航
|
||||
*/
|
||||
getPATEOAS(args) {
|
||||
throw new Error('子类必须实现 getPATEOAS 方法');
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化输出
|
||||
* @param {string} purpose - 目的说明
|
||||
* @param {string} content - 内容
|
||||
* @param {PATEOASNavigation} pateoas - PATEOAS导航
|
||||
* @returns {PouchOutput} 格式化的输出
|
||||
*/
|
||||
formatOutput(purpose, content, pateoas) {
|
||||
const output = {
|
||||
purpose,
|
||||
content,
|
||||
pateoas,
|
||||
context: this.context,
|
||||
format: this.outputFormat
|
||||
};
|
||||
|
||||
if (this.outputFormat === 'json') {
|
||||
return output;
|
||||
}
|
||||
|
||||
// 人类可读格式
|
||||
return {
|
||||
...output,
|
||||
toString() {
|
||||
const divider = '='.repeat(60);
|
||||
const nextSteps = pateoas.nextActions
|
||||
.map(action => ` - ${action.name}: ${action.description}\n 命令: ${action.command}`)
|
||||
.join('\n');
|
||||
|
||||
return `
|
||||
${divider}
|
||||
🎯 锦囊目的:${purpose}
|
||||
${divider}
|
||||
|
||||
📜 锦囊内容:
|
||||
${content}
|
||||
|
||||
🔄 下一步行动:
|
||||
${nextSteps}
|
||||
|
||||
📍 当前状态:${pateoas.currentState}
|
||||
${divider}
|
||||
`;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BasePouchCommand;
|
||||
200
src/lib/core/pouch/PouchCLI.js
Normal file
200
src/lib/core/pouch/PouchCLI.js
Normal file
@ -0,0 +1,200 @@
|
||||
const PouchStateMachine = require('./state/PouchStateMachine');
|
||||
const PouchRegistry = require('./PouchRegistry');
|
||||
const commands = require('./commands');
|
||||
|
||||
/**
|
||||
* 锦囊CLI主入口
|
||||
* 提供命令行接口和统一的执行入口
|
||||
*/
|
||||
class PouchCLI {
|
||||
constructor() {
|
||||
this.stateMachine = new PouchStateMachine();
|
||||
this.registry = new PouchRegistry();
|
||||
this.initialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化CLI
|
||||
*/
|
||||
async initialize() {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 批量注册所有命令
|
||||
this.registry.registerBatch({
|
||||
init: commands.InitCommand,
|
||||
hello: commands.HelloCommand,
|
||||
action: commands.ActionCommand,
|
||||
learn: commands.LearnCommand,
|
||||
recall: commands.RecallCommand,
|
||||
remember: commands.RememberCommand
|
||||
});
|
||||
|
||||
// 将命令注册到状态机
|
||||
for (const name of this.registry.list()) {
|
||||
const command = this.registry.get(name);
|
||||
this.stateMachine.registerCommand(name, command);
|
||||
}
|
||||
|
||||
// 加载历史状态
|
||||
await this.stateMachine.loadState();
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令
|
||||
* @param {string} commandName - 命令名称
|
||||
* @param {Array} args - 命令参数
|
||||
* @returns {Promise<PouchOutput>} 执行结果
|
||||
*/
|
||||
async execute(commandName, args = []) {
|
||||
// 确保已初始化
|
||||
if (!this.initialized) {
|
||||
await this.initialize();
|
||||
}
|
||||
|
||||
// 验证命令是否存在
|
||||
if (!this.registry.validate(commandName)) {
|
||||
throw new Error(`未知命令: ${commandName}\n使用 'promptx help' 查看可用命令`);
|
||||
}
|
||||
|
||||
try {
|
||||
// 通过状态机执行命令
|
||||
const result = await this.stateMachine.transition(commandName, args);
|
||||
|
||||
// 如果结果有 toString 方法,打印人类可读格式
|
||||
if (result && result.toString && typeof result.toString === 'function') {
|
||||
console.log(result.toString());
|
||||
} else {
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(`执行命令出错: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取帮助信息
|
||||
* @returns {string} 帮助文本
|
||||
*/
|
||||
getHelp() {
|
||||
const commands = this.registry.getCommandDetails();
|
||||
const currentState = this.stateMachine.getCurrentState();
|
||||
const availableTransitions = this.stateMachine.getAvailableTransitions();
|
||||
|
||||
let help = `
|
||||
🎯 PromptX 锦囊系统帮助
|
||||
========================
|
||||
|
||||
当前状态: ${currentState}
|
||||
可用转换: ${availableTransitions.join(', ')}
|
||||
|
||||
📋 可用命令:
|
||||
`;
|
||||
|
||||
for (const cmd of commands) {
|
||||
help += `\n ${cmd.name.padEnd(12)} - ${cmd.purpose}`;
|
||||
}
|
||||
|
||||
help += `
|
||||
|
||||
💡 使用示例:
|
||||
promptx init # 初始化工作环境
|
||||
promptx hello # 发现可用角色
|
||||
promptx action copywriter # 激活文案专家
|
||||
promptx learn scrum # 学习敏捷知识
|
||||
promptx recall frontend # 检索前端记忆
|
||||
|
||||
🔄 PATEOAS 导航:
|
||||
每个命令执行后都会提供下一步的建议操作,
|
||||
按照提示即可完成完整的工作流程。
|
||||
|
||||
📚 更多信息请访问: https://github.com/yourusername/promptx
|
||||
`;
|
||||
|
||||
return help;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前状态信息
|
||||
* @returns {StateContext} 状态上下文
|
||||
*/
|
||||
getStatus() {
|
||||
return {
|
||||
currentState: this.stateMachine.getCurrentState(),
|
||||
availableCommands: this.registry.list(),
|
||||
availableTransitions: this.stateMachine.getAvailableTransitions(),
|
||||
context: this.stateMachine.context,
|
||||
initialized: this.initialized
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析命令行输入
|
||||
* @param {string} input - 用户输入
|
||||
* @returns {Object} 解析结果
|
||||
*/
|
||||
parseCommand(input) {
|
||||
const parts = input.trim().split(/\s+/);
|
||||
const command = parts[0];
|
||||
const args = parts.slice(1);
|
||||
|
||||
return {
|
||||
command: command,
|
||||
args: args
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行交互式CLI
|
||||
*/
|
||||
async runInteractive() {
|
||||
console.log('🎯 欢迎使用 PromptX 锦囊系统!');
|
||||
console.log('输入 "help" 查看帮助,"exit" 退出\n');
|
||||
|
||||
const readline = require('readline');
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
prompt: 'promptx> '
|
||||
});
|
||||
|
||||
rl.prompt();
|
||||
|
||||
rl.on('line', async (line) => {
|
||||
const input = line.trim();
|
||||
|
||||
if (input === 'exit' || input === 'quit') {
|
||||
console.log('再见!');
|
||||
rl.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (input === 'help') {
|
||||
console.log(this.getHelp());
|
||||
} else if (input === 'status') {
|
||||
console.log(JSON.stringify(this.getStatus(), null, 2));
|
||||
} else if (input) {
|
||||
const { command, args } = this.parseCommand(input);
|
||||
try {
|
||||
await this.execute(command, args);
|
||||
} catch (error) {
|
||||
console.error(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
rl.prompt();
|
||||
});
|
||||
|
||||
rl.on('close', () => {
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PouchCLI;
|
||||
91
src/lib/core/pouch/PouchRegistry.js
Normal file
91
src/lib/core/pouch/PouchRegistry.js
Normal file
@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 锦囊命令注册器
|
||||
* 负责管理和注册所有锦囊命令
|
||||
*/
|
||||
class PouchRegistry {
|
||||
constructor() {
|
||||
this.commands = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册锦囊命令
|
||||
* @param {string} name - 命令名称
|
||||
* @param {BasePouchCommand} command - 命令实例
|
||||
*/
|
||||
register(name, command) {
|
||||
if (!name || typeof name !== 'string') {
|
||||
throw new Error('命令名称必须是非空字符串');
|
||||
}
|
||||
|
||||
if (!command || typeof command.execute !== 'function') {
|
||||
throw new Error('命令必须实现 execute 方法');
|
||||
}
|
||||
|
||||
this.commands.set(name.toLowerCase(), command);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取锦囊命令
|
||||
* @param {string} name - 命令名称
|
||||
* @returns {BasePouchCommand} 命令实例
|
||||
*/
|
||||
get(name) {
|
||||
return this.commands.get(name.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出所有已注册的命令
|
||||
* @returns {string[]} 命令名称列表
|
||||
*/
|
||||
list() {
|
||||
return Array.from(this.commands.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证命令是否存在
|
||||
* @param {string} name - 命令名称
|
||||
* @returns {boolean} 是否存在
|
||||
*/
|
||||
validate(name) {
|
||||
return this.commands.has(name.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取命令详情
|
||||
* @returns {Object[]} 命令详情列表
|
||||
*/
|
||||
getCommandDetails() {
|
||||
const details = [];
|
||||
|
||||
for (const [name, command] of this.commands) {
|
||||
details.push({
|
||||
name: name,
|
||||
purpose: command.getPurpose ? command.getPurpose() : '未定义',
|
||||
className: command.constructor.name
|
||||
});
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空注册器
|
||||
*/
|
||||
clear() {
|
||||
this.commands.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量注册命令
|
||||
* @param {Object} commandMap - 命令映射对象
|
||||
*/
|
||||
registerBatch(commandMap) {
|
||||
for (const [name, CommandClass] of Object.entries(commandMap)) {
|
||||
if (typeof CommandClass === 'function') {
|
||||
this.register(name.toLowerCase(), new CommandClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PouchRegistry;
|
||||
179
src/lib/core/pouch/README.md
Normal file
179
src/lib/core/pouch/README.md
Normal file
@ -0,0 +1,179 @@
|
||||
# 锦囊框架 (Pouch Framework)
|
||||
|
||||
基于 PATEOAS (Prompt as the Engine of Application State) 理念的 AI-First CLI 框架。
|
||||
|
||||
## 🎯 核心理念
|
||||
|
||||
锦囊框架实现了"诸葛锦囊"的设计模式,每个锦囊都是:
|
||||
- **自包含的专家知识单元**:独立执行,不依赖上下文
|
||||
- **状态驱动的导航系统**:通过 PATEOAS 引导下一步操作
|
||||
- **AI 友好的接口设计**:专为 AI 使用而优化
|
||||
|
||||
## 🏗️ 架构设计
|
||||
|
||||
```
|
||||
锦囊框架
|
||||
├── BasePouchCommand # 基础命令抽象类
|
||||
├── PouchCLI # CLI 主入口
|
||||
├── PouchRegistry # 命令注册器
|
||||
├── PouchStateMachine # 状态机管理器
|
||||
└── Commands/ # 五个核心锦囊
|
||||
├── InitCommand # 初始化锦囊
|
||||
├── HelloCommand # 角色发现锦囊
|
||||
├── ActionCommand # 角色激活锦囊
|
||||
├── LearnCommand # 领域学习锦囊
|
||||
└── RecallCommand # 记忆检索锦囊
|
||||
```
|
||||
|
||||
## 📦 快速开始
|
||||
|
||||
### 1. 引入框架
|
||||
|
||||
```javascript
|
||||
const { cli } = require('./lib/core/pouch');
|
||||
|
||||
// 或者引入完整框架
|
||||
const { PouchCLI, BasePouchCommand } = require('./lib/core/pouch');
|
||||
```
|
||||
|
||||
### 2. 执行命令
|
||||
|
||||
```javascript
|
||||
// 初始化环境
|
||||
await cli.execute('init');
|
||||
|
||||
// 发现可用角色
|
||||
await cli.execute('hello');
|
||||
|
||||
// 激活特定角色
|
||||
await cli.execute('action', ['copywriter']);
|
||||
|
||||
// 学习领域知识
|
||||
await cli.execute('learn', ['scrum']);
|
||||
|
||||
// 检索记忆
|
||||
await cli.execute('recall', ['frontend']);
|
||||
```
|
||||
|
||||
### 3. 获取状态
|
||||
|
||||
```javascript
|
||||
// 获取当前状态
|
||||
const status = cli.getStatus();
|
||||
|
||||
// 获取帮助信息
|
||||
const help = cli.getHelp();
|
||||
```
|
||||
|
||||
## 🔧 创建自定义锦囊
|
||||
|
||||
### 1. 继承 BasePouchCommand
|
||||
|
||||
```javascript
|
||||
const BasePouchCommand = require('./lib/core/pouch/BasePouchCommand');
|
||||
|
||||
class CustomCommand extends BasePouchCommand {
|
||||
getPurpose() {
|
||||
return '自定义锦囊的目的说明';
|
||||
}
|
||||
|
||||
async getContent(args) {
|
||||
// 返回锦囊的核心内容(提示词)
|
||||
return `这是自定义锦囊的内容...`;
|
||||
}
|
||||
|
||||
getPATEOAS(args) {
|
||||
// 返回 PATEOAS 导航信息
|
||||
return {
|
||||
currentState: 'custom-state',
|
||||
availableTransitions: ['next-command'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '下一步操作',
|
||||
description: '操作描述',
|
||||
command: 'promptx next-command'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 注册命令
|
||||
|
||||
```javascript
|
||||
const registry = new PouchRegistry();
|
||||
registry.register('custom', new CustomCommand());
|
||||
```
|
||||
|
||||
## 🌟 核心特性
|
||||
|
||||
### 三层输出结构
|
||||
|
||||
每个锦囊都输出三层信息:
|
||||
|
||||
1. **Purpose(目的)**:说明锦囊的作用
|
||||
2. **Content(内容)**:核心提示词或知识
|
||||
3. **PATEOAS(导航)**:下一步操作指引
|
||||
|
||||
### 状态机管理
|
||||
|
||||
- 自动记录状态历史
|
||||
- 持久化状态到 `.promptx.json`
|
||||
- 支持状态回溯和恢复
|
||||
|
||||
### 灵活的输出格式
|
||||
|
||||
```javascript
|
||||
// 设置为 JSON 格式
|
||||
command.setOutputFormat('json');
|
||||
|
||||
// 设置为人类可读格式(默认)
|
||||
command.setOutputFormat('human');
|
||||
```
|
||||
|
||||
## 📋 命令列表
|
||||
|
||||
| 命令 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| init | 初始化工作环境 | `promptx init` |
|
||||
| hello | 发现可用角色 | `promptx hello` |
|
||||
| action | 激活特定角色 | `promptx action copywriter` |
|
||||
| learn | 学习领域知识 | `promptx learn scrum` |
|
||||
| recall | 检索相关记忆 | `promptx recall test` |
|
||||
|
||||
## 🚀 进阶用法
|
||||
|
||||
### 交互式模式
|
||||
|
||||
```javascript
|
||||
const cli = new PouchCLI();
|
||||
await cli.runInteractive();
|
||||
```
|
||||
|
||||
### 批量执行
|
||||
|
||||
```javascript
|
||||
const commands = [
|
||||
{ name: 'init', args: [] },
|
||||
{ name: 'hello', args: [] },
|
||||
{ name: 'action', args: ['frontend'] }
|
||||
];
|
||||
|
||||
for (const cmd of commands) {
|
||||
await cli.execute(cmd.name, cmd.args);
|
||||
}
|
||||
```
|
||||
|
||||
## 🤝 贡献指南
|
||||
|
||||
欢迎贡献新的锦囊命令!请确保:
|
||||
|
||||
1. 继承 `BasePouchCommand`
|
||||
2. 实现三个核心方法
|
||||
3. 提供清晰的 PATEOAS 导航
|
||||
4. 编写测试用例
|
||||
|
||||
## <20><> 许可证
|
||||
|
||||
MIT License
|
||||
325
src/lib/core/pouch/commands/ActionCommand.js
Normal file
325
src/lib/core/pouch/commands/ActionCommand.js
Normal file
@ -0,0 +1,325 @@
|
||||
const BasePouchCommand = require('../BasePouchCommand');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* 角色激活锦囊命令
|
||||
* 负责分析角色文件,提取需要学习的thought、execution和knowledge
|
||||
*/
|
||||
class ActionCommand extends BasePouchCommand {
|
||||
constructor() {
|
||||
super();
|
||||
// 获取HelloCommand的角色注册表
|
||||
this.helloCommand = null;
|
||||
}
|
||||
|
||||
getPurpose() {
|
||||
return '激活特定AI角色,分析并生成具体的思维模式、行为模式和知识学习计划';
|
||||
}
|
||||
|
||||
async getContent(args) {
|
||||
const [roleId] = args;
|
||||
|
||||
if (!roleId) {
|
||||
return `❌ 请指定要激活的角色ID
|
||||
|
||||
🔍 使用方法:
|
||||
\`\`\`bash
|
||||
promptx action <角色ID>
|
||||
\`\`\`
|
||||
|
||||
💡 查看可用角色:
|
||||
\`\`\`bash
|
||||
promptx hello
|
||||
\`\`\``;
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. 获取角色信息
|
||||
const roleInfo = await this.getRoleInfo(roleId);
|
||||
if (!roleInfo) {
|
||||
return `❌ 角色 "${roleId}" 不存在!
|
||||
|
||||
🔍 请使用以下命令查看可用角色:
|
||||
\`\`\`bash
|
||||
promptx hello
|
||||
\`\`\``;
|
||||
}
|
||||
|
||||
// 2. 分析角色文件,提取依赖
|
||||
const dependencies = await this.analyzeRoleDependencies(roleInfo);
|
||||
|
||||
// 3. 生成学习计划 (新版本:以role://开头)
|
||||
return this.generateLearningPlan(roleInfo.id, dependencies);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Action command error:', error);
|
||||
return `❌ 激活角色 "${roleId}" 时发生错误。
|
||||
|
||||
🔍 可能的原因:
|
||||
- 角色文件不存在或格式错误
|
||||
- 权限不足
|
||||
- 系统资源问题
|
||||
|
||||
💡 请使用 \`promptx hello\` 查看可用角色列表。`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色信息(从HelloCommand)
|
||||
*/
|
||||
async getRoleInfo(roleId) {
|
||||
// 懒加载HelloCommand实例
|
||||
if (!this.helloCommand) {
|
||||
const HelloCommand = require('./HelloCommand');
|
||||
this.helloCommand = new HelloCommand();
|
||||
}
|
||||
|
||||
return this.helloCommand.getRoleInfo(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析角色文件,提取thought和execution依赖
|
||||
*/
|
||||
async analyzeRoleDependencies(roleInfo) {
|
||||
try {
|
||||
// 处理文件路径,将@package://前缀替换为实际路径
|
||||
let filePath = roleInfo.file;
|
||||
if (filePath.startsWith('@package://')) {
|
||||
filePath = filePath.replace('@package://', '');
|
||||
}
|
||||
|
||||
// 读取角色文件内容
|
||||
const roleContent = await fs.readFile(filePath, 'utf-8');
|
||||
|
||||
// 提取所有资源引用
|
||||
const resourceRegex = /@([!?]?)([a-zA-Z][a-zA-Z0-9_-]*):\/\/([a-zA-Z0-9_\/.,-]+?)(?=[\s\)\],]|$)/g;
|
||||
const matches = Array.from(roleContent.matchAll(resourceRegex));
|
||||
|
||||
const dependencies = {
|
||||
thoughts: new Set(),
|
||||
executions: new Set(),
|
||||
knowledge: [roleInfo.id] // 角色自身的knowledge
|
||||
};
|
||||
|
||||
// 分类依赖
|
||||
matches.forEach(match => {
|
||||
const [fullMatch, priority, protocol, resource] = match;
|
||||
|
||||
if (protocol === 'thought') {
|
||||
dependencies.thoughts.add(resource);
|
||||
} else if (protocol === 'execution') {
|
||||
dependencies.executions.add(resource);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
thoughts: dependencies.thoughts,
|
||||
executions: dependencies.executions,
|
||||
knowledge: dependencies.knowledge
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error analyzing role dependencies:', error);
|
||||
// 如果分析失败,返回基础结构
|
||||
return {
|
||||
thoughts: [],
|
||||
executions: [],
|
||||
knowledge: [roleInfo.id]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成学习指引(基于分析出的依赖)
|
||||
*/
|
||||
generateLearningGuide(roleInfo, dependencies) {
|
||||
let guide = `🎬 **角色激活计划:${roleInfo.name}**
|
||||
|
||||
📋 **角色概述**
|
||||
${roleInfo.description}
|
||||
|
||||
`;
|
||||
|
||||
// 思维模式部分
|
||||
if (dependencies.thoughts.length > 0) {
|
||||
guide += `## 🧠 第一步:学习思维模式
|
||||
掌握角色所需的核心思考技能
|
||||
|
||||
`;
|
||||
dependencies.thoughts.forEach((thought, index) => {
|
||||
guide += `### ${index + 1}. ${thought}
|
||||
\`\`\`bash
|
||||
promptx learn thought://${thought}
|
||||
\`\`\`
|
||||
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
// 行为模式部分
|
||||
if (dependencies.executions.length > 0) {
|
||||
guide += `## ⚖️ 第二步:学习行为模式
|
||||
掌握角色所需的核心执行技能
|
||||
|
||||
`;
|
||||
dependencies.executions.forEach((execution, index) => {
|
||||
guide += `### ${index + 1}. ${execution}
|
||||
\`\`\`bash
|
||||
promptx learn execution://${execution}
|
||||
\`\`\`
|
||||
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
// 知识部分
|
||||
guide += `## 📚 第三步:学习专业知识
|
||||
获取角色的领域知识体系
|
||||
|
||||
`;
|
||||
dependencies.knowledge.forEach((knowledge, index) => {
|
||||
guide += `### ${index + 1}. ${knowledge} 领域知识
|
||||
\`\`\`bash
|
||||
promptx learn knowledge://${knowledge}
|
||||
\`\`\`
|
||||
|
||||
`;
|
||||
});
|
||||
|
||||
// 编排学习
|
||||
guide += `## 🎪 第四步:学习编排方式
|
||||
理解如何组合使用已学的技能
|
||||
|
||||
\`\`\`bash
|
||||
promptx learn personality://${roleInfo.id}
|
||||
\`\`\`
|
||||
|
||||
\`\`\`bash
|
||||
promptx learn principle://${roleInfo.id}
|
||||
\`\`\`
|
||||
|
||||
## ✅ 角色激活确认
|
||||
|
||||
完成学习后,请确认角色激活:
|
||||
|
||||
1. **思维确认**:🧠 "我已掌握所需的思考技能!"
|
||||
2. **行为确认**:⚖️ "我已掌握所需的执行技能!"
|
||||
3. **知识确认**:📚 "我已具备领域专业知识!"
|
||||
4. **编排确认**:🎪 "我已理解技能的组合使用方式!"
|
||||
|
||||
## 🎯 下一步操作
|
||||
|
||||
角色激活完成后,可以:
|
||||
- 📝 **开始专业工作** - 运用角色能力解决实际问题
|
||||
- 🔍 **调用记忆** - 使用 \`promptx recall\` 检索相关经验
|
||||
- 🔄 **切换角色** - 使用 \`promptx hello\` 选择其他专业角色
|
||||
|
||||
💡 **设计理念**:基于 DPML 基础协议组合,通过thought和execution的灵活编排实现角色能力。`;
|
||||
|
||||
return guide;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成学习计划
|
||||
*/
|
||||
generateLearningPlan(roleId, dependencies) {
|
||||
const { thoughts, executions } = dependencies;
|
||||
|
||||
let plan = `🎭 **准备激活角色:${roleId}**\n\n`;
|
||||
|
||||
// 第一步:学习完整角色
|
||||
plan += `## 🎯 第一步:掌握角色全貌\n`;
|
||||
plan += `理解角色的完整定义和核心特征\n\n`;
|
||||
plan += `\`\`\`bash\n`;
|
||||
plan += `promptx learn role://${roleId}\n`;
|
||||
plan += `\`\`\`\n\n`;
|
||||
|
||||
// 第二步:学习思维模式
|
||||
if (thoughts.size > 0) {
|
||||
plan += `## 🧠 第二步:掌握思维模式\n`;
|
||||
plan += `学习角色特定的思考方式和认知框架\n\n`;
|
||||
|
||||
Array.from(thoughts).forEach((thought, index) => {
|
||||
plan += `\`\`\`bash\n`;
|
||||
plan += `promptx learn thought://${thought}\n`;
|
||||
plan += `\`\`\`\n\n`;
|
||||
});
|
||||
}
|
||||
|
||||
// 第三步:掌握执行技能
|
||||
if (executions.size > 0) {
|
||||
plan += `## ⚡ 第${thoughts.size > 0 ? '三' : '二'}步:掌握执行技能\n`;
|
||||
plan += `学习角色的行为模式和操作技能\n\n`;
|
||||
|
||||
Array.from(executions).forEach((execution, index) => {
|
||||
plan += `\`\`\`bash\n`;
|
||||
plan += `promptx learn execution://${execution}\n`;
|
||||
plan += `\`\`\`\n\n`;
|
||||
});
|
||||
}
|
||||
|
||||
// 激活确认
|
||||
const stepCount = thoughts.size > 0 ? (executions.size > 0 ? '四' : '三') : (executions.size > 0 ? '三' : '二');
|
||||
plan += `## 🎪 第${stepCount}步:完成角色激活\n`;
|
||||
plan += `确认角色能力已完全激活\n\n`;
|
||||
plan += `✅ **角色激活检查清单**:\n`;
|
||||
plan += `- [x] 已学习完整角色定义\n`;
|
||||
if (thoughts.size > 0) plan += `- [x] 已掌握 ${thoughts.size} 个思维模式\n`;
|
||||
if (executions.size > 0) plan += `- [x] 已掌握 ${executions.size} 个执行技能\n`;
|
||||
plan += `- [x] 可以开始以${roleId}身份工作\n\n`;
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
getPATEOAS(args) {
|
||||
const [roleId] = args;
|
||||
|
||||
if (!roleId) {
|
||||
return {
|
||||
currentState: 'action_awaiting_role',
|
||||
availableTransitions: ['hello'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '查看可用角色',
|
||||
description: '返回角色发现页面',
|
||||
command: 'promptx hello',
|
||||
priority: 'high'
|
||||
}
|
||||
],
|
||||
metadata: {
|
||||
message: '需要指定角色ID'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
currentState: 'action_plan_generated',
|
||||
availableTransitions: ['learn', 'recall', 'hello'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '开始学习',
|
||||
description: '按计划开始学习技能',
|
||||
command: `promptx learn`,
|
||||
priority: 'high'
|
||||
},
|
||||
{
|
||||
name: '返回角色选择',
|
||||
description: '选择其他角色',
|
||||
command: 'promptx hello',
|
||||
priority: 'low'
|
||||
}
|
||||
],
|
||||
metadata: {
|
||||
targetRole: roleId,
|
||||
planGenerated: true,
|
||||
architecture: 'DPML协议组合',
|
||||
approach: '分析-提取-编排',
|
||||
systemVersion: '锦囊串联状态机 v1.0',
|
||||
designPhilosophy: 'AI use CLI get prompt for AI'
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ActionCommand;
|
||||
225
src/lib/core/pouch/commands/HelloCommand.js
Normal file
225
src/lib/core/pouch/commands/HelloCommand.js
Normal file
@ -0,0 +1,225 @@
|
||||
const BasePouchCommand = require('../BasePouchCommand');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* 角色发现锦囊命令
|
||||
* 负责展示可用的AI角色和领域专家
|
||||
*/
|
||||
class HelloCommand extends BasePouchCommand {
|
||||
constructor() {
|
||||
super();
|
||||
// 角色注册表 - 硬编码版本,未来可扩展为动态发现
|
||||
this.ROLES_REGISTRY = [
|
||||
{
|
||||
id: 'video-copywriter',
|
||||
name: '🎬 视频文案专家',
|
||||
description: '专业视频内容创作与营销文案,具备创意性、故事性和营销性思维',
|
||||
category: '内容创作',
|
||||
domain: 'video-copywriting',
|
||||
file: '@package://prompt/domain/copywriter/video-copywriter.role.md'
|
||||
},
|
||||
{
|
||||
id: 'product-owner',
|
||||
name: '🎯 产品负责人',
|
||||
description: '敏捷开发核心决策者,具备全栈产品管理能力和技术理解',
|
||||
category: '项目管理',
|
||||
domain: 'scrum-product-ownership',
|
||||
file: '@package://prompt/domain/scrum/role/product-owner.role.md'
|
||||
},
|
||||
{
|
||||
id: 'prompt-developer',
|
||||
name: '🔧 提示词开发者',
|
||||
description: '探索性、系统性和批判性思维的提示词设计专家',
|
||||
category: '技术开发',
|
||||
domain: 'prompt-engineering',
|
||||
file: '@package://prompt/domain/prompt/prompt-developer.role.md'
|
||||
},
|
||||
{
|
||||
id: 'test-assistant',
|
||||
name: '🧪 测试助手',
|
||||
description: '基础测试角色,具备思考和记忆处理能力',
|
||||
category: '质量保证',
|
||||
domain: 'testing',
|
||||
file: '@package://prompt/domain/test/test.role.md'
|
||||
},
|
||||
{
|
||||
id: 'assistant',
|
||||
name: '🙋 智能助手',
|
||||
description: '通用助理角色,提供基础的助理服务和记忆支持',
|
||||
category: '通用服务',
|
||||
domain: 'general-assistance',
|
||||
file: '@package://prompt/domain/assistant/assistant.role.md'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
getPurpose() {
|
||||
return '发现并展示所有可用的AI角色和领域专家,帮助选择合适的专业身份开始工作';
|
||||
}
|
||||
|
||||
async getContent(args) {
|
||||
const rolesByCategory = this.groupRolesByCategory();
|
||||
const totalRoles = this.ROLES_REGISTRY.length;
|
||||
|
||||
let content = `👋 欢迎来到 PromptX 锦囊系统!
|
||||
|
||||
🎭 **可用的AI角色与领域专家** (共 ${totalRoles} 个角色)
|
||||
|
||||
`;
|
||||
|
||||
// 按分类展示角色
|
||||
for (const [category, roles] of Object.entries(rolesByCategory)) {
|
||||
content += `## ${this.getCategoryIcon(category)} ${category}\n\n`;
|
||||
|
||||
roles.forEach(role => {
|
||||
content += `### ${role.name}\n`;
|
||||
content += `- **角色ID**: \`${role.id}\`\n`;
|
||||
content += `- **专业领域**: ${role.domain}\n`;
|
||||
content += `- **能力描述**: ${role.description}\n\n`;
|
||||
});
|
||||
}
|
||||
|
||||
content += `
|
||||
🎯 **下一步操作指南**
|
||||
|
||||
选择一个角色,使用以下命令激活专业能力:
|
||||
|
||||
\`\`\`bash
|
||||
# 1. 激活角色 (推荐)
|
||||
promptx action <角色ID>
|
||||
|
||||
# 2. 或直接学习角色知识
|
||||
promptx learn <角色ID>
|
||||
\`\`\`
|
||||
|
||||
💡 **使用示例**
|
||||
\`\`\`bash
|
||||
promptx action video-copywriter # 激活视频文案专家
|
||||
promptx action product-owner # 激活产品负责人
|
||||
promptx action prompt-developer # 激活提示词开发者
|
||||
\`\`\`
|
||||
|
||||
🔄 **锦囊串联流程**
|
||||
👋 **hello**(发现角色) → ⚡ **action**(激活角色) → 📚 **learn**(学习知识) → 🔍 **recall**(应用经验)
|
||||
`;
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
getPATEOAS(args) {
|
||||
const availableRoles = this.ROLES_REGISTRY.map(role => ({
|
||||
roleId: role.id,
|
||||
name: role.name,
|
||||
category: role.category,
|
||||
actionCommand: `promptx action ${role.id}`
|
||||
}));
|
||||
|
||||
return {
|
||||
currentState: 'role_discovery',
|
||||
availableTransitions: ['action', 'learn', 'init', 'recall'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '激活视频文案专家',
|
||||
description: '成为专业的视频内容创作者',
|
||||
command: 'promptx action video-copywriter',
|
||||
priority: 'high'
|
||||
},
|
||||
{
|
||||
name: '激活产品负责人',
|
||||
description: '成为敏捷开发的决策者',
|
||||
command: 'promptx action product-owner',
|
||||
priority: 'high'
|
||||
},
|
||||
{
|
||||
name: '激活提示词开发者',
|
||||
description: '成为提示词设计专家',
|
||||
command: 'promptx action prompt-developer',
|
||||
priority: 'medium'
|
||||
},
|
||||
{
|
||||
name: '激活智能助手',
|
||||
description: '成为通用助理',
|
||||
command: 'promptx action assistant',
|
||||
priority: 'low'
|
||||
},
|
||||
{
|
||||
name: '学习特定领域',
|
||||
description: '深入学习某个专业领域',
|
||||
command: 'promptx learn <domain>',
|
||||
parameters: {
|
||||
domain: '可选值:copywriter, scrum, prompt, test, assistant'
|
||||
}
|
||||
}
|
||||
],
|
||||
metadata: {
|
||||
totalRoles: this.ROLES_REGISTRY.length,
|
||||
categories: [...new Set(this.ROLES_REGISTRY.map(r => r.category))],
|
||||
availableRoles: availableRoles,
|
||||
systemVersion: '锦囊串联状态机 v1.0',
|
||||
designPhilosophy: 'AI use CLI get prompt for AI'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 按分类分组角色
|
||||
*/
|
||||
groupRolesByCategory() {
|
||||
const grouped = {};
|
||||
|
||||
this.ROLES_REGISTRY.forEach(role => {
|
||||
if (!grouped[role.category]) {
|
||||
grouped[role.category] = [];
|
||||
}
|
||||
grouped[role.category].push(role);
|
||||
});
|
||||
|
||||
return grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类图标
|
||||
*/
|
||||
getCategoryIcon(category) {
|
||||
const icons = {
|
||||
'内容创作': '✍️',
|
||||
'项目管理': '📊',
|
||||
'技术开发': '💻',
|
||||
'质量保证': '🔍',
|
||||
'通用服务': '🤖'
|
||||
};
|
||||
|
||||
return icons[category] || '🎯';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色信息(提供给其他命令使用)
|
||||
*/
|
||||
getRoleInfo(roleId) {
|
||||
return this.ROLES_REGISTRY.find(role => role.id === roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有角色列表
|
||||
*/
|
||||
getAllRoles() {
|
||||
return this.ROLES_REGISTRY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 未来扩展:动态角色发现
|
||||
* TODO: 实现真正的文件扫描和解析
|
||||
*/
|
||||
async discoverAvailableDomains() {
|
||||
// 预留接口,未来实现动态角色发现
|
||||
// 1. 扫描 prompt/domain/ 目录
|
||||
// 2. 解析 .role.md 文件
|
||||
// 3. 提取元数据和描述
|
||||
// 4. 构建动态注册表
|
||||
|
||||
return this.ROLES_REGISTRY.map(role => role.domain);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HelloCommand;
|
||||
146
src/lib/core/pouch/commands/InitCommand.js
Normal file
146
src/lib/core/pouch/commands/InitCommand.js
Normal file
@ -0,0 +1,146 @@
|
||||
const BasePouchCommand = require('../BasePouchCommand');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const { ResourceManager } = require('../../resource');
|
||||
|
||||
/**
|
||||
* 初始化锦囊命令
|
||||
* 负责准备工作环境和传达系统协议
|
||||
*/
|
||||
class InitCommand extends BasePouchCommand {
|
||||
constructor() {
|
||||
super();
|
||||
this.resourceManager = new ResourceManager();
|
||||
}
|
||||
|
||||
getPurpose() {
|
||||
return '初始化PromptX工作环境,传达系统基本诺记(协议体系)';
|
||||
}
|
||||
|
||||
async getContent(args) {
|
||||
const [workspacePath = '.'] = args;
|
||||
|
||||
// 1. 技术初始化
|
||||
await this.initializeWorkspace(workspacePath);
|
||||
|
||||
// 2. 加载协议体系
|
||||
const protocolContent = await this.loadProtocolSystem();
|
||||
|
||||
return `🎯 PromptX 系统初始化完成!
|
||||
|
||||
## 🏗️ 技术环境准备
|
||||
✅ 创建了项目目录结构
|
||||
✅ 配置了 .promptx/pouch.json 锦囊状态文件
|
||||
✅ 准备了锦囊状态机框架
|
||||
|
||||
## 📋 系统基本诺记 (协议体系)
|
||||
|
||||
${protocolContent}
|
||||
|
||||
## 🚀 开始使用
|
||||
|
||||
现在你已经获得了 PromptX 的完整理念和协议体系。
|
||||
每个锦囊都是独立的智慧单元,即使AI忘记了上下文,锦囊依然能够独立执行。
|
||||
|
||||
### 🎒 核心锦囊流程
|
||||
\`\`\`
|
||||
🏗️init(已完成) → 👋hello → ⚡action → 📚learn → 🔍recall → 循环
|
||||
\`\`\`
|
||||
|
||||
你现在可以开始探索锦囊世界了!`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载协议体系内容
|
||||
*/
|
||||
async loadProtocolSystem() {
|
||||
try {
|
||||
// 加载完整协议体系:PATEOAS + DPML + 所有标签协议
|
||||
const result = await this.resourceManager.resolve('@prompt://protocols');
|
||||
|
||||
if (result.success) {
|
||||
return result.content;
|
||||
} else {
|
||||
console.warn('⚠️ 协议加载失败:', result.error?.message);
|
||||
return this.getCoreProtocolSummary();
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('⚠️ 无法加载完整协议体系,使用核心摘要:', error.message);
|
||||
return this.getCoreProtocolSummary();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取核心协议摘要(fallback)
|
||||
*/
|
||||
getCoreProtocolSummary() {
|
||||
return `### 🎯 核心理念:AI use CLI get prompt for AI
|
||||
|
||||
**PATEOAS协议** - Prompt as the Engine of Application State
|
||||
- 🎒 锦囊自包含:每个命令包含完整执行信息
|
||||
- 🔗 串联无依赖:即使AI忘记上文,也能继续执行
|
||||
- 🎯 分阶段专注:每个锦囊只关注当前任务
|
||||
- 🔄 Prompt驱动:每个输出引导AI发现下一步操作
|
||||
|
||||
**DPML协议** - Deepractice Prompt Markup Language
|
||||
- 📋 标准化标记:使用 \`<thinking>\`、\`<executing>\` 等标签
|
||||
- 🏷️ 语义清晰:通过标签明确表达提示词结构
|
||||
- 🔗 协议绑定:支持 \`A:B\` 语法表达实现关系
|
||||
|
||||
**三大解决方案**
|
||||
- **上下文遗忘** → 锦囊自包含,每个命令独立执行
|
||||
- **注意力分散** → 分阶段专注,每锦囊专注单一任务
|
||||
- **能力局限** → 即时专家化,通过提示词获得专业能力`;
|
||||
}
|
||||
|
||||
getPATEOAS(args) {
|
||||
return {
|
||||
currentState: 'initialized',
|
||||
availableTransitions: ['hello', 'action', 'learn'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '发现角色',
|
||||
description: '探索可用的AI角色和领域专家',
|
||||
command: 'promptx hello'
|
||||
},
|
||||
{
|
||||
name: '查看帮助',
|
||||
description: '了解更多锦囊使用方法',
|
||||
command: 'promptx help'
|
||||
}
|
||||
],
|
||||
metadata: {
|
||||
timestamp: new Date().toISOString(),
|
||||
version: '0.0.1'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async initializeWorkspace(workspacePath) {
|
||||
// 创建基础目录结构
|
||||
const dirs = [
|
||||
'prompt/core',
|
||||
'prompt/domain',
|
||||
'prompt/protocol',
|
||||
'prompt/resource',
|
||||
'.promptx'
|
||||
];
|
||||
|
||||
for (const dir of dirs) {
|
||||
await fs.ensureDir(path.join(workspacePath, dir));
|
||||
}
|
||||
|
||||
// 创建锦囊状态配置文件
|
||||
const configPath = path.join(workspacePath, '.promptx', 'pouch.json');
|
||||
if (!await fs.pathExists(configPath)) {
|
||||
await fs.writeJson(configPath, {
|
||||
version: '0.0.1',
|
||||
initialized: new Date().toISOString(),
|
||||
defaultFormat: 'human',
|
||||
stateHistory: []
|
||||
}, { spaces: 2 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = InitCommand;
|
||||
242
src/lib/core/pouch/commands/LearnCommand.js
Normal file
242
src/lib/core/pouch/commands/LearnCommand.js
Normal file
@ -0,0 +1,242 @@
|
||||
const BasePouchCommand = require('../BasePouchCommand');
|
||||
const ResourceManager = require('../../resource/resourceManager');
|
||||
|
||||
/**
|
||||
* 智能学习锦囊命令
|
||||
* 支持加载thought、execution、memory等协议资源,以及角色的personality、principle、knowledge
|
||||
*/
|
||||
class LearnCommand extends BasePouchCommand {
|
||||
constructor() {
|
||||
super();
|
||||
this.resourceManager = new ResourceManager();
|
||||
}
|
||||
|
||||
getPurpose() {
|
||||
return '智能学习指定协议的资源内容,支持thought、execution、memory等DPML协议以及角色组件';
|
||||
}
|
||||
|
||||
async getContent(args) {
|
||||
const [resourceUrl] = args;
|
||||
|
||||
if (!resourceUrl) {
|
||||
return this.getUsageHelp();
|
||||
}
|
||||
|
||||
try {
|
||||
// 直接使用ResourceManager解析资源
|
||||
const content = await this.resourceManager.resolve(resourceUrl);
|
||||
|
||||
// 解析协议信息
|
||||
const urlMatch = resourceUrl.match(/^([a-zA-Z]+):\/\/(.+)$/);
|
||||
const [, protocol, resourceId] = urlMatch;
|
||||
|
||||
return this.formatSuccessResponse(protocol, resourceId, content);
|
||||
|
||||
} catch (error) {
|
||||
return this.formatErrorResponse(resourceUrl, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化成功响应
|
||||
*/
|
||||
formatSuccessResponse(protocol, resourceId, content) {
|
||||
const protocolLabels = {
|
||||
thought: '🧠 思维模式',
|
||||
execution: '⚡ 执行模式',
|
||||
memory: '💾 记忆模式',
|
||||
personality: '👤 角色人格',
|
||||
principle: '⚖️ 行为原则',
|
||||
knowledge: '📚 专业知识'
|
||||
};
|
||||
|
||||
const label = protocolLabels[protocol] || `📄 ${protocol}`;
|
||||
|
||||
return `✅ **成功学习${label}:${resourceId}**
|
||||
|
||||
## 📋 学习内容
|
||||
|
||||
${content}
|
||||
|
||||
## 🎯 学习效果
|
||||
- ✅ **已激活${label}能力**
|
||||
- ✅ **相关知识已整合到AI认知体系**
|
||||
- ✅ **可立即应用于实际场景**
|
||||
|
||||
## 🔄 下一步行动:
|
||||
- 继续学习: 学习其他相关资源
|
||||
命令: \`promptx learn <protocol>://<resource-id>\`
|
||||
- 应用记忆: 检索相关经验
|
||||
命令: \`promptx recall\`
|
||||
- 激活角色: 激活完整角色能力
|
||||
命令: \`promptx action <role-id>\`
|
||||
|
||||
📍 当前状态:learned_${protocol}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化错误响应
|
||||
*/
|
||||
formatErrorResponse(resourceUrl, errorMessage) {
|
||||
return `❌ 学习资源失败:${resourceUrl}
|
||||
|
||||
🔍 错误详情:
|
||||
${errorMessage}
|
||||
|
||||
💡 支持的协议:
|
||||
- \`thought://resource-id\` - 学习思维模式
|
||||
- \`execution://resource-id\` - 学习执行模式
|
||||
- \`memory://resource-id\` - 学习记忆模式
|
||||
- \`personality://role-id\` - 学习角色思维
|
||||
- \`principle://role-id\` - 学习角色原则
|
||||
- \`knowledge://role-id\` - 学习角色知识
|
||||
|
||||
🔍 查看可用资源:
|
||||
\`\`\`bash
|
||||
promptx action <role-id> # 查看角色的所有依赖
|
||||
\`\`\`
|
||||
|
||||
🔄 下一步行动:
|
||||
- 继续学习: 学习其他资源
|
||||
命令: promptx learn <protocol>://<resource-id>
|
||||
- 应用记忆: 检索相关经验
|
||||
命令: promptx recall
|
||||
- 激活角色: 激活完整角色能力
|
||||
命令: promptx action <role-id>
|
||||
- 查看角色列表: 选择其他角色
|
||||
命令: promptx hello`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取使用帮助
|
||||
*/
|
||||
getUsageHelp() {
|
||||
return `🎓 **Learn锦囊 - 智能学习系统**
|
||||
|
||||
## 📖 基本用法
|
||||
\`\`\`bash
|
||||
promptx learn <protocol>://<resource-id>
|
||||
\`\`\`
|
||||
|
||||
## 🎯 支持的协议
|
||||
|
||||
### 🔧 DPML核心协议
|
||||
- **\`thought://\`** - 思维模式资源
|
||||
- **\`execution://\`** - 执行模式资源
|
||||
- **\`memory://\`** - 记忆系统资源
|
||||
|
||||
### 👤 角色组件协议
|
||||
- **\`personality://\`** - 角色人格特征
|
||||
- **\`principle://\`** - 行为原则
|
||||
- **\`knowledge://\`** - 专业知识
|
||||
|
||||
## 📝 使用示例
|
||||
\`\`\`bash
|
||||
# 学习执行技能
|
||||
promptx learn execution://deal-at-reference
|
||||
|
||||
# 学习思维模式
|
||||
promptx learn thought://prompt-developer
|
||||
|
||||
# 学习角色人格
|
||||
promptx learn personality://video-copywriter
|
||||
\`\`\`
|
||||
|
||||
## 🔍 发现可学习资源
|
||||
\`\`\`bash
|
||||
promptx action <role-id> # 查看角色需要的所有资源
|
||||
promptx hello # 查看可用角色列表
|
||||
\`\`\`
|
||||
|
||||
🔄 下一步行动:
|
||||
- 激活角色: 分析角色依赖
|
||||
命令: promptx action <role-id>
|
||||
- 查看角色: 选择感兴趣的角色
|
||||
命令: promptx hello`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取PATEOAS导航信息
|
||||
*/
|
||||
getPATEOAS(args) {
|
||||
const [resourceUrl] = args;
|
||||
|
||||
if (!resourceUrl) {
|
||||
return {
|
||||
currentState: 'learn_awaiting_resource',
|
||||
availableTransitions: ['hello', 'action'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '查看可用角色',
|
||||
description: '返回角色选择页面',
|
||||
command: 'promptx hello',
|
||||
priority: 'high'
|
||||
},
|
||||
{
|
||||
name: '生成学习计划',
|
||||
description: '为特定角色生成学习计划',
|
||||
command: 'promptx action <role-id>',
|
||||
priority: 'high'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
const urlMatch = resourceUrl.match(/^([a-zA-Z]+):\/\/(.+)$/);
|
||||
if (!urlMatch) {
|
||||
return {
|
||||
currentState: 'learn_error',
|
||||
availableTransitions: ['hello', 'action'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '查看使用帮助',
|
||||
description: '重新学习命令使用方法',
|
||||
command: 'promptx learn',
|
||||
priority: 'high'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
const [, protocol, resourceId] = urlMatch;
|
||||
|
||||
return {
|
||||
currentState: `learned_${protocol}`,
|
||||
availableTransitions: ['learn', 'recall', 'hello', 'action'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '继续学习',
|
||||
description: '学习其他资源',
|
||||
command: 'promptx learn <protocol>://<resource-id>',
|
||||
priority: 'medium'
|
||||
},
|
||||
{
|
||||
name: '应用记忆',
|
||||
description: '检索相关经验',
|
||||
command: 'promptx recall',
|
||||
priority: 'medium'
|
||||
},
|
||||
{
|
||||
name: '激活角色',
|
||||
description: '激活完整角色能力',
|
||||
command: 'promptx action <role-id>',
|
||||
priority: 'high'
|
||||
},
|
||||
{
|
||||
name: '查看角色列表',
|
||||
description: '选择其他角色',
|
||||
command: 'promptx hello',
|
||||
priority: 'low'
|
||||
}
|
||||
],
|
||||
metadata: {
|
||||
learnedResource: resourceUrl,
|
||||
protocol: protocol,
|
||||
resourceId: resourceId,
|
||||
systemVersion: '锦囊串联状态机 v1.0'
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LearnCommand;
|
||||
217
src/lib/core/pouch/commands/RecallCommand.js
Normal file
217
src/lib/core/pouch/commands/RecallCommand.js
Normal file
@ -0,0 +1,217 @@
|
||||
const BasePouchCommand = require('../BasePouchCommand');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* 记忆检索锦囊命令
|
||||
* 负责从记忆库中检索相关知识和经验
|
||||
*/
|
||||
class RecallCommand extends BasePouchCommand {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
getPurpose() {
|
||||
return 'AI主动检索记忆中的专业知识、最佳实践和历史经验';
|
||||
}
|
||||
|
||||
async getContent(args) {
|
||||
const [query] = args;
|
||||
|
||||
try {
|
||||
const memories = await this.getAllMemories(query);
|
||||
|
||||
if (memories.length === 0) {
|
||||
return `🧠 AI记忆体系中暂无内容。
|
||||
|
||||
💡 建议:
|
||||
1. 使用 promptx remember 内化新知识
|
||||
2. 使用 promptx learn 学习后再内化
|
||||
3. 开始构建AI的专业知识体系`;
|
||||
}
|
||||
|
||||
const formattedMemories = this.formatRetrievedKnowledge(memories, query);
|
||||
|
||||
return `🧠 AI记忆体系 ${query ? `检索"${query}"` : '全部记忆'} (${memories.length}条):
|
||||
|
||||
${formattedMemories}
|
||||
|
||||
💡 记忆运用建议:
|
||||
1. 结合当前任务场景灵活运用
|
||||
2. 根据实际情况调整和变通
|
||||
3. 持续学习和增强记忆能力`;
|
||||
} catch (error) {
|
||||
return `❌ 检索记忆时出错:${error.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
getPATEOAS(args) {
|
||||
const [query] = args;
|
||||
|
||||
if (!query) {
|
||||
return {
|
||||
currentState: 'recall-waiting',
|
||||
availableTransitions: ['hello', 'learn'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '查看领域',
|
||||
description: '查看可检索的领域',
|
||||
command: 'promptx hello'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
const domain = this.extractDomain(query);
|
||||
|
||||
return {
|
||||
currentState: `recalled-${query}`,
|
||||
availableTransitions: ['action', 'learn', 'remember'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '应用记忆',
|
||||
description: `使用检索到的${query}知识`,
|
||||
command: `promptx action ${query}`
|
||||
},
|
||||
{
|
||||
name: '深入学习',
|
||||
description: `学习更多${domain}知识`,
|
||||
command: `promptx learn ${domain}`
|
||||
},
|
||||
{
|
||||
name: '增强记忆',
|
||||
description: 'AI内化新的知识增强记忆',
|
||||
command: `promptx remember ${query}-update`
|
||||
},
|
||||
{
|
||||
name: '相关检索',
|
||||
description: '检索相关领域知识',
|
||||
command: `promptx recall ${this.getRelatedQuery(query)}`
|
||||
}
|
||||
],
|
||||
metadata: {
|
||||
query: query,
|
||||
resultCount: this.lastSearchCount || 0,
|
||||
searchTime: new Date().toISOString()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有记忆(紧凑格式)
|
||||
*/
|
||||
async getAllMemories(query) {
|
||||
this.lastSearchCount = 0;
|
||||
const memories = [];
|
||||
|
||||
// 读取单一记忆文件
|
||||
const memoryFile = path.join(process.cwd(), '.promptx/memory/declarative.md');
|
||||
|
||||
try {
|
||||
if (await fs.pathExists(memoryFile)) {
|
||||
const content = await fs.readFile(memoryFile, 'utf-8');
|
||||
const lines = content.split('\n');
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('- ')) {
|
||||
// 解析记忆行
|
||||
const memory = this.parseMemoryLine(line);
|
||||
if (memory && (!query || this.matchesMemory(memory, query))) {
|
||||
memories.push(memory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error reading memories:', error);
|
||||
}
|
||||
|
||||
this.lastSearchCount = memories.length;
|
||||
return memories;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析记忆行(紧凑格式)
|
||||
*/
|
||||
parseMemoryLine(line) {
|
||||
// 格式:- 2025/05/31 14:30 内容 #key #tag1 #tag2 #评分:8 #有效期:长期
|
||||
const match = line.match(/^- (\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}) (.*?) (#\w+.*?)$/);
|
||||
if (!match) return null;
|
||||
|
||||
const [, timestamp, content, tagsStr] = match;
|
||||
const tags = tagsStr.split(' ').filter(t => t.startsWith('#'));
|
||||
const keyTag = tags.find(t => !t.includes(':') && !['#敏捷开发', '#测试', '#部署', '#前端开发', '#后端开发', '#AI', '#最佳实践', '#流程管理', '#工具使用', '#其他'].includes(t));
|
||||
|
||||
return {
|
||||
timestamp,
|
||||
content,
|
||||
key: keyTag ? keyTag.substring(1) : 'unknown',
|
||||
tags,
|
||||
source: keyTag ? keyTag.substring(1) : 'unknown'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查记忆是否匹配查询
|
||||
*/
|
||||
matchesMemory(memory, query) {
|
||||
const lowerQuery = query.toLowerCase();
|
||||
return memory.content.toLowerCase().includes(lowerQuery) ||
|
||||
memory.key.toLowerCase().includes(lowerQuery) ||
|
||||
memory.tags.some(tag => tag.toLowerCase().includes(lowerQuery));
|
||||
}
|
||||
|
||||
matchesQuery(content, query) {
|
||||
const lowerContent = content.toLowerCase();
|
||||
const lowerQuery = query.toLowerCase();
|
||||
const keywords = lowerQuery.split(/\s+/);
|
||||
|
||||
return keywords.some(keyword => lowerContent.includes(keyword));
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化检索到的记忆(紧凑格式)
|
||||
*/
|
||||
formatRetrievedKnowledge(memories, query) {
|
||||
return memories.map((memory, index) => {
|
||||
const content = memory.content.length > 120 ?
|
||||
memory.content.substring(0, 120) + '...' :
|
||||
memory.content;
|
||||
|
||||
return `📝 ${index + 1}. **${memory.key}** (${memory.timestamp})
|
||||
|
||||
${content}
|
||||
|
||||
${memory.tags.slice(0, 5).join(' ')}
|
||||
|
||||
---`;
|
||||
}).join('\n\n');
|
||||
}
|
||||
|
||||
extractDomain(query) {
|
||||
const domains = ['copywriter', 'scrum', 'developer', 'test', 'prompt'];
|
||||
const lowerQuery = query.toLowerCase();
|
||||
|
||||
return domains.find(domain => lowerQuery.includes(domain)) || null;
|
||||
}
|
||||
|
||||
getRelatedQuery(query) {
|
||||
const relatedMap = {
|
||||
'copywriter': 'marketing',
|
||||
'scrum': 'agile',
|
||||
'frontend': 'ui',
|
||||
'backend': 'api',
|
||||
'test': 'qa'
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(relatedMap)) {
|
||||
if (query.toLowerCase().includes(key)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return query + '-advanced';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RecallCommand;
|
||||
328
src/lib/core/pouch/commands/RememberCommand.js
Normal file
328
src/lib/core/pouch/commands/RememberCommand.js
Normal file
@ -0,0 +1,328 @@
|
||||
const BasePouchCommand = require('../BasePouchCommand');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* 记忆保存锦囊命令
|
||||
* 负责将知识、经验和最佳实践保存到记忆库中
|
||||
*/
|
||||
class RememberCommand extends BasePouchCommand {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
getPurpose() {
|
||||
return '增强AI长期记忆能力,主动内化专业知识、最佳实践和项目经验';
|
||||
}
|
||||
|
||||
async getContent(args) {
|
||||
const [key, ...valueParts] = args;
|
||||
const value = valueParts.join(' ');
|
||||
|
||||
if (!key) {
|
||||
return this.getUsageHelp();
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
return `❌ 请提供要内化的知识内容
|
||||
|
||||
🔍 使用方法:
|
||||
\`\`\`bash
|
||||
promptx remember <记忆标识> <知识内容>
|
||||
\`\`\`
|
||||
|
||||
📝 示例:
|
||||
\`\`\`bash
|
||||
promptx remember copywriter-tips "视频文案要有强烈的画面感和节奏感"
|
||||
promptx remember scrum-daily "每日站会应该控制在15分钟内,关注昨天、今天、阻碍"
|
||||
\`\`\``;
|
||||
}
|
||||
|
||||
try {
|
||||
const memoryEntry = await this.saveMemory(key, value);
|
||||
|
||||
return this.formatSaveResponse(key, value, memoryEntry);
|
||||
|
||||
} catch (error) {
|
||||
return `❌ 记忆内化失败:${error.message}
|
||||
|
||||
💡 可能的原因:
|
||||
- AI记忆体系目录权限不足
|
||||
- 磁盘空间不够
|
||||
- 记忆标识格式不正确
|
||||
|
||||
🔧 解决方案:
|
||||
1. 检查 .promptx 目录权限
|
||||
2. 确保磁盘空间充足
|
||||
3. 使用简洁的记忆标识(字母、数字、连字符)`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将知识内化到AI记忆体系(紧凑格式)
|
||||
*/
|
||||
async saveMemory(key, value) {
|
||||
// 1. 确保AI记忆体系目录存在
|
||||
const memoryDir = await this.ensureMemoryDirectory();
|
||||
|
||||
// 2. 使用单一记忆文件
|
||||
const memoryFile = path.join(memoryDir, 'declarative.md');
|
||||
|
||||
// 3. 格式化为一行记忆
|
||||
const memoryLine = this.formatMemoryLine(key, value);
|
||||
|
||||
// 4. 追加到记忆文件
|
||||
const action = await this.appendToMemoryFile(memoryFile, key, memoryLine);
|
||||
|
||||
return {
|
||||
key,
|
||||
value,
|
||||
filePath: memoryFile,
|
||||
action,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保AI记忆体系目录存在
|
||||
*/
|
||||
async ensureMemoryDirectory() {
|
||||
const promptxDir = path.join(process.cwd(), '.promptx');
|
||||
const memoryDir = path.join(promptxDir, 'memory');
|
||||
|
||||
await fs.ensureDir(memoryDir);
|
||||
|
||||
return memoryDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化为一行记忆(紧凑格式)
|
||||
*/
|
||||
formatMemoryLine(key, value) {
|
||||
const now = new Date();
|
||||
const timestamp = `${now.getFullYear()}/${String(now.getMonth() + 1).padStart(2, '0')}/${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
|
||||
|
||||
// 自动生成标签
|
||||
const tags = this.generateTags(key, value);
|
||||
|
||||
return `- ${timestamp} ${value} #${key} ${tags} #评分:8 #有效期:长期`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动生成标签
|
||||
*/
|
||||
generateTags(key, value) {
|
||||
const tags = [];
|
||||
const lowerKey = key.toLowerCase();
|
||||
const lowerValue = value.toLowerCase();
|
||||
|
||||
// 基于key生成标签
|
||||
if (lowerKey.includes('scrum') || lowerKey.includes('agile')) tags.push('#敏捷开发');
|
||||
if (lowerKey.includes('test') || lowerKey.includes('qa')) tags.push('#测试');
|
||||
if (lowerKey.includes('deploy') || lowerKey.includes('发布')) tags.push('#部署');
|
||||
if (lowerKey.includes('react') || lowerKey.includes('前端')) tags.push('#前端开发');
|
||||
if (lowerKey.includes('api') || lowerKey.includes('后端')) tags.push('#后端开发');
|
||||
if (lowerKey.includes('prompt') || lowerKey.includes('ai')) tags.push('#AI');
|
||||
|
||||
// 基于value生成标签
|
||||
if (lowerValue.includes('最佳实践') || lowerValue.includes('规则')) tags.push('#最佳实践');
|
||||
if (lowerValue.includes('流程') || lowerValue.includes('步骤')) tags.push('#流程管理');
|
||||
if (lowerValue.includes('命令') || lowerValue.includes('工具')) tags.push('#工具使用');
|
||||
|
||||
return tags.join(' ') || '#其他';
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加到记忆文件
|
||||
*/
|
||||
async appendToMemoryFile(memoryFile, key, memoryLine) {
|
||||
// 初始化文件(如果不存在)
|
||||
if (!await fs.pathExists(memoryFile)) {
|
||||
await fs.writeFile(memoryFile, `# 陈述性记忆
|
||||
|
||||
## 高价值记忆(评分 ≥ 7)
|
||||
|
||||
${memoryLine}
|
||||
|
||||
`);
|
||||
return 'created';
|
||||
}
|
||||
|
||||
// 读取现有内容
|
||||
const content = await fs.readFile(memoryFile, 'utf-8');
|
||||
|
||||
// 检查是否已存在相同key的记忆
|
||||
const keyPattern = new RegExp(`^- .*#${key}\\b`, 'm');
|
||||
if (keyPattern.test(content)) {
|
||||
// 替换现有记忆
|
||||
const updatedContent = content.replace(keyPattern, memoryLine);
|
||||
await fs.writeFile(memoryFile, updatedContent);
|
||||
return 'updated';
|
||||
} else {
|
||||
// 追加新记忆(在高价值记忆部分)
|
||||
const insertPosition = content.indexOf('\n\n') + 2;
|
||||
const updatedContent = content.slice(0, insertPosition) + memoryLine + '\n\n' + content.slice(insertPosition);
|
||||
await fs.writeFile(memoryFile, updatedContent);
|
||||
return 'created';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 格式化保存响应(简化版本)
|
||||
*/
|
||||
formatSaveResponse(key, value, memoryEntry) {
|
||||
const { action, timestamp } = memoryEntry;
|
||||
|
||||
const actionLabels = {
|
||||
created: '✅ AI已内化新记忆',
|
||||
updated: '🔄 AI已更新记忆'
|
||||
};
|
||||
|
||||
return `${actionLabels[action]}:${key}
|
||||
|
||||
## 📋 记忆详情
|
||||
- **记忆标识**: \`${key}\`
|
||||
- **内化时间**: ${timestamp.split('T')[0]}
|
||||
- **知识内容**: ${value.length > 100 ? value.substring(0, 100) + '...' : value}
|
||||
|
||||
## 🎯 能力增强效果
|
||||
- ✅ **知识已内化到AI长期记忆**
|
||||
- ✅ **可通过recall命令主动检索**
|
||||
- ✅ **支持跨会话记忆保持**
|
||||
|
||||
## 🔄 下一步行动:
|
||||
- 记忆检索: 验证知识内化效果
|
||||
命令: \`promptx recall ${key}\`
|
||||
- 能力强化: 学习相关知识增强记忆
|
||||
命令: \`promptx learn <protocol>://<resource-id>\`
|
||||
- 应用实践: 在实际场景中运用记忆
|
||||
命令: \`promptx action <role-id>\`
|
||||
|
||||
📍 当前状态:memory_saved`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取使用帮助
|
||||
*/
|
||||
getUsageHelp() {
|
||||
return `🧠 **Remember锦囊 - AI记忆增强系统**
|
||||
|
||||
## 📖 基本用法
|
||||
\`\`\`bash
|
||||
promptx remember <记忆标识> <知识内容>
|
||||
\`\`\`
|
||||
|
||||
## 💡 记忆内化示例
|
||||
|
||||
### 📝 AI记忆内化
|
||||
AI学习和内化各种专业知识
|
||||
\`\`\`bash
|
||||
promptx remember "deploy-process" "1.构建代码 2.运行测试 3.部署到staging 4.验证功能 5.发布生产"
|
||||
promptx remember "debug-case-001" "用户反馈视频加载慢,排查发现是CDN配置问题,修改后加载速度提升60%"
|
||||
promptx remember "react-hooks" "React Hooks允许在函数组件中使用state和其他React特性"
|
||||
promptx remember "code-review-rules" "每个PR至少需要2个人review,必须包含测试用例"
|
||||
\`\`\`
|
||||
|
||||
## 💡 记忆标识规范
|
||||
- 使用简洁的英文标识
|
||||
- 支持连字符分隔
|
||||
- 例如:\`copywriter-tips\`、\`scrum-daily\`、\`react-best-practice\`
|
||||
|
||||
## 🔍 记忆检索与应用
|
||||
\`\`\`bash
|
||||
promptx recall <关键词> # AI主动检索记忆
|
||||
promptx action <role-id> # AI运用记忆激活角色
|
||||
\`\`\`
|
||||
|
||||
🔄 下一步行动:
|
||||
- 开始记忆: 内化第一条知识
|
||||
命令: promptx remember <key> <content>
|
||||
- 学习资源: 学习新知识再内化
|
||||
命令: promptx learn <protocol>://<resource>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取PATEOAS导航信息
|
||||
*/
|
||||
getPATEOAS(args) {
|
||||
const [key, ...valueParts] = args;
|
||||
const value = valueParts.join(' ');
|
||||
|
||||
if (!key) {
|
||||
return {
|
||||
currentState: 'remember_awaiting_input',
|
||||
availableTransitions: ['hello', 'learn', 'recall'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '查看角色',
|
||||
description: '选择角色获取专业知识',
|
||||
command: 'promptx hello',
|
||||
priority: 'medium'
|
||||
},
|
||||
{
|
||||
name: '学习资源',
|
||||
description: '学习新知识然后保存',
|
||||
command: 'promptx learn <protocol>://<resource>',
|
||||
priority: 'high'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
return {
|
||||
currentState: 'remember_awaiting_content',
|
||||
availableTransitions: ['remember', 'recall'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '重新输入',
|
||||
description: '提供完整的记忆内容',
|
||||
command: `promptx remember ${key} <content>`,
|
||||
priority: 'high'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
currentState: 'memory_saved',
|
||||
availableTransitions: ['recall', 'learn', 'action', 'remember'],
|
||||
nextActions: [
|
||||
{
|
||||
name: '检索记忆',
|
||||
description: '测试记忆是否可检索',
|
||||
command: `promptx recall ${key}`,
|
||||
priority: 'high'
|
||||
},
|
||||
{
|
||||
name: '学习强化',
|
||||
description: '学习相关知识加强记忆',
|
||||
command: 'promptx learn <protocol>://<resource>',
|
||||
priority: 'medium'
|
||||
},
|
||||
{
|
||||
name: '应用记忆',
|
||||
description: '在实际场景中应用记忆',
|
||||
command: 'promptx action <role-id>',
|
||||
priority: 'medium'
|
||||
},
|
||||
{
|
||||
name: '继续内化',
|
||||
description: 'AI继续内化更多知识',
|
||||
command: 'promptx remember <key> <content>',
|
||||
priority: 'low'
|
||||
}
|
||||
],
|
||||
metadata: {
|
||||
savedMemory: key,
|
||||
memoryLength: value.length,
|
||||
timestamp: new Date().toISOString(),
|
||||
systemVersion: '锦囊串联状态机 v1.0'
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RememberCommand;
|
||||
19
src/lib/core/pouch/commands/index.js
Normal file
19
src/lib/core/pouch/commands/index.js
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 锦囊命令导出
|
||||
*/
|
||||
|
||||
const InitCommand = require('./InitCommand');
|
||||
const HelloCommand = require('./HelloCommand');
|
||||
const ActionCommand = require('./ActionCommand');
|
||||
const LearnCommand = require('./LearnCommand');
|
||||
const RecallCommand = require('./RecallCommand');
|
||||
const RememberCommand = require('./RememberCommand');
|
||||
|
||||
module.exports = {
|
||||
InitCommand,
|
||||
HelloCommand,
|
||||
ActionCommand,
|
||||
LearnCommand,
|
||||
RecallCommand,
|
||||
RememberCommand
|
||||
};
|
||||
43
src/lib/core/pouch/index.js
Normal file
43
src/lib/core/pouch/index.js
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 锦囊框架 (PATEOAS Framework)
|
||||
* Prompt as the Engine of Application State
|
||||
*
|
||||
* 这是一个革命性的AI-First CLI框架,通过锦囊串联实现AI的状态管理。
|
||||
* 每个锦囊都是独立的专家知识单元,通过PATEOAS导航实现状态转换。
|
||||
*/
|
||||
|
||||
const PouchCLI = require('./PouchCLI');
|
||||
const PouchRegistry = require('./PouchRegistry');
|
||||
const PouchStateMachine = require('./state/PouchStateMachine');
|
||||
const BasePouchCommand = require('./BasePouchCommand');
|
||||
const commands = require('./commands');
|
||||
|
||||
// 创建全局CLI实例
|
||||
const cli = new PouchCLI();
|
||||
|
||||
module.exports = {
|
||||
// 主要导出
|
||||
PouchCLI,
|
||||
cli,
|
||||
|
||||
// 框架组件
|
||||
PouchRegistry,
|
||||
PouchStateMachine,
|
||||
BasePouchCommand,
|
||||
|
||||
// 内置命令
|
||||
commands,
|
||||
|
||||
// 便捷方法
|
||||
execute: async (commandName, args) => {
|
||||
return await cli.execute(commandName, args);
|
||||
},
|
||||
|
||||
help: () => {
|
||||
return cli.getHelp();
|
||||
},
|
||||
|
||||
status: () => {
|
||||
return cli.getStatus();
|
||||
}
|
||||
};
|
||||
47
src/lib/core/pouch/interfaces.js
Normal file
47
src/lib/core/pouch/interfaces.js
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 锦囊框架核心接口定义
|
||||
* PATEOAS (Prompt as the Engine of Application State)
|
||||
*/
|
||||
|
||||
/**
|
||||
* 动作定义
|
||||
* @typedef {Object} Action
|
||||
* @property {string} name - 动作名称
|
||||
* @property {string} description - 动作描述
|
||||
* @property {string} command - 执行命令
|
||||
* @property {Object} [parameters] - 命令参数
|
||||
* @property {string} [condition] - 执行条件
|
||||
*/
|
||||
|
||||
/**
|
||||
* PATEOAS导航信息
|
||||
* @typedef {Object} PATEOASNavigation
|
||||
* @property {Action[]} nextActions - 下一步可执行的动作列表
|
||||
* @property {string} currentState - 当前状态
|
||||
* @property {string[]} availableTransitions - 可用的状态转换
|
||||
* @property {Object} [metadata] - 额外的元数据
|
||||
*/
|
||||
|
||||
/**
|
||||
* 状态上下文
|
||||
* @typedef {Object} StateContext
|
||||
* @property {string} currentPouch - 当前锦囊
|
||||
* @property {string[]} history - 历史记录
|
||||
* @property {Object} [userProfile] - 用户配置
|
||||
* @property {Object} [sessionData] - 会话数据
|
||||
* @property {Object} [domainContext] - 领域上下文
|
||||
*/
|
||||
|
||||
/**
|
||||
* 锦囊输出格式
|
||||
* @typedef {Object} PouchOutput
|
||||
* @property {string} purpose - 锦囊目的说明
|
||||
* @property {string} content - 锦囊内容(提示词)
|
||||
* @property {PATEOASNavigation} pateoas - PATEOAS导航信息
|
||||
* @property {StateContext} [context] - 状态上下文
|
||||
* @property {'human'|'json'} [format='human'] - 输出格式
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// 这些是类型定义,JavaScript中不需要导出
|
||||
};
|
||||
173
src/lib/core/pouch/state/PouchStateMachine.js
Normal file
173
src/lib/core/pouch/state/PouchStateMachine.js
Normal file
@ -0,0 +1,173 @@
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* 锦囊状态机管理器
|
||||
* 负责管理锦囊之间的状态转换
|
||||
*/
|
||||
class PouchStateMachine {
|
||||
constructor() {
|
||||
this.currentState = 'initial';
|
||||
this.stateHistory = [];
|
||||
this.context = {
|
||||
currentPouch: '',
|
||||
history: [],
|
||||
userProfile: {},
|
||||
sessionData: {},
|
||||
domainContext: {}
|
||||
};
|
||||
this.commands = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册锦囊命令
|
||||
* @param {string} name - 命令名称
|
||||
* @param {BasePouchCommand} command - 命令实例
|
||||
*/
|
||||
registerCommand(name, command) {
|
||||
this.commands.set(name, command);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行状态转换
|
||||
* @param {string} commandName - 命令名称
|
||||
* @param {Array} args - 命令参数
|
||||
* @returns {Promise<PouchOutput>} 执行结果
|
||||
*/
|
||||
async transition(commandName, args = []) {
|
||||
// 获取命令对应的锦囊
|
||||
const command = this.commands.get(commandName);
|
||||
if (!command) {
|
||||
throw new Error(`未找到命令: ${commandName}`);
|
||||
}
|
||||
|
||||
// 记录历史
|
||||
this.stateHistory.push({
|
||||
from: this.currentState,
|
||||
command: commandName,
|
||||
timestamp: new Date().toISOString(),
|
||||
args: args
|
||||
});
|
||||
|
||||
// 更新上下文
|
||||
this.context.currentPouch = commandName;
|
||||
this.context.history = this.stateHistory.map(h => h.command || h.to);
|
||||
|
||||
// 设置命令上下文
|
||||
command.setContext(this.context);
|
||||
|
||||
// 执行命令
|
||||
const result = await command.execute(args);
|
||||
|
||||
// 根据PATEOAS导航更新状态
|
||||
if (result && result.pateoas && result.pateoas.currentState) {
|
||||
this.currentState = result.pateoas.currentState;
|
||||
}
|
||||
|
||||
// 保存状态
|
||||
await this.saveState();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前状态
|
||||
* @returns {string} 当前状态
|
||||
*/
|
||||
getCurrentState() {
|
||||
return this.currentState;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可用的状态转换
|
||||
* @returns {string[]} 可转换的状态列表
|
||||
*/
|
||||
getAvailableTransitions() {
|
||||
const transitions = {
|
||||
'initial': ['init', 'hello'],
|
||||
'initialized': ['hello', 'action', 'learn'],
|
||||
'discovering': ['action', 'learn', 'init'],
|
||||
'activated': ['learn', 'recall', 'hello'],
|
||||
'learned': ['action', 'recall', 'hello'],
|
||||
'recalled': ['action', 'learn', 'remember']
|
||||
};
|
||||
|
||||
// 根据当前状态的前缀匹配
|
||||
for (const [statePrefix, availableStates] of Object.entries(transitions)) {
|
||||
if (this.currentState.startsWith(statePrefix)) {
|
||||
return availableStates;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认可转换状态
|
||||
return ['hello', 'init'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 保存状态到文件
|
||||
*/
|
||||
async saveState() {
|
||||
const promptxDir = path.join(process.cwd(), '.promptx');
|
||||
const configPath = path.join(promptxDir, 'pouch.json');
|
||||
|
||||
try {
|
||||
// 确保 .promptx 目录存在
|
||||
await fs.ensureDir(promptxDir);
|
||||
|
||||
let config = {};
|
||||
if (await fs.pathExists(configPath)) {
|
||||
config = await fs.readJson(configPath);
|
||||
}
|
||||
|
||||
config.currentState = this.currentState;
|
||||
config.stateHistory = this.stateHistory.slice(-50); // 只保留最近50条记录
|
||||
config.lastUpdated = new Date().toISOString();
|
||||
|
||||
await fs.writeJson(configPath, config, { spaces: 2 });
|
||||
} catch (error) {
|
||||
console.error('保存状态失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件加载状态
|
||||
*/
|
||||
async loadState() {
|
||||
const configPath = path.join(process.cwd(), '.promptx', 'pouch.json');
|
||||
|
||||
try {
|
||||
if (await fs.pathExists(configPath)) {
|
||||
const config = await fs.readJson(configPath);
|
||||
|
||||
if (config.currentState) {
|
||||
this.currentState = config.currentState;
|
||||
}
|
||||
|
||||
if (config.stateHistory) {
|
||||
this.stateHistory = config.stateHistory;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载状态失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置状态机
|
||||
*/
|
||||
reset() {
|
||||
this.currentState = 'initial';
|
||||
this.stateHistory = [];
|
||||
this.context = {
|
||||
currentPouch: '',
|
||||
history: [],
|
||||
userProfile: {},
|
||||
sessionData: {},
|
||||
domainContext: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PouchStateMachine;
|
||||
78
src/lib/core/resource/protocols/ExecutionProtocol.js
Normal file
78
src/lib/core/resource/protocols/ExecutionProtocol.js
Normal file
@ -0,0 +1,78 @@
|
||||
const ResourceProtocol = require('./ResourceProtocol');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* 执行模式协议处理器
|
||||
* 处理 execution:// 协议的资源解析
|
||||
*/
|
||||
class ExecutionProtocol extends ResourceProtocol {
|
||||
constructor() {
|
||||
super('execution');
|
||||
this.registry = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置注册表
|
||||
*/
|
||||
setRegistry(registry) {
|
||||
this.registry = registry || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议信息
|
||||
*/
|
||||
getProtocolInfo() {
|
||||
return {
|
||||
name: 'execution',
|
||||
description: '执行模式资源协议',
|
||||
location: 'execution://{execution_id}',
|
||||
examples: [
|
||||
'execution://deal-at-reference',
|
||||
'execution://prompt-developer',
|
||||
'execution://memory-trigger'
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析资源路径
|
||||
*/
|
||||
async resolvePath(resourcePath, queryParams) {
|
||||
const executionId = resourcePath.trim();
|
||||
|
||||
if (!this.registry[executionId]) {
|
||||
throw new Error(`执行模式 "${executionId}" 未在注册表中找到`);
|
||||
}
|
||||
|
||||
let resolvedPath = this.registry[executionId];
|
||||
|
||||
// 处理 @package:// 前缀
|
||||
if (resolvedPath.startsWith('@package://')) {
|
||||
resolvedPath = resolvedPath.replace('@package://', '');
|
||||
}
|
||||
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载资源内容
|
||||
*/
|
||||
async loadContent(resolvedPath, queryParams) {
|
||||
try {
|
||||
const content = await fs.readFile(resolvedPath, 'utf-8');
|
||||
return content;
|
||||
} catch (error) {
|
||||
throw new Error(`无法加载执行模式文件 ${resolvedPath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证资源路径
|
||||
*/
|
||||
validatePath(resourcePath) {
|
||||
return /^[a-zA-Z0-9_-]+$/.test(resourcePath);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ExecutionProtocol;
|
||||
@ -17,6 +17,14 @@ class PackageProtocol extends ResourceProtocol {
|
||||
this.installModeCache = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置注册表(保持与其他协议的一致性)
|
||||
*/
|
||||
setRegistry(registry) {
|
||||
// Package协议不使用注册表,但为了一致性提供此方法
|
||||
this.registry = registry || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议信息
|
||||
*/
|
||||
|
||||
@ -35,6 +35,14 @@ class ProjectProtocol extends ResourceProtocol {
|
||||
this.projectRootCache = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置注册表(保持与其他协议的一致性)
|
||||
*/
|
||||
setRegistry(registry) {
|
||||
// Project协议不使用注册表,但为了一致性提供此方法
|
||||
this.registry = registry || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议信息
|
||||
* @returns {object} 协议信息
|
||||
|
||||
255
src/lib/core/resource/protocols/PromptProtocol.js
Normal file
255
src/lib/core/resource/protocols/PromptProtocol.js
Normal file
@ -0,0 +1,255 @@
|
||||
const ResourceProtocol = require('./ResourceProtocol');
|
||||
const path = require('path');
|
||||
const fs = require('fs').promises;
|
||||
const { glob } = require('glob');
|
||||
const { promisify } = require('util');
|
||||
|
||||
/**
|
||||
* PromptX内置提示词资源协议实现
|
||||
* 实现@prompt://协议,用于访问PromptX内置的提示词资源
|
||||
*/
|
||||
class PromptProtocol extends ResourceProtocol {
|
||||
constructor(options = {}) {
|
||||
super('prompt', options);
|
||||
|
||||
// PromptX 内置资源注册表
|
||||
this.registry = new Map([
|
||||
['protocols', '@package://prompt/protocol/**/*.md'],
|
||||
['core', '@package://prompt/core/**/*.md'],
|
||||
['domain', '@package://prompt/domain/**/*.md'],
|
||||
['resource', '@package://prompt/resource/**/*.md'],
|
||||
['bootstrap', '@package://bootstrap.md']
|
||||
]);
|
||||
|
||||
// 依赖的其他协议
|
||||
this.packageProtocol = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置依赖的协议
|
||||
* @param {PackageProtocol} packageProtocol - 包协议实例
|
||||
*/
|
||||
setPackageProtocol(packageProtocol) {
|
||||
this.packageProtocol = packageProtocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置注册表
|
||||
*/
|
||||
setRegistry(registry) {
|
||||
this.registry = registry || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议信息
|
||||
*/
|
||||
getProtocolInfo() {
|
||||
return {
|
||||
name: 'prompt',
|
||||
description: 'PromptX内置提示词资源协议',
|
||||
location: 'prompt://{resource_id}',
|
||||
examples: [
|
||||
'prompt://protocols',
|
||||
'prompt://core',
|
||||
'prompt://domain',
|
||||
'prompt://bootstrap'
|
||||
],
|
||||
availableResources: Array.from(this.registry.keys()),
|
||||
params: this.getSupportedParams()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 支持的查询参数
|
||||
*/
|
||||
getSupportedParams() {
|
||||
return {
|
||||
...super.getSupportedParams(),
|
||||
merge: 'boolean - 是否合并多个文件内容',
|
||||
separator: 'string - 文件间分隔符',
|
||||
include_filename: 'boolean - 是否包含文件名标题'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证资源路径
|
||||
*/
|
||||
validatePath(resourcePath) {
|
||||
if (!super.validatePath(resourcePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否在注册表中
|
||||
return this.registry.has(resourcePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析资源路径
|
||||
*/
|
||||
async resolvePath(resourcePath, queryParams) {
|
||||
// 验证资源是否存在
|
||||
if (!this.registry.has(resourcePath)) {
|
||||
throw new Error(`未找到 prompt 资源: ${resourcePath}。可用资源: ${Array.from(this.registry.keys()).join(', ')}`);
|
||||
}
|
||||
|
||||
// 获取对应的包路径
|
||||
const packagePath = this.registry.get(resourcePath);
|
||||
return packagePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载资源内容
|
||||
*/
|
||||
async loadContent(packagePath, queryParams) {
|
||||
// 确保有包协议依赖
|
||||
if (!this.packageProtocol) {
|
||||
throw new Error('PromptProtocol 需要 PackageProtocol 依赖');
|
||||
}
|
||||
|
||||
// 检查是否是通配符路径
|
||||
if (packagePath.includes('**') || packagePath.includes('*')) {
|
||||
return await this.loadMultipleFiles(packagePath, queryParams);
|
||||
} else {
|
||||
return await this.loadSingleFile(packagePath, queryParams);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载单个文件
|
||||
*/
|
||||
async loadSingleFile(packagePath, queryParams) {
|
||||
try {
|
||||
// 移除协议前缀
|
||||
const cleanPath = packagePath.replace('@package://', '');
|
||||
const result = await this.packageProtocol.loadContent(cleanPath, queryParams);
|
||||
return result.content || result;
|
||||
} catch (error) {
|
||||
throw new Error(`加载单个文件失败 ${packagePath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载多个文件(通配符支持)
|
||||
*/
|
||||
async loadMultipleFiles(packagePath, queryParams) {
|
||||
try {
|
||||
// 获取包根目录
|
||||
const packageRoot = await this.packageProtocol.getPackageRoot();
|
||||
|
||||
// 移除协议前缀并构建搜索路径
|
||||
const cleanPath = packagePath.replace('@package://', '');
|
||||
const searchPattern = path.join(packageRoot, cleanPath);
|
||||
|
||||
// 使用 glob 查找匹配的文件
|
||||
const files = await glob(searchPattern, {
|
||||
ignore: ['**/node_modules/**', '**/.git/**']
|
||||
});
|
||||
|
||||
if (files.length === 0) {
|
||||
throw new Error(`没有找到匹配的文件: ${packagePath}`);
|
||||
}
|
||||
|
||||
// 读取所有文件内容
|
||||
const contents = [];
|
||||
for (const filePath of files.sort()) {
|
||||
try {
|
||||
const content = await fs.readFile(filePath, 'utf8');
|
||||
const relativePath = path.relative(packageRoot, filePath);
|
||||
|
||||
contents.push({
|
||||
path: relativePath,
|
||||
content: content
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn(`警告: 无法读取文件 ${filePath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 合并内容
|
||||
return this.mergeContents(contents, queryParams);
|
||||
} catch (error) {
|
||||
throw new Error(`加载多个文件失败 ${packagePath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并多个文件内容
|
||||
*/
|
||||
mergeContents(contents, queryParams) {
|
||||
const merge = queryParams?.get('merge') !== 'false'; // 默认合并
|
||||
const separator = queryParams?.get('separator') || '\n\n---\n\n';
|
||||
const includeFilename = queryParams?.get('include_filename') !== 'false'; // 默认包含文件名
|
||||
|
||||
if (!merge) {
|
||||
// 不合并,返回 JSON 格式
|
||||
return JSON.stringify(contents, null, 2);
|
||||
}
|
||||
|
||||
// 合并所有内容
|
||||
const mergedParts = contents.map(({ path, content }) => {
|
||||
let part = '';
|
||||
|
||||
if (includeFilename) {
|
||||
part += `# ${path}\n\n`;
|
||||
}
|
||||
|
||||
part += content;
|
||||
|
||||
return part;
|
||||
});
|
||||
|
||||
return mergedParts.join(separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查资源是否存在
|
||||
*/
|
||||
async exists(resourcePath, queryParams) {
|
||||
try {
|
||||
const packagePath = await this.resolvePath(resourcePath, queryParams);
|
||||
|
||||
if (packagePath.includes('**') || packagePath.includes('*')) {
|
||||
// 通配符路径:检查是否有匹配的文件
|
||||
const packageRoot = await this.packageProtocol.getPackageRoot();
|
||||
const cleanPath = packagePath.replace('@package://', '');
|
||||
const searchPattern = path.join(packageRoot, cleanPath);
|
||||
const files = await glob(searchPattern);
|
||||
return files.length > 0;
|
||||
} else {
|
||||
// 单个文件:检查文件是否存在
|
||||
const cleanPath = packagePath.replace('@package://', '');
|
||||
return await this.packageProtocol.exists(cleanPath, queryParams);
|
||||
}
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出所有可用资源
|
||||
*/
|
||||
listResources() {
|
||||
return Array.from(this.registry.entries()).map(([key, value]) => ({
|
||||
id: key,
|
||||
path: value,
|
||||
description: this.getResourceDescription(key)
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源描述
|
||||
*/
|
||||
getResourceDescription(resourceId) {
|
||||
const descriptions = {
|
||||
'protocols': 'DPML协议规范文档',
|
||||
'core': '核心思维和执行模式',
|
||||
'domain': '领域专家角色定义',
|
||||
'resource': '资源管理和路径解析',
|
||||
'bootstrap': 'PromptX启动引导文件'
|
||||
};
|
||||
|
||||
return descriptions[resourceId] || '未知资源';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PromptProtocol;
|
||||
79
src/lib/core/resource/protocols/RoleProtocol.js
Normal file
79
src/lib/core/resource/protocols/RoleProtocol.js
Normal file
@ -0,0 +1,79 @@
|
||||
const ResourceProtocol = require('./ResourceProtocol');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* AI角色协议处理器
|
||||
* 处理 role:// 协议的资源解析,直接加载完整role文件
|
||||
*/
|
||||
class RoleProtocol extends ResourceProtocol {
|
||||
constructor() {
|
||||
super('role');
|
||||
this.registry = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置注册表
|
||||
*/
|
||||
setRegistry(registry) {
|
||||
this.registry = registry || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议信息
|
||||
*/
|
||||
getProtocolInfo() {
|
||||
return {
|
||||
name: 'role',
|
||||
description: 'AI角色资源协议',
|
||||
location: 'role://{role_id}',
|
||||
examples: [
|
||||
'role://video-copywriter',
|
||||
'role://product-owner',
|
||||
'role://assistant',
|
||||
'role://prompt-developer'
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析资源路径
|
||||
*/
|
||||
async resolvePath(resourcePath, queryParams) {
|
||||
const roleId = resourcePath.trim();
|
||||
|
||||
if (!this.registry[roleId]) {
|
||||
throw new Error(`角色 "${roleId}" 未在注册表中找到。可用角色:${Object.keys(this.registry).join(', ')}`);
|
||||
}
|
||||
|
||||
let resolvedPath = this.registry[roleId];
|
||||
|
||||
// 处理 @package:// 前缀
|
||||
if (resolvedPath.startsWith('@package://')) {
|
||||
resolvedPath = resolvedPath.replace('@package://', '');
|
||||
}
|
||||
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载资源内容
|
||||
*/
|
||||
async loadContent(resolvedPath, queryParams) {
|
||||
try {
|
||||
const content = await fs.readFile(resolvedPath, 'utf-8');
|
||||
return content;
|
||||
} catch (error) {
|
||||
throw new Error(`无法加载角色文件 ${resolvedPath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证资源路径
|
||||
*/
|
||||
validatePath(resourcePath) {
|
||||
return /^[a-zA-Z0-9_-]+$/.test(resourcePath);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RoleProtocol;
|
||||
77
src/lib/core/resource/protocols/ThoughtProtocol.js
Normal file
77
src/lib/core/resource/protocols/ThoughtProtocol.js
Normal file
@ -0,0 +1,77 @@
|
||||
const ResourceProtocol = require('./ResourceProtocol');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* 思维模式协议处理器
|
||||
* 处理 thought:// 协议的资源解析
|
||||
*/
|
||||
class ThoughtProtocol extends ResourceProtocol {
|
||||
constructor() {
|
||||
super('thought');
|
||||
this.registry = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置注册表
|
||||
*/
|
||||
setRegistry(registry) {
|
||||
this.registry = registry || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议信息
|
||||
*/
|
||||
getProtocolInfo() {
|
||||
return {
|
||||
name: 'thought',
|
||||
description: '思维模式资源协议',
|
||||
location: 'thought://{thought_id}',
|
||||
examples: [
|
||||
'thought://prompt-developer',
|
||||
'thought://product-owner'
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析资源路径
|
||||
*/
|
||||
async resolvePath(resourcePath, queryParams) {
|
||||
const thoughtId = resourcePath.trim();
|
||||
|
||||
if (!this.registry[thoughtId]) {
|
||||
throw new Error(`思维模式 "${thoughtId}" 未在注册表中找到`);
|
||||
}
|
||||
|
||||
let resolvedPath = this.registry[thoughtId];
|
||||
|
||||
// 处理 @package:// 前缀
|
||||
if (resolvedPath.startsWith('@package://')) {
|
||||
resolvedPath = resolvedPath.replace('@package://', '');
|
||||
}
|
||||
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载资源内容
|
||||
*/
|
||||
async loadContent(resolvedPath, queryParams) {
|
||||
try {
|
||||
const content = await fs.readFile(resolvedPath, 'utf-8');
|
||||
return content;
|
||||
} catch (error) {
|
||||
throw new Error(`无法加载思维模式文件 ${resolvedPath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证资源路径
|
||||
*/
|
||||
validatePath(resourcePath) {
|
||||
return /^[a-zA-Z0-9_-]+$/.test(resourcePath);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ThoughtProtocol;
|
||||
@ -49,6 +49,14 @@ class UserProtocol extends ResourceProtocol {
|
||||
this.dirCache = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置注册表(保持与其他协议的一致性)
|
||||
*/
|
||||
setRegistry(registry) {
|
||||
// User协议不使用注册表,但为了一致性提供此方法
|
||||
this.registry = registry || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议信息
|
||||
* @returns {object} 协议信息
|
||||
|
||||
@ -2,319 +2,140 @@ const ResourceProtocolParser = require('./resourceProtocolParser');
|
||||
const ResourceRegistry = require('./resourceRegistry');
|
||||
const { ResourceResult } = require('./types');
|
||||
const logger = require('../../utils/logger');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
// 导入协议实现
|
||||
const PackageProtocol = require('./protocols/PackageProtocol');
|
||||
const ProjectProtocol = require('./protocols/ProjectProtocol');
|
||||
const UserProtocol = require('./protocols/UserProtocol');
|
||||
const PromptProtocol = require('./protocols/PromptProtocol');
|
||||
|
||||
/**
|
||||
* 资源管理器
|
||||
* 基于DPML资源协议的统一资源管理入口
|
||||
* 资源管理器 - 统一管理各种协议的资源加载
|
||||
*/
|
||||
class ResourceManager {
|
||||
constructor(options = {}) {
|
||||
this.parser = new ResourceProtocolParser();
|
||||
this.registry = new ResourceRegistry();
|
||||
this.workingDirectory = options.workingDirectory || process.cwd();
|
||||
|
||||
// 暂时直接实现简单的加载功能,后续可扩展为独立组件
|
||||
this.cache = new Map();
|
||||
this.enableCache = options.enableCache !== false;
|
||||
constructor() {
|
||||
this.protocolHandlers = new Map();
|
||||
this.registry = null;
|
||||
this.initialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析并获取资源
|
||||
* @param {string} resourceRef - DPML资源引用
|
||||
* @param {object} options - 选项
|
||||
* @returns {Promise<ResourceResult>} 资源结果
|
||||
* 初始化资源管理器
|
||||
*/
|
||||
async resolve(resourceRef, options = {}) {
|
||||
async initialize() {
|
||||
if (this.initialized) return;
|
||||
|
||||
try {
|
||||
logger.debug(`Resolving resource: ${resourceRef}`);
|
||||
// 从统一注册表加载所有协议信息
|
||||
await this.loadUnifiedRegistry();
|
||||
|
||||
// 1. 解析资源引用
|
||||
const parsed = this.parser.parse(resourceRef);
|
||||
logger.debug(`Parsed reference:`, parsed);
|
||||
|
||||
// 2. 通过注册表解析路径
|
||||
const resolvedPath = this.registry.resolve(parsed.protocol, parsed.path);
|
||||
logger.debug(`Resolved path: ${resolvedPath}`);
|
||||
|
||||
// 3. 处理可能的嵌套引用
|
||||
if (resolvedPath.startsWith('@')) {
|
||||
logger.debug(`Detected nested reference: ${resolvedPath}`);
|
||||
return await this.resolve(resolvedPath, options);
|
||||
}
|
||||
|
||||
// 4. 加载资源内容
|
||||
let content = await this.loadResource(resolvedPath, parsed, options);
|
||||
// 注册协议处理器
|
||||
await this.registerProtocolHandlers();
|
||||
|
||||
// 5. 检查内容是否是另一个资源引用(用于嵌套引用)
|
||||
if (content.trim().startsWith('@')) {
|
||||
logger.debug(`Content is a nested reference: ${content.trim()}`);
|
||||
return await this.resolve(content.trim(), options);
|
||||
}
|
||||
|
||||
// 6. 创建结果
|
||||
const result = ResourceResult.success(content, {
|
||||
originalRef: resourceRef,
|
||||
resolvedPath: resolvedPath,
|
||||
protocol: parsed.protocol,
|
||||
loadingSemantics: parsed.loadingSemantics,
|
||||
queryParams: parsed.queryParams.getAll()
|
||||
});
|
||||
|
||||
result.sources = [resolvedPath];
|
||||
result.format = options.format || 'text';
|
||||
|
||||
logger.debug(`Resource resolved successfully`);
|
||||
return result;
|
||||
|
||||
this.initialized = true;
|
||||
} catch (error) {
|
||||
logger.error(`Failed to resolve resource ${resourceRef}:`, error.message);
|
||||
return ResourceResult.error(error, { originalRef: resourceRef });
|
||||
throw new Error(`ResourceManager初始化失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量解析多个资源
|
||||
* @param {string[]} resourceRefs - 资源引用列表
|
||||
* @param {object} options - 选项
|
||||
* @returns {Promise<ResourceResult[]>} 资源结果列表
|
||||
* 加载统一资源注册表
|
||||
*/
|
||||
async resolveMultiple(resourceRefs, options = {}) {
|
||||
const results = [];
|
||||
async loadUnifiedRegistry() {
|
||||
const registryPath = path.resolve(__dirname, '../../../resource.registry.json');
|
||||
|
||||
for (const ref of resourceRefs) {
|
||||
const result = await this.resolve(ref, options);
|
||||
results.push(result);
|
||||
if (!await fs.pathExists(registryPath)) {
|
||||
throw new Error(`统一资源注册表文件不存在: ${registryPath}`);
|
||||
}
|
||||
|
||||
const registryContent = await fs.readJSON(registryPath);
|
||||
this.registry = registryContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册协议处理器
|
||||
*/
|
||||
async registerProtocolHandlers() {
|
||||
// 动态导入协议处理器
|
||||
const protocolsDir = path.join(__dirname, 'protocols');
|
||||
const protocolFiles = await fs.readdir(protocolsDir);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载单个资源
|
||||
* @param {string} resourcePath - 资源路径
|
||||
* @param {ParsedReference} parsed - 解析后的引用
|
||||
* @param {object} options - 选项
|
||||
* @returns {Promise<string>} 资源内容
|
||||
*/
|
||||
async loadResource(resourcePath, parsed, options = {}) {
|
||||
// 检查缓存
|
||||
const cacheKey = `${resourcePath}:${JSON.stringify(parsed.queryParams.getAll())}`;
|
||||
if (this.enableCache && this.cache.has(cacheKey)) {
|
||||
logger.debug(`Cache hit for: ${cacheKey}`);
|
||||
return this.cache.get(cacheKey);
|
||||
}
|
||||
|
||||
let content = '';
|
||||
|
||||
// 根据协议类型加载资源
|
||||
if (parsed.protocol === 'file' || resourcePath.startsWith('/') || resourcePath.includes('./')) {
|
||||
content = await this.loadFileResource(resourcePath, parsed.queryParams);
|
||||
} else if (parsed.protocol === 'http' || parsed.protocol === 'https') {
|
||||
content = await this.loadHttpResource(resourcePath, parsed.queryParams);
|
||||
} else if (parsed.protocol === 'prompt') {
|
||||
// prompt协议通过注册表已经解析为文件路径
|
||||
content = await this.loadFileResource(resourcePath, parsed.queryParams);
|
||||
} else {
|
||||
throw new Error(`Unsupported protocol: ${parsed.protocol}`);
|
||||
}
|
||||
|
||||
// 应用查询参数过滤
|
||||
content = this.applyQueryParams(content, parsed.queryParams);
|
||||
|
||||
// 缓存结果
|
||||
if (this.enableCache) {
|
||||
this.cache.set(cacheKey, content);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载文件资源
|
||||
* @param {string} filePath - 文件路径
|
||||
* @param {QueryParams} queryParams - 查询参数
|
||||
* @returns {Promise<string>} 文件内容
|
||||
*/
|
||||
async loadFileResource(filePath, queryParams) {
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
|
||||
// 处理相对路径
|
||||
let fullPath = filePath;
|
||||
if (!path.isAbsolute(filePath)) {
|
||||
fullPath = path.resolve(this.workingDirectory, filePath);
|
||||
}
|
||||
|
||||
// 处理通配符
|
||||
if (fullPath.includes('*')) {
|
||||
return await this.loadGlobPattern(fullPath, queryParams);
|
||||
}
|
||||
|
||||
// 读取单个文件
|
||||
try {
|
||||
const content = await fs.readFile(fullPath, 'utf8');
|
||||
return content;
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to read file ${fullPath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载通配符模式的文件
|
||||
* @param {string} pattern - 通配符模式
|
||||
* @param {QueryParams} queryParams - 查询参数
|
||||
* @returns {Promise<string>} 合并后的内容
|
||||
*/
|
||||
async loadGlobPattern(pattern, queryParams) {
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const { glob } = require('glob');
|
||||
|
||||
try {
|
||||
const files = await glob(pattern, { nodir: true });
|
||||
|
||||
if (files.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 排序文件
|
||||
files.sort();
|
||||
|
||||
const contents = [];
|
||||
for (const file of files) {
|
||||
try {
|
||||
const content = await fs.readFile(file, 'utf8');
|
||||
const relativePath = path.relative(this.workingDirectory, file);
|
||||
|
||||
// 添加文件分隔符
|
||||
const separator = '='.repeat(80);
|
||||
const header = `### 文件: ${relativePath}`;
|
||||
contents.push(`${separator}\n${header}\n${separator}\n\n${content}`);
|
||||
} catch (error) {
|
||||
logger.warn(`Failed to read file ${file}: ${error.message}`);
|
||||
for (const file of protocolFiles) {
|
||||
if (file.endsWith('.js') && file !== 'ResourceProtocol.js') {
|
||||
// 将文件名映射到协议名:ExecutionProtocol.js -> execution
|
||||
const protocolName = file.replace('Protocol.js', '').toLowerCase();
|
||||
const ProtocolClass = require(path.join(protocolsDir, file));
|
||||
const protocolHandler = new ProtocolClass();
|
||||
|
||||
// 从统一注册表获取协议配置
|
||||
const protocolConfig = this.registry.protocols[protocolName];
|
||||
if (protocolConfig && protocolConfig.registry) {
|
||||
protocolHandler.setRegistry(protocolConfig.registry);
|
||||
}
|
||||
}
|
||||
|
||||
return contents.join('\n\n');
|
||||
} catch (error) {
|
||||
throw new Error(`Glob pattern error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载HTTP资源
|
||||
* @param {string} url - URL地址
|
||||
* @param {QueryParams} queryParams - 查询参数
|
||||
* @returns {Promise<string>} 响应内容
|
||||
*/
|
||||
async loadHttpResource(url, queryParams) {
|
||||
// 简单实现,实际项目中可以使用axios等库
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = url.startsWith('https://') ? https : http;
|
||||
|
||||
client.get(url, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
resolve(data);
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
reject(new Error(`HTTP request failed: ${err.message}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用查询参数过滤
|
||||
* @param {string} content - 原始内容
|
||||
* @param {QueryParams} queryParams - 查询参数
|
||||
* @returns {string} 处理后的内容
|
||||
*/
|
||||
applyQueryParams(content, queryParams) {
|
||||
let result = content;
|
||||
|
||||
// 处理行范围过滤
|
||||
if (queryParams.line) {
|
||||
result = this.applyLineFilter(result, queryParams.line);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用行范围过滤
|
||||
* @param {string} content - 内容
|
||||
* @param {string} lineRange - 行范围 "5-10"
|
||||
* @returns {string} 过滤后的内容
|
||||
*/
|
||||
applyLineFilter(content, lineRange) {
|
||||
const lines = content.split('\n');
|
||||
|
||||
if (lineRange.includes('-')) {
|
||||
const [start, end] = lineRange.split('-').map(n => parseInt(n.trim()));
|
||||
if (!isNaN(start) && !isNaN(end)) {
|
||||
// 转换为0基索引,并确保范围有效
|
||||
const startIdx = Math.max(0, start - 1);
|
||||
const endIdx = Math.min(lines.length, end);
|
||||
return lines.slice(startIdx, endIdx).join('\n');
|
||||
}
|
||||
} else {
|
||||
const lineNum = parseInt(lineRange);
|
||||
if (!isNaN(lineNum) && lineNum > 0 && lineNum <= lines.length) {
|
||||
return lines[lineNum - 1];
|
||||
this.protocolHandlers.set(protocolName, protocolHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析资源路径并获取内容
|
||||
*/
|
||||
async resolveResource(resourceUrl) {
|
||||
await this.initialize();
|
||||
|
||||
const urlMatch = resourceUrl.match(/^([a-zA-Z]+):\/\/(.+)$/);
|
||||
if (!urlMatch) {
|
||||
throw new Error(`无效的资源URL格式: ${resourceUrl}`);
|
||||
}
|
||||
|
||||
const [, protocol, path] = urlMatch;
|
||||
const handler = this.protocolHandlers.get(protocol);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证资源引用
|
||||
* @param {string} resourceRef - 资源引用
|
||||
* @returns {boolean} 是否有效
|
||||
*/
|
||||
isValidReference(resourceRef) {
|
||||
try {
|
||||
const parsed = this.parser.parse(resourceRef);
|
||||
return this.registry.validateReference(parsed.protocol, parsed.path);
|
||||
} catch (error) {
|
||||
return false;
|
||||
if (!handler) {
|
||||
throw new Error(`未注册的协议: ${protocol}`);
|
||||
}
|
||||
|
||||
return await handler.resolve(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取注册表信息
|
||||
* @param {string} protocol - 协议名(可选)
|
||||
* @returns {object} 注册表信息
|
||||
* resolve方法的别名,保持向后兼容
|
||||
*/
|
||||
getRegistryInfo(protocol) {
|
||||
if (protocol) {
|
||||
return this.registry.getProtocolInfo(protocol);
|
||||
async resolve(resourceUrl) {
|
||||
return await this.resolveResource(resourceUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议的注册表信息
|
||||
*/
|
||||
getProtocolRegistry(protocol) {
|
||||
if (!this.registry) {
|
||||
throw new Error('ResourceManager未初始化');
|
||||
}
|
||||
return this.registry.getRegistryInfo();
|
||||
|
||||
const protocolConfig = this.registry.protocols[protocol];
|
||||
return protocolConfig ? protocolConfig.registry : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出可用协议
|
||||
* @returns {string[]} 协议列表
|
||||
* 获取所有已注册的协议
|
||||
*/
|
||||
listProtocols() {
|
||||
return this.registry.listProtocols();
|
||||
getAvailableProtocols() {
|
||||
return this.registry ? Object.keys(this.registry.protocols) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* 获取协议的描述信息
|
||||
*/
|
||||
clearCache() {
|
||||
this.cache.clear();
|
||||
logger.debug('Resource cache cleared');
|
||||
getProtocolInfo(protocol) {
|
||||
if (!this.registry) {
|
||||
throw new Error('ResourceManager未初始化');
|
||||
}
|
||||
|
||||
return this.registry.protocols[protocol];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user