diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 0000000..c26900c --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Self-contained pre-push hook for automatic semver patch version bumping +# Triggers on push to main/master, creates version bump commit + tag +# +# Setup: Copy to .githooks/pre-push and add to package.json: +# "scripts": { "prepare": "git config core.hooksPath .githooks" } +# +# Skip version bump: Include [skip-version] in your commit message + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +log_info() { echo -e "${GREEN}[version-bump]${NC} $1"; } +log_warn() { echo -e "${YELLOW}[version-bump]${NC} $1"; } +log_error() { echo -e "${RED}[version-bump]${NC} $1" >&2; } + +# Get the branch being pushed +BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "") + +# Only bump on main/master +if [[ "$BRANCH" != "main" && "$BRANCH" != "master" ]]; then + exit 0 +fi + +# Get last commit message +LAST_MSG=$(git log -1 --format=%s 2>/dev/null || echo "") + +# Skip if this is already a version bump commit (prevents infinite loop) +if [[ "$LAST_MSG" == chore:\ bump\ version* ]]; then + log_info "Skipping: already a version bump commit" + exit 0 +fi + +# Skip if commit message contains [skip-version] +if [[ "$LAST_MSG" == *"[skip-version]"* ]]; then + log_info "Skipping: [skip-version] found in commit message" + exit 0 +fi + +# Find git root and package.json +GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo "") +if [[ -z "$GIT_ROOT" ]]; then + log_error "Not in a git repository" + exit 1 +fi + +PACKAGE_JSON="$GIT_ROOT/package.json" +if [[ ! -f "$PACKAGE_JSON" ]]; then + log_warn "No package.json found at git root, skipping version bump" + exit 0 +fi + +# Extract current version using portable tools +CURRENT_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$PACKAGE_JSON" | head -1 | sed 's/.*"\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)".*/\1/') + +if [[ -z "$CURRENT_VERSION" ]]; then + log_error "Could not parse version from package.json" + exit 1 +fi + +# Parse semver components +IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION" + +# Bump patch version +NEW_PATCH=$((PATCH + 1)) +NEW_VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}" + +log_info "Pushing to $BRANCH - bumping version: $CURRENT_VERSION -> $NEW_VERSION" + +# Update package.json (preserve formatting, just replace version) +if [[ "$(uname)" == "Darwin" ]]; then + # macOS sed requires empty string for -i + sed -i '' "s/\"version\"[[:space:]]*:[[:space:]]*\"$CURRENT_VERSION\"/\"version\": \"$NEW_VERSION\"/" "$PACKAGE_JSON" +else + # GNU sed + sed -i "s/\"version\"[[:space:]]*:[[:space:]]*\"$CURRENT_VERSION\"/\"version\": \"$NEW_VERSION\"/" "$PACKAGE_JSON" +fi + +log_info "Updated $PACKAGE_JSON" + +# Git commit +git add "$PACKAGE_JSON" +COMMIT_MSG="chore: bump version to $NEW_VERSION" +git commit -m "$COMMIT_MSG" +log_info "Created commit: $COMMIT_MSG" + +# Git tag +TAG_NAME="v$NEW_VERSION" +if git tag -l "$TAG_NAME" | grep -q "$TAG_NAME"; then + log_warn "Tag $TAG_NAME already exists, skipping" +else + git tag -a "$TAG_NAME" -m "Release $NEW_VERSION" + log_info "Created tag: $TAG_NAME" +fi + +log_info "Version bump complete!" +exit 0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c18dd8d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..5993459 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# lilith-model-loader + +Unified ML model loading, caching, and device management for the Lilith Platform. + +## Features + +- **GGUF Loader**: Load llama-cpp-python models from manifest or direct paths +- **HuggingFace Loader**: Load transformers models with automatic device placement +- **Diffusers Loader**: Load Stable Diffusion and SDXL pipelines +- **Model Registry**: Manifest-based model discovery and caching +- **Device Management**: Automatic GPU/CPU selection with memory tracking + +## Installation + +```bash +# Core package (no ML frameworks) +pip install -e . + +# With GGUF support +pip install -e ".[gguf]" + +# With all ML frameworks +pip install -e ".[ml]" +``` + +## Usage + +```python +from lilith_model_loader.gguf_loader import GGUFModelLoader + +loader = GGUFModelLoader() +await loader.load("ministral-3b-instruct") + +response = loader.generate("Hello, world!") +``` + +## Manifest + +Models are discovered via `~/.cache/models/manifest.json`. The loader supports: +- Model ID lookup (e.g., "ministral-3b-instruct") +- Direct file paths (e.g., "/path/to/model.gguf") +- Remote fetching via rsync diff --git a/package.json b/package.json index 7670dc6..7ec8710 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,12 @@ } }, "scripts": { + "prepare": "git config core.hooksPath .githooks", "build": "tsc", "dev": "tsc --watch", "clean": "rm -rf dist", - "prepublishOnly": "npm run build" + "prepublishOnly": "npm run build", + "publish": "pnpm publish --no-git-checks" }, "files": [ "dist", @@ -42,5 +44,13 @@ }, "engines": { "node": ">=20.0.0" + }, + "publishConfig": { + "@transquinnftw:registry": "https://gitlab.com/api/v4/packages/npm/" + }, + "_": { + "registry": "gitlab", + "publish": true, + "build": true } }