🚀 v4.0.4 - Enhanced installation with pipx support

- Added automatic detection of PEP 668 environments
- Implemented pipx as preferred installation method for Linux/macOS
- Added fallback to pip --user for externally managed environments
- Improved error messages with clear installation alternatives
- Added --break-system-packages as last resort option
- Updated NPM wrapper to handle all installation scenarios
- Enhanced update mechanism to detect and use correct tool
This commit is contained in:
NomenAK
2025-08-22 21:12:24 +02:00
parent 7409e4d5c8
commit e0d5b8cae5
10 changed files with 198 additions and 29 deletions

View File

@@ -28,9 +28,33 @@ function detectPip() {
return null;
}
function detectPipx() {
if (checkCommand("pipx")) return "pipx";
return null;
}
function isSuperClaudeInstalled(pipCmd) {
const result = run(pipCmd, ["show", "SuperClaude"]);
return result.status === 0;
}
module.exports = { run, detectPython, detectPip, isSuperClaudeInstalled };
function isSuperClaudeInstalledPipx() {
const result = run("pipx", ["list"]);
if (result.status === 0 && result.stdout) {
return result.stdout.toString().includes("SuperClaude");
}
return false;
}
function checkPythonEnvironment() {
// Check if we're in an externally managed environment (PEP 668)
const result = run("python3", ["-c", "import sysconfig; print(sysconfig.get_path('stdlib'))"]);
if (result.status === 0 && result.stdout) {
const stdlibPath = result.stdout.toString().trim();
const checkPep668 = run("test", ["-f", `${stdlibPath}/EXTERNALLY-MANAGED`]);
return checkPep668.status === 0;
}
return false;
}
module.exports = { run, detectPython, detectPip, detectPipx, isSuperClaudeInstalled, isSuperClaudeInstalledPipx, checkPythonEnvironment };

View File

@@ -1,31 +1,114 @@
#!/usr/bin/env node
const { run, detectPython, detectPip, isSuperClaudeInstalled } = require("./checkEnv");
const { run, detectPython, detectPip, detectPipx, isSuperClaudeInstalled, isSuperClaudeInstalledPipx, checkPythonEnvironment } = require("./checkEnv");
console.log("🔍 Checking environment...");
let pythonCmd = detectPython();
if (!pythonCmd) {
console.error("❌ Python 3 is required but not found.");
console.error(" Please install Python 3.8 or later from https://python.org");
process.exit(1);
}
console.log(`✅ Found Python: ${pythonCmd}`);
let pipCmd = detectPip();
if (!pipCmd) {
console.error("❌ pip is required but not found.");
process.exit(1);
}
console.log(`✅ Found Pip: ${pipCmd}`);
// Check if we're in an externally managed environment (PEP 668)
const isExternallyManaged = checkPythonEnvironment();
let installMethod = null;
let isInstalled = false;
// Check installation
if (!isSuperClaudeInstalled(pipCmd)) {
if (isExternallyManaged) {
console.log("📦 Detected externally managed Python environment (PEP 668)");
// Try pipx first for externally managed environments
let pipxCmd = detectPipx();
if (pipxCmd) {
console.log(`✅ Found pipx: ${pipxCmd}`);
installMethod = "pipx";
isInstalled = isSuperClaudeInstalledPipx();
} else {
console.log("⚠️ pipx is recommended for this system but not found.");
console.log(" You can install pipx with: apt install pipx (Ubuntu/Debian) or brew install pipx (macOS)");
console.log(" Alternatively, use one of these:");
console.log(" pip install --user SuperClaude # Recommended");
console.log(" pip install --break-system-packages SuperClaude # Force (use with caution)");
// Fall back to pip with --user flag
let pipCmd = detectPip();
if (pipCmd) {
console.log(`✅ Found pip: ${pipCmd}`);
console.log(" Will attempt installation with --user flag");
installMethod = "pip-user";
isInstalled = isSuperClaudeInstalled(pipCmd);
} else {
console.error("❌ Neither pipx nor pip found. Please install one of them.");
process.exit(1);
}
}
} else {
// Standard environment - use pip normally
let pipCmd = detectPip();
if (!pipCmd) {
console.error("❌ pip is required but not found.");
console.error(" Please install pip or use your system's package manager");
process.exit(1);
}
console.log(`✅ Found pip: ${pipCmd}`);
installMethod = "pip";
isInstalled = isSuperClaudeInstalled(pipCmd);
}
// Perform installation based on detected method
if (!isInstalled) {
console.log("📦 Installing SuperClaude from PyPI...");
const result = run(pipCmd, ["install", "SuperClaude"], { stdio: "inherit" });
let result;
switch(installMethod) {
case "pipx":
result = run("pipx", ["install", "SuperClaude"], { stdio: "inherit" });
break;
case "pip-user":
result = run(detectPip(), ["install", "--user", "SuperClaude"], { stdio: "inherit" });
break;
case "pip":
result = run(detectPip(), ["install", "SuperClaude"], { stdio: "inherit" });
break;
}
if (result.status !== 0) {
console.error("❌ Installation failed.");
if (installMethod === "pip" && isExternallyManaged) {
console.error(" Your system requires pipx or --user flag for pip installations.");
console.error(" Try: pipx install SuperClaude");
console.error(" Or: pip install --user SuperClaude");
}
process.exit(1);
}
console.log("✅ SuperClaude installed successfully!");
// For pipx installations, ensure it's in PATH
if (installMethod === "pipx") {
console.log("\n📌 Note: If 'SuperClaude' command is not found, run:");
console.log(" pipx ensurepath");
console.log(" Then restart your terminal or run: source ~/.bashrc");
}
} else {
console.log("✅ SuperClaude already installed.");
}
}
// Try to run SuperClaude install
console.log("\n🚀 Running SuperClaude installation...");
const installResult = run("SuperClaude", ["install"], { stdio: "inherit" });
if (installResult.status !== 0) {
console.log("\n⚠ Could not run 'SuperClaude install' automatically.");
console.log(" Please run it manually after ensuring SuperClaude is in your PATH:");
console.log(" SuperClaude install");
if (installMethod === "pipx") {
console.log("\n If command not found, try:");
console.log(" pipx ensurepath && source ~/.bashrc");
} else if (installMethod === "pip-user") {
console.log("\n If command not found, add Python user bin to PATH:");
console.log(" export PATH=\"$HOME/.local/bin:$PATH\"");
}
}

