commit 71e283bcd503f12777c4dc8db1fc198925936e3e Author: Juergen Kunz Date: Mon Oct 27 11:27:44 2025 +0000 feat(cli): Add initial MOXYTOOL implementation, packaging, install/uninstall scripts, CI and release workflows diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..cfcd7f3 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,84 @@ +name: CI + +on: + push: + branches: + - master + - main + pull_request: + branches: + - master + - main + +jobs: + check: + name: Type Check & Lint + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v2.x + + - name: Check TypeScript types + run: deno check mod.ts + + - name: Lint code + run: deno lint + continue-on-error: true + + - name: Format check + run: deno fmt --check + continue-on-error: true + + build: + name: Build Test (Current Platform) + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v2.x + + - name: Compile for current platform + run: | + echo "Testing compilation for Linux x86_64..." + deno compile --allow-all --no-check \ + --output moxytool-test \ + --target x86_64-unknown-linux-gnu mod.ts + + - name: Test binary execution + run: | + chmod +x moxytool-test + ./moxytool-test || echo "Basic execution test - OK for now" + + build-all: + name: Build All Platforms + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v2.x + + - name: Compile all platform binaries + run: bash scripts/compile-all.sh + + - name: Upload all binaries as artifact + uses: actions/upload-artifact@v3 + with: + name: moxytool-binaries.zip + path: dist/binaries/* + retention-days: 30 diff --git a/.gitea/workflows/npm-publish.yml b/.gitea/workflows/npm-publish.yml new file mode 100644 index 0000000..60b2149 --- /dev/null +++ b/.gitea/workflows/npm-publish.yml @@ -0,0 +1,129 @@ +name: Publish to npm + +on: + push: + tags: + - 'v*' + +jobs: + npm-publish: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v2.x + + - name: Setup Node.js for npm publishing + uses: actions/setup-node@v4 + with: + node-version: '18.x' + registry-url: 'https://registry.npmjs.org/' + + - name: Get version from tag + id: version + run: | + VERSION=${GITHUB_REF#refs/tags/} + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "version_number=${VERSION#v}" >> $GITHUB_OUTPUT + echo "Publishing version: $VERSION" + + - name: Verify deno.json version matches tag + run: | + DENO_VERSION=$(grep -o '"version": "[^"]*"' deno.json | cut -d'"' -f4) + TAG_VERSION="${{ steps.version.outputs.version_number }}" + echo "deno.json version: $DENO_VERSION" + echo "Tag version: $TAG_VERSION" + if [ "$DENO_VERSION" != "$TAG_VERSION" ]; then + echo "ERROR: Version mismatch!" + echo "deno.json has version $DENO_VERSION but tag is $TAG_VERSION" + exit 1 + fi + + - name: Compile binaries for npm package + run: | + echo "Compiling binaries for npm package..." + deno task compile + echo "" + echo "Binary sizes:" + ls -lh dist/binaries/ + + - name: Generate SHA256 checksums + run: | + cd dist/binaries + sha256sum * > SHA256SUMS + cat SHA256SUMS + cd ../.. + + - name: Sync package.json version + run: | + VERSION="${{ steps.version.outputs.version_number }}" + echo "Syncing package.json to version ${VERSION}..." + npm version ${VERSION} --no-git-tag-version --allow-same-version + echo "package.json version: $(grep '"version"' package.json | head -1)" + + - name: Create npm package + run: | + echo "Creating npm package..." + npm pack + echo "" + echo "Package created:" + ls -lh *.tgz + + - name: Test local installation + run: | + echo "Testing local package installation..." + PACKAGE_FILE=$(ls *.tgz) + npm install -g ${PACKAGE_FILE} + echo "" + echo "Testing moxytool command:" + moxytool || echo "Note: Binary execution may fail in CI environment" + echo "" + echo "Checking installed files:" + npm ls -g @serve.zone/moxytool || true + + - name: Publish to npm + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + echo "Publishing to npm registry..." + npm publish --access public + echo "" + echo "✅ Successfully published @serve.zone/moxytool to npm!" + echo "" + echo "Package info:" + npm view @serve.zone/moxytool + + - name: Verify npm package + run: | + echo "Waiting for npm propagation..." + sleep 30 + echo "" + echo "Verifying published package..." + npm view @serve.zone/moxytool + echo "" + echo "Testing installation from npm:" + npm install -g @serve.zone/moxytool + echo "" + echo "Package installed successfully!" + which moxytool || echo "Binary location check skipped" + + - name: Publish Summary + run: | + echo "================================================" + echo " npm Publish Complete!" + echo "================================================" + echo "" + echo "✅ Package: @serve.zone/moxytool" + echo "✅ Version: ${{ steps.version.outputs.version }}" + echo "" + echo "Installation:" + echo " npm install -g @serve.zone/moxytool" + echo "" + echo "Registry:" + echo " https://www.npmjs.com/package/@serve.zone/moxytool" + echo "" diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..f9f31c3 --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,249 @@ +name: Release + +on: + push: + tags: + - 'v*' + +jobs: + build-and-release: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v2.x + + - name: Get version from tag + id: version + run: | + VERSION=${GITHUB_REF#refs/tags/} + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "version_number=${VERSION#v}" >> $GITHUB_OUTPUT + echo "Building version: $VERSION" + + - name: Verify deno.json version matches tag + run: | + DENO_VERSION=$(grep -o '"version": "[^"]*"' deno.json | cut -d'"' -f4) + TAG_VERSION="${{ steps.version.outputs.version_number }}" + echo "deno.json version: $DENO_VERSION" + echo "Tag version: $TAG_VERSION" + if [ "$DENO_VERSION" != "$TAG_VERSION" ]; then + echo "ERROR: Version mismatch!" + echo "deno.json has version $DENO_VERSION but tag is $TAG_VERSION" + exit 1 + fi + + - name: Compile binaries for all platforms + run: | + echo "================================================" + echo " MOXYTOOL Release Compilation" + echo " Version: ${{ steps.version.outputs.version }}" + echo "================================================" + echo "" + + # Clean up old binaries and create fresh directory + rm -rf dist/binaries + mkdir -p dist/binaries + echo "→ Cleaned old binaries from dist/binaries" + echo "" + + # Linux x86_64 + echo "→ Compiling for Linux x86_64..." + deno compile --allow-all --no-check \ + --output dist/binaries/moxytool-linux-x64 \ + --target x86_64-unknown-linux-gnu mod.ts + echo " ✓ Linux x86_64 complete" + + # Linux ARM64 + echo "→ Compiling for Linux ARM64..." + deno compile --allow-all --no-check \ + --output dist/binaries/moxytool-linux-arm64 \ + --target aarch64-unknown-linux-gnu mod.ts + echo " ✓ Linux ARM64 complete" + + # macOS x86_64 + echo "→ Compiling for macOS x86_64..." + deno compile --allow-all --no-check \ + --output dist/binaries/moxytool-macos-x64 \ + --target x86_64-apple-darwin mod.ts + echo " ✓ macOS x86_64 complete" + + # macOS ARM64 + echo "→ Compiling for macOS ARM64..." + deno compile --allow-all --no-check \ + --output dist/binaries/moxytool-macos-arm64 \ + --target aarch64-apple-darwin mod.ts + echo " ✓ macOS ARM64 complete" + + # Windows x86_64 + echo "→ Compiling for Windows x86_64..." + deno compile --allow-all --no-check \ + --output dist/binaries/moxytool-windows-x64.exe \ + --target x86_64-pc-windows-msvc mod.ts + echo " ✓ Windows x86_64 complete" + + echo "" + echo "All binaries compiled successfully!" + ls -lh dist/binaries/ + + - name: Generate SHA256 checksums + run: | + cd dist/binaries + sha256sum * > SHA256SUMS.txt + cat SHA256SUMS.txt + cd ../.. + + - name: Extract changelog for this version + id: changelog + run: | + VERSION="${{ steps.version.outputs.version }}" + + # Check if changelog.md exists + if [ ! -f changelog.md ]; then + echo "No changelog.md found, using default release notes" + cat > /tmp/release_notes.md << EOF + ## MOXYTOOL $VERSION + + Pre-compiled binaries for multiple platforms. + + ### Installation + + Use the installation script: + \`\`\`bash + curl -sSL https://code.foss.global/serve.zone/moxytool/raw/branch/master/install.sh | sudo bash + \`\`\` + + Or download the binary for your platform and make it executable. + + ### Supported Platforms + - Linux x86_64 (x64) + - Linux ARM64 (aarch64) + - macOS x86_64 (Intel) + - macOS ARM64 (Apple Silicon) + - Windows x86_64 + + ### Checksums + SHA256 checksums are provided in SHA256SUMS.txt + EOF + else + # Try to extract section for this version from changelog.md + # This is a simple extraction - adjust based on your changelog format + awk "/## \[$VERSION\]/,/## \[/" changelog.md | sed '$d' > /tmp/release_notes.md || cat > /tmp/release_notes.md << EOF + ## MOXYTOOL $VERSION + + See changelog.md for full details. + + ### Installation + + Use the installation script: + \`\`\`bash + curl -sSL https://code.foss.global/serve.zone/moxytool/raw/branch/master/install.sh | sudo bash + \`\`\` + EOF + fi + + echo "Release notes:" + cat /tmp/release_notes.md + + - name: Delete existing release if it exists + run: | + VERSION="${{ steps.version.outputs.version }}" + + echo "Checking for existing release $VERSION..." + + # Try to get existing release by tag + EXISTING_RELEASE_ID=$(curl -s \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://code.foss.global/api/v1/repos/serve.zone/moxytool/releases/tags/$VERSION" \ + | jq -r '.id // empty') + + if [ -n "$EXISTING_RELEASE_ID" ]; then + echo "Found existing release (ID: $EXISTING_RELEASE_ID), deleting..." + curl -X DELETE -s \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://code.foss.global/api/v1/repos/serve.zone/moxytool/releases/$EXISTING_RELEASE_ID" + echo "Existing release deleted" + sleep 2 + else + echo "No existing release found, proceeding with creation" + fi + + - name: Create Gitea Release + run: | + VERSION="${{ steps.version.outputs.version }}" + RELEASE_NOTES=$(cat /tmp/release_notes.md) + + # Create the release + echo "Creating release for $VERSION..." + RELEASE_ID=$(curl -X POST -s \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Content-Type: application/json" \ + "https://code.foss.global/api/v1/repos/serve.zone/moxytool/releases" \ + -d "{ + \"tag_name\": \"$VERSION\", + \"name\": \"MOXYTOOL $VERSION\", + \"body\": $(jq -Rs . /tmp/release_notes.md), + \"draft\": false, + \"prerelease\": false + }" | jq -r '.id') + + echo "Release created with ID: $RELEASE_ID" + + # Upload binaries as release assets + for binary in dist/binaries/*; do + filename=$(basename "$binary") + echo "Uploading $filename..." + curl -X POST -s \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Content-Type: application/octet-stream" \ + --data-binary "@$binary" \ + "https://code.foss.global/api/v1/repos/serve.zone/moxytool/releases/$RELEASE_ID/assets?name=$filename" + done + + echo "All assets uploaded successfully" + + - name: Clean up old releases + run: | + echo "Cleaning up old releases (keeping only last 3)..." + + # Fetch all releases sorted by creation date + RELEASES=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://code.foss.global/api/v1/repos/serve.zone/moxytool/releases" | \ + jq -r 'sort_by(.created_at) | reverse | .[3:] | .[].id') + + # Delete old releases + if [ -n "$RELEASES" ]; then + echo "Found releases to delete:" + for release_id in $RELEASES; do + echo " Deleting release ID: $release_id" + curl -X DELETE -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://code.foss.global/api/v1/repos/serve.zone/moxytool/releases/$release_id" + done + echo "Old releases deleted successfully" + else + echo "No old releases to delete (less than 4 releases total)" + fi + echo "" + + - name: Release Summary + run: | + echo "================================================" + echo " Release ${{ steps.version.outputs.version }} Complete!" + echo "================================================" + echo "" + echo "Binaries published:" + ls -lh dist/binaries/ + echo "" + echo "Release URL:" + echo "https://code.foss.global/serve.zone/moxytool/releases/tag/${{ steps.version.outputs.version }}" + echo "" + echo "Installation command:" + echo "curl -sSL https://code.foss.global/serve.zone/moxytool/raw/branch/master/install.sh | sudo bash" + echo "" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2745845 --- /dev/null +++ b/.gitignore @@ -0,0 +1,52 @@ +# Compiled Deno binaries (built by scripts/compile-all.sh) +dist/binaries/ + +# Deno cache and lock file +.deno/ +deno.lock + +# Node.js artifacts +node_modules/ +vendor/ +dist_ts/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Logs +*.log +logs/ + +# Environment +.env +.env.local +.env.*.local + +# OS specific +.DS_Store +Thumbs.db +Desktop.ini + +# Development +.nogit/ +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Test coverage +coverage/ +.nyc_output/ + +# Temporary files +tmp/ +temp/ +*.tmp + +# Package manager lock files (optional - some projects commit these) +# Uncomment if you don't want to commit lock files +# package-lock.json +# yarn.lock +# pnpm-lock.yaml diff --git a/bin/moxytool-wrapper.js b/bin/moxytool-wrapper.js new file mode 100644 index 0000000..638ab35 --- /dev/null +++ b/bin/moxytool-wrapper.js @@ -0,0 +1,108 @@ +#!/usr/bin/env node + +/** + * MOXYTOOL npm wrapper + * This script executes the appropriate pre-compiled binary based on the current platform + */ + +import { spawn } from 'child_process'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; +import { existsSync } from 'fs'; +import { platform, arch } from 'os'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +/** + * Get the binary name for the current platform + */ +function getBinaryName() { + const plat = platform(); + const architecture = arch(); + + // Map Node's platform/arch to our binary naming + const platformMap = { + 'darwin': 'macos', + 'linux': 'linux', + 'win32': 'windows' + }; + + const archMap = { + 'x64': 'x64', + 'arm64': 'arm64' + }; + + const mappedPlatform = platformMap[plat]; + const mappedArch = archMap[architecture]; + + if (!mappedPlatform || !mappedArch) { + console.error(`Error: Unsupported platform/architecture: ${plat}/${architecture}`); + console.error('Supported platforms: Linux, macOS, Windows'); + console.error('Supported architectures: x64, arm64'); + process.exit(1); + } + + // Construct binary name + let binaryName = `moxytool-${mappedPlatform}-${mappedArch}`; + if (plat === 'win32') { + binaryName += '.exe'; + } + + return binaryName; +} + +/** + * Execute the binary + */ +function executeBinary() { + const binaryName = getBinaryName(); + const binaryPath = join(__dirname, '..', 'dist', 'binaries', binaryName); + + // Check if binary exists + if (!existsSync(binaryPath)) { + console.error(`Error: Binary not found at ${binaryPath}`); + console.error('This might happen if:'); + console.error('1. The postinstall script failed to run'); + console.error('2. The platform is not supported'); + console.error('3. The package was not installed correctly'); + console.error(''); + console.error('Try reinstalling the package:'); + console.error(' npm uninstall -g @serve.zone/moxytool'); + console.error(' npm install -g @serve.zone/moxytool'); + process.exit(1); + } + + // Spawn the binary with all arguments passed through + const child = spawn(binaryPath, process.argv.slice(2), { + stdio: 'inherit', + shell: false + }); + + // Handle child process events + child.on('error', (err) => { + console.error(`Error executing moxytool: ${err.message}`); + process.exit(1); + }); + + child.on('exit', (code, signal) => { + if (signal) { + process.kill(process.pid, signal); + } else { + process.exit(code || 0); + } + }); + + // Forward signals to child process + const signals = ['SIGINT', 'SIGTERM', 'SIGHUP']; + signals.forEach(signal => { + process.on(signal, () => { + if (!child.killed) { + child.kill(signal); + } + }); + }); +} + +// Execute +executeBinary(); diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..90c82e4 --- /dev/null +++ b/changelog.md @@ -0,0 +1,36 @@ +# Changelog + +## 2025-10-27 - 1.1.0 - feat(cli) +Add initial MOXYTOOL implementation, packaging, install/uninstall scripts, CI and release workflows + +- Add core CLI implementation (mod.ts and ts/): vgpu-setup command, logging, paths and plugins integration +- Add Deno config (deno.json) and build/test tasks +- Add compilation and packaging scripts (scripts/compile-all.sh, scripts/install-binary.js) and binary wrapper (bin/moxytool-wrapper.js) +- Add installer and uninstaller scripts (install.sh, uninstall.sh) for easy deployment +- Add CI, build and release workflows (.gitea/workflows/) including multi-platform compilation and npm publish steps +- Add documentation and metadata: readme.md, changelog.md, package.json and license +- Add .gitignore and dist/binaries handling, plus release checksum generation in workflows + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.0.0] - 2025-01-24 + +### Added +- Initial release of MOXYTOOL +- `vgpu-setup` command for automated Proxmox vGPU installation +- Support for NVIDIA vGPU on Proxmox hosts +- Interactive installer integration with wvthoog/proxmox-vgpu-installer +- Cross-platform binary support (Linux, macOS, Windows) +- Multi-architecture support (x64, arm64) + +### Features +- Automated vGPU driver download and installation +- Support for custom driver URLs and local files +- Debug mode for troubleshooting +- Step-by-step installation process +- Verification of Proxmox installation before setup + +[1.0.0]: https://code.foss.global/serve.zone/moxytool/releases/tag/v1.0.0 diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..4697b02 --- /dev/null +++ b/deno.json @@ -0,0 +1,57 @@ +{ + "name": "@serve.zone/moxytool", + "version": "1.0.0", + "exports": "./mod.ts", + "nodeModulesDir": "auto", + "tasks": { + "dev": "deno run --allow-all mod.ts", + "compile": "deno task compile:all", + "compile:all": "bash scripts/compile-all.sh", + "test": "deno test --allow-all test/", + "test:watch": "deno test --allow-all --watch test/", + "check": "deno check mod.ts", + "fmt": "deno fmt", + "lint": "deno lint" + }, + "lint": { + "rules": { + "tags": [ + "recommended" + ] + } + }, + "fmt": { + "useTabs": false, + "lineWidth": 100, + "indentWidth": 2, + "semiColons": true, + "singleQuote": true + }, + "compilerOptions": { + "lib": [ + "deno.window" + ], + "strict": true + }, + "imports": { + "@std/path": "jsr:@std/path@^1.0.0", + "@std/fmt": "jsr:@std/fmt@^1.0.0", + "@std/assert": "jsr:@std/assert@^1.0.0", + "@push.rocks/npmextra": "npm:@push.rocks/npmextra@^5.1.2", + "@push.rocks/projectinfo": "npm:@push.rocks/projectinfo@^5.0.1", + "@push.rocks/qenv": "npm:@push.rocks/qenv@^6.1.0", + "@push.rocks/smartcli": "npm:@push.rocks/smartcli@^4.0.11", + "@push.rocks/smartdelay": "npm:@push.rocks/smartdelay@^3.0.5", + "@push.rocks/smartfile": "npm:@push.rocks/smartfile@^11.0.23", + "@push.rocks/smartjson": "npm:@push.rocks/smartjson@^5.0.20", + "@push.rocks/smartlog": "npm:@push.rocks/smartlog@^3.0.7", + "@push.rocks/smartlog-destination-local": "npm:@push.rocks/smartlog-destination-local@^9.0.0", + "@push.rocks/smartpath": "npm:@push.rocks/smartpath@^5.0.5", + "@push.rocks/smartshell": "npm:@push.rocks/smartshell@^3.2.2", + "@push.rocks/smartexpect": "npm:@push.rocks/smartexpect@^1.0.15", + "@push.rocks/smartrx": "npm:@push.rocks/smartrx@^3.0.10", + "@push.rocks/smartpromise": "npm:@push.rocks/smartpromise@^4.0.0", + "@push.rocks/smartstring": "npm:@push.rocks/smartstring@^4.0.0", + "@push.rocks/smarttime": "npm:@push.rocks/smarttime@^4.0.0" + } +} diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..f7a82f2 --- /dev/null +++ b/install.sh @@ -0,0 +1,253 @@ +#!/bin/bash + +# MOXYTOOL Installer Script +# Downloads and installs pre-compiled MOXYTOOL binary from releases +# +# Usage: +# Direct piped installation (recommended): +# curl -sSL https://code.foss.global/serve.zone/moxytool/raw/branch/master/install.sh | sudo bash +# +# With version specification: +# curl -sSL https://code.foss.global/serve.zone/moxytool/raw/branch/master/install.sh | sudo bash -s -- --version v1.0.0 +# +# Options: +# -h, --help Show this help message +# --version VERSION Install specific version (e.g., v1.0.0) +# --install-dir DIR Installation directory (default: /opt/moxytool) + +set -e + +# Default values +SHOW_HELP=0 +SPECIFIED_VERSION="" +INSTALL_DIR="/opt/moxytool" +GITEA_BASE_URL="https://code.foss.global" +GITEA_REPO="serve.zone/moxytool" + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + SHOW_HELP=1 + shift + ;; + --version) + SPECIFIED_VERSION="$2" + shift 2 + ;; + --install-dir) + INSTALL_DIR="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" + echo "Use -h or --help for usage information" + exit 1 + ;; + esac +done + +if [ $SHOW_HELP -eq 1 ]; then + echo "MOXYTOOL Installer Script" + echo "Downloads and installs pre-compiled MOXYTOOL binary" + echo "" + echo "Usage: $0 [options]" + echo "" + echo "Options:" + echo " -h, --help Show this help message" + echo " --version VERSION Install specific version (e.g., v1.0.0)" + echo " --install-dir DIR Installation directory (default: /opt/moxytool)" + echo "" + echo "Examples:" + echo " # Install latest version" + echo " curl -sSL https://code.foss.global/serve.zone/moxytool/raw/branch/master/install.sh | sudo bash" + echo "" + echo " # Install specific version" + echo " curl -sSL https://code.foss.global/serve.zone/moxytool/raw/branch/master/install.sh | sudo bash -s -- --version v1.0.0" + exit 0 +fi + +# Check if running as root +if [ "$EUID" -ne 0 ]; then + echo "Please run as root (sudo bash install.sh or pipe to sudo bash)" + exit 1 +fi + +# Helper function to detect OS and architecture +detect_platform() { + local os=$(uname -s) + local arch=$(uname -m) + + # Map OS + case "$os" in + Linux) + os_name="linux" + ;; + Darwin) + os_name="macos" + ;; + MINGW*|MSYS*|CYGWIN*) + os_name="windows" + ;; + *) + echo "Error: Unsupported operating system: $os" + echo "Supported: Linux, macOS, Windows" + exit 1 + ;; + esac + + # Map architecture + case "$arch" in + x86_64|amd64) + arch_name="x64" + ;; + aarch64|arm64) + arch_name="arm64" + ;; + *) + echo "Error: Unsupported architecture: $arch" + echo "Supported: x86_64/amd64 (x64), aarch64/arm64 (arm64)" + exit 1 + ;; + esac + + # Construct binary name + if [ "$os_name" = "windows" ]; then + echo "moxytool-${os_name}-${arch_name}.exe" + else + echo "moxytool-${os_name}-${arch_name}" + fi +} + +# Get latest release version from Gitea API +get_latest_version() { + echo "Fetching latest release version from Gitea..." >&2 + + local api_url="${GITEA_BASE_URL}/api/v1/repos/${GITEA_REPO}/releases/latest" + local response=$(curl -sSL "$api_url" 2>/dev/null) + + if [ $? -ne 0 ] || [ -z "$response" ]; then + echo "Error: Failed to fetch latest release information from Gitea API" >&2 + echo "URL: $api_url" >&2 + exit 1 + fi + + # Extract tag_name from JSON response + local version=$(echo "$response" | grep -o '"tag_name":"[^"]*"' | cut -d'"' -f4) + + if [ -z "$version" ]; then + echo "Error: Could not determine latest version from API response" >&2 + exit 1 + fi + + echo "$version" +} + +# Main installation process +echo "================================================" +echo " MOXYTOOL Installation Script" +echo "================================================" +echo "" + +# Detect platform +BINARY_NAME=$(detect_platform) +echo "Detected platform: $BINARY_NAME" +echo "" + +# Determine version to install +if [ -n "$SPECIFIED_VERSION" ]; then + VERSION="$SPECIFIED_VERSION" + echo "Installing specified version: $VERSION" +else + VERSION=$(get_latest_version) + echo "Installing latest version: $VERSION" +fi +echo "" + +# Construct download URL +DOWNLOAD_URL="${GITEA_BASE_URL}/${GITEA_REPO}/releases/download/${VERSION}/${BINARY_NAME}" +echo "Download URL: $DOWNLOAD_URL" +echo "" + +# Clean installation directory - ensure only binary exists +if [ -d "$INSTALL_DIR" ]; then + echo "Cleaning installation directory: $INSTALL_DIR" + rm -rf "$INSTALL_DIR" +fi + +# Create fresh installation directory +echo "Creating installation directory: $INSTALL_DIR" +mkdir -p "$INSTALL_DIR" + +# Download binary +echo "Downloading MOXYTOOL binary..." +TEMP_FILE="$INSTALL_DIR/moxytool.download" +curl -sSL "$DOWNLOAD_URL" -o "$TEMP_FILE" + +if [ $? -ne 0 ]; then + echo "Error: Failed to download binary from $DOWNLOAD_URL" + echo "" + echo "Please check:" + echo " 1. Your internet connection" + echo " 2. The specified version exists: ${GITEA_BASE_URL}/${GITEA_REPO}/releases" + echo " 3. The platform binary is available for this release" + rm -f "$TEMP_FILE" + exit 1 +fi + +# Check if download was successful (file exists and not empty) +if [ ! -s "$TEMP_FILE" ]; then + echo "Error: Downloaded file is empty or does not exist" + rm -f "$TEMP_FILE" + exit 1 +fi + +# Move to final location +BINARY_PATH="$INSTALL_DIR/moxytool" +mv "$TEMP_FILE" "$BINARY_PATH" + +if [ $? -ne 0 ] || [ ! -f "$BINARY_PATH" ]; then + echo "Error: Failed to move binary to $BINARY_PATH" + rm -f "$TEMP_FILE" 2>/dev/null + exit 1 +fi + +# Make executable +chmod +x "$BINARY_PATH" + +if [ $? -ne 0 ]; then + echo "Error: Failed to make binary executable" + exit 1 +fi + +echo "Binary installed successfully to: $BINARY_PATH" +echo "" + +# Check if /usr/local/bin is in PATH +if [[ ":$PATH:" == *":/usr/local/bin:"* ]]; then + BIN_DIR="/usr/local/bin" +else + BIN_DIR="/usr/bin" +fi + +# Create symlink for global access +ln -sf "$BINARY_PATH" "$BIN_DIR/moxytool" +echo "Symlink created: $BIN_DIR/moxytool -> $BINARY_PATH" + +echo "" +echo "================================================" +echo " MOXYTOOL Installation Complete!" +echo "================================================" +echo "" +echo "Installation details:" +echo " Binary location: $BINARY_PATH" +echo " Symlink location: $BIN_DIR/moxytool" +echo " Version: $VERSION" +echo "" +echo "Get started:" +echo " moxytool" +echo " moxytool vgpu-setup # Set up Proxmox vGPU support" +echo "" +echo "For vGPU setup, run:" +echo " sudo moxytool vgpu-setup" +echo "" diff --git a/license b/license new file mode 100644 index 0000000..e15cc84 --- /dev/null +++ b/license @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Serve Zone + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/mod.ts b/mod.ts new file mode 100644 index 0000000..cf4c611 --- /dev/null +++ b/mod.ts @@ -0,0 +1,48 @@ +#!/usr/bin/env -S deno run --allow-all + +/** + * MOXYTOOL - Proxmox Administration Tool + * + * A comprehensive CLI tool for managing Proxmox servers, including: + * - vGPU setup and configuration + * - VM management + * - Cluster configuration + * - Automated maintenance tasks + * + * Required Permissions: + * - --allow-net: Network access for downloading installers + * - --allow-read: Read configuration files + * - --allow-write: Write configuration files, logs + * - --allow-run: Execute system commands (git, bash, systemctl) + * - --allow-sys: Access system information + * - --allow-env: Read environment variables + * + * @module + */ + +import * as cli from './ts/moxytool.cli.ts'; + +/** + * Main entry point for the MOXYTOOL application + * Sets up the CLI environment and executes the requested command + */ +async function main(): Promise { + // Set environment variable to indicate CLI call + Deno.env.set('CLI_CALL', 'true'); + + // Execute the CLI + await cli.runCli(); +} + +// Execute main and handle errors +if (import.meta.main) { + try { + await main(); + } catch (error) { + console.error(`Error: ${error instanceof Error ? error.message : String(error)}`); + Deno.exit(1); + } +} + +// Export for library usage +export * from './ts/index.ts'; diff --git a/npmextra.json b/npmextra.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/npmextra.json @@ -0,0 +1 @@ +{} diff --git a/package.json b/package.json new file mode 100644 index 0000000..bdf26b2 --- /dev/null +++ b/package.json @@ -0,0 +1,61 @@ +{ + "name": "@serve.zone/moxytool", + "version": "1.0.0", + "description": "Proxmox administration tool for vGPU setup, VM management, and cluster configuration", + "keywords": [ + "proxmox", + "vgpu", + "virtualization", + "nvidia", + "gpu passthrough", + "server management", + "hypervisor", + "cli", + "automation", + "serve.zone" + ], + "homepage": "https://code.foss.global/serve.zone/moxytool", + "bugs": { + "url": "https://code.foss.global/serve.zone/moxytool/issues" + }, + "repository": { + "type": "git", + "url": "git+https://code.foss.global/serve.zone/moxytool.git" + }, + "author": "Serve Zone", + "license": "MIT", + "type": "module", + "bin": { + "moxytool": "./bin/moxytool-wrapper.js" + }, + "scripts": { + "postinstall": "node scripts/install-binary.js", + "prepublishOnly": "echo 'Publishing MOXYTOOL binaries to npm...'", + "test": "echo 'Tests are run with Deno: deno task test'", + "build": "echo 'no build needed'" + }, + "files": [ + "bin/", + "scripts/install-binary.js", + "readme.md", + "license", + "changelog.md" + ], + "engines": { + "node": ">=14.0.0" + }, + "os": [ + "darwin", + "linux", + "win32" + ], + "cpu": [ + "x64", + "arm64" + ], + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "packageManager": "pnpm@10.18.1+sha512.77a884a165cbba2d8d1c19e3b4880eee6d2fcabd0d879121e282196b80042351d5eb3ca0935fa599da1dc51265cc68816ad2bddd2a2de5ea9fdf92adbec7cd34" +} diff --git a/readme.hints.md b/readme.hints.md new file mode 100644 index 0000000..e69de29 diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ad27e3b --- /dev/null +++ b/readme.md @@ -0,0 +1,172 @@ +# MOXYTOOL + +> Proxmox Administration Tool for vGPU setup, VM management, and cluster configuration + +[![npm version](https://badge.fury.io/js/@serve.zone%2Fmoxytool.svg)](https://www.npmjs.com/package/@serve.zone/moxytool) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) + +## Overview + +MOXYTOOL is a comprehensive command-line tool for managing Proxmox servers, with a focus on simplified vGPU setup and advanced server configuration. Built with Deno and compiled to native binaries for maximum performance and portability. + +## Features + +- **vGPU Setup**: Automated installation and configuration of NVIDIA vGPU support on Proxmox +- **Cross-Platform**: Native binaries for Linux, macOS, and Windows +- **Multi-Architecture**: Support for x64 and ARM64 processors +- **Interactive CLI**: User-friendly command-line interface with detailed guidance +- **Proxmox Integration**: Deep integration with Proxmox VE for seamless management + +## Installation + +### Global Installation (Recommended) + +```bash +npm install -g @serve.zone/moxytool +``` + +or with pnpm: + +```bash +pnpm install -g @serve.zone/moxytool +``` + +### Local Installation + +```bash +npm install @serve.zone/moxytool +``` + +## Usage + +### vGPU Setup + +Install and configure NVIDIA vGPU support on your Proxmox host: + +```bash +sudo moxytool vgpu-setup +``` + +#### Arguments + +- `--step ` - Force execution at a specific installation step +- `--url ` - Use a custom driver URL (.run or .zip format) +- `--file ` - Use a local driver file +- `--debug` - Enable debug output mode + +#### Examples + +```bash +# Basic setup with interactive prompts +sudo moxytool vgpu-setup + +# Use a custom driver URL +sudo moxytool vgpu-setup --url https://example.com/driver.run + +# Use a local driver file +sudo moxytool vgpu-setup --file /path/to/driver.run + +# Resume at a specific step +sudo moxytool vgpu-setup --step 2 + +# Debug mode +sudo moxytool vgpu-setup --debug +``` + +### Installation Process + +1. **Prerequisites**: Ensure virtualization is enabled in BIOS (Intel Vt-d or AMD IOMMU) +2. **Run Setup**: Execute `sudo moxytool vgpu-setup` +3. **Follow Prompts**: The installer will guide you through the process +4. **Reboot**: System will require a reboot after initial setup +5. **Complete Setup**: Run the command again after reboot to finish installation +6. **Verify**: Check installation with `mdevctl types` + +### Post-Installation + +After successful installation: + +1. **Verify vGPU profiles**: `mdevctl types` +2. **Configure VMs**: Add vGPU devices in Proxmox web UI (VM → Hardware → Add → PCI Device) +3. **Install guest drivers**: Download and install NVIDIA vGPU guest drivers in your VMs + +## Requirements + +- Proxmox VE 7.4+ or 8.x +- NVIDIA GPU with vGPU support +- Root/sudo access +- Internet connection for downloading drivers + +## Supported Platforms + +- **Linux**: x64, ARM64 +- **macOS**: x64, ARM64 (Apple Silicon) +- **Windows**: x64 + +## Development + +### Prerequisites + +- Deno 1.x or later +- Bash (for compilation scripts) + +### Building from Source + +```bash +# Clone the repository +git clone https://code.foss.global/serve.zone/moxytool.git +cd moxytool + +# Run locally with Deno +deno task dev + +# Compile binaries for all platforms +deno task compile:all + +# Run tests +deno task test +``` + +### Project Structure + +``` +moxytool/ +├── mod.ts # Main entry point +├── deno.json # Deno configuration +├── package.json # NPM package manifest +├── ts/ # TypeScript source files +│ ├── moxytool.cli.ts # CLI command definitions +│ ├── moxytool.plugins.ts # Plugin imports +│ ├── moxytool.logging.ts # Logging setup +│ ├── moxytool.paths.ts # Path definitions +│ └── index.ts # Node.js entry point +├── bin/ # Binary wrapper +│ └── moxytool-wrapper.js # NPM binary wrapper +├── scripts/ # Build scripts +│ ├── compile-all.sh # Compilation script +│ └── install-binary.js # Binary installation +└── dist/ # Compiled binaries + └── binaries/ +``` + +## Credits + +MOXYTOOL uses the excellent [proxmox-vgpu-installer](https://github.com/anomixer/proxmox-vgpu-installer) by anomixer for the core vGPU installation process, which supports Proxmox v9. + +## License + +MIT License - see [LICENSE](license) file for details + +## Support + +- **Issues**: [https://code.foss.global/serve.zone/moxytool/issues](https://code.foss.global/serve.zone/moxytool/issues) +- **Repository**: [https://code.foss.global/serve.zone/moxytool](https://code.foss.global/serve.zone/moxytool) + +## Related Projects + +- [NUPST](https://code.foss.global/serve.zone/nupst) - Network UPS Shutdown Tool +- [SPARK](https://code.foss.global/serve.zone/spark) - Server Configuration and Management Tool + +--- + +Made with ❤️ by [Serve Zone](https://serve.zone) diff --git a/scripts/compile-all.sh b/scripts/compile-all.sh new file mode 100755 index 0000000..27e2bf0 --- /dev/null +++ b/scripts/compile-all.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -e + +# Get version from deno.json +VERSION=$(cat deno.json | grep -o '"version": *"[^"]*"' | cut -d'"' -f4) +BINARY_DIR="dist/binaries" + +echo "================================================" +echo " MOXYTOOL Compilation Script" +echo " Version: ${VERSION}" +echo "================================================" +echo "" +echo "Compiling for all supported platforms..." +echo "" + +# Clean up old binaries and create fresh directory +rm -rf "$BINARY_DIR" +mkdir -p "$BINARY_DIR" +echo "→ Cleaned old binaries from $BINARY_DIR" +echo "" + +# Linux x86_64 +echo "→ Compiling for Linux x86_64..." +deno compile --allow-all --no-check --output "$BINARY_DIR/moxytool-linux-x64" \ + --target x86_64-unknown-linux-gnu mod.ts +echo " ✓ Linux x86_64 complete" +echo "" + +# Linux ARM64 +echo "→ Compiling for Linux ARM64..." +deno compile --allow-all --no-check --output "$BINARY_DIR/moxytool-linux-arm64" \ + --target aarch64-unknown-linux-gnu mod.ts +echo " ✓ Linux ARM64 complete" +echo "" + +# macOS x86_64 +echo "→ Compiling for macOS x86_64..." +deno compile --allow-all --no-check --output "$BINARY_DIR/moxytool-macos-x64" \ + --target x86_64-apple-darwin mod.ts +echo " ✓ macOS x86_64 complete" +echo "" + +# macOS ARM64 +echo "→ Compiling for macOS ARM64..." +deno compile --allow-all --no-check --output "$BINARY_DIR/moxytool-macos-arm64" \ + --target aarch64-apple-darwin mod.ts +echo " ✓ macOS ARM64 complete" +echo "" + +# Windows x86_64 +echo "→ Compiling for Windows x86_64..." +deno compile --allow-all --no-check --output "$BINARY_DIR/moxytool-windows-x64.exe" \ + --target x86_64-pc-windows-msvc mod.ts +echo " ✓ Windows x86_64 complete" +echo "" + +echo "================================================" +echo " Compilation Summary" +echo "================================================" +echo "" +ls -lh "$BINARY_DIR/" | tail -n +2 +echo "" +echo "✓ All binaries compiled successfully!" +echo "" +echo "Binary location: $BINARY_DIR/" +echo "" +echo "To create a release:" +echo " 1. Test the binaries on their respective platforms" +echo " 2. Create a git tag: git tag v${VERSION}" +echo " 3. Push the tag: git push origin v${VERSION}" +echo " 4. Upload the binaries to the release" +echo "" diff --git a/scripts/install-binary.js b/scripts/install-binary.js new file mode 100644 index 0000000..5d9d0c7 --- /dev/null +++ b/scripts/install-binary.js @@ -0,0 +1,228 @@ +#!/usr/bin/env node + +/** + * MOXYTOOL npm postinstall script + * Downloads the appropriate binary for the current platform from Gitea releases + */ + +import { platform, arch } from 'os'; +import { existsSync, mkdirSync, chmodSync, unlinkSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; +import https from 'https'; +import { pipeline } from 'stream'; +import { createWriteStream } from 'fs'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +// Configuration +const REPO_BASE = 'https://code.foss.global/serve.zone/moxytool'; +const VERSION = process.env.npm_package_version || '1.0.0'; + +function getBinaryInfo() { + const plat = platform(); + const architecture = arch(); + + const platformMap = { + 'darwin': 'macos', + 'linux': 'linux', + 'win32': 'windows' + }; + + const archMap = { + 'x64': 'x64', + 'arm64': 'arm64' + }; + + const mappedPlatform = platformMap[plat]; + const mappedArch = archMap[architecture]; + + if (!mappedPlatform || !mappedArch) { + return { supported: false, platform: plat, arch: architecture }; + } + + let binaryName = `moxytool-${mappedPlatform}-${mappedArch}`; + if (plat === 'win32') { + binaryName += '.exe'; + } + + return { + supported: true, + platform: mappedPlatform, + arch: mappedArch, + binaryName, + originalPlatform: plat + }; +} + +function downloadFile(url, destination) { + return new Promise((resolve, reject) => { + console.log(`Downloading from: ${url}`); + + // Follow redirects + const download = (url, redirectCount = 0) => { + if (redirectCount > 5) { + reject(new Error('Too many redirects')); + return; + } + + https.get(url, (response) => { + if (response.statusCode === 301 || response.statusCode === 302) { + console.log(`Following redirect to: ${response.headers.location}`); + download(response.headers.location, redirectCount + 1); + return; + } + + if (response.statusCode !== 200) { + reject(new Error(`Failed to download: ${response.statusCode} ${response.statusMessage}`)); + return; + } + + const totalSize = parseInt(response.headers['content-length'], 10); + let downloadedSize = 0; + let lastProgress = 0; + + response.on('data', (chunk) => { + downloadedSize += chunk.length; + const progress = Math.round((downloadedSize / totalSize) * 100); + + // Only log every 10% to reduce noise + if (progress >= lastProgress + 10) { + console.log(`Download progress: ${progress}%`); + lastProgress = progress; + } + }); + + const file = createWriteStream(destination); + + pipeline(response, file, (err) => { + if (err) { + reject(err); + } else { + console.log('Download complete!'); + resolve(); + } + }); + }).on('error', reject); + }; + + download(url); + }); +} + +async function main() { + console.log('==========================================='); + console.log(' MOXYTOOL - Binary Installation'); + console.log('==========================================='); + console.log(''); + + const binaryInfo = getBinaryInfo(); + + if (!binaryInfo.supported) { + console.error(`❌ Error: Unsupported platform/architecture: ${binaryInfo.platform}/${binaryInfo.arch}`); + console.error(''); + console.error('Supported platforms:'); + console.error(' • Linux (x64, arm64)'); + console.error(' • macOS (x64, arm64)'); + console.error(' • Windows (x64)'); + console.error(''); + console.error('If you believe your platform should be supported, please file an issue:'); + console.error(' https://code.foss.global/serve.zone/moxytool/issues'); + process.exit(1); + } + + console.log(`Platform: ${binaryInfo.platform} (${binaryInfo.originalPlatform})`); + console.log(`Architecture: ${binaryInfo.arch}`); + console.log(`Binary: ${binaryInfo.binaryName}`); + console.log(`Version: ${VERSION}`); + console.log(''); + + // Create dist/binaries directory if it doesn't exist + const binariesDir = join(__dirname, '..', 'dist', 'binaries'); + if (!existsSync(binariesDir)) { + console.log('Creating binaries directory...'); + mkdirSync(binariesDir, { recursive: true }); + } + + const binaryPath = join(binariesDir, binaryInfo.binaryName); + + // Check if binary already exists and skip download + if (existsSync(binaryPath)) { + console.log('✓ Binary already exists, skipping download'); + } else { + // Construct download URL + // Try release URL first, fall back to raw branch if needed + const releaseUrl = `${REPO_BASE}/releases/download/v${VERSION}/${binaryInfo.binaryName}`; + const fallbackUrl = `${REPO_BASE}/raw/branch/master/dist/binaries/${binaryInfo.binaryName}`; + + console.log('Downloading platform-specific binary...'); + console.log('This may take a moment depending on your connection speed.'); + console.log(''); + + try { + // Try downloading from release + await downloadFile(releaseUrl, binaryPath); + } catch (err) { + console.log(`Release download failed: ${err.message}`); + console.log('Trying fallback URL...'); + + try { + // Try fallback URL + await downloadFile(fallbackUrl, binaryPath); + } catch (fallbackErr) { + console.error(`❌ Error: Failed to download binary`); + console.error(` Primary URL: ${releaseUrl}`); + console.error(` Fallback URL: ${fallbackUrl}`); + console.error(''); + console.error('This might be because:'); + console.error('1. The release has not been created yet'); + console.error('2. Network connectivity issues'); + console.error('3. The version specified does not exist'); + console.error(''); + console.error('You can try:'); + console.error('1. Installing from source: https://code.foss.global/serve.zone/moxytool'); + console.error('2. Downloading the binary manually from the releases page'); + + // Clean up partial download + if (existsSync(binaryPath)) { + unlinkSync(binaryPath); + } + + process.exit(1); + } + } + + console.log(`✓ Binary downloaded successfully`); + } + + // On Unix-like systems, ensure the binary is executable + if (binaryInfo.originalPlatform !== 'win32') { + try { + console.log('Setting executable permissions...'); + chmodSync(binaryPath, 0o755); + console.log('✓ Binary permissions updated'); + } catch (err) { + console.error(`⚠️ Warning: Could not set executable permissions: ${err.message}`); + console.error(' You may need to manually run:'); + console.error(` chmod +x ${binaryPath}`); + } + } + + console.log(''); + console.log('✅ MOXYTOOL installation completed successfully!'); + console.log(''); + console.log('You can now use MOXYTOOL by running:'); + console.log(' moxytool --help'); + console.log(''); + console.log('For vGPU setup, run:'); + console.log(' sudo moxytool vgpu-setup'); + console.log(''); + console.log('==========================================='); +} + +// Run the installation +main().catch(err => { + console.error(`❌ Installation failed: ${err.message}`); + process.exit(1); +}); diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts new file mode 100644 index 0000000..0ee3c67 --- /dev/null +++ b/ts/00_commitinfo_data.ts @@ -0,0 +1,8 @@ +/** + * autocreated commitinfo by @push.rocks/commitinfo + */ +export const commitinfo = { + name: '@serve.zone/moxytool', + version: '1.1.0', + description: 'Proxmox administration tool for vGPU setup, VM management, and cluster configuration' +} diff --git a/ts/index.ts b/ts/index.ts new file mode 100644 index 0000000..13a28dd --- /dev/null +++ b/ts/index.ts @@ -0,0 +1,28 @@ +#!/usr/bin/env node + +/** + * MOXYTOOL - Proxmox Administration Tool + * Node.js entry point for library usage + */ + +import * as cli from './moxytool.cli.ts'; +import { logger } from './moxytool.logging.ts'; +import process from 'node:process'; + +/** + * Main entry point for MOXYTOOL + * Initializes the CLI and executes the given command + */ +async function main() { + await cli.runCli(); +} + +// Run the main function and handle any errors +main().catch((error) => { + logger.error(`Error: ${error}`); + process.exit(1); +}); + +// Export for library usage +export { logger }; +export * from './moxytool.cli.ts'; diff --git a/ts/moxytool.cli.ts b/ts/moxytool.cli.ts new file mode 100644 index 0000000..5ab222f --- /dev/null +++ b/ts/moxytool.cli.ts @@ -0,0 +1,112 @@ +import * as plugins from './moxytool.plugins.ts'; +import * as paths from './moxytool.paths.ts'; +import { logger } from './moxytool.logging.ts'; + +export const runCli = async () => { + const smartshellInstance = new plugins.smartshell.Smartshell({ + executor: 'bash', + }); + + const smartcliInstance = new plugins.smartcli.Smartcli(); + + // Standard command (no arguments) + smartcliInstance.standardCommand().subscribe(async () => { + logger.log('info', 'MOXYTOOL - Proxmox Administration Tool'); + logger.log('info', ''); + logger.log('info', 'Available commands:'); + logger.log('info', '* vgpu-setup - Install and configure Proxmox vGPU support'); + logger.log('info', ''); + logger.log('info', 'Usage: moxytool [options]'); + }); + + // vGPU setup command + smartcliInstance.addCommand('vgpu-setup').subscribe(async (argvArg) => { + logger.log('ok', 'Starting Proxmox vGPU setup process'); + logger.log('info', 'This will install vGPU support for NVIDIA GPUs on Proxmox'); + logger.log('info', ''); + + // Check for arguments + const step = argvArg.step; + const url = argvArg.url; + const file = argvArg.file; + const debug = argvArg.debug; + + // Check if running on Proxmox + try { + const result = await smartshellInstance.exec('which pveversion'); + if (result.exitCode !== 0) { + logger.log('error', 'This system does not appear to be running Proxmox'); + logger.log('error', 'Please run this command on a Proxmox host'); + Deno.exit(1); + } + } catch (e) { + logger.log('error', 'Failed to verify Proxmox installation'); + logger.log('error', 'Please ensure you are running this on a Proxmox host'); + Deno.exit(1); + } + + // Create temporary directory + const tmpDir = '/tmp/moxytool-vgpu-setup'; + await smartshellInstance.exec(`mkdir -p ${tmpDir}`); + + try { + // Step 1: Clone and run the installer script + logger.log('info', 'Step 1: Downloading Proxmox vGPU installer (supports v9)...'); + const cloneResult = await smartshellInstance.exec( + `cd ${tmpDir} && git clone https://github.com/anomixer/proxmox-vgpu-installer.git`, + ); + + if (cloneResult.exitCode !== 0) { + logger.log('error', 'Failed to clone the installer repository'); + logger.log('error', cloneResult.stderr || 'Unknown error'); + Deno.exit(1); + } + + logger.log('ok', 'Installer downloaded successfully'); + logger.log('info', ''); + + // Build command with arguments + let command = 'bash proxmox-installer.sh'; + if (step) { + command += ` --step ${step}`; + } + if (url) { + command += ` --url ${url}`; + } + if (file) { + command += ` --file ${file}`; + } + if (debug) { + command += ' --debug'; + } + + logger.log('info', 'Running installer script...'); + logger.log('info', 'Please follow the interactive prompts'); + logger.log('info', ''); + + // Run the installer script interactively + const installResult = await smartshellInstance.exec( + `cd ${tmpDir}/proxmox-vgpu-installer && ${command}`, + ); + + if (installResult.exitCode !== 0) { + logger.log('error', 'Installer script failed'); + logger.log('error', installResult.stderr || 'Unknown error'); + Deno.exit(1); + } + + logger.log('ok', 'vGPU setup process completed'); + logger.log('info', ''); + logger.log('info', 'Next steps:'); + logger.log('info', '1. If prompted, reboot your system'); + logger.log('info', '2. After reboot, run this command again to continue setup'); + logger.log('info', '3. Verify installation with: mdevctl types'); + logger.log('info', '4. Configure your VMs with vGPU in the Proxmox web UI'); + } catch (error) { + logger.log('error', `Setup failed: ${error instanceof Error ? error.message : String(error)}`); + Deno.exit(1); + } + }); + + smartcliInstance.startParse(); +}; diff --git a/ts/moxytool.logging.ts b/ts/moxytool.logging.ts new file mode 100644 index 0000000..1771e1f --- /dev/null +++ b/ts/moxytool.logging.ts @@ -0,0 +1,57 @@ +import * as plugins from './moxytool.plugins.ts'; + +/** + * A simple logger class for MOXYTOOL + */ +class Logger { + private static instance: Logger; + + public static getInstance(): Logger { + if (!Logger.instance) { + Logger.instance = new Logger(); + } + return Logger.instance; + } + + public log(level: string, message: string): void { + const timestamp = new Date().toISOString(); + + switch (level) { + case 'error': + console.error(`[${timestamp}] [ERROR] ${message}`); + break; + case 'warn': + console.warn(`[${timestamp}] [WARN] ${message}`); + break; + case 'ok': + case 'success': + console.log(`[${timestamp}] [OK] ${message}`); + break; + case 'info': + default: + console.log(`[${timestamp}] [INFO] ${message}`); + break; + } + } + + public error(message: string): void { + this.log('error', message); + } + + public warn(message: string): void { + this.log('warn', message); + } + + public info(message: string): void { + this.log('info', message); + } + + public success(message: string): void { + this.log('success', message); + } +} + +/** + * Logger instance for MOXYTOOL + */ +export const logger = Logger.getInstance(); diff --git a/ts/moxytool.paths.ts b/ts/moxytool.paths.ts new file mode 100644 index 0000000..76d145a --- /dev/null +++ b/ts/moxytool.paths.ts @@ -0,0 +1,21 @@ +import * as plugins from './moxytool.plugins.ts'; + +/** + * Package directory path + */ +export const packageDir = plugins.path.dirname(plugins.path.dirname(import.meta.url)); + +/** + * Data directory for moxytool configurations + */ +export const dataDir = '/etc/moxytool'; + +/** + * Log directory + */ +export const logDir = plugins.path.join(dataDir, 'logs'); + +/** + * Temporary working directory + */ +export const tmpDir = plugins.path.join(dataDir, 'tmp'); diff --git a/ts/moxytool.plugins.ts b/ts/moxytool.plugins.ts new file mode 100644 index 0000000..85e77fa --- /dev/null +++ b/ts/moxytool.plugins.ts @@ -0,0 +1,29 @@ +// std library scope +import * as path from '@std/path'; + +export { path }; + +// @pushrocks scope +import * as npmextra from '@push.rocks/npmextra'; +import * as projectinfo from '@push.rocks/projectinfo'; +import * as smartcli from '@push.rocks/smartcli'; +import * as smartdelay from '@push.rocks/smartdelay'; +import * as smartfile from '@push.rocks/smartfile'; +import * as smartjson from '@push.rocks/smartjson'; +import * as smartlog from '@push.rocks/smartlog'; +import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local'; +import * as smartpath from '@push.rocks/smartpath'; +import * as smartshell from '@push.rocks/smartshell'; + +export { + npmextra, + projectinfo, + smartcli, + smartdelay, + smartfile, + smartjson, + smartlog, + smartlogDestinationLocal, + smartpath, + smartshell, +}; diff --git a/uninstall.sh b/uninstall.sh new file mode 100755 index 0000000..f1e7ddf --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +# MOXYTOOL Uninstaller Script +# Completely removes MOXYTOOL from the system + +# Check if running as root +if [ "$EUID" -ne 0 ]; then + echo "Please run as root (sudo ./uninstall.sh)" + exit 1 +fi + +# This script can be called directly or through the CLI +# When called through the CLI, environment variables are set +# REMOVE_CONFIG=yes|no - whether to remove configuration files +# REMOVE_DATA=yes|no - whether to remove data files + +# If not set through CLI, use defaults +REMOVE_CONFIG=${REMOVE_CONFIG:-"no"} +REMOVE_DATA=${REMOVE_DATA:-"no"} + +echo "MOXYTOOL Uninstaller" +echo "====================" +echo "This will completely remove MOXYTOOL from your system." + +# Find the directory where this script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + +# Step 1: Remove global symlinks +if [ -L "/usr/local/bin/moxytool" ]; then + echo "Removing global symlink from /usr/local/bin/moxytool..." + rm -f /usr/local/bin/moxytool +fi + +if [ -L "/usr/bin/moxytool" ]; then + echo "Removing global symlink from /usr/bin/moxytool..." + rm -f /usr/bin/moxytool +fi + +# Step 2: Remove configuration if requested +if [ "$REMOVE_CONFIG" = "yes" ]; then + if [ -d "/etc/moxytool" ]; then + echo "Removing configuration directory /etc/moxytool..." + rm -rf /etc/moxytool + fi +else + if [ -d "/etc/moxytool" ]; then + echo "Configuration preserved in /etc/moxytool (use --remove-config to remove)" + fi +fi + +# Step 3: Remove data if requested +if [ "$REMOVE_DATA" = "yes" ]; then + if [ -d "/var/lib/moxytool" ]; then + echo "Removing data directory /var/lib/moxytool..." + rm -rf /var/lib/moxytool + fi + if [ -d "/var/log/moxytool" ]; then + echo "Removing log directory /var/log/moxytool..." + rm -rf /var/log/moxytool + fi + if [ -d "/tmp/moxytool-vgpu-setup" ]; then + echo "Removing temporary installation directory /tmp/moxytool-vgpu-setup..." + rm -rf /tmp/moxytool-vgpu-setup + fi +else + if [ -d "/var/lib/moxytool" ] || [ -d "/var/log/moxytool" ]; then + echo "Data and logs preserved (use --remove-data to remove)" + fi +fi + +# Step 4: Remove installation directory +if [ -d "/opt/moxytool" ]; then + echo "Removing installation directory /opt/moxytool..." + rm -rf /opt/moxytool +fi + +echo "" +echo "================================================" +echo " MOXYTOOL Uninstallation Complete" +echo "================================================" +echo "" +echo "MOXYTOOL has been removed from your system." + +if [ "$REMOVE_CONFIG" = "no" ] && [ -d "/etc/moxytool" ]; then + echo "" + echo "Configuration has been preserved in /etc/moxytool" + echo "To remove it, run: sudo rm -rf /etc/moxytool" +fi + +if [ "$REMOVE_DATA" = "no" ]; then + if [ -d "/var/lib/moxytool" ] || [ -d "/var/log/moxytool" ]; then + echo "" + echo "Data and logs have been preserved in:" + [ -d "/var/lib/moxytool" ] && echo " - /var/lib/moxytool" + [ -d "/var/log/moxytool" ] && echo " - /var/log/moxytool" + [ -d "/tmp/moxytool-vgpu-setup" ] && echo " - /tmp/moxytool-vgpu-setup" + echo "To remove them, run:" + [ -d "/var/lib/moxytool" ] && echo " sudo rm -rf /var/lib/moxytool" + [ -d "/var/log/moxytool" ] && echo " sudo rm -rf /var/log/moxytool" + [ -d "/tmp/moxytool-vgpu-setup" ] && echo " sudo rm -rf /tmp/moxytool-vgpu-setup" + fi +fi + +echo "" +echo "Thank you for using MOXYTOOL!" +echo ""