Files
PromptX/promptx.js

341 lines
9.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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,
tags: options.tags && options.tags.length > 0 ? options.tags : defaultOptions.tags
};
console.log('最终选项:', finalOptions); // 添加调试输出
// 构建记忆条目,确保格式统一
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: '短期'
};
console.log('原始参数:', args); // 调试输出
// 解析标签和其他选项
for (let arg of args) {
// 移除参数前后的引号(如果有)
arg = arg.replace(/^['"]|['"]$/g, '').trim();
console.log('处理参数:', arg); // 调试输出
if (arg.startsWith('#')) {
// 检查是否是特殊标记
if (arg.includes('评分:')) {
const score = parseInt(arg.split('评分:')[1]);
console.log('解析评分:', score); // 调试输出
if (!isNaN(score) && score >= 1 && score <= 10) {
options.score = score;
}
} else if (arg.includes('有效期:')) {
const duration = arg.split('有效期:')[1];
console.log('解析有效期:', duration); // 调试输出
if (['短期', '中期', '长期'].includes(duration)) {
options.duration = duration;
}
} else {
// 普通标签
const tag = arg.slice(1);
console.log('解析标签:', tag); // 调试输出
if (tag) {
options.tags.push(tag);
}
}
}
}
// 如果没有标签,使用默认标签
if (options.tags.length === 0) {
options.tags = ['其他'];
}
console.log('解析结果:', options); // 调试输出
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] [#评分:7] [#有效期:长期]');
} else {
try {
// 获取所有参数
const allArgs = process.argv.slice(2); // 从 remember 开始的所有参数
console.log('所有参数:', allArgs);
// 找到第一个标签(以#开头的参数)的位置
const tagStartIndex = allArgs.findIndex(arg => arg.startsWith('#'));
console.log('标签起始位置:', tagStartIndex);
// 如果没有找到标签,使用所有剩余参数作为内容
const contentEndIndex = tagStartIndex === -1 ? allArgs.length : tagStartIndex;
// 组合记忆内容(去掉 remember 命令)
const memoryContent = allArgs.slice(1, contentEndIndex).join(' ');
console.log('记忆内容:', memoryContent);
// 获取所有标签和选项
const memoryArgs = allArgs.slice(contentEndIndex);
console.log('记忆参数:', memoryArgs);
const options = parseMemoryArgs(memoryContent, memoryArgs);
console.log('解析的选项:', options);
addMemory(memoryContent, options);
} catch (err) {
console.error('错误:', err.message);
console.log('使用方法: node promptx.js remember 记忆内容 [#标签1 #标签2] [#评分:7] [#有效期:长期]');
}
}
break;
case 'help':
printHelp();
break;
default:
console.error(`错误: 未知命令 "${command}"`);
printHelp();
break;
}