Files
PromptX/promptx.js

419 lines
12 KiB
JavaScript
Executable File
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, '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 printCore() {
const coreDir = path.join(promptxDir, 'core');
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;
}
// 收集核心目录下的所有文件
const coreFiles = collectMarkdownFiles(coreDir);
// 文件按字母顺序排序
coreFiles.sort();
// 合并到总文件列表
allFiles = allFiles.concat(coreFiles);
console.log(`从 core 目录收集了 ${coreFiles.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 {string[]} args - 其他参数
*/
function parseMemoryArgs(content, args) {
const options = {
tags: [],
score: 5,
duration: '短期'
};
// 从内容中提取标签、评分和有效期
const contentParts = content.trim().split(/\s+/);
let cleanContent = [];
for (let part of contentParts) {
if (part.startsWith('#')) {
// 检查是否是特殊标记
if (part.includes('评分:')) {
const scoreText = part.split('评分:')[1].trim();
const score = parseInt(scoreText);
if (!isNaN(score) && score >= 1 && score <= 10) {
options.score = score;
}
} else if (part.includes('有效期:')) {
const duration = part.split('有效期:')[1].trim();
if (['短期', '中期', '长期'].includes(duration)) {
options.duration = duration;
}
} else {
// 普通标签
const tag = part.slice(1);
if (tag) {
options.tags.push(tag);
}
}
} else {
cleanContent.push(part);
}
}
// 处理剩余的命令行参数
for (let arg of args) {
// 移除参数前后的引号(如果有)
arg = arg.replace(/^['"]|['"]$/g, '').trim();
if (arg.startsWith('#')) {
// 检查是否是特殊标记
if (arg.includes('评分:')) {
const score = parseInt(arg.split('评分:')[1]);
if (!isNaN(score) && score >= 1 && score <= 10) {
options.score = score;
}
} else if (arg.includes('有效期:')) {
const duration = arg.split('有效期:')[1];
if (['短期', '中期', '长期'].includes(duration)) {
options.duration = duration;
}
} else {
// 普通标签
const tag = arg.slice(1);
if (tag) {
options.tags.push(tag);
}
}
}
}
// 如果没有标签,使用默认标签
if (options.tags.length === 0) {
options.tags = ['其他'];
}
// 返回清理后的内容和选项
return {
cleanContent: cleanContent.join(' '),
options: options
};
}
/**
* 添加记忆条目
* @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
};
// 构建记忆条目,确保格式统一
const memoryEntry = `\n- ${finalOptions.timestamp} ${content.trim()} ${finalOptions.tags.map(tag => `#${tag}`).join(' ')} #评分:${finalOptions.score} #有效期:${finalOptions.duration}\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);
}
}
/**
* 打印帮助信息
*/
function printHelp() {
console.log(`
PromptX 工具 - 协议和角色内容查看器
使用方法:
node promptx.js - 打印所有协议内容 (按protocol、resource顺序)
node promptx.js protocols - 同上,打印所有协议内容
node promptx.js core - 打印所有核心提示词内容
node promptx.js role <路径> - 打印指定角色文件内容
node promptx.js file <路径> - 打印指定文件内容
node promptx.js remember <内容> - 添加记忆条目,标签、评分和有效期可直接包含在内容中
node promptx.js help - 显示此帮助信息
记忆命令用法:
将标签、评分和有效期直接包含在内容字符串中,时间戳会自动添加到行首
#标签名 - 添加标签 (可多个)
#评分:数字 - 设置重要性评分 (1-10)
#有效期:时长 - 设置有效期 (短期/中期/长期)
示例:
node promptx.js remember "用户提出了重要建议 #用户反馈 #改进建议 #评分:8 #有效期:长期"
node promptx.js remember "临时配置信息 #配置 #评分:3 #有效期:短期"
`);
}
// 根据命令执行相应功能
switch (command) {
case 'protocols':
printProtocols();
break;
case 'core':
printCore();
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 #评分:8 #有效期:长期"');
} else {
try {
// 记忆内容就是传入的第一个参数
const memoryContent = param;
// 解析内容中的标签、评分和有效期
const { cleanContent, options } = parseMemoryArgs(memoryContent, []);
// 添加记忆
addMemory(cleanContent, options);
} catch (err) {
console.error('错误:', err.message);
console.log('使用方法: node promptx.js remember "记忆内容 #标签1 #标签2 #评分:8 #有效期:长期"');
}
}
break;
case 'help':
printHelp();
break;
default:
console.error(`错误: 未知命令 "${command}"`);
printHelp();
break;
}