mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
feat: 重构安装和升级命令以支持全局子目录的安装和排除
This commit is contained in:
@@ -14,6 +14,9 @@ const __dirname = dirname(__filename);
|
|||||||
// Source directories to install
|
// Source directories to install
|
||||||
const SOURCE_DIRS = ['.claude', '.codex', '.gemini', '.qwen'];
|
const SOURCE_DIRS = ['.claude', '.codex', '.gemini', '.qwen'];
|
||||||
|
|
||||||
|
// Subdirectories that should always be installed to global (~/.claude/)
|
||||||
|
const GLOBAL_SUBDIRS = ['workflows', 'scripts', 'templates'];
|
||||||
|
|
||||||
// Get package root directory (ccw/src/commands -> ccw)
|
// Get package root directory (ccw/src/commands -> ccw)
|
||||||
function getPackageRoot() {
|
function getPackageRoot() {
|
||||||
return join(__dirname, '..', '..');
|
return join(__dirname, '..', '..');
|
||||||
@@ -122,13 +125,30 @@ export async function installCommand(options) {
|
|||||||
let totalDirs = 0;
|
let totalDirs = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// For Path mode, install workflows to global first
|
||||||
|
if (mode === 'Path') {
|
||||||
|
const globalPath = homedir();
|
||||||
|
for (const subdir of GLOBAL_SUBDIRS) {
|
||||||
|
const srcWorkflows = join(sourceDir, '.claude', subdir);
|
||||||
|
if (existsSync(srcWorkflows)) {
|
||||||
|
const destWorkflows = join(globalPath, '.claude', subdir);
|
||||||
|
spinner.text = `Installing ${subdir} to global...`;
|
||||||
|
const { files, directories } = await copyDirectory(srcWorkflows, destWorkflows, manifest);
|
||||||
|
totalFiles += files;
|
||||||
|
totalDirs += directories;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const dir of availableDirs) {
|
for (const dir of availableDirs) {
|
||||||
const srcPath = join(sourceDir, dir);
|
const srcPath = join(sourceDir, dir);
|
||||||
const destPath = join(installPath, dir);
|
const destPath = join(installPath, dir);
|
||||||
|
|
||||||
spinner.text = `Installing ${dir}...`;
|
spinner.text = `Installing ${dir}...`;
|
||||||
|
|
||||||
const { files, directories } = await copyDirectory(srcPath, destPath, manifest);
|
// For Path mode on .claude, exclude global subdirs (they're already installed to global)
|
||||||
|
const excludeDirs = (mode === 'Path' && dir === '.claude') ? GLOBAL_SUBDIRS : [];
|
||||||
|
const { files, directories } = await copyDirectory(srcPath, destPath, manifest, excludeDirs);
|
||||||
totalFiles += files;
|
totalFiles += files;
|
||||||
totalDirs += directories;
|
totalDirs += directories;
|
||||||
}
|
}
|
||||||
@@ -265,9 +285,10 @@ async function createBackup(installPath, manifest) {
|
|||||||
* @param {string} src - Source directory
|
* @param {string} src - Source directory
|
||||||
* @param {string} dest - Destination directory
|
* @param {string} dest - Destination directory
|
||||||
* @param {Object} manifest - Manifest to track files (optional)
|
* @param {Object} manifest - Manifest to track files (optional)
|
||||||
|
* @param {string[]} excludeDirs - Directory names to exclude (optional)
|
||||||
* @returns {Object} - Count of files and directories
|
* @returns {Object} - Count of files and directories
|
||||||
*/
|
*/
|
||||||
async function copyDirectory(src, dest, manifest = null) {
|
async function copyDirectory(src, dest, manifest = null, excludeDirs = []) {
|
||||||
let files = 0;
|
let files = 0;
|
||||||
let directories = 0;
|
let directories = 0;
|
||||||
|
|
||||||
@@ -281,6 +302,11 @@ async function copyDirectory(src, dest, manifest = null) {
|
|||||||
const entries = readdirSync(src);
|
const entries = readdirSync(src);
|
||||||
|
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
|
// Skip excluded directories
|
||||||
|
if (excludeDirs.includes(entry)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const srcPath = join(src, entry);
|
const srcPath = join(src, entry);
|
||||||
const destPath = join(dest, entry);
|
const destPath = join(dest, entry);
|
||||||
const stat = statSync(srcPath);
|
const stat = statSync(srcPath);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { existsSync, readdirSync, statSync, copyFileSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
import { existsSync, readdirSync, statSync, copyFileSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
||||||
import { join, dirname, basename } from 'path';
|
import { join, dirname, basename } from 'path';
|
||||||
|
import { homedir } from 'os';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import inquirer from 'inquirer';
|
import inquirer from 'inquirer';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
@@ -12,6 +13,9 @@ const __dirname = dirname(__filename);
|
|||||||
// Source directories to install
|
// Source directories to install
|
||||||
const SOURCE_DIRS = ['.claude', '.codex', '.gemini', '.qwen'];
|
const SOURCE_DIRS = ['.claude', '.codex', '.gemini', '.qwen'];
|
||||||
|
|
||||||
|
// Subdirectories that should always be installed to global (~/.claude/)
|
||||||
|
const GLOBAL_SUBDIRS = ['workflows', 'scripts', 'templates'];
|
||||||
|
|
||||||
// Get package root directory (ccw/src/commands -> ccw)
|
// Get package root directory (ccw/src/commands -> ccw)
|
||||||
function getPackageRoot() {
|
function getPackageRoot() {
|
||||||
return join(__dirname, '..', '..');
|
return join(__dirname, '..', '..');
|
||||||
@@ -210,6 +214,7 @@ export async function upgradeCommand(options) {
|
|||||||
*/
|
*/
|
||||||
async function performUpgrade(manifest, sourceDir, version) {
|
async function performUpgrade(manifest, sourceDir, version) {
|
||||||
const installPath = manifest.installation_path;
|
const installPath = manifest.installation_path;
|
||||||
|
const mode = manifest.installation_mode;
|
||||||
|
|
||||||
// Get available source directories
|
// Get available source directories
|
||||||
const availableDirs = SOURCE_DIRS.filter(dir => existsSync(join(sourceDir, dir)));
|
const availableDirs = SOURCE_DIRS.filter(dir => existsSync(join(sourceDir, dir)));
|
||||||
@@ -219,17 +224,33 @@ async function performUpgrade(manifest, sourceDir, version) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create new manifest
|
// Create new manifest
|
||||||
const newManifest = createManifest(manifest.installation_mode, installPath);
|
const newManifest = createManifest(mode, installPath);
|
||||||
|
|
||||||
let totalFiles = 0;
|
let totalFiles = 0;
|
||||||
let totalDirs = 0;
|
let totalDirs = 0;
|
||||||
|
|
||||||
|
// For Path mode, upgrade workflows to global first
|
||||||
|
if (mode === 'Path') {
|
||||||
|
const globalPath = homedir();
|
||||||
|
for (const subdir of GLOBAL_SUBDIRS) {
|
||||||
|
const srcWorkflows = join(sourceDir, '.claude', subdir);
|
||||||
|
if (existsSync(srcWorkflows)) {
|
||||||
|
const destWorkflows = join(globalPath, '.claude', subdir);
|
||||||
|
const { files, directories } = await copyDirectory(srcWorkflows, destWorkflows, newManifest);
|
||||||
|
totalFiles += files;
|
||||||
|
totalDirs += directories;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Copy each directory
|
// Copy each directory
|
||||||
for (const dir of availableDirs) {
|
for (const dir of availableDirs) {
|
||||||
const srcPath = join(sourceDir, dir);
|
const srcPath = join(sourceDir, dir);
|
||||||
const destPath = join(installPath, dir);
|
const destPath = join(installPath, dir);
|
||||||
|
|
||||||
const { files, directories } = await copyDirectory(srcPath, destPath, newManifest);
|
// For Path mode on .claude, exclude global subdirs (they're already installed to global)
|
||||||
|
const excludeDirs = (mode === 'Path' && dir === '.claude') ? GLOBAL_SUBDIRS : [];
|
||||||
|
const { files, directories } = await copyDirectory(srcPath, destPath, newManifest, excludeDirs);
|
||||||
totalFiles += files;
|
totalFiles += files;
|
||||||
totalDirs += directories;
|
totalDirs += directories;
|
||||||
}
|
}
|
||||||
@@ -263,9 +284,10 @@ async function performUpgrade(manifest, sourceDir, version) {
|
|||||||
* @param {string} src - Source directory
|
* @param {string} src - Source directory
|
||||||
* @param {string} dest - Destination directory
|
* @param {string} dest - Destination directory
|
||||||
* @param {Object} manifest - Manifest to track files
|
* @param {Object} manifest - Manifest to track files
|
||||||
|
* @param {string[]} excludeDirs - Directory names to exclude (optional)
|
||||||
* @returns {Object} - Count of files and directories
|
* @returns {Object} - Count of files and directories
|
||||||
*/
|
*/
|
||||||
async function copyDirectory(src, dest, manifest) {
|
async function copyDirectory(src, dest, manifest, excludeDirs = []) {
|
||||||
let files = 0;
|
let files = 0;
|
||||||
let directories = 0;
|
let directories = 0;
|
||||||
|
|
||||||
@@ -279,6 +301,11 @@ async function copyDirectory(src, dest, manifest) {
|
|||||||
const entries = readdirSync(src);
|
const entries = readdirSync(src);
|
||||||
|
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
|
// Skip excluded directories
|
||||||
|
if (excludeDirs.includes(entry)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const srcPath = join(src, entry);
|
const srcPath = join(src, entry);
|
||||||
const destPath = join(dest, entry);
|
const destPath = join(dest, entry);
|
||||||
const stat = statSync(srcPath);
|
const stat = statSync(srcPath);
|
||||||
|
|||||||
Reference in New Issue
Block a user