#!/usr/bin/env bash set -euo pipefail # create-release-packages.sh (workflow-local) # Build Spec Kit template release archives for each supported AI assistant and script type. # Usage: .github/workflows/scripts/create-release-packages.sh # Version argument should include leading 'v'. # Optionally set AGENTS and/or SCRIPTS env vars to limit what gets built. # AGENTS : space or comma separated subset of: claude gemini copilot (default: all) # SCRIPTS : space or comma separated subset of: sh ps (default: both) # Examples: # AGENTS=claude SCRIPTS=sh $0 v0.2.0 # AGENTS="copilot,gemini" $0 v0.2.0 # SCRIPTS=ps $0 v0.2.0 if [[ $# -ne 1 ]]; then echo "Usage: $0 " >&2 exit 1 fi NEW_VERSION="$1" if [[ ! $NEW_VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "Version must look like v0.0.0" >&2 exit 1 fi echo "Building release packages for $NEW_VERSION" rm -rf sdd-package-base* sdd-*-package-* spec-kit-template-*-${NEW_VERSION}.zip || true mkdir -p sdd-package-base SPEC_DIR="sdd-package-base/.specify" mkdir -p "$SPEC_DIR" [[ -d memory ]] && { cp -r memory "$SPEC_DIR/"; echo "Copied memory -> .specify"; } [[ -d scripts ]] && { cp -r scripts "$SPEC_DIR/"; echo "Copied scripts -> .specify/scripts"; } [[ -d templates ]] && { mkdir -p "$SPEC_DIR/templates"; find templates -type f -not -path "templates/commands/*" -exec cp --parents {} "$SPEC_DIR"/ \; ; echo "Copied templates -> .specify/templates"; } rewrite_paths() { sed -E \ -e 's@(/?)memory/@.specify/memory/@g' \ -e 's@(/?)scripts/@.specify/scripts/@g' \ -e 's@(/?)templates/@.specify/templates/@g' } generate_commands() { local agent=$1 ext=$2 arg_format=$3 output_dir=$4 script_variant=$5 mkdir -p "$output_dir" for template in templates/commands/*.md; do [[ -f "$template" ]] || continue local name description raw_body variant_line injected body file_norm delim_count name=$(basename "$template" .md) # Normalize line endings first (remove CR) for consistent regex matching file_norm=$(tr -d '\r' < "$template") # Extract description from frontmatter description=$(printf '%s\n' "$file_norm" | awk '/^description:/ {sub(/^description:[[:space:]]*/, ""); print; exit}') # Count YAML frontmatter delimiter lines delim_count=$(printf '%s\n' "$file_norm" | grep -c '^---$' || true) if [[ $delim_count -ge 2 ]]; then # Grab everything after the second --- line raw_body=$(printf '%s\n' "$file_norm" | awk '/^---$/ {if(++c==2){next}; if(c>=2){print}}') else # Fallback: no proper frontmatter detected; use entire file content (still allowing variant parsing) raw_body=$file_norm fi # If somehow still empty, fallback once more to whole normalized file if [[ -z ${raw_body// /} ]]; then echo "Warning: body extraction empty for $template; using full file" >&2 raw_body=$file_norm fi # Find single-line variant comment matching the variant: or variant_line=$(printf '%s\n' "$raw_body" | awk -v sv="$script_variant" '//, m); if (m[1]!="") {print m[1]; exit}}') if [[ -z $variant_line ]]; then echo "Warning: no variant line found for $script_variant in $template" >&2 variant_line="(Missing variant command for $script_variant)" fi # Replace the token VARIANT-INJECT with the selected variant line injected=$(printf '%s\n' "$raw_body" | sed "s/VARIANT-INJECT/${variant_line//\//\/}/") # Remove all single-line variant comments injected=$(printf '%s\n' "$injected" | sed '//, m); if(m[1]!=""){print m[1]; exit}}' "$plan_tpl") if [[ -n $variant_line ]]; then tmp_file=$(mktemp) sed "s/VARIANT-INJECT/${variant_line//\//\/}/" "$plan_tpl" | sed "/__AGENT__/s//${agent}/g" | sed '/