feat: 实现动态命令前缀检测机制 - 新增 PromptXConfig 工具类统一管理 .promptx 目录配置文件 - 重构 constants.js 为函数式,支持动态命令前缀检测 - init 命令自动保存用户实际使用的命令前缀 - 优先级:环境变量 > 配置文件 > npm环境检测 > 默认值 - 解决 AI 提示命令与用户实际使用不一致的问题 - 完整的 E2E 测试覆盖所有使用场景 核心价值:用户怎么调用 init,AI 就提示相同的命令前缀,确保 AI-First CLI 的用户体验一致性
This commit is contained in:
@ -2,7 +2,7 @@ const BasePouchCommand = require('../BasePouchCommand')
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const { ResourceManager } = require('../../resource')
|
||||
const { COMMANDS } = require('../../../../constants')
|
||||
const { COMMANDS, saveCommandPrefix } = require('../../../../constants')
|
||||
|
||||
/**
|
||||
* 初始化锦囊命令
|
||||
@ -24,7 +24,10 @@ class InitCommand extends BasePouchCommand {
|
||||
// 1. 技术初始化
|
||||
await this.initializeWorkspace(workspacePath)
|
||||
|
||||
// 2. 加载协议体系
|
||||
// 2. 保存命令前缀配置
|
||||
const savedPrefix = await saveCommandPrefix()
|
||||
|
||||
// 3. 加载协议体系
|
||||
const protocolContent = await this.loadProtocolSystem()
|
||||
|
||||
return `🎯 PromptX 系统初始化完成!
|
||||
@ -32,6 +35,7 @@ class InitCommand extends BasePouchCommand {
|
||||
## 🏗️ 技术环境准备
|
||||
✅ 创建了项目目录结构
|
||||
✅ 配置了 .promptx/pouch.json 锦囊状态文件
|
||||
✅ 保存了命令前缀配置:${savedPrefix || '默认前缀'}
|
||||
✅ 准备了锦囊状态机框架
|
||||
|
||||
## 📋 系统基本诺记 (协议体系)
|
||||
|
||||
129
src/lib/utils/promptxConfig.js
Normal file
129
src/lib/utils/promptxConfig.js
Normal file
@ -0,0 +1,129 @@
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
|
||||
/**
|
||||
* PromptX配置文件管理工具
|
||||
* 统一管理.promptx目录下的所有配置文件
|
||||
*/
|
||||
class PromptXConfig {
|
||||
constructor(baseDir = process.cwd()) {
|
||||
this.baseDir = baseDir
|
||||
this.promptxDir = path.join(baseDir, '.promptx')
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保.promptx目录存在
|
||||
*/
|
||||
async ensureDir() {
|
||||
await fs.ensureDir(this.promptxDir)
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取JSON配置文件
|
||||
* @param {string} filename - 文件名(不含路径)
|
||||
* @param {*} defaultValue - 文件不存在时的默认值
|
||||
* @returns {Promise<*>} 配置对象
|
||||
*/
|
||||
async readJson(filename, defaultValue = {}) {
|
||||
const filePath = path.join(this.promptxDir, filename)
|
||||
try {
|
||||
if (await fs.pathExists(filePath)) {
|
||||
return await fs.readJson(filePath)
|
||||
}
|
||||
return defaultValue
|
||||
} catch (error) {
|
||||
console.warn(`读取配置文件失败 ${filename}:`, error.message)
|
||||
return defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入JSON配置文件
|
||||
* @param {string} filename - 文件名(不含路径)
|
||||
* @param {*} data - 要写入的数据
|
||||
* @param {Object} options - 选项
|
||||
*/
|
||||
async writeJson(filename, data, options = { spaces: 2 }) {
|
||||
await this.ensureDir()
|
||||
const filePath = path.join(this.promptxDir, filename)
|
||||
await fs.writeJson(filePath, data, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文本配置文件
|
||||
* @param {string} filename - 文件名(不含路径)
|
||||
* @param {string} defaultValue - 文件不存在时的默认值
|
||||
* @returns {Promise<string>} 文件内容
|
||||
*/
|
||||
async readText(filename, defaultValue = '') {
|
||||
const filePath = path.join(this.promptxDir, filename)
|
||||
try {
|
||||
if (await fs.pathExists(filePath)) {
|
||||
return await fs.readFile(filePath, 'utf8')
|
||||
}
|
||||
return defaultValue
|
||||
} catch (error) {
|
||||
console.warn(`读取配置文件失败 ${filename}:`, error.message)
|
||||
return defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入文本配置文件
|
||||
* @param {string} filename - 文件名(不含路径)
|
||||
* @param {string} content - 要写入的内容
|
||||
*/
|
||||
async writeText(filename, content) {
|
||||
await this.ensureDir()
|
||||
const filePath = path.join(this.promptxDir, filename)
|
||||
await fs.writeFile(filePath, content, 'utf8')
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查配置文件是否存在
|
||||
* @param {string} filename - 文件名(不含路径)
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async exists(filename) {
|
||||
const filePath = path.join(this.promptxDir, filename)
|
||||
return await fs.pathExists(filePath)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除配置文件
|
||||
* @param {string} filename - 文件名(不含路径)
|
||||
*/
|
||||
async remove(filename) {
|
||||
const filePath = path.join(this.promptxDir, filename)
|
||||
try {
|
||||
await fs.remove(filePath)
|
||||
} catch (error) {
|
||||
console.warn(`删除配置文件失败 ${filename}:`, error.message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置文件路径
|
||||
* @param {string} filename - 文件名(不含路径)
|
||||
* @returns {string} 完整路径
|
||||
*/
|
||||
getPath(filename) {
|
||||
return path.join(this.promptxDir, filename)
|
||||
}
|
||||
|
||||
/**
|
||||
* 原子性更新JSON配置文件
|
||||
* 读取 -> 修改 -> 写入,避免并发问题
|
||||
* @param {string} filename - 文件名
|
||||
* @param {Function} updater - 更新函数 (oldData) => newData
|
||||
* @param {*} defaultValue - 文件不存在时的默认值
|
||||
*/
|
||||
async updateJson(filename, updater, defaultValue = {}) {
|
||||
const oldData = await this.readJson(filename, defaultValue)
|
||||
const newData = await updater(oldData)
|
||||
await this.writeJson(filename, newData)
|
||||
return newData
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PromptXConfig
|
||||
Reference in New Issue
Block a user