backup materials and knowledge-base docs
This commit is contained in:
354
文档润色流和知识库构建流/claude-scholar/scripts/lib/package-manager.js
Normal file
354
文档润色流和知识库构建流/claude-scholar/scripts/lib/package-manager.js
Normal file
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* 包管理器检测系统
|
||||
* 智能检测并管理 npm、pnpm、yarn、bun 等包管理器
|
||||
*
|
||||
* @module package-manager
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { commandExists, readJSON, getProjectRoot, getClaudeConfigDir, isWindows } = require('./utils');
|
||||
|
||||
// 包管理器配置
|
||||
const PACKAGE_MANAGERS = {
|
||||
npm: {
|
||||
name: 'npm',
|
||||
lockFile: 'package-lock.json',
|
||||
installCmd: 'npm install',
|
||||
runCmd: 'npm run',
|
||||
execCmd: 'npx',
|
||||
globalFlag: '--global'
|
||||
},
|
||||
pnpm: {
|
||||
name: 'pnpm',
|
||||
lockFile: 'pnpm-lock.yaml',
|
||||
installCmd: 'pnpm install',
|
||||
runCmd: 'pnpm',
|
||||
execCmd: 'pnpm dlx',
|
||||
globalFlag: '--global'
|
||||
},
|
||||
yarn: {
|
||||
name: 'yarn',
|
||||
lockFile: 'yarn.lock',
|
||||
installCmd: 'yarn install',
|
||||
runCmd: 'yarn',
|
||||
execCmd: 'yarn dlx',
|
||||
globalFlag: 'global'
|
||||
},
|
||||
bun: {
|
||||
name: 'bun',
|
||||
lockFile: 'bun.lockb',
|
||||
installCmd: 'bun install',
|
||||
runCmd: 'bun run',
|
||||
execCmd: 'bun x',
|
||||
globalFlag: '--global'
|
||||
}
|
||||
};
|
||||
|
||||
// 检测优先级
|
||||
const DETECTION_PRIORITY = ['pnpm', 'bun', 'yarn', 'npm'];
|
||||
|
||||
/**
|
||||
* 获取项目配置文件路径
|
||||
* @returns {string} 配置文件路径
|
||||
*/
|
||||
function getProjectConfigPath() {
|
||||
const projectRoot = getProjectRoot();
|
||||
if (projectRoot) {
|
||||
return path.join(projectRoot, '.claude', 'package-manager.json');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局配置文件路径
|
||||
* @returns {string} 配置文件路径
|
||||
*/
|
||||
function getGlobalConfigPath() {
|
||||
return path.join(getClaudeConfigDir(), 'package-manager.json');
|
||||
}
|
||||
|
||||
/**
|
||||
* 从环境变量检测包管理器
|
||||
* @returns {string|null} 包管理器名称或 null
|
||||
*/
|
||||
function detectFromEnvironment() {
|
||||
const envPm = process.env.CLAUDE_PACKAGE_MANAGER;
|
||||
if (envPm && PACKAGE_MANAGERS[envPm]) {
|
||||
return envPm;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从项目配置检测包管理器
|
||||
* @returns {string|null} 包管理器名称或 null
|
||||
*/
|
||||
function detectFromProjectConfig() {
|
||||
const configPath = getProjectConfigPath();
|
||||
if (configPath && fs.existsSync(configPath)) {
|
||||
const config = readJSON(configPath);
|
||||
if (config && config.packageManager && PACKAGE_MANAGERS[config.packageManager]) {
|
||||
return config.packageManager;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从全局配置检测包管理器
|
||||
* @returns {string|null} 包管理器名称或 null
|
||||
*/
|
||||
function detectFromGlobalConfig() {
|
||||
const configPath = getGlobalConfigPath();
|
||||
if (configPath && fs.existsSync(configPath)) {
|
||||
const config = readJSON(configPath);
|
||||
if (config && config.packageManager && PACKAGE_MANAGERS[config.packageManager]) {
|
||||
return config.packageManager;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 package.json 检测包管理器
|
||||
* @returns {string|null} 包管理器名称或 null
|
||||
*/
|
||||
function detectFromPackageJson() {
|
||||
const projectRoot = getProjectRoot();
|
||||
if (!projectRoot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const packageJsonPath = path.join(projectRoot, 'package.json');
|
||||
if (!fs.existsSync(packageJsonPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const packageJson = readJSON(packageJsonPath);
|
||||
if (!packageJson) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查 packageManager 字段
|
||||
if (packageJson.packageManager) {
|
||||
// 格式: "npm@8.0.0" 或 "pnpm@7.0.0"
|
||||
const match = packageJson.packageManager.match(/^([a-zA-Z]+)@/);
|
||||
if (match && PACKAGE_MANAGERS[match[1]]) {
|
||||
return match[1];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从锁文件检测包管理器
|
||||
* @returns {string|null} 包管理器名称或 null
|
||||
*/
|
||||
function detectFromLockFile() {
|
||||
const projectRoot = getProjectRoot();
|
||||
if (!projectRoot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 按优先级检查锁文件
|
||||
for (const pm of DETECTION_PRIORITY) {
|
||||
const lockFile = path.join(projectRoot, PACKAGE_MANAGERS[pm].lockFile);
|
||||
if (fs.existsSync(lockFile)) {
|
||||
return pm;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从可用命令检测包管理器
|
||||
* @returns {string|null} 包管理器名称或 null
|
||||
*/
|
||||
function detectFromAvailableCommands() {
|
||||
for (const pm of DETECTION_PRIORITY) {
|
||||
if (commandExists(pm)) {
|
||||
return pm;
|
||||
}
|
||||
}
|
||||
// npm 始终可用(Node.js 自带)
|
||||
return 'npm';
|
||||
}
|
||||
|
||||
/**
|
||||
* 智能检测包管理器
|
||||
* @param {Object} options - 检测选项
|
||||
* @returns {{name: string, source: string, config: Object}} 检测结果
|
||||
*/
|
||||
function getPackageManager(options = {}) {
|
||||
const {
|
||||
skipEnvironment = false,
|
||||
skipProjectConfig = false,
|
||||
skipGlobalConfig = false,
|
||||
skipPackageJson = false,
|
||||
skipLockFile = false,
|
||||
skipAvailable = false
|
||||
} = options;
|
||||
|
||||
// 按优先级检测
|
||||
const detectors = [
|
||||
!skipEnvironment && { detector: detectFromEnvironment, source: 'environment' },
|
||||
!skipProjectConfig && { detector: detectFromProjectConfig, source: 'project-config' },
|
||||
!skipPackageJson && { detector: detectFromPackageJson, source: 'package.json' },
|
||||
!skipLockFile && { detector: detectFromLockFile, source: 'lock-file' },
|
||||
!skipGlobalConfig && { detector: detectFromGlobalConfig, source: 'global-config' },
|
||||
!skipAvailable && { detector: detectFromAvailableCommands, source: 'available' }
|
||||
].filter(Boolean);
|
||||
|
||||
for (const { detector, source } of detectors) {
|
||||
const pm = detector();
|
||||
if (pm && PACKAGE_MANAGERS[pm]) {
|
||||
return {
|
||||
name: pm,
|
||||
source,
|
||||
config: PACKAGE_MANAGERS[pm]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 默认回退到 npm
|
||||
return {
|
||||
name: 'npm',
|
||||
source: 'default',
|
||||
config: PACKAGE_MANAGERS.npm
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置项目包管理器
|
||||
* @param {string} packageManager - 包管理器名称
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
function setProjectPackageManager(packageManager) {
|
||||
if (!PACKAGE_MANAGERS[packageManager]) {
|
||||
console.error(`不支持的包管理器: ${packageManager}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const configPath = getProjectConfigPath();
|
||||
if (!configPath) {
|
||||
console.error('无法找到项目根目录');
|
||||
return false;
|
||||
}
|
||||
|
||||
const configDir = path.dirname(configPath);
|
||||
if (!fs.existsSync(configDir)) {
|
||||
fs.mkdirSync(configDir, { recursive: true });
|
||||
}
|
||||
|
||||
try {
|
||||
fs.writeFileSync(
|
||||
configPath,
|
||||
JSON.stringify({ packageManager }, null, 2),
|
||||
'utf8'
|
||||
);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(`写入配置失败: ${err.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置全局包管理器
|
||||
* @param {string} packageManager - 包管理器名称
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
function setGlobalPackageManager(packageManager) {
|
||||
if (!PACKAGE_MANAGERS[packageManager]) {
|
||||
console.error(`不支持的包管理器: ${packageManager}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const configPath = getGlobalConfigPath();
|
||||
const configDir = path.dirname(configPath);
|
||||
|
||||
if (!fs.existsSync(configDir)) {
|
||||
fs.mkdirSync(configDir, { recursive: true });
|
||||
}
|
||||
|
||||
try {
|
||||
fs.writeFileSync(
|
||||
configPath,
|
||||
JSON.stringify({ packageManager }, null, 2),
|
||||
'utf8'
|
||||
);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(`写入配置失败: ${err.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建包管理器命令
|
||||
* @param {string} commandType - 命令类型 (install, run, exec)
|
||||
* @param {Object} options - 选项
|
||||
* @returns {string} 完整命令
|
||||
*/
|
||||
function buildCommand(commandType, options = {}) {
|
||||
const pm = getPackageManager();
|
||||
const config = pm.config;
|
||||
|
||||
switch (commandType) {
|
||||
case 'install':
|
||||
return config.installCmd;
|
||||
case 'run':
|
||||
return `${config.runCmd} ${options.script || ''}`;
|
||||
case 'exec':
|
||||
return `${config.execCmd} ${options.package || ''}`;
|
||||
default:
|
||||
return config.installCmd;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有可用的包管理器
|
||||
* @returns {Array<{name: string, available: boolean}>} 可用包管理器列表
|
||||
*/
|
||||
function getAvailablePackageManagers() {
|
||||
return Object.keys(PACKAGE_MANAGERS).map(name => ({
|
||||
name,
|
||||
available: commandExists(name)
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印包管理器信息
|
||||
*/
|
||||
function printPackageManagerInfo() {
|
||||
const pm = getPackageManager();
|
||||
console.log(`当前包管理器: ${pm.name} (来源: ${pm.source})`);
|
||||
console.log(`配置:`);
|
||||
console.log(` 安装命令: ${pm.config.installCmd}`);
|
||||
console.log(` 运行命令: ${pm.config.runCmd}`);
|
||||
console.log(` 执行命令: ${pm.config.execCmd}`);
|
||||
}
|
||||
|
||||
// 导出所有函数
|
||||
module.exports = {
|
||||
PACKAGE_MANAGERS,
|
||||
DETECTION_PRIORITY,
|
||||
getPackageManager,
|
||||
setProjectPackageManager,
|
||||
setGlobalPackageManager,
|
||||
buildCommand,
|
||||
getAvailablePackageManagers,
|
||||
printPackageManagerInfo,
|
||||
getProjectConfigPath,
|
||||
getGlobalConfigPath,
|
||||
// 为 setup-package-manager.js 添加的导出
|
||||
setPreferredPackageManager: setGlobalPackageManager,
|
||||
detectFromLockFile,
|
||||
detectFromPackageJson,
|
||||
getSelectionPrompt: () => {
|
||||
return '\n💡 运行 /setup-pm 配置首选包管理器\n';
|
||||
}
|
||||
};
|
||||
233
文档润色流和知识库构建流/claude-scholar/scripts/lib/utils.js
Normal file
233
文档润色流和知识库构建流/claude-scholar/scripts/lib/utils.js
Normal file
@@ -0,0 +1,233 @@
|
||||
/**
|
||||
* 跨平台工具函数库
|
||||
* 为 Claude Code 插件提供跨平台兼容性支持
|
||||
*
|
||||
* @module utils
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const { execSync, spawnSync } = require('child_process');
|
||||
|
||||
// 平台检测常量
|
||||
const isWindows = process.platform === 'win32';
|
||||
const isMacOS = process.platform === 'darwin';
|
||||
const isLinux = process.platform === 'linux';
|
||||
|
||||
/**
|
||||
* 获取用户主目录(跨平台)
|
||||
* @returns {string} 用户主目录路径
|
||||
*/
|
||||
function getHomeDir() {
|
||||
return os.homedir();
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保目录存在,如不存在则创建(跨平台)
|
||||
* @param {string} dirPath - 目录路径
|
||||
* @returns {string} 目录路径
|
||||
*/
|
||||
function ensureDir(dirPath) {
|
||||
if (!fs.existsSync(dirPath)) {
|
||||
fs.mkdirSync(dirPath, { recursive: true });
|
||||
}
|
||||
return dirPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查命令是否存在(跨平台)
|
||||
* @param {string} cmd - 命令名称
|
||||
* @returns {boolean} 命令是否存在
|
||||
*/
|
||||
function commandExists(cmd) {
|
||||
// 验证命令名称安全性
|
||||
if (!/^[a-zA-Z0-9_.-]+$/.test(cmd)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (isWindows) {
|
||||
// Windows 使用 where 命令
|
||||
const result = spawnSync('where', [cmd], { stdio: 'pipe' });
|
||||
return result.status === 0;
|
||||
} else {
|
||||
// Unix-like 系统使用 which 命令
|
||||
const result = spawnSync('which', [cmd], { stdio: 'pipe' });
|
||||
return result.status === 0;
|
||||
}
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全执行命令(跨平台)
|
||||
* @param {string} cmd - 要执行的命令
|
||||
* @param {Object} options - 执行选项
|
||||
* @returns {{success: boolean, output: string, error?: string}} 执行结果
|
||||
*/
|
||||
function runCommand(cmd, options = {}) {
|
||||
try {
|
||||
const result = execSync(cmd, {
|
||||
encoding: 'utf8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
...options
|
||||
});
|
||||
return { success: true, output: result.trim() };
|
||||
} catch (err) {
|
||||
return {
|
||||
success: false,
|
||||
output: err.stdout || '',
|
||||
error: err.stderr || err.message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Claude 配置目录(跨平台)
|
||||
* @returns {string} Claude 配置目录路径
|
||||
*/
|
||||
function getClaudeConfigDir() {
|
||||
const homeDir = getHomeDir();
|
||||
return path.join(homeDir, '.claude');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目根目录(跨平台)
|
||||
* @param {string} startDir - 起始目录
|
||||
* @returns {string|null} 项目根目录或 null
|
||||
*/
|
||||
function getProjectRoot(startDir = process.cwd()) {
|
||||
let currentDir = startDir;
|
||||
|
||||
while (currentDir !== path.parse(currentDir).root) {
|
||||
// 检查是否存在 .claude-plugin 目录
|
||||
const pluginDir = path.join(currentDir, '.claude-plugin');
|
||||
if (fs.existsSync(pluginDir)) {
|
||||
return currentDir;
|
||||
}
|
||||
|
||||
// 检查是否存在 package.json
|
||||
const packageJson = path.join(currentDir, 'package.json');
|
||||
if (fs.existsSync(packageJson)) {
|
||||
return currentDir;
|
||||
}
|
||||
|
||||
// 向上移动
|
||||
currentDir = path.dirname(currentDir);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 路径拼接(跨平台)
|
||||
* @param {...string} paths - 路径片段
|
||||
* @returns {string} 拼接后的路径
|
||||
*/
|
||||
function joinPath(...paths) {
|
||||
return path.join(...paths);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取绝对路径(跨平台)
|
||||
* @param {...string} paths - 路径片段
|
||||
* @returns {string} 绝对路径
|
||||
*/
|
||||
function resolvePath(...paths) {
|
||||
return path.resolve(...paths);
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化路径(跨平台)
|
||||
* @param {string} filePath - 文件路径
|
||||
* @returns {string} 规范化后的路径
|
||||
*/
|
||||
function normalizePath(filePath) {
|
||||
return path.normalize(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 JSON 文件(跨平台)
|
||||
* @param {string} filePath - JSON 文件路径
|
||||
* @returns {Object|null} 解析后的 JSON 对象或 null
|
||||
*/
|
||||
function readJSON(filePath) {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
return JSON.parse(content);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入 JSON 文件(跨平台)
|
||||
* @param {string} filePath - JSON 文件路径
|
||||
* @param {Object} data - 要写入的数据
|
||||
* @param {number|object|string} space - JSON 缩进空格数
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
function writeJSON(filePath, data, space = 2) {
|
||||
try {
|
||||
ensureDir(path.dirname(filePath));
|
||||
fs.writeFileSync(filePath, JSON.stringify(data, null, space), 'utf8');
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制文件(跨平台)
|
||||
* @param {string} src - 源文件路径
|
||||
* @param {string} dest - 目标文件路径
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
function copyFile(src, dest) {
|
||||
try {
|
||||
ensureDir(path.dirname(dest));
|
||||
fs.copyFileSync(src, dest);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平台信息
|
||||
* @returns {Object} 平台信息对象
|
||||
*/
|
||||
function getPlatformInfo() {
|
||||
return {
|
||||
platform: process.platform,
|
||||
isWindows,
|
||||
isMacOS,
|
||||
isLinux,
|
||||
arch: process.arch,
|
||||
nodeVersion: process.version,
|
||||
homeDir: getHomeDir(),
|
||||
tempDir: os.tmpdir()
|
||||
};
|
||||
}
|
||||
|
||||
// 导出所有函数
|
||||
module.exports = {
|
||||
isWindows,
|
||||
isMacOS,
|
||||
isLinux,
|
||||
getHomeDir,
|
||||
ensureDir,
|
||||
commandExists,
|
||||
runCommand,
|
||||
getClaudeConfigDir,
|
||||
getProjectRoot,
|
||||
joinPath,
|
||||
resolvePath,
|
||||
normalizePath,
|
||||
readJSON,
|
||||
writeJSON,
|
||||
copyFile,
|
||||
getPlatformInfo
|
||||
};
|
||||
Reference in New Issue
Block a user