feat: Add workbench and major cleanup, refactor, and updates (#21)
* FreeCAD addon support for Workbench and Plugins * docs: refactor docs and clean up linters, etc. * Remove mdformat * test: improve test coverage * test:Lots of general fixes * chore: more general fixes
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
# CodeRabbit CLI commands
|
||||
# Usage: just coderabbit::install, just coderabbit::review, etc.
|
||||
#
|
||||
# CodeRabbit CLI provides AI-powered code reviews in your terminal.
|
||||
# https://www.coderabbit.ai/cli
|
||||
#
|
||||
# IMPORTANT - RATE LIMITS:
|
||||
# - Free tier: 1 review per hour
|
||||
# - Pro tier: 5 reviews per hour
|
||||
# Run reviews manually when needed to avoid hitting limits.
|
||||
#
|
||||
# Note: In CI, skip CodeRabbit CLI since the GitHub App handles PR reviews.
|
||||
# These commands are for local, on-demand development workflow only.
|
||||
|
||||
# =============================================================================
|
||||
# Installation
|
||||
# =============================================================================
|
||||
|
||||
# Install CodeRabbit CLI (prefers Homebrew on macOS/Linux, falls back to official installer)
|
||||
#
|
||||
# SECURITY NOTE:
|
||||
# - Homebrew (preferred): Uses Homebrew's cask verification and signed binaries
|
||||
# from https://formulae.brew.sh/cask/coderabbit
|
||||
# - Fallback installer: Downloads from https://cli.coderabbit.ai/install.sh
|
||||
# The installer script is from CodeRabbit's official domain and installs
|
||||
# signed binaries. We download to a temp file first for inspection if needed.
|
||||
#
|
||||
# Trust decision: CodeRabbit is a well-known code review service with a public
|
||||
# GitHub organization (https://github.com/coderabbitai). The CLI is optional
|
||||
# and only used for local development reviews.
|
||||
install:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "Installing CodeRabbit CLI..."
|
||||
|
||||
# Prefer Homebrew if available (macOS and Linux)
|
||||
if command -v brew &>/dev/null; then
|
||||
echo "Using Homebrew to install CodeRabbit CLI..."
|
||||
brew install --cask coderabbit
|
||||
echo ""
|
||||
echo "CodeRabbit CLI installed via Homebrew."
|
||||
echo "Run 'just coderabbit::login' to authenticate."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Fallback: Download installer to temp file first (allows inspection)
|
||||
echo "Homebrew not found. Using official installer..."
|
||||
INSTALLER_URL="https://cli.coderabbit.ai/install.sh"
|
||||
TEMP_SCRIPT=$(mktemp /tmp/coderabbit-install.XXXXXX.sh)
|
||||
|
||||
echo "Downloading installer to: $TEMP_SCRIPT"
|
||||
curl -fsSL "$INSTALLER_URL" -o "$TEMP_SCRIPT"
|
||||
|
||||
echo "Installer downloaded. You can inspect it at: $TEMP_SCRIPT"
|
||||
echo "Executing installer..."
|
||||
sh "$TEMP_SCRIPT"
|
||||
|
||||
# Clean up
|
||||
rm -f "$TEMP_SCRIPT"
|
||||
|
||||
echo ""
|
||||
echo "CodeRabbit CLI installed. Run 'just coderabbit::login' to authenticate."
|
||||
|
||||
# Check if CodeRabbit CLI is installed
|
||||
check-installed:
|
||||
@command -v coderabbit >/dev/null 2>&1 || { echo "CodeRabbit CLI not installed. Run: just coderabbit::install"; exit 1; }
|
||||
@coderabbit --version
|
||||
|
||||
# =============================================================================
|
||||
# Authentication
|
||||
# =============================================================================
|
||||
|
||||
# Login to CodeRabbit (opens browser for authentication)
|
||||
login: check-installed
|
||||
coderabbit auth login
|
||||
|
||||
# Logout from CodeRabbit
|
||||
logout: check-installed
|
||||
coderabbit auth logout
|
||||
|
||||
# Check authentication status
|
||||
auth-status: check-installed
|
||||
coderabbit auth status
|
||||
|
||||
# =============================================================================
|
||||
# Code Reviews
|
||||
# =============================================================================
|
||||
|
||||
# Review staged changes (preserves user's staging state)
|
||||
review: check-installed
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "Reviewing staged changes..."
|
||||
|
||||
# Check if there are staged changes
|
||||
if ! git diff --cached --quiet; then
|
||||
# Stash unstaged changes, keeping staged changes in working tree
|
||||
# This allows coderabbit to review only what's staged
|
||||
STASH_OUTPUT=$(git stash push --keep-index -m "coderabbit-review-temp" 2>&1) || true
|
||||
|
||||
# Run the review on staged changes
|
||||
coderabbit review --plain --type uncommitted || true
|
||||
|
||||
# Restore unstaged changes if we stashed anything
|
||||
if [[ "$STASH_OUTPUT" != "No local changes to save" ]]; then
|
||||
git stash pop --quiet || true
|
||||
fi
|
||||
else
|
||||
echo "No staged changes to review. Stage changes with 'git add' first."
|
||||
echo "Or use 'just coderabbit::review-all' to review all uncommitted changes."
|
||||
fi
|
||||
|
||||
# Review staged changes with auto-fix suggestions (preserves user's staging state)
|
||||
review-fix: check-installed
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "Reviewing staged changes with auto-fix..."
|
||||
|
||||
# Check if there are staged changes
|
||||
if ! git diff --cached --quiet; then
|
||||
# Stash unstaged changes, keeping staged changes in working tree
|
||||
STASH_OUTPUT=$(git stash push --keep-index -m "coderabbit-review-temp" 2>&1) || true
|
||||
|
||||
# Run the review with auto-fix on staged changes
|
||||
coderabbit review --plain --type uncommitted --auto-fix || true
|
||||
|
||||
# Restore unstaged changes if we stashed anything
|
||||
if [[ "$STASH_OUTPUT" != "No local changes to save" ]]; then
|
||||
git stash pop --quiet || true
|
||||
fi
|
||||
else
|
||||
echo "No staged changes to review. Stage changes with 'git add' first."
|
||||
fi
|
||||
|
||||
# Review ALL uncommitted changes (staged + unstaged)
|
||||
review-all: check-installed
|
||||
@echo "Reviewing all uncommitted changes..."
|
||||
coderabbit review --plain --type uncommitted
|
||||
|
||||
# Review the last commit
|
||||
review-last: check-installed
|
||||
coderabbit review --plain --type committed --base-commit HEAD~1
|
||||
|
||||
# Review changes since a specific commit (usage: just coderabbit::review-since abc123)
|
||||
review-since commit: check-installed
|
||||
coderabbit review --plain --type committed --base-commit {{commit}}
|
||||
|
||||
# Review changes between current branch and main
|
||||
review-branch: check-installed
|
||||
coderabbit review --plain --type committed --base-commit main
|
||||
|
||||
# =============================================================================
|
||||
# Output Formats
|
||||
# =============================================================================
|
||||
|
||||
# Generate prompt-only output for staged changes (for AI agents like Claude Code)
|
||||
prompt-only: check-installed
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Check if there are staged changes
|
||||
if ! git diff --cached --quiet; then
|
||||
# Stash unstaged changes, keeping staged changes in working tree
|
||||
STASH_OUTPUT=$(git stash push --keep-index -m "coderabbit-prompt-temp" 2>&1) || true
|
||||
|
||||
# Generate prompt for staged changes
|
||||
coderabbit review --prompt-only --type uncommitted || true
|
||||
|
||||
# Restore unstaged changes if we stashed anything
|
||||
if [[ "$STASH_OUTPUT" != "No local changes to save" ]]; then
|
||||
git stash pop --quiet || true
|
||||
fi
|
||||
else
|
||||
echo "No staged changes. Stage changes with 'git add' first."
|
||||
fi
|
||||
|
||||
# Review staged changes with JSON output
|
||||
review-json: check-installed
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Check if there are staged changes
|
||||
if ! git diff --cached --quiet; then
|
||||
# Stash unstaged changes, keeping staged changes in working tree
|
||||
STASH_OUTPUT=$(git stash push --keep-index -m "coderabbit-json-temp" 2>&1) || true
|
||||
|
||||
# Run review with JSON output
|
||||
coderabbit review --format json --type uncommitted || true
|
||||
|
||||
# Restore unstaged changes if we stashed anything
|
||||
if [[ "$STASH_OUTPUT" != "No local changes to save" ]]; then
|
||||
git stash pop --quiet || true
|
||||
fi
|
||||
else
|
||||
echo "No staged changes. Stage changes with 'git add' first."
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Configuration
|
||||
# =============================================================================
|
||||
|
||||
# Show CodeRabbit configuration
|
||||
config-show: check-installed
|
||||
coderabbit config show
|
||||
|
||||
# Show help for all CodeRabbit commands
|
||||
help: check-installed
|
||||
coderabbit --help
|
||||
@@ -1,10 +1,14 @@
|
||||
# Documentation commands
|
||||
# Usage: just docs::build, just docs::serve, etc.
|
||||
# Usage: just documentation::build, just documentation::serve, etc.
|
||||
|
||||
# Build documentation
|
||||
build:
|
||||
uv run mkdocs build
|
||||
|
||||
# Build documentation with strict mode (fails on warnings, for CI)
|
||||
build-strict:
|
||||
uv run mkdocs build --strict
|
||||
|
||||
# Serve documentation locally
|
||||
serve:
|
||||
uv run mkdocs serve
|
||||
|
||||
+189
-95
@@ -1,11 +1,11 @@
|
||||
# FreeCAD plugin and macro commands
|
||||
# Usage: just freecad::run-gui, just freecad::install-bridge-macro, etc.
|
||||
# FreeCAD workbench and macro commands
|
||||
# Usage: just freecad::run-gui, just freecad::install-workbench, etc.
|
||||
|
||||
# Project root directory (justfile_directory() returns the main justfile's directory)
|
||||
project_root := justfile_directory()
|
||||
|
||||
# =============================================================================
|
||||
# Running FreeCAD
|
||||
# Running FreeCAD with MCP Bridge
|
||||
# =============================================================================
|
||||
|
||||
# Run MCP bridge server in FreeCAD headless mode
|
||||
@@ -13,7 +13,8 @@ run-headless:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
PROJECT_DIR="{{project_root}}"
|
||||
SCRIPT_PATH="${PROJECT_DIR}/src/freecad_mcp/freecad_plugin/headless_server.py"
|
||||
# Use the headless server from the addon directory (source of truth)
|
||||
SCRIPT_PATH="${PROJECT_DIR}/addon/FreecadRobustMCP/freecad_mcp_bridge/headless_server.py"
|
||||
|
||||
# Find FreeCADCmd executable based on OS
|
||||
FREECAD_CMD=""
|
||||
@@ -64,9 +65,6 @@ run-headless:
|
||||
echo "Using FreeCAD: $FREECAD_CMD"
|
||||
echo ""
|
||||
|
||||
# Add project src to PYTHONPATH so FreeCAD can find the module
|
||||
export PYTHONPATH="${PROJECT_DIR}/src:${PYTHONPATH:-}"
|
||||
|
||||
# Run FreeCADCmd with the headless server script
|
||||
"$FREECAD_CMD" "$SCRIPT_PATH"
|
||||
|
||||
@@ -75,7 +73,7 @@ run-headless-custom freecad_cmd:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
PROJECT_DIR="{{project_root}}"
|
||||
SCRIPT_PATH="${PROJECT_DIR}/src/freecad_mcp/freecad_plugin/headless_server.py"
|
||||
SCRIPT_PATH="${PROJECT_DIR}/addon/FreecadRobustMCP/freecad_mcp_bridge/headless_server.py"
|
||||
|
||||
if [[ ! -x "{{freecad_cmd}}" ]]; then
|
||||
echo "ERROR: FreeCADCmd not found or not executable: {{freecad_cmd}}"
|
||||
@@ -85,28 +83,60 @@ run-headless-custom freecad_cmd:
|
||||
echo "Using FreeCAD: {{freecad_cmd}}"
|
||||
echo ""
|
||||
|
||||
# Add project src to PYTHONPATH so FreeCAD can find the module
|
||||
export PYTHONPATH="${PROJECT_DIR}/src:${PYTHONPATH:-}"
|
||||
|
||||
# Run FreeCADCmd with the headless server script
|
||||
"{{freecad_cmd}}" "$SCRIPT_PATH"
|
||||
|
||||
# Run FreeCAD GUI with MCP bridge plugin auto-started
|
||||
# Run FreeCAD GUI with MCP bridge (requires workbench to be installed)
|
||||
run-gui:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
PROJECT_DIR="{{project_root}}"
|
||||
|
||||
# Use the gui_startup.py script from the project
|
||||
STARTUP_SCRIPT="${PROJECT_DIR}/src/freecad_mcp/freecad_plugin/gui_startup.py"
|
||||
# Create a temporary startup script that starts the MCP bridge
|
||||
STARTUP_SCRIPT=$(mktemp /tmp/freecad_mcp_startup.XXXXXX.py)
|
||||
|
||||
if [[ ! -f "$STARTUP_SCRIPT" ]]; then
|
||||
echo "ERROR: Startup script not found: $STARTUP_SCRIPT"
|
||||
exit 1
|
||||
fi
|
||||
# Use the server from the installed workbench location
|
||||
# Note: For development, use run-gui-custom which passes the addon path explicitly
|
||||
cat > "$STARTUP_SCRIPT" << 'PYTHON_EOF'
|
||||
# FreeCAD MCP Bridge Auto-Start Script
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Set environment variable for the project path
|
||||
export FREECAD_MCP_PROJECT_PATH="${PROJECT_DIR}/src"
|
||||
# Determine installed workbench location based on platform
|
||||
if sys.platform == "darwin":
|
||||
addon_path = Path.home() / "Library" / "Application Support" / "FreeCAD" / "Mod" / "FreecadRobustMCP" / "freecad_mcp_bridge"
|
||||
elif sys.platform == "win32":
|
||||
addon_path = Path(os.environ.get("APPDATA", "")) / "FreeCAD" / "Mod" / "FreecadRobustMCP" / "freecad_mcp_bridge"
|
||||
else:
|
||||
addon_path = Path.home() / ".local" / "share" / "FreeCAD" / "Mod" / "FreecadRobustMCP" / "freecad_mcp_bridge"
|
||||
|
||||
if not addon_path.exists():
|
||||
import FreeCAD
|
||||
FreeCAD.Console.PrintError("MCP Bridge workbench not found.\n")
|
||||
FreeCAD.Console.PrintError(f"Expected at: {addon_path}\n")
|
||||
FreeCAD.Console.PrintError("Install the workbench first: just freecad::install-workbench\n")
|
||||
else:
|
||||
try:
|
||||
addon_path_str = str(addon_path)
|
||||
if addon_path_str not in sys.path:
|
||||
sys.path.insert(0, addon_path_str)
|
||||
from server import FreecadMCPPlugin
|
||||
plugin = FreecadMCPPlugin(
|
||||
host="localhost",
|
||||
port=9876,
|
||||
xmlrpc_port=9875,
|
||||
enable_xmlrpc=True,
|
||||
)
|
||||
plugin.start()
|
||||
import FreeCAD
|
||||
FreeCAD.Console.PrintMessage("\nMCP Bridge started!\n")
|
||||
FreeCAD.Console.PrintMessage(" - XML-RPC: localhost:9875\n")
|
||||
FreeCAD.Console.PrintMessage(" - Socket: localhost:9876\n\n")
|
||||
except Exception as e:
|
||||
import FreeCAD
|
||||
FreeCAD.Console.PrintError(f"Failed to start MCP Bridge: {e}\n")
|
||||
PYTHON_EOF
|
||||
|
||||
# Find FreeCAD GUI executable based on OS
|
||||
FREECAD_GUI=""
|
||||
@@ -158,9 +188,6 @@ run-gui:
|
||||
echo "Using FreeCAD: $FREECAD_GUI"
|
||||
echo ""
|
||||
|
||||
# Add project src to PYTHONPATH so FreeCAD can find the module
|
||||
export PYTHONPATH="${PROJECT_DIR}/src:${PYTHONPATH:-}"
|
||||
|
||||
# Launch FreeCAD with the startup script
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# macOS: Use 'open' with --args to pass the script
|
||||
@@ -184,15 +211,18 @@ run-gui-custom freecad_path:
|
||||
# Create a temporary startup script
|
||||
STARTUP_SCRIPT=$(mktemp /tmp/freecad_mcp_startup.XXXXXX.py)
|
||||
|
||||
# Use the server from the addon directory
|
||||
ADDON_PATH="${PROJECT_DIR}/addon/FreecadRobustMCP/freecad_mcp_bridge"
|
||||
|
||||
cat > "$STARTUP_SCRIPT" << EOF
|
||||
# FreeCAD MCP Bridge Auto-Start Script
|
||||
import sys
|
||||
project_path = "${PROJECT_DIR}/src"
|
||||
if project_path not in sys.path:
|
||||
sys.path.insert(0, project_path)
|
||||
addon_path = "${ADDON_PATH}"
|
||||
if addon_path not in sys.path:
|
||||
sys.path.insert(0, addon_path)
|
||||
|
||||
try:
|
||||
from freecad_mcp.freecad_plugin.server import FreecadMCPPlugin
|
||||
from server import FreecadMCPPlugin
|
||||
plugin = FreecadMCPPlugin(
|
||||
host="localhost",
|
||||
port=9876,
|
||||
@@ -200,10 +230,12 @@ run-gui-custom freecad_path:
|
||||
enable_xmlrpc=True,
|
||||
)
|
||||
plugin.start()
|
||||
import FreeCAD
|
||||
FreeCAD.Console.PrintMessage("\\nMCP Bridge started!\\n")
|
||||
FreeCAD.Console.PrintMessage(" - XML-RPC: localhost:9875\\n")
|
||||
FreeCAD.Console.PrintMessage(" - Socket: localhost:9876\\n\\n")
|
||||
except Exception as e:
|
||||
import FreeCAD
|
||||
FreeCAD.Console.PrintError(f"Failed to start MCP Bridge: {e}\\n")
|
||||
EOF
|
||||
|
||||
@@ -211,8 +243,6 @@ run-gui-custom freecad_path:
|
||||
echo "Using FreeCAD: {{freecad_path}}"
|
||||
echo ""
|
||||
|
||||
export PYTHONPATH="${PROJECT_DIR}/src:${PYTHONPATH:-}"
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]] && [[ "{{freecad_path}}" == *.app ]]; then
|
||||
open -a "{{freecad_path}}" --args "$STARTUP_SCRIPT"
|
||||
else
|
||||
@@ -222,52 +252,9 @@ run-gui-custom freecad_path:
|
||||
echo "FreeCAD is starting with MCP bridge..."
|
||||
|
||||
# =============================================================================
|
||||
# Macro Installation
|
||||
# Macro Installation (MultiExport, CutObjectForMagnets)
|
||||
# =============================================================================
|
||||
|
||||
# Install the StartMCPBridge macro to FreeCAD's macro directory
|
||||
install-bridge-macro:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
PROJECT_DIR="{{project_root}}"
|
||||
|
||||
# Determine macro directory based on OS
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
MACRO_DIR="$HOME/Library/Application Support/FreeCAD/Macro"
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
MACRO_DIR="$HOME/.local/share/FreeCAD/Macro"
|
||||
else
|
||||
MACRO_DIR="$APPDATA/FreeCAD/Macro"
|
||||
fi
|
||||
|
||||
mkdir -p "$MACRO_DIR"
|
||||
|
||||
# Copy the macro file and replace the placeholder with the actual project path
|
||||
sed "s|__PROJECT_PATH__|${PROJECT_DIR}/src|g" \
|
||||
"${PROJECT_DIR}/macros/Start_MCP_Bridge/StartMCPBridge.FCMacro" \
|
||||
> "$MACRO_DIR/StartMCPBridge.FCMacro"
|
||||
|
||||
echo "StartMCPBridge macro installed to: $MACRO_DIR"
|
||||
echo ""
|
||||
echo "To use:"
|
||||
echo " 1. Start FreeCAD"
|
||||
echo " 2. Go to: Macro -> Macros -> StartMCPBridge -> Execute"
|
||||
echo " 3. Restart your MCP client (Claude Code, etc.) to connect"
|
||||
|
||||
# Uninstall the StartMCPBridge macro
|
||||
uninstall-bridge-macro:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
MACRO_DIR="$HOME/Library/Application Support/FreeCAD/Macro"
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
MACRO_DIR="$HOME/.local/share/FreeCAD/Macro"
|
||||
else
|
||||
MACRO_DIR="$APPDATA/FreeCAD/Macro"
|
||||
fi
|
||||
rm -f "$MACRO_DIR/StartMCPBridge.FCMacro"
|
||||
echo "StartMCPBridge macro uninstalled"
|
||||
|
||||
# Install the CutObjectForMagnets macro to FreeCAD's macro directory
|
||||
install-cut-macro:
|
||||
#!/usr/bin/env bash
|
||||
@@ -371,42 +358,149 @@ uninstall-export-macro:
|
||||
echo "MultiExport macro uninstalled"
|
||||
|
||||
# Install all macros to FreeCAD's macro directory
|
||||
install-all-macros: install-bridge-macro install-cut-macro install-export-macro
|
||||
install-all-macros: install-cut-macro install-export-macro
|
||||
@echo "All macros installed successfully!"
|
||||
|
||||
# Uninstall all macros from FreeCAD's macro directory
|
||||
uninstall-all-macros: uninstall-bridge-macro uninstall-cut-macro uninstall-export-macro
|
||||
uninstall-all-macros: uninstall-cut-macro uninstall-export-macro
|
||||
@echo "All macros uninstalled successfully!"
|
||||
|
||||
# =============================================================================
|
||||
# Plugin Installation
|
||||
# Workbench Addon Installation
|
||||
# =============================================================================
|
||||
|
||||
# Install the FreeCAD plugin to user's FreeCAD directory
|
||||
install-plugin:
|
||||
# Install the FreeCAD Robust MCP workbench addon to FreeCAD's Mod directory
|
||||
install-workbench:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
PLUGIN_DIR="$HOME/Library/Application Support/FreeCAD/Mod/MCPBridge"
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
PLUGIN_DIR="$HOME/.local/share/FreeCAD/Mod/MCPBridge"
|
||||
else
|
||||
PLUGIN_DIR="$APPDATA/FreeCAD/Mod/MCPBridge"
|
||||
fi
|
||||
mkdir -p "$PLUGIN_DIR"
|
||||
cp -r src/freecad_mcp/freecad_plugin/* "$PLUGIN_DIR/"
|
||||
echo "Plugin installed to: $PLUGIN_DIR"
|
||||
PROJECT_DIR="{{project_root}}"
|
||||
ADDON_NAME="FreecadRobustMCP"
|
||||
|
||||
# Uninstall the FreeCAD plugin
|
||||
uninstall-plugin:
|
||||
# Determine FreeCAD Mod directory based on OS
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
MOD_DIR="$HOME/Library/Application Support/FreeCAD/Mod"
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
MOD_DIR="$HOME/.local/share/FreeCAD/Mod"
|
||||
else
|
||||
MOD_DIR="$APPDATA/FreeCAD/Mod"
|
||||
fi
|
||||
|
||||
ADDON_DEST="$MOD_DIR/$ADDON_NAME"
|
||||
|
||||
# Create Mod directory if it doesn't exist
|
||||
mkdir -p "$MOD_DIR"
|
||||
|
||||
# Remove existing installation if present
|
||||
if [[ -d "$ADDON_DEST" ]]; then
|
||||
echo "Removing existing installation at: $ADDON_DEST"
|
||||
rm -rf "$ADDON_DEST"
|
||||
fi
|
||||
|
||||
# Copy the addon directory
|
||||
cp -r "${PROJECT_DIR}/addon/$ADDON_NAME" "$ADDON_DEST"
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "FreeCAD Robust MCP Workbench installed!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Installation path: $ADDON_DEST"
|
||||
echo ""
|
||||
echo "To use:"
|
||||
echo " 1. Start FreeCAD"
|
||||
echo " 2. Select the 'MCP Bridge' workbench from the workbench selector"
|
||||
echo " 3. Click 'Start MCP Bridge' in the toolbar"
|
||||
echo " 4. Connect your MCP client (Claude Code, etc.) to FreeCAD"
|
||||
echo ""
|
||||
|
||||
# Uninstall the FreeCAD Robust MCP workbench addon
|
||||
uninstall-workbench:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
ADDON_NAME="FreecadRobustMCP"
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
PLUGIN_DIR="$HOME/Library/Application Support/FreeCAD/Mod/MCPBridge"
|
||||
MOD_DIR="$HOME/Library/Application Support/FreeCAD/Mod"
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
PLUGIN_DIR="$HOME/.local/share/FreeCAD/Mod/MCPBridge"
|
||||
MOD_DIR="$HOME/.local/share/FreeCAD/Mod"
|
||||
else
|
||||
PLUGIN_DIR="$APPDATA/FreeCAD/Mod/MCPBridge"
|
||||
MOD_DIR="$APPDATA/FreeCAD/Mod"
|
||||
fi
|
||||
rm -rf "$PLUGIN_DIR"
|
||||
echo "Plugin uninstalled"
|
||||
|
||||
ADDON_DEST="$MOD_DIR/$ADDON_NAME"
|
||||
|
||||
if [[ -d "$ADDON_DEST" ]]; then
|
||||
rm -rf "$ADDON_DEST"
|
||||
echo "FreeCAD Robust MCP Workbench uninstalled from: $ADDON_DEST"
|
||||
else
|
||||
echo "Workbench not found at: $ADDON_DEST"
|
||||
fi
|
||||
|
||||
# Check workbench installation status
|
||||
mcp-status:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Determine directories based on OS
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
MOD_DIR="$HOME/Library/Application Support/FreeCAD/Mod"
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
MOD_DIR="$HOME/.local/share/FreeCAD/Mod"
|
||||
else
|
||||
MOD_DIR="$APPDATA/FreeCAD/Mod"
|
||||
fi
|
||||
|
||||
echo "=========================================="
|
||||
echo "MCP Bridge Installation Status"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# Check workbench
|
||||
if [[ -d "$MOD_DIR/FreecadRobustMCP" ]]; then
|
||||
echo "✓ Workbench addon: INSTALLED"
|
||||
echo " Path: $MOD_DIR/FreecadRobustMCP"
|
||||
echo ""
|
||||
echo "To use:"
|
||||
echo " 1. Start FreeCAD"
|
||||
echo " 2. Select 'MCP Bridge' workbench"
|
||||
echo " 3. Click 'Start MCP Bridge' in toolbar"
|
||||
else
|
||||
echo "✗ Workbench addon: NOT INSTALLED"
|
||||
echo ""
|
||||
echo "To install:"
|
||||
echo " just freecad::install-workbench"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check for legacy installations that should be cleaned up
|
||||
LEGACY_COUNT=0
|
||||
|
||||
if [[ -d "$MOD_DIR/MCPBridge" ]]; then
|
||||
echo "⚠ Legacy plugin found: $MOD_DIR/MCPBridge"
|
||||
echo " Run: rm -rf \"$MOD_DIR/MCPBridge\""
|
||||
((LEGACY_COUNT++)) || true
|
||||
fi
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
MACRO_DIR="$HOME/Library/Application Support/FreeCAD/Macro"
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
MACRO_DIR="$HOME/.local/share/FreeCAD/Macro"
|
||||
else
|
||||
MACRO_DIR="$APPDATA/FreeCAD/Macro"
|
||||
fi
|
||||
|
||||
if [[ -f "$MACRO_DIR/StartMCPBridge.FCMacro" ]]; then
|
||||
echo "⚠ Legacy macro found: $MACRO_DIR/StartMCPBridge.FCMacro"
|
||||
echo " Run: rm \"$MACRO_DIR/StartMCPBridge.FCMacro\""
|
||||
((LEGACY_COUNT++)) || true
|
||||
fi
|
||||
|
||||
if [[ $LEGACY_COUNT -gt 0 ]]; then
|
||||
echo ""
|
||||
echo "Note: Legacy installations can be removed. The workbench replaces them."
|
||||
fi
|
||||
|
||||
echo "=========================================="
|
||||
|
||||
# Check if the workbench addon is installed (alias for mcp-status)
|
||||
workbench-status: mcp-status
|
||||
|
||||
+35
-19
@@ -1,10 +1,34 @@
|
||||
# Code quality commands
|
||||
# Usage: just quality::check, just quality::format, etc.
|
||||
#
|
||||
# Note: Tools installed via mise (gitleaks, markdownlint-cli2, etc.) use `mise exec`.
|
||||
# Python tools use `uv run`. This ensures commands work even without mise shell activation.
|
||||
|
||||
# Run all pre-commit checks
|
||||
check:
|
||||
check: _check-safety-auth
|
||||
uv run pre-commit run --all-files
|
||||
|
||||
# Verify Safety CLI authentication (skipped in CI where SAFETY_API_KEY is used)
|
||||
_check-safety-auth:
|
||||
#!/usr/bin/env bash
|
||||
# Skip check if SAFETY_API_KEY is set (CI environment)
|
||||
if [[ -n "${SAFETY_API_KEY:-}" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
# Check if authenticated locally
|
||||
if ! uv run safety auth status >/dev/null 2>&1; then
|
||||
echo "ERROR: Safety CLI not authenticated."
|
||||
echo ""
|
||||
echo "Safety CLI requires a free account for dependency vulnerability scanning."
|
||||
echo "Run the following command to authenticate:"
|
||||
echo ""
|
||||
echo " uv run safety auth login"
|
||||
echo ""
|
||||
echo "This only needs to be done once per machine."
|
||||
echo "See CLAUDE.md for more details."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Format code with ruff
|
||||
format:
|
||||
uv run ruff format src tests
|
||||
@@ -21,7 +45,7 @@ typecheck:
|
||||
# Run security scanning (code vulnerabilities)
|
||||
security:
|
||||
uv run bandit -c pyproject.toml -r src
|
||||
uv pip list --format=freeze | uv run safety check --stdin
|
||||
uv run safety scan --detailed-output
|
||||
|
||||
# Run spell checking
|
||||
spellcheck:
|
||||
@@ -35,15 +59,15 @@ spellcheck:
|
||||
secrets: secrets-gitleaks secrets-detect secrets-trufflehog # pragma: allowlist secret
|
||||
@echo "All secrets scans complete!"
|
||||
|
||||
# Run gitleaks secrets scanner
|
||||
# Run gitleaks secrets scanner (installed via mise)
|
||||
secrets-gitleaks:
|
||||
uv run gitleaks detect --config .gitleaks.toml --verbose
|
||||
mise exec -- gitleaks detect --config .gitleaks.toml --verbose
|
||||
|
||||
# Run gitleaks on git history
|
||||
secrets-gitleaks-history:
|
||||
uv run gitleaks detect --config .gitleaks.toml --verbose --log-opts="--all"
|
||||
mise exec -- gitleaks detect --config .gitleaks.toml --verbose --log-opts="--all"
|
||||
|
||||
# Run detect-secrets scanner
|
||||
# Run detect-secrets scanner (installed via uv)
|
||||
secrets-detect:
|
||||
uv run detect-secrets scan --baseline .secrets.baseline
|
||||
|
||||
@@ -55,26 +79,18 @@ secrets-audit:
|
||||
secrets-baseline-update:
|
||||
uv run detect-secrets scan --baseline .secrets.baseline --update
|
||||
|
||||
# Run trufflehog for verified secrets
|
||||
# Run trufflehog for verified secrets (via pre-commit - not installed standalone)
|
||||
secrets-trufflehog:
|
||||
uv run trufflehog filesystem . --no-update --only-verified
|
||||
|
||||
# Run trufflehog on git history
|
||||
secrets-trufflehog-history:
|
||||
uv run trufflehog git file://. --no-update --only-verified
|
||||
uv run pre-commit run trufflehog --all-files
|
||||
|
||||
# =============================================================================
|
||||
# Markdown Linting
|
||||
# =============================================================================
|
||||
|
||||
# Lint all markdown files
|
||||
# Lint all markdown files (markdownlint-cli2 installed via mise)
|
||||
markdown-lint:
|
||||
uv run markdownlint-cli2 "**/*.md"
|
||||
mise exec -- markdownlint-cli2 "**/*.md"
|
||||
|
||||
# Lint and fix markdown files
|
||||
markdown-fix:
|
||||
uv run markdownlint-cli2 --fix "**/*.md"
|
||||
|
||||
# Format markdown files with mdformat
|
||||
markdown-format:
|
||||
uv run mdformat docs/*.md README.md ARCHITECTURE-MCP.md CLAUDE.md
|
||||
mise exec -- markdownlint-cli2 --fix "**/*.md"
|
||||
|
||||
Reference in New Issue
Block a user