diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..452293b6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,85 @@ +name: Bug Report +description: Something isn't working as expected +labels: ["bug"] +body: + - type: checkboxes + id: checklist + attributes: + label: Before submitting + options: + - label: I searched existing issues and didn't find a duplicate + required: true + - label: I'm running the latest version of Stirling Image + required: true + + - type: textarea + id: description + attributes: + label: Description + description: What happened, and what did you expect to happen? + placeholder: | + When I try to resize an image, the output is blank. + I expected the resized image to be returned normally. + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to reproduce + description: How can we reproduce this? + placeholder: | + 1. Upload a PNG image + 2. Select "Resize" tool + 3. Set width to 500 + 4. Click "Process" + 5. Downloaded file is 0 bytes + validations: + required: true + + - type: textarea + id: docker-setup + attributes: + label: Docker setup + description: Paste your `docker run` command or `docker-compose.yml` (remove any sensitive values). + render: shell + validations: + required: true + + - type: input + id: image-tag + attributes: + label: Image tag + description: Which Docker image tag are you using? + placeholder: "e.g. latest, 1.11.0" + validations: + required: true + + - type: dropdown + id: platform + attributes: + label: Platform + options: + - AMD64 (Intel/AMD) + - ARM64 (Apple Silicon, Raspberry Pi) + validations: + required: true + + - type: input + id: browser + attributes: + label: Browser + placeholder: "e.g. Chrome 130, Firefox 133, Safari 18" + + - type: textarea + id: logs + attributes: + label: Logs + description: Paste any relevant container logs (`docker logs `). + render: shell + + - type: textarea + id: screenshots + attributes: + label: Screenshots + description: If applicable, add screenshots to help explain the problem. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..8460e358 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Documentation + url: https://stirling-image.github.io/stirling-image/ + about: Check the docs for setup guides, configuration, and API reference. + - name: Security vulnerability + url: https://github.com/stirling-image/stirling-image/security/advisories/new + about: Report security issues privately through GitHub Security Advisories. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..f2270331 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,45 @@ +name: Feature Request +description: Suggest a new tool, improvement, or change +labels: ["enhancement"] +body: + - type: checkboxes + id: checklist + attributes: + label: Before submitting + options: + - label: I searched existing issues and didn't find a duplicate + required: true + + - type: textarea + id: problem + attributes: + label: Problem + description: What problem does this solve? Describe the use case or frustration. + placeholder: | + I frequently need to convert AVIF files to JPEG, but there's no tool for it. + I currently have to use an external service which means my images leave my machine. + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed solution + description: How do you think this should work? + placeholder: | + Add an AVIF option to the format conversion tool, similar to how + HEIC and WebP are already supported. + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Have you tried any workarounds? Are there other approaches that could work? + + - type: textarea + id: context + attributes: + label: Additional context + description: Screenshots, links, examples, or anything else that helps explain the request. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..8fb25df1 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,12 @@ + + +**This project does not accept pull requests.** Please close this PR and [open an issue](https://github.com/stirling-image/stirling-image/issues/new/choose) instead. See [CONTRIBUTING.md](CONTRIBUTING.md) for details. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8d204d94..ca7c60ad 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,8 +1,7 @@ name: Release on: - push: - branches: [main] + workflow_dispatch: permissions: contents: write @@ -14,7 +13,6 @@ jobs: release: name: Semantic Release runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, '[skip ci]')" outputs: new_version: ${{ steps.check.outputs.version }} steps: @@ -46,14 +44,36 @@ jobs: run: | if [ -f .release-version ]; then echo "version=$(cat .release-version)" >> "$GITHUB_OUTPUT" + else + echo "::error::semantic-release did not produce a new version. No releasable commits found." + exit 1 fi docker: - name: Docker Build & Push + name: Build (${{ matrix.platform }}) needs: release - if: needs.release.outputs.new_version != '' - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + runner: ubuntu-latest + - platform: linux/arm64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} steps: + - name: Free disk space + run: | + sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \ + /usr/local/share/boost /opt/hostedtoolcache/CodeQL + sudo docker system prune -af + df -h / + + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + - name: Checkout release tag uses: actions/checkout@v4 with: @@ -62,8 +82,64 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: | + stirlingimage/stirling-image + ghcr.io/${{ github.repository }} + + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6 + with: + context: . + file: docker/Dockerfile + platforms: ${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,"name=stirlingimage/stirling-image,ghcr.io/${{ github.repository }}",push-by-digest=true,name-canonical=true,push=true + cache-from: type=gha,scope=${{ env.PLATFORM_PAIR }} + cache-to: type=gha,mode=max,scope=${{ env.PLATFORM_PAIR }} + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + manifest: + name: Create Multi-Arch Manifests + needs: [release, docker] + runs-on: ubuntu-latest + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true - name: Log in to Docker Hub uses: docker/login-action@v3 @@ -91,14 +167,16 @@ jobs: type=semver,pattern={{major}},value=v${{ needs.release.outputs.new_version }} type=raw,value=latest - - name: Build and push - uses: docker/build-push-action@v6 - with: - context: . - file: docker/Dockerfile - push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha,scope=unified - cache-to: type=gha,mode=max,scope=unified + - name: Create Docker Hub manifest + working-directory: /tmp/digests + run: | + docker buildx imagetools create \ + $(jq -cr '.tags | map(select(startswith("stirlingimage/")) | "-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf 'stirlingimage/stirling-image@sha256:%s ' *) + + - name: Create GHCR manifest + working-directory: /tmp/digests + run: | + docker buildx imagetools create \ + $(jq -cr '.tags | map(select(startswith("ghcr.io/")) | "-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf 'ghcr.io/${{ github.repository }}@sha256:%s ' *) diff --git a/.gitignore b/.gitignore index 04b51951..853f77df 100644 --- a/.gitignore +++ b/.gitignore @@ -31,8 +31,6 @@ blob-report/ # IDE / tool scratch .superpowers/ -.claude/ -CLAUDE.md docs/superpowers/ PRD.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c71abaa..da6a1c20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -744,7 +744,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed -- Internal planning docs (`docs/superpowers/`) and Claude Code config (`.claude/`) from version control — these stay local only +- Internal planning docs (`docs/superpowers/`) and AI tool config from version control - these stay local only ## [0.7.0] - 2026-03-24 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d57ebe8f..43ba555d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,102 +1,25 @@ # Contributing to Stirling Image -Thanks for your interest in contributing. There are many ways to help beyond writing code: reporting bugs, suggesting features, improving docs, and adding translations. +Thanks for your interest in the project. Community feedback helps shape Stirling Image, and there are several ways to get involved. -## Issues +## How to contribute -Before opening an issue, search existing ones to avoid duplicates. +The best way to contribute is through [GitHub Issues](https://github.com/stirling-image/stirling-image/issues): -- **Bug reports**: Include steps to reproduce, expected vs. actual behavior, and your environment (OS, Docker version, browser). -- **Feature requests**: Describe the problem you want solved, not just the solution. Context helps. -- **Questions**: Open an issue. We will do our best to respond quickly. +- **Bug reports** - Found something broken? Open a bug report with steps to reproduce, your Docker setup, and what you expected to happen. +- **Feature requests** - Have an idea for a new tool or improvement? Describe the problem you want solved and why it matters to you. +- **Feedback** - Thoughts on the UI, workflow, documentation, or anything else? We want to hear it. ## Pull requests -1. **Open an issue first.** Describe what you want to change and why. Wait for a maintainer to confirm the direction before writing code. -2. **Fork the repo** and create a branch from `main`. -3. **Make your changes.** Follow the conventions in [CLAUDE.md](CLAUDE.md) (formatting, file structure, commit style). -4. **Test your changes.** Run `pnpm test` and `pnpm lint` before pushing. If you changed UI, run `pnpm test:e2e` too. -5. **Submit a PR.** Reference the issue number. Keep the title short and descriptive. +We do not accept pull requests. All development is handled internally to maintain architectural consistency and code quality across the project. -### Commit messages +If you've found a bug, please open an issue describing it rather than submitting a fix. If you have a suggestion for how something should work, describe it in a feature request. Your input is valuable even without a code contribution. -We use [Conventional Commits](https://www.conventionalcommits.org/) for automated releases: +## Forking -- `feat:` new feature (triggers a minor version bump) -- `fix:` bug fix (triggers a patch version bump) -- `docs:` documentation only -- `test:` adding or fixing tests -- `refactor:` code change that doesn't fix a bug or add a feature -- `chore:` maintenance (CI, deps, config) +You're welcome to fork the project for your own use under the terms of the [AGPLv3 license](LICENSE). The [Developer Guide](https://stirling-image.github.io/stirling-image/guide/developer) covers setup, architecture, and how to add new tools. -Example: `feat: add HEIC to PNG conversion support` +## Security -### What makes a good PR - -- One logical change per PR. If you need to refactor something to add a feature, that can be one PR, but don't mix unrelated changes. -- Clear commit messages that explain why, not just what. -- Tests for new behavior when possible. -- No unrelated formatting changes (Biome handles formatting). - -## Development setup - -Full instructions are in the [Developer Guide](https://stirling-image.github.io/stirling-image/guide/developer). The short version: - -```bash -git clone https://github.com/stirling-image/stirling-image.git -cd stirling-image -pnpm install -pnpm dev # starts both frontend and backend -``` - -The frontend runs at http://localhost:1349 and proxies API calls to the backend on port 13490. - -### Running tests - -```bash -pnpm lint # Biome lint + format check -pnpm typecheck # TypeScript across all workspaces -pnpm test # unit + integration tests -pnpm test:e2e # Playwright end-to-end tests -``` - -All of these run in CI on every PR. Make sure they pass locally first. - -## Adding a new tool - -Tools follow a consistent pattern. You will need to touch three places: - -1. **Backend route** in `apps/api/src/routes/tools/` using `createToolRoute()` from the tool factory. -2. **Frontend settings component** in `apps/web/src/components/tools/` with the tool's UI controls. -3. **i18n entry** in `packages/shared/src/i18n/en.ts` with the tool's name and description. - -See the [Developer Guide](https://stirling-image.github.io/stirling-image/guide/developer) for a walkthrough. - -## Translations - -We currently ship English only, but the i18n system is designed for easy extension. If you want to add a language, see the [Translation Guide](https://stirling-image.github.io/stirling-image/guide/translations). - -## Code style - -Biome handles formatting and linting. The rules are in `biome.json` and enforced by a pre-commit hook. Don't modify the Biome or TypeScript config files to silence warnings. Fix the code instead. - -Quick summary: - -- Double quotes, semicolons, 2-space indentation -- ES modules everywhere -- Zod for API input validation -- No `any` types without justification - -## License and Contributor License Agreement - -Stirling Image is dual-licensed under the [AGPLv3](LICENSE) and a commercial license. To keep this dual-licensing possible, all contributions must be submitted under the following terms: - -By submitting a pull request or otherwise contributing code to this project, you agree that: - -1. Your contributions are your original work (or you have the right to submit them). -2. You grant me a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license to use, reproduce, modify, distribute, sublicense, and relicense your contributions under any license, including the AGPLv3 and any commercial license I offer for this project. -3. You understand that your contributions will be publicly available under the AGPLv3 and may also be included in commercially licensed versions of the software. - -This is necessary because the project offers a commercial license alongside the open-source AGPLv3. Without this agreement, contributed code could only be distributed under the AGPLv3, which would prevent offering a commercial option. - -If you have questions about this, open an issue before contributing. +If you discover a security vulnerability, please report it privately through [GitHub Security Advisories](https://github.com/stirling-image/stirling-image/security/advisories/new) rather than opening a public issue. diff --git a/README.md b/README.md index 0737cbbc..7b009eba 100644 --- a/README.md +++ b/README.md @@ -42,22 +42,16 @@ docker run -d -p 1349:1349 -v stirling-data:/data stirlingimage/stirling-image:l Open http://localhost:1349 in your browser.
-Looking for the Lite or CUDA image? Click here. +Have an NVIDIA GPU? Click here for GPU acceleration.
-**Lite** (~1.5 GB) - all image tools, no AI: +Add `--gpus all` for GPU-accelerated background removal, upscaling, and OCR: ```bash -docker run -d -p 1349:1349 -v stirling-data:/data stirlingimage/stirling-image:lite +docker run -d -p 1349:1349 --gpus all -v stirling-data:/data stirlingimage/stirling-image:latest ``` -**CUDA** (~14 GB) - GPU-accelerated background removal, upscaling, and OCR: - -```bash -docker run -d -p 1349:1349 --gpus all -v stirling-data:/data stirlingimage/stirling-image:cuda -``` - -> CUDA needs an NVIDIA GPU and [Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Falls back to CPU if no GPU is found. See [Docker Tags](https://stirling-image.github.io/stirling-image/guide/docker-tags) for benchmarks and Docker Compose examples. +> Requires an NVIDIA GPU and [Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Falls back to CPU if no GPU is found. See [Docker Tags](https://stirling-image.github.io/stirling-image/guide/docker-tags) for benchmarks and Docker Compose examples.
@@ -70,7 +64,7 @@ docker run -d -p 1349:1349 --gpus all -v stirling-data:/data stirlingimage/stirl You will be asked to change your password on first login. This is enforced for all new accounts and cannot be skipped in production. -For Docker Compose, persistent storage, and other setup options, see the [Getting Started Guide](https://stirling-image.github.io/stirling-image/guide/getting-started). For details on all image variants (full, lite, cuda), see [Docker Tags](https://stirling-image.github.io/stirling-image/guide/docker-tags). +For Docker Compose, persistent storage, and other setup options, see the [Getting Started Guide](https://stirling-image.github.io/stirling-image/guide/getting-started). For GPU acceleration and tag details, see [Docker Tags](https://stirling-image.github.io/stirling-image/guide/docker-tags). ## Documentation @@ -81,13 +75,9 @@ For Docker Compose, persistent storage, and other setup options, see the [Gettin - [Developer Guide](https://stirling-image.github.io/stirling-image/guide/developer) - [Translation Guide](https://stirling-image.github.io/stirling-image/guide/translations) -## Contributing +## Feedback -Contributions welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines, the [Developer Guide](https://stirling-image.github.io/stirling-image/guide/developer) for setup, and the [Translation Guide](https://stirling-image.github.io/stirling-image/guide/translations) for adding languages. - -## Support - -Bug reports and feature requests: [GitHub Issues](https://github.com/stirling-image/stirling-image/issues) +Found a bug or have a feature idea? Open a [GitHub Issue](https://github.com/stirling-image/stirling-image/issues). We don't accept pull requests, but your feedback directly shapes the project. See [CONTRIBUTING.md](CONTRIBUTING.md) for details. diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 30a9813d..709c2d3f 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -23,14 +23,6 @@ import { teamsRoutes } from "./routes/teams.js"; import { registerToolRoutes } from "./routes/tools/index.js"; import { userFileRoutes } from "./routes/user-files.js"; -// Warn about deprecated STIRLING_VARIANT env var -if (process.env.STIRLING_VARIANT) { - console.warn( - `WARNING: STIRLING_VARIANT="${process.env.STIRLING_VARIANT}" is set but ignored. ` + - "There is now a single unified image with all features. Remove STIRLING_VARIANT from your environment.", - ); -} - // Run before anything else runMigrations(); console.log("Database initialized"); diff --git a/apps/api/src/routes/settings.ts b/apps/api/src/routes/settings.ts index a19861fe..2f2b1a9c 100644 --- a/apps/api/src/routes/settings.ts +++ b/apps/api/src/routes/settings.ts @@ -6,7 +6,6 @@ * GET /api/v1/settings/:key — Get a specific setting */ -import { PYTHON_SIDECAR_TOOLS } from "@stirling-image/shared"; import { eq } from "drizzle-orm"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import { db, schema } from "../db/index.js"; @@ -27,10 +26,7 @@ export async function settingsRoutes(app: FastifyInstance): Promise { settings[row.key] = row.value; } - const variant = process.env.STIRLING_VARIANT === "lite" ? "lite" : "full"; - const variantUnavailableTools = variant === "lite" ? [...PYTHON_SIDECAR_TOOLS] : []; - - return reply.send({ settings, variant, variantUnavailableTools }); + return reply.send({ settings }); }); // PUT /api/v1/settings — Save settings (admin only) diff --git a/apps/api/src/routes/tools/index.ts b/apps/api/src/routes/tools/index.ts index 70512ab3..f369d020 100644 --- a/apps/api/src/routes/tools/index.ts +++ b/apps/api/src/routes/tools/index.ts @@ -1,4 +1,4 @@ -import { PYTHON_SIDECAR_TOOLS, TOOLS } from "@stirling-image/shared"; +import { TOOLS } from "@stirling-image/shared"; import { eq } from "drizzle-orm"; import type { FastifyInstance } from "fastify"; import { db, schema } from "../../db/index.js"; @@ -70,10 +70,6 @@ export async function registerToolRoutes(app: FastifyInstance): Promise { // Build skip set const skipTools = new Set([...disabledTools, ...(enableExperimental ? [] : experimentalToolIds)]); - // In lite mode, register 501 stubs for AI tools instead of real handlers - const isLite = process.env.STIRLING_VARIANT === "lite"; - const liteStubTools = new Set(PYTHON_SIDECAR_TOOLS); - const toolRegistrations: Array<{ id: string; register: (app: FastifyInstance) => void; @@ -133,7 +129,6 @@ export async function registerToolRoutes(app: FastifyInstance): Promise { ]; let skipped = 0; - let stubbed = 0; for (const { id, register } of toolRegistrations) { if (skipTools.has(id)) { app.log.info(`Skipping disabled/experimental tool: ${id}`); @@ -141,24 +136,11 @@ export async function registerToolRoutes(app: FastifyInstance): Promise { continue; } - if (isLite && liteStubTools.has(id)) { - // Register a 501 stub instead of the real handler - app.post(`/api/v1/tools/${id}`, async (_request, reply) => { - return reply.status(501).send({ - statusCode: 501, - error: "Not Available", - message: `The "${id}" tool requires the full image. Pull stirlingimage/stirling-image:latest for all features.`, - }); - }); - stubbed++; - continue; - } - register(app); } - const registered = toolRegistrations.length - skipped - stubbed; + const registered = toolRegistrations.length - skipped; app.log.info( - `Tool routes: ${registered} active, ${stubbed} lite-stubbed, ${skipped} skipped (${toolRegistrations.length} total)`, + `Tool routes: ${registered} active, ${skipped} skipped (${toolRegistrations.length} total)`, ); } diff --git a/apps/docs/.vitepress/config.mts b/apps/docs/.vitepress/config.mts index aa5b3fed..8f2d8001 100644 --- a/apps/docs/.vitepress/config.mts +++ b/apps/docs/.vitepress/config.mts @@ -46,7 +46,7 @@ export default defineConfig({ `, customTemplateVariables: { description: - "Self-hosted, open-source image processing platform with 30+ tools. Runs in a single Docker container. Available as :latest (full, ~11 GB with AI/ML) or :lite (~1.5 GB, image processing only).", + "Self-hosted, open-source image processing platform with 30+ tools including AI/ML. Runs in a single Docker container with GPU auto-detection.", details: "Resize, compress, convert, remove backgrounds, upscale, run OCR, and more - without sending images to external services.", }, diff --git a/apps/docs/guide/deployment.md b/apps/docs/guide/deployment.md index f09ad629..4712c01a 100644 --- a/apps/docs/guide/deployment.md +++ b/apps/docs/guide/deployment.md @@ -110,9 +110,16 @@ Set `client_max_body_size` to match your `MAX_UPLOAD_SIZE_MB` value. ## CI/CD -The GitHub repository has two workflows: +The GitHub repository has three workflows: -- **release.yml** -- On release, builds a multi-arch Docker image (amd64 + arm64), and pushes to Docker Hub (`stirlingimage/stirling-image`) and GitHub Container Registry (`ghcr.io/stirling-image/stirling-image`). -- **deploy-docs.yml** -- Builds this documentation site and deploys it to GitHub Pages. +- **ci.yml** -- Runs automatically on every push and PR. Lints, typechecks, tests, builds, and validates the Docker image (without pushing). +- **release.yml** -- Triggered manually via `workflow_dispatch`. Runs semantic-release to create a version tag and GitHub release, then builds a multi-arch Docker image (amd64 + arm64) and pushes to Docker Hub (`stirlingimage/stirling-image`) and GitHub Container Registry (`ghcr.io/stirling-image/stirling-image`). +- **deploy-docs.yml** -- Builds this documentation site and deploys it to GitHub Pages on push to `main`. -Both run automatically. No manual steps needed after merging to `main`. +To create a release, go to **Actions > Release > Run workflow** in the GitHub UI, or run: + +```bash +gh workflow run release.yml +``` + +Semantic-release determines the version from commit history. The `latest` Docker tag always points to the most recent release. diff --git a/apps/docs/guide/developer.md b/apps/docs/guide/developer.md index 20f80d8e..101e9d92 100644 --- a/apps/docs/guide/developer.md +++ b/apps/docs/guide/developer.md @@ -198,12 +198,6 @@ Build the full production image locally: docker build -f docker/Dockerfile -t stirling-image:latest . ``` -Build the lite image (no Python/AI, ~1.5 GB): - -```bash -docker build --build-arg VARIANT=lite -f docker/Dockerfile -t stirling-image:lite . -``` - Use BuildKit cache mounts for faster rebuilds: ```bash diff --git a/apps/docs/guide/docker-tags.md b/apps/docs/guide/docker-tags.md index 5824d807..832f23ce 100644 --- a/apps/docs/guide/docker-tags.md +++ b/apps/docs/guide/docker-tags.md @@ -118,9 +118,6 @@ volumes: ## Migration from previous tags -If you were using `:lite` or `:cuda` tags, switch to `:latest`: - -- **From `:lite`**: Pull `:latest`. You now have all AI tools included. -- **From `:cuda`**: Pull `:latest` and keep `--gpus all`. Same GPU support, unified image. +If you were using the `:cuda` tag, switch to `:latest` and keep `--gpus all`. Same GPU support, unified image. Your data and settings are preserved in the volumes. diff --git a/apps/docs/guide/getting-started.md b/apps/docs/guide/getting-started.md index c484d385..65f90726 100644 --- a/apps/docs/guide/getting-started.md +++ b/apps/docs/guide/getting-started.md @@ -14,21 +14,11 @@ docker run -d \ Open `http://localhost:1349` in your browser. Log in with `admin` / `admin`. -::: tip Lite image -Don't need AI tools (background removal, upscaling, OCR, face blur, object eraser)? Use the lite image instead - 1.5 GB vs 11 GB: - -```bash -stirlingimage/stirling-image:lite -``` - -All 27+ image processing tools work the same. See [Docker Tags](./docker-tags) for the full comparison. -::: - ::: tip GPU acceleration -Have an NVIDIA GPU? The CUDA image auto-detects your GPU and accelerates background removal (2.7x), upscaling (3x), and OCR (1.5x): +Have an NVIDIA GPU? Add `--gpus all` to accelerate background removal (2.7x), upscaling (3x), and OCR (1.5x): ```bash -docker run -d --gpus all -p 1349:1349 -v stirling-data:/data stirlingimage/stirling-image:cuda +docker run -d --gpus all -p 1349:1349 -v stirling-data:/data stirlingimage/stirling-image:latest ``` Requires [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Falls back to CPU if no GPU is found. See [Docker Tags](./docker-tags) for details and benchmarks. diff --git a/apps/web/src/components/common/tool-card.tsx b/apps/web/src/components/common/tool-card.tsx index 27def704..3dd64e7b 100644 --- a/apps/web/src/components/common/tool-card.tsx +++ b/apps/web/src/components/common/tool-card.tsx @@ -1,58 +1,17 @@ import type { Tool } from "@stirling-image/shared"; import * as icons from "lucide-react"; -import { FileImage, Sparkles, Star } from "lucide-react"; +import { FileImage, Star } from "lucide-react"; import { Link } from "react-router-dom"; -import { toast } from "sonner"; import { cn } from "@/lib/utils"; interface ToolCardProps { tool: Tool; - variantUnavailable?: boolean; } -export function ToolCard({ tool, variantUnavailable }: ToolCardProps) { +export function ToolCard({ tool }: ToolCardProps) { const iconsMap = icons as unknown as Record>; const IconComponent = iconsMap[tool.icon] || FileImage; - if (variantUnavailable) { - return ( -
- - -
- ); - } - return (
- {variant === "lite" && ( -
-
- -
-

Lite mode

-

- AI tools are unavailable. Use the{" "} - - latest - {" "} - or{" "} - - full - {" "} - tag for all features. -

-
-
-
- )} {CATEGORIES.filter((cat) => groupedTools.has(cat.id)).map((category) => (

@@ -77,11 +52,7 @@ export function ToolPanel() {

{groupedTools.get(category.id)?.map((tool) => ( - + ))}
diff --git a/apps/web/src/pages/home-page.tsx b/apps/web/src/pages/home-page.tsx index 5e2d2757..71421b05 100644 --- a/apps/web/src/pages/home-page.tsx +++ b/apps/web/src/pages/home-page.tsx @@ -1,12 +1,10 @@ import { CATEGORIES, TOOLS } from "@stirling-image/shared"; import * as icons from "lucide-react"; -import { useCallback, useEffect, useMemo } from "react"; +import { useCallback, useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import { toast } from "sonner"; import { ImageViewer } from "@/components/common/image-viewer"; import { MultiImageViewer } from "@/components/common/multi-image-viewer"; import { AppLayout } from "@/components/layout/app-layout"; -import { cn } from "@/lib/utils"; import { useFileStore } from "@/stores/file-store"; import { useSettingsStore } from "@/stores/settings-store"; @@ -17,14 +15,12 @@ export function HomePage() { const { setFiles, files, reset, originalBlobUrl, selectedFileName, selectedFileSize } = useFileStore(); const navigate = useNavigate(); - const { variantUnavailableTools, fetch: fetchSettings } = useSettingsStore(); + const { fetch: fetchSettings } = useSettingsStore(); useEffect(() => { fetchSettings(); }, [fetchSettings]); - const unavailableSet = useMemo(() => new Set(variantUnavailableTools), [variantUnavailableTools]); - const handleFiles = useCallback( (newFiles: File[]) => { reset(); @@ -33,25 +29,6 @@ export function HomePage() { [setFiles, reset], ); - const handleToolClick = (route: string, toolId: string) => { - if (unavailableSet.has(toolId)) { - toast("This tool requires the full image.", { - description: - "Pull stirlingimage/stirling-image:latest for all features including AI tools.", - action: { - label: "Learn more", - onClick: () => - window.open( - "https://stirling-image.github.io/stirling-image/guide/docker-tags", - "_blank", - ), - }, - }); - return; - } - navigate(route); - }; - const hasFile = files.length > 0; // If no file uploaded, show default layout (tool panel + dropzone) @@ -103,11 +80,8 @@ export function HomePage() {