Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Deploy any project to Vercel (preview or production) with smart detection of git remotes and existing links
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
resources/deploy.sh
1#!/bin/bash23# Vercel Deployment Script (via claimable deploy endpoint)4# Usage: ./deploy.sh [project-path]5# Returns: JSON with previewUrl, claimUrl, deploymentId, projectId67set -euo pipefail89DEPLOY_ENDPOINT="https://claude-skills-deploy.vercel.com/api/deploy"1011# Detect framework from package.json12detect_framework() {13local pkg_json="$1"1415if [ ! -f "$pkg_json" ]; then16echo "null"17return18fi1920local content=$(cat "$pkg_json")2122# Helper to check if a package exists in dependencies or devDependencies.23# Use exact matching by default, with a separate prefix matcher for scoped24# package families like "@remix-run/".25has_dep_exact() {26echo "$content" | grep -q "\"$1\""27}2829has_dep_prefix() {30echo "$content" | grep -q "\"$1"31}3233# Order matters - check more specific frameworks first3435# Blitz36if has_dep_exact "blitz"; then echo "blitzjs"; return; fi3738# Next.js39if has_dep_exact "next"; then echo "nextjs"; return; fi4041# Gatsby42if has_dep_exact "gatsby"; then echo "gatsby"; return; fi4344# Remix45if has_dep_prefix "@remix-run/"; then echo "remix"; return; fi4647# React Router (v7 framework mode)48if has_dep_prefix "@react-router/"; then echo "react-router"; return; fi4950# TanStack Start51if has_dep_exact "@tanstack/start"; then echo "tanstack-start"; return; fi5253# Astro54if has_dep_exact "astro"; then echo "astro"; return; fi5556# Hydrogen (Shopify)57if has_dep_exact "@shopify/hydrogen"; then echo "hydrogen"; return; fi5859# SvelteKit60if has_dep_exact "@sveltejs/kit"; then echo "sveltekit-1"; return; fi6162# Svelte (standalone)63if has_dep_exact "svelte"; then echo "svelte"; return; fi6465# Nuxt66if has_dep_exact "nuxt"; then echo "nuxtjs"; return; fi6768# Vue with Vitepress69if has_dep_exact "vitepress"; then echo "vitepress"; return; fi7071# Vue with Vuepress72if has_dep_exact "vuepress"; then echo "vuepress"; return; fi7374# Gridsome75if has_dep_exact "gridsome"; then echo "gridsome"; return; fi7677# SolidStart78if has_dep_exact "@solidjs/start"; then echo "solidstart-1"; return; fi7980# Docusaurus81if has_dep_exact "@docusaurus/core"; then echo "docusaurus-2"; return; fi8283# RedwoodJS84if has_dep_prefix "@redwoodjs/"; then echo "redwoodjs"; return; fi8586# Hexo87if has_dep_exact "hexo"; then echo "hexo"; return; fi8889# Eleventy90if has_dep_exact "@11ty/eleventy"; then echo "eleventy"; return; fi9192# Angular / Ionic Angular93if has_dep_exact "@ionic/angular"; then echo "ionic-angular"; return; fi94if has_dep_exact "@angular/core"; then echo "angular"; return; fi9596# Ionic React97if has_dep_exact "@ionic/react"; then echo "ionic-react"; return; fi9899# Create React App100if has_dep_exact "react-scripts"; then echo "create-react-app"; return; fi101102# Ember103if has_dep_exact "ember-cli" || has_dep_exact "ember-source"; then echo "ember"; return; fi104105# Dojo106if has_dep_exact "@dojo/framework"; then echo "dojo"; return; fi107108# Polymer109if has_dep_prefix "@polymer/"; then echo "polymer"; return; fi110111# Preact112if has_dep_exact "preact"; then echo "preact"; return; fi113114# Stencil115if has_dep_exact "@stencil/core"; then echo "stencil"; return; fi116117# UmiJS118if has_dep_exact "umi"; then echo "umijs"; return; fi119120# Sapper (legacy Svelte)121if has_dep_exact "sapper"; then echo "sapper"; return; fi122123# Saber124if has_dep_exact "saber"; then echo "saber"; return; fi125126# Sanity127if has_dep_exact "sanity"; then echo "sanity-v3"; return; fi128if has_dep_prefix "@sanity/"; then echo "sanity"; return; fi129130# Storybook131if has_dep_prefix "@storybook/"; then echo "storybook"; return; fi132133# NestJS134if has_dep_exact "@nestjs/core"; then echo "nestjs"; return; fi135136# Elysia137if has_dep_exact "elysia"; then echo "elysia"; return; fi138139# Hono140if has_dep_exact "hono"; then echo "hono"; return; fi141142# Fastify143if has_dep_exact "fastify"; then echo "fastify"; return; fi144145# h3146if has_dep_exact "h3"; then echo "h3"; return; fi147148# Nitro149if has_dep_exact "nitropack"; then echo "nitro"; return; fi150151# Express152if has_dep_exact "express"; then echo "express"; return; fi153154# Vite (generic - check last among JS frameworks)155if has_dep_exact "vite"; then echo "vite"; return; fi156157# Parcel158if has_dep_exact "parcel"; then echo "parcel"; return; fi159160# No framework detected161echo "null"162}163164# Parse arguments165INPUT_PATH="${1:-.}"166167# Create temp directory for packaging168TEMP_DIR=$(mktemp -d)169TARBALL="$TEMP_DIR/project.tgz"170STAGING_DIR="$TEMP_DIR/staging"171CLEANUP_TEMP=true172173cleanup() {174if [ "$CLEANUP_TEMP" = true ]; then175rm -rf "$TEMP_DIR"176fi177}178trap cleanup EXIT179180echo "Preparing deployment..." >&2181182# Check if input is a .tgz file or a directory183FRAMEWORK="null"184185if [ -f "$INPUT_PATH" ] && [[ "$INPUT_PATH" == *.tgz ]]; then186# Input is already a tarball, use it directly187echo "Using provided tarball..." >&2188TARBALL="$INPUT_PATH"189CLEANUP_TEMP=false190# Can't detect framework from tarball, leave as null191elif [ -d "$INPUT_PATH" ]; then192# Input is a directory, need to tar it193PROJECT_PATH=$(cd "$INPUT_PATH" && pwd)194195# Detect framework from package.json196FRAMEWORK=$(detect_framework "$PROJECT_PATH/package.json")197198# Stage files into a temporary directory to avoid mutating the source tree.199mkdir -p "$STAGING_DIR"200echo "Staging project files..." >&2201tar -C "$PROJECT_PATH" \202--exclude='node_modules' \203--exclude='.git' \204--exclude='.env' \205--exclude='.env.*' \206-cf - . | tar -C "$STAGING_DIR" -xf -207208# Check if this is a static HTML project (no package.json)209if [ ! -f "$PROJECT_PATH/package.json" ]; then210# Find HTML files in root211HTML_FILES=$(find "$STAGING_DIR" -maxdepth 1 -name "*.html" -type f)212HTML_COUNT=$(printf '%s\n' "$HTML_FILES" | sed '/^$/d' | wc -l | tr -d '[:space:]')213214# If there's exactly one HTML file and it's not index.html, rename it215if [ "$HTML_COUNT" -eq 1 ]; then216HTML_FILE=$(echo "$HTML_FILES" | head -1)217BASENAME=$(basename "$HTML_FILE")218if [ "$BASENAME" != "index.html" ]; then219echo "Renaming $BASENAME to index.html..." >&2220mv "$HTML_FILE" "$STAGING_DIR/index.html"221fi222fi223fi224225# Create tarball from the staging directory226echo "Creating deployment package..." >&2227tar -czf "$TARBALL" -C "$STAGING_DIR" .228else229echo "Error: Input must be a directory or a .tgz file" >&2230exit 1231fi232233if [ "$FRAMEWORK" != "null" ]; then234echo "Detected framework: $FRAMEWORK" >&2235fi236237# Deploy238echo "Deploying..." >&2239RESPONSE=$(curl -s -X POST "$DEPLOY_ENDPOINT" -F "file=@$TARBALL" -F "framework=$FRAMEWORK")240241# Check for error in response242if echo "$RESPONSE" | grep -q '"error"'; then243ERROR_MSG=$(echo "$RESPONSE" | grep -o '"error":"[^"]*"' | cut -d'"' -f4)244echo "Error: $ERROR_MSG" >&2245exit 1246fi247248# Extract URLs from response249PREVIEW_URL=$(echo "$RESPONSE" | grep -o '"previewUrl":"[^"]*"' | cut -d'"' -f4)250CLAIM_URL=$(echo "$RESPONSE" | grep -o '"claimUrl":"[^"]*"' | cut -d'"' -f4)251252if [ -z "$PREVIEW_URL" ]; then253echo "Error: Could not extract preview URL from response" >&2254echo "$RESPONSE" >&2255exit 1256fi257258echo "Deployment started. Waiting for build to complete..." >&2259echo "Preview URL: $PREVIEW_URL" >&2260261# Poll the preview URL until it returns a non-5xx response (5xx = still building)262MAX_ATTEMPTS=60 # 5 minutes max (60 * 5 seconds)263ATTEMPT=0264265while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do266HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$PREVIEW_URL")267268if [ "$HTTP_STATUS" -eq 200 ]; then269echo "" >&2270echo "Deployment ready!" >&2271break272elif [ "$HTTP_STATUS" -ge 500 ]; then273# 5xx means still building/deploying274echo "Building... (attempt $((ATTEMPT + 1))/$MAX_ATTEMPTS)" >&2275sleep 5276ATTEMPT=$((ATTEMPT + 1))277elif [ "$HTTP_STATUS" -ge 400 ] && [ "$HTTP_STATUS" -lt 500 ]; then278# 4xx might be an error or the app itself returns 4xx - it's responding279echo "" >&2280echo "Deployment ready (returned $HTTP_STATUS)!" >&2281break282else283# Any other status, assume it's ready284echo "" >&2285echo "Deployment ready!" >&2286break287fi288done289290if [ $ATTEMPT -eq $MAX_ATTEMPTS ]; then291echo "" >&2292echo "Warning: Timed out waiting for deployment, but it may still be building." >&2293fi294295echo "" >&2296echo "Preview URL: $PREVIEW_URL" >&2297echo "Claim URL: $CLAIM_URL" >&2298echo "" >&2299300# Output JSON for programmatic use301echo "$RESPONSE"302