feat(cli): Add initial MOXYTOOL implementation, packaging, install/uninstall scripts, CI and release workflows
This commit is contained in:
84
.gitea/workflows/ci.yml
Normal file
84
.gitea/workflows/ci.yml
Normal file
@@ -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
|
||||||
129
.gitea/workflows/npm-publish.yml
Normal file
129
.gitea/workflows/npm-publish.yml
Normal file
@@ -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 ""
|
||||||
249
.gitea/workflows/release.yml
Normal file
249
.gitea/workflows/release.yml
Normal file
@@ -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 ""
|
||||||
52
.gitignore
vendored
Normal file
52
.gitignore
vendored
Normal file
@@ -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
|
||||||
108
bin/moxytool-wrapper.js
Normal file
108
bin/moxytool-wrapper.js
Normal file
@@ -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();
|
||||||
36
changelog.md
Normal file
36
changelog.md
Normal file
@@ -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
|
||||||
57
deno.json
Normal file
57
deno.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
253
install.sh
Executable file
253
install.sh
Executable file
@@ -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 ""
|
||||||
21
license
Normal file
21
license
Normal file
@@ -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.
|
||||||
48
mod.ts
Normal file
48
mod.ts
Normal file
@@ -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<void> {
|
||||||
|
// 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';
|
||||||
1
npmextra.json
Normal file
1
npmextra.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
61
package.json
Normal file
61
package.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
0
readme.hints.md
Normal file
0
readme.hints.md
Normal file
172
readme.md
Normal file
172
readme.md
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# MOXYTOOL
|
||||||
|
|
||||||
|
> Proxmox Administration Tool for vGPU setup, VM management, and cluster configuration
|
||||||
|
|
||||||
|
[](https://www.npmjs.com/package/@serve.zone/moxytool)
|
||||||
|
[](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 <number>` - Force execution at a specific installation step
|
||||||
|
- `--url <url>` - Use a custom driver URL (.run or .zip format)
|
||||||
|
- `--file <path>` - 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)
|
||||||
72
scripts/compile-all.sh
Executable file
72
scripts/compile-all.sh
Executable file
@@ -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 ""
|
||||||
228
scripts/install-binary.js
Normal file
228
scripts/install-binary.js
Normal file
@@ -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);
|
||||||
|
});
|
||||||
8
ts/00_commitinfo_data.ts
Normal file
8
ts/00_commitinfo_data.ts
Normal file
@@ -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'
|
||||||
|
}
|
||||||
28
ts/index.ts
Normal file
28
ts/index.ts
Normal file
@@ -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';
|
||||||
112
ts/moxytool.cli.ts
Normal file
112
ts/moxytool.cli.ts
Normal file
@@ -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 <command> [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();
|
||||||
|
};
|
||||||
57
ts/moxytool.logging.ts
Normal file
57
ts/moxytool.logging.ts
Normal file
@@ -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();
|
||||||
21
ts/moxytool.paths.ts
Normal file
21
ts/moxytool.paths.ts
Normal file
@@ -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');
|
||||||
29
ts/moxytool.plugins.ts
Normal file
29
ts/moxytool.plugins.ts
Normal file
@@ -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,
|
||||||
|
};
|
||||||
106
uninstall.sh
Executable file
106
uninstall.sh
Executable file
@@ -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 ""
|
||||||
Reference in New Issue
Block a user