#!/usr/bin/env node const fs = require('fs'); const path = require('path'); // 简单的命令行参数处理 const args = process.argv.slice(2); const command = args[0] || 'protocols'; // 默认执行protocols命令,而不是help const param = args[1]; // role命令时的角色文件路径 // 获取脚本所在目录和PromptX根目录 const scriptDir = __dirname; const promptxDir = scriptDir; // 脚本现在就在PromptX目录内 /** * 打印所有协议内容 */ function printProtocols() { // 定义目录优先级顺序 const directories = [ { path: path.join(promptxDir, 'protocol'), name: 'protocol' }, { path: path.join(promptxDir, 'core'), name: 'core' }, { path: path.join(promptxDir, 'resource'), name: 'resource' } ]; let allFiles = []; // 递归查找文件函数 function collectMarkdownFiles(dir) { if (!fs.existsSync(dir)) { console.warn(`警告: 目录不存在 ${dir}`); return []; } let files = []; const entries = fs.readdirSync(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { files = files.concat(collectMarkdownFiles(fullPath)); } else if (entry.isFile() && entry.name.endsWith('.md')) { files.push(fullPath); } } return files; } // 按目录优先级收集文件 for (const dir of directories) { const dirFiles = collectMarkdownFiles(dir.path); // 每个目录内的文件按字母顺序排序 dirFiles.sort(); // 合并到总文件列表 allFiles = allFiles.concat(dirFiles); console.log(`从 ${dir.name} 目录收集了 ${dirFiles.length} 个文件`); } // 没有文件时的提示 if (allFiles.length === 0) { console.log("未找到任何协议文件。请确认PromptX目录结构是否正确。"); return; } // 打印每个文件 for (const file of allFiles) { const relativePath = path.relative(promptxDir, file); const separator = "=".repeat(80); console.log(`\n${separator}\n### 文件: ${relativePath}\n${separator}\n`); try { const content = fs.readFileSync(file, 'utf8'); console.log(content); } catch (err) { console.error(`读取文件错误: ${file}`, err); } } console.log(`\n总计读取了 ${allFiles.length} 个协议文件。`); } /** * 打印指定角色内容 */ function printRole(rolePath) { // 如果传入的是相对路径,则基于PromptX目录解析 let fullPath; if (path.isAbsolute(rolePath)) { fullPath = rolePath; } else { fullPath = path.join(promptxDir, rolePath); } if (!fs.existsSync(fullPath)) { console.error(`错误: 角色文件不存在: ${fullPath}`); return; } try { const content = fs.readFileSync(fullPath, 'utf8'); const separator = "=".repeat(80); console.log(`\n${separator}\n### 角色文件: ${path.relative(promptxDir, fullPath)}\n${separator}\n`); console.log(content); } catch (err) { console.error(`读取角色文件错误: ${fullPath}`, err); } } /** * 打印指定路径的文件内容 */ function printFile(filePath) { // 如果传入的是相对路径,则基于PromptX目录解析 let fullPath; if (path.isAbsolute(filePath)) { fullPath = filePath; } else { fullPath = path.join(promptxDir, filePath); } if (!fs.existsSync(fullPath)) { console.error(`错误: 文件不存在: ${fullPath}`); return; } try { const content = fs.readFileSync(fullPath, 'utf8'); const separator = "=".repeat(80); console.log(`\n${separator}\n### 文件: ${path.relative(promptxDir, fullPath)}\n${separator}\n`); console.log(content); } catch (err) { console.error(`读取文件错误: ${fullPath}`, err); } } /** * 添加记忆条目 * @param {string} content - 记忆内容 * @param {object} options - 配置选项 */ function addMemory(content, options = {}) { const defaultOptions = { tags: ['其他'], score: 5, duration: '短期', timestamp: new Date().toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }) }; const finalOptions = { ...defaultOptions, ...options }; // 构建记忆条目,确保格式统一 const memoryEntry = `\n- ${content.trim()} ${finalOptions.tags.map(tag => `#${tag}`).join(' ')} #评分:${finalOptions.score} #有效期:${finalOptions.duration} #时间:${finalOptions.timestamp}\n`; // 确保.memory目录存在 const memoryDir = path.join(process.cwd(), '.memory'); if (!fs.existsSync(memoryDir)) { fs.mkdirSync(memoryDir, { recursive: true }); } // 追加到记忆文件 const memoryFile = path.join(memoryDir, 'declarative.md'); try { // 如果文件不存在,创建文件并添加标题 if (!fs.existsSync(memoryFile)) { fs.writeFileSync(memoryFile, '# 陈述性记忆库\n\n## 高价值记忆(评分 ≥ 7)\n'); } fs.appendFileSync(memoryFile, memoryEntry); console.log('✅ 记忆已成功保存'); // 如果评分大于等于7,输出高价值提醒 if (finalOptions.score >= 7) { console.log('🌟 这是一条高价值记忆'); } } catch (err) { console.error('❌ 记忆保存失败:', err); } } /** * 解析记忆命令参数 * @param {string} content - 记忆内容 * @param {string[]} args - 其他参数 */ function parseMemoryArgs(content, args) { const options = { tags: [], score: 5, duration: '短期' }; // 解析标签和其他选项 args.forEach(arg => { if (arg.startsWith('#')) { // 去掉#号并添加到标签数组 options.tags.push(arg.slice(1).trim()); } else if (arg.startsWith('score:')) { const score = parseInt(arg.split(':')[1]); if (!isNaN(score) && score >= 1 && score <= 10) { options.score = score; } } else if (arg.startsWith('duration:')) { const duration = arg.split(':')[1].trim(); if (['短期', '长期'].includes(duration)) { options.duration = duration; } } }); // 如果没有标签,使用默认标签 if (options.tags.length === 0) { options.tags = ['其他']; } return options; } /** * 打印帮助信息 */ function printHelp() { console.log(` PromptX 工具 - 协议和角色内容查看器 使用方法: node promptx.js - 打印所有协议内容 (按protocol、core、resource顺序) node promptx.js protocols - 同上,打印所有协议内容 node promptx.js role <路径> - 打印指定角色文件内容 node promptx.js file <路径> - 打印指定文件内容 node promptx.js remember <内容> [选项] - 添加记忆条目 node promptx.js help - 显示此帮助信息 记忆命令选项: #标签名 - 添加标签 (可多个) score:数字 - 设置重要性评分 (1-10) duration:时长 - 设置有效期 (短期/长期) 示例: node promptx.js remember "用户提出了重要建议" #用户反馈 #改进建议 score:7 duration:长期 node promptx.js remember "临时配置信息" #配置 score:3 `); } // 根据命令执行相应功能 switch (command) { case 'protocols': printProtocols(); break; case 'role': if (!param) { console.error('错误: 缺少角色文件路径'); printHelp(); } else { printRole(param); } break; case 'file': if (!param) { console.error('错误: 缺少文件路径'); printHelp(); } else { printFile(param); } break; case 'remember': if (!param) { console.error('错误: 缺少记忆内容'); console.log('使用方法: node promptx.js remember "记忆内容" [#标签1 #标签2] [score:7] [duration:长期]'); } else { const memoryContent = param; const memoryArgs = args.slice(2); // 获取其他参数 const options = parseMemoryArgs(memoryContent, memoryArgs); addMemory(memoryContent, options); } break; case 'help': printHelp(); break; default: console.error(`错误: 未知命令 "${command}"`); printHelp(); break; }