upload-dmg

$npx mdskill add popmechanic/VibesOS/upload-dmg

Uploads the latest desktop DMG and update artifacts to install.vibesos.com.

  • Solves the need to release a new desktop app version.
  • Depends on Bash, jq, and the install worker's R2 bucket.
  • Reads the version from plugin.json and verifies artifact files exist.
  • Uploads the DMG and optional update artifacts to the remote server.

SKILL.md

.github/skills/upload-dmgView on GitHub ↗
---
name: upload-dmg
description: Upload the latest desktop DMG and update artifacts to install.vibesos.com. Use when the user says "upload the DMG", "update install link", "push new DMG", or "release desktop app".
license: MIT
allowed-tools: Bash, Read
metadata:
  author: "Marcus Estes"
---

## Upload DMG and Update Artifacts to install.vibesos.com

Upload the latest built DMG and auto-updater artifacts to the install worker's R2 bucket.

### Steps

1. Read the version from plugin.json:

```bash
VIBES_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "${CLAUDE_SKILL_DIR}")")}"
VERSION=$(jq -r .version "$VIBES_ROOT/.claude-plugin/plugin.json")
echo "Version: $VERSION"
```

2. Verify the DMG and update artifacts exist:

```bash
VIBES_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "${CLAUDE_SKILL_DIR}")")}"
ARTIFACTS="$VIBES_ROOT/vibes-desktop/artifacts"
DMG_PATH="$ARTIFACTS/stable-macos-arm64-VibesOS.dmg"
if [ ! -f "$DMG_PATH" ]; then
  echo "ERROR: DMG not found at $DMG_PATH — run 'bash scripts/build-desktop.sh' first"
  exit 1
fi
ls -lh "$DMG_PATH"

# Check for update artifacts (optional — first build with baseUrl won't have them)
UPDATE_JSON="$ARTIFACTS/stable-macos-arm64-update.json"
UPDATE_TAR="$ARTIFACTS/stable-macos-arm64-VibesOS.app.tar.zst"
[ -f "$UPDATE_JSON" ] && echo "Found: $(basename $UPDATE_JSON)" || echo "No update.json (first build?)"
[ -f "$UPDATE_TAR" ] && echo "Found: $(basename $UPDATE_TAR) ($(ls -lh "$UPDATE_TAR" | awk '{print $5}'))" || echo "No .tar.zst (first build?)"
PATCH_COUNT=$(ls "$ARTIFACTS"/*.patch 2>/dev/null | wc -l | tr -d ' ')
echo "Patch files: $PATCH_COUNT"
```

3. Upload the DMG:

```bash
VIBES_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "${CLAUDE_SKILL_DIR}")")}"
VERSION=$(jq -r .version "$VIBES_ROOT/.claude-plugin/plugin.json")
DMG_PATH="$VIBES_ROOT/vibes-desktop/artifacts/stable-macos-arm64-VibesOS.dmg"
UPLOAD_KEY=$(grep INSTALL_UPLOAD_KEY "$VIBES_ROOT/.env" | cut -d= -f2)

curl -X PUT "https://install.vibesos.com/upload?filename=VibesOS-${VERSION}.dmg" \
  -H "X-Upload-Key: ${UPLOAD_KEY}" \
  --data-binary "@${DMG_PATH}" \
  --progress-bar -w "\nHTTP %{http_code}\n"
```

4. Upload update artifacts (update.json and .tar.zst):

```bash
VIBES_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "${CLAUDE_SKILL_DIR}")")}"
ARTIFACTS="$VIBES_ROOT/vibes-desktop/artifacts"
UPLOAD_KEY=$(grep INSTALL_UPLOAD_KEY "$VIBES_ROOT/.env" | cut -d= -f2)

UPDATE_JSON="$ARTIFACTS/stable-macos-arm64-update.json"
UPDATE_TAR="$ARTIFACTS/stable-macos-arm64-VibesOS.app.tar.zst"

if [ -f "$UPDATE_JSON" ]; then
  echo "Uploading update.json..."
  curl -X PUT "https://install.vibesos.com/upload?filename=updates/stable-macos-arm64-update.json" \
    -H "X-Upload-Key: ${UPLOAD_KEY}" \
    --data-binary "@${UPDATE_JSON}" \
    -s -w "HTTP %{http_code}\n"
else
  echo "Skipping update.json (not found)"
fi

if [ -f "$UPDATE_TAR" ]; then
  echo "Uploading .tar.zst..."
  curl -X PUT "https://install.vibesos.com/upload?filename=updates/stable-macos-arm64-VibesOS.app.tar.zst" \
    -H "X-Upload-Key: ${UPLOAD_KEY}" \
    --data-binary "@${UPDATE_TAR}" \
    --progress-bar -w "\nHTTP %{http_code}\n"
else
  echo "Skipping .tar.zst (not found)"
fi
```

5. Upload patch files (if any):

```bash
VIBES_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "${CLAUDE_SKILL_DIR}")")}"
ARTIFACTS="$VIBES_ROOT/vibes-desktop/artifacts"
UPLOAD_KEY=$(grep INSTALL_UPLOAD_KEY "$VIBES_ROOT/.env" | cut -d= -f2)

PATCHES=$(ls "$ARTIFACTS"/*.patch 2>/dev/null)
if [ -n "$PATCHES" ]; then
  for PATCH in $PATCHES; do
    BASENAME=$(basename "$PATCH")
    echo "Uploading patch: $BASENAME..."
    curl -X PUT "https://install.vibesos.com/upload?filename=updates/${BASENAME}" \
      -H "X-Upload-Key: ${UPLOAD_KEY}" \
      --data-binary "@${PATCH}" \
      -s -w "HTTP %{http_code}\n"
  done
else
  echo "No patch files to upload"
fi
```

6. Confirm the upload by reporting the version and download URL:

```
Uploaded VibesOS-{VERSION}.dmg + update artifacts
Download: https://install.vibesos.com
Update check: https://install.vibesos.com/updates/stable-macos-arm64-update.json
```

More from popmechanic/VibesOS

SkillDescription
cloudflareSelf-contained deploy automation — invoke directly, do not decompose. Deploys a Vibes app to Cloudflare Workers via the Deploy API. Use when deploying, publishing, going live, pushing to production, or hosting on the edge.
factorySelf-contained SaaS pipeline — invoke directly, do not decompose. Generates a factory app with landing page, Stripe subscription checkout, Vibe Token economics, and deploys to Cloudflare Workers. Use when the user wants to monetize an app, add billing, create token-backed revenue sharing, or turn an app into a business.
launchSelf-contained SaaS pipeline — invoke directly, do not decompose.
riffSelf-contained parallel generator — invoke directly, do not decompose. Generates 3-10 app variations in parallel for comparing ideas. Use when user says "explore options", "give me variations", "riff on this", "brainstorm approaches", or wants to see multiple interpretations of a concept.
sellSelf-contained SaaS automation — invoke directly, do not decompose. Transforms a Vibes app into a multi-tenant SaaS with subdomain-based tenancy. Adds Pocket ID authentication, subscription gating, and generates a unified app with landing page, tenant routing, and admin dashboard. Use when the user wants to monetize an app, add auth and billing, create a SaaS product, add subscriptions, or turn an app into a business.
vibesSelf-contained app generator — invoke this skill directly, do not decompose into sub-steps. Generates React web apps with TinyBase reactive data store. Use when creating new web applications, adding components, or working with real-time data. Ideal for quick prototypes and single-page apps that need real-time data sync.
vibes-brainstormLightweight requirements gathering before app generation. Asks non-technical multiple-choice questions to understand user intent, then produces a brief for the generate prompt.