npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@black-magic/craft-maintenance

v0.0.8

Published

CLI tool to backup and update Craft CMS sites on SiteGround

Readme

craft-site-maintenance

CLI tool to automate Craft CMS maintenance on SiteGround-hosted sites. Connects via SSH, creates backups (DB + config + composer files), updates plugins one by one, downloads a local copy of the backup, and automatically rolls back on failure.

Installation

# Run without installing
pnpm dlx @black-magic/craft-maintenance

# Or install globally
pnpm add -g @black-magic/craft-maintenance

Setup

Create a .craft-maintenance.json file in the directory where you'll run the command, or in ~/ for global use:

{
  "localBackupDir": "~/craft-backups",
  "sites": [
    {
      "sshAlias": "blackmagic",
      "siteDir": "example.com",
      "phpBin": "php82"
    }
  ]
}

localBackupDir is optional — defaults to ~/craft-backups. Backups are saved as {localBackupDir}/{siteDir}/{timestamp}.tar.gz.

You can also specify a config file explicitly:

craft-maintenance --config /path/to/config.json

SSH connection options

There are two ways to specify the SSH connection for each site:

Option A — SSH config alias (recommended)

If the site is already in your ~/.ssh/config, reference the alias directly:

{
  sshAlias: "blackmagic",   // Host entry in ~/.ssh/config
  siteDir: "example.com",   // directory under ~/www/ on the server
  phpBin: "php82",
}

~/.ssh/config entry:

Host blackmagic
  HostName ssh.example.siteground.com
  User u1234-abc12def34gh
  Port 18765
  IdentityFile ~/.ssh/id_rsa_siteground

If IdentityFile is omitted, the SSH agent (SSH_AUTH_SOCK) is used automatically.

Option B — explicit credentials

{
  ssh: {
    host: "ssh.example.siteground.com",
    username: "u1234-abc12def34gh",
    port: 18765,
    privateKeyPath: "~/.ssh/id_rsa_siteground",
  },
  siteDir: "example.com",
  phpBin: "php82",
}

Usage

craft-maintenance             # interactive update
craft-maintenance --dry-run   # preview pending updates without making changes
craft-maintenance --status    # check last run status for all configured sites
craft-maintenance --config /path/to/config.json

During development:

pnpm dev
pnpm dev -- --dry-run
pnpm dev -- --status

Normal mode

  1. Select which sites to update (multi-select)
  2. Confirm
  3. For each site, sequentially:
    • Shows working directory on the remote server
    • Creates a timestamped backup: DB, config/, composer.json, composer.lock
    • Compresses the backup and downloads it locally via SCP
    • Deletes the remote backup folder (only after successful download)
    • Updates each plugin individually with craft update {handle}
    • On failure: automatically rolls back to the pre-update state
  4. Shows a summary with local backup path per site

Dry-run mode (--dry-run)

Connects via SSH and runs craft update to list pending plugin/package updates — without making any changes or requiring confirmation.

Status mode (--status)

Connects to each configured site and reads .craft-maintenance-status.json to show the result of the last maintenance run. No changes are made.

✓  example.com      success        2026-04-02 14:30  craft/cms 5.1→5.2
⚠  other.com        failed_update  2026-03-28 09:12  Failed on: feed-me
✗  broken.com       failed_rollback 2026-03-15 09:12  ← REQUIRES MANUAL INTERVENTION
–  new.com          never run

What gets backed up

Before any update, the tool creates a backup on the remote server at $HOME/www/{siteDir}/.craft-backups/{timestamp}/:

| File | Description | |------|-------------| | db-backup.sql | Full database dump via craft db/backup | | config/ | Copy of the entire config/ directory | | composer.json | Composer manifest | | composer.lock | Locked dependency versions |

The backup folder is then compressed into a .tar.gz and downloaded to your local machine at {localBackupDir}/{siteDir}/{timestamp}.tar.gz. The remote folder is deleted after a successful download — if the download fails, the remote copy is kept.

After a successful run, each site also has a status file at $HOME/www/{siteDir}/.craft-maintenance-status.json with the result of the last operation.

Auto-rollback

If any plugin update fails, the tool immediately runs a rollback:

  1. Restore composer.json + composer.lock from backup
  2. Run composer install --no-interaction to restore vendor/
  3. Restore config/ from backup
  4. Restore the database via craft db/restore

The final summary distinguishes three states:

| State | Meaning | |-------|---------| | ✓ Updated | Update succeeded | | ⚠ Rolled back | Update failed, site restored to pre-update state | | ✗ Critical | Update failed and rollback also failed — manual intervention required |

Build

pnpm build   # Compiles to dist/index.js (ESM bundle)

Commit conventions

This project uses Conventional Commits, enforced via commitlint on every commit:

feat: add dry-run flag
fix: handle SSH timeout gracefully
chore: update dependencies

To regenerate CHANGELOG.md from commit history:

pnpm changelog        # from last tag to HEAD
pnpm changelog:all    # entire history
pnpm changelog v1.0.0 # from a specific tag

SiteGround SSH notes

  • SSH port is 18765, not 22
  • Home directory: /home/{username}/, sites under /home/{username}/www/{domain}/
  • PHP binaries: php82, php83 (not php or php-cli)
  • Craft executable: $HOME/www/{domain}/craft
  • Docroot: public_html/ (not web/)