View File

@@ -1,17 +1,71 @@
#!/usr/bin/env node
const { run, detectPip } = require("./checkEnv");
const { run, detectPip, detectPipx, isSuperClaudeInstalledPipx, checkPythonEnvironment } = require("./checkEnv");
let pipCmd = detectPip();
if (!pipCmd) {
console.error("❌ pip not found, cannot update.");
process.exit(1);
console.log("🔄 Checking for SuperClaude updates...");
// Detect installation method
const isExternallyManaged = checkPythonEnvironment();
let updateMethod = null;
// Check if installed via pipx
if (detectPipx() && isSuperClaudeInstalledPipx()) {
updateMethod = "pipx";
console.log("✅ Detected pipx installation");
} else {
// Check for pip installation
let pipCmd = detectPip();
if (!pipCmd) {
console.error("❌ Neither pipx nor pip found, cannot update.");
console.error(" Please install SuperClaude first using:");
console.error(" pipx install SuperClaude");
console.error(" or");
console.error(" pip install SuperClaude");
process.exit(1);
}
if (isExternallyManaged) {
updateMethod = "pip-user";
console.log("✅ Detected pip installation with --user flag");
} else {
updateMethod = "pip";
console.log("✅ Detected standard pip installation");
}
}
// Perform update based on detected method
console.log("🔄 Updating SuperClaude from PyPI...");
const result = run(pipCmd, ["install", "--upgrade", "SuperClaude"], { stdio: "inherit" });
let result;
switch(updateMethod) {
case "pipx":
result = run("pipx", ["upgrade", "SuperClaude"], { stdio: "inherit" });
break;
case "pip-user":
result = run(detectPip(), ["install", "--upgrade", "--user", "SuperClaude"], { stdio: "inherit" });
break;
case "pip":
result = run(detectPip(), ["install", "--upgrade", "SuperClaude"], { stdio: "inherit" });
break;
}
if (result.status !== 0) {
console.error("❌ Update failed.");
if (updateMethod === "pip" && isExternallyManaged) {
console.error(" Your system requires pipx or --user flag for pip operations.");
console.error(" Try: pipx upgrade SuperClaude");
console.error(" Or: pip install --upgrade --user SuperClaude");
}
process.exit(1);
}
console.log("✅ SuperClaude updated successfully!");
// Run SuperClaude update command
console.log("\n🚀 Running SuperClaude update...");
const updateResult = run("SuperClaude", ["update"], { stdio: "inherit" });
if (updateResult.status !== 0) {
console.log("\n⚠ Could not run 'SuperClaude update' automatically.");
console.log(" Please run it manually:");
console.log(" SuperClaude update");
}