Files
gh-onezerocompany-claude-pr…/skills/spec-author/scripts/generate-spec.sh
2025-11-30 08:45:31 +08:00

187 lines
5.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Generate Spec from Template
# Creates a new spec file in docs/specs/ from a template
set -o pipefail
TEMPLATE_NAME="${1:-.}"
SPEC_ID="${2:-.}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Find git repo root for reliable path resolution
# This allows scripts to work when called from any directory in the repo
if git -C "$SCRIPT_DIR" rev-parse --git-dir > /dev/null 2>&1; then
PROJECT_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel)"
else
# Fallback to relative path traversal (4 levels up from scripts/)
# From: project-root/project-basics/skills/spec-author/scripts/
# To: project-root/
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
fi
# Specs are always stored in the git repo root under docs/specs/
SPECS_DIR="$PROJECT_ROOT/docs/specs"
# Function to get folder name for spec type (same as template name)
get_spec_folder() {
local template=$1
case "$template" in
business-requirement|technical-requirement|design-document|api-contract|data-model|component|plan|milestone|flow-schematic|deployment-procedure|configuration-schema)
echo "$template"
;;
*)
echo ""
;;
esac
}
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Print usage
usage() {
echo "Usage: generate-spec.sh <template-type> [<spec-id> | --next <slug>]"
echo ""
echo "Template types:"
echo " - business-requirement (brd-XXX-slug)"
echo " - technical-requirement (prd-XXX-slug)"
echo " - design-document (des-XXX-slug)"
echo " - api-contract (api-XXX-slug)"
echo " - data-model (data-XXX-slug)"
echo " - component (cmp-XXX-slug)"
echo " - plan (pln-XXX-slug)"
echo " - milestone (mls-XXX-slug)"
echo " - flow-schematic (flow-XXX-slug)"
echo " - deployment-procedure (deploy-XXX-slug)"
echo " - configuration-schema (config-XXX-slug)"
echo ""
echo "Spec ID: Use the full ID (e.g., brd-001-user-export)"
echo " OR use --next <slug> to auto-generate next ID"
echo ""
echo "Examples:"
echo " generate-spec.sh business-requirement brd-001-user-export"
echo " Creates: docs/specs/business-requirement/brd-001-user-export.md"
echo ""
echo " generate-spec.sh business-requirement --next user-export"
echo " Auto-determines next ID (e.g., brd-002-user-export)"
echo ""
echo " generate-spec.sh api-contract --next"
echo " Auto-determines next ID without slug (e.g., api-001)"
exit 1
}
if [ "$TEMPLATE_NAME" = "-h" ] || [ "$TEMPLATE_NAME" = "--help" ] || [ -z "$TEMPLATE_NAME" ]; then
usage
fi
# Handle --next flag for auto-generating next ID
if [ "$SPEC_ID" = "--next" ]; then
# Check if slug is provided as third argument
SLUG="${3:-}"
if [ -n "$SLUG" ]; then
SPEC_ID=$("$SCRIPT_DIR/next-id.sh" "$TEMPLATE_NAME" --with-slug "$SLUG" --quiet)
else
SPEC_ID=$("$SCRIPT_DIR/next-id.sh" "$TEMPLATE_NAME" --quiet)
fi
if [ $? -ne 0 ]; then
echo -e "${RED}✗ Error: Failed to determine next ID${NC}"
exit 1
fi
echo -e "${BLUE}Auto-generated ID: $SPEC_ID${NC}"
echo ""
elif [ -z "$SPEC_ID" ]; then
usage
fi
# Check if template exists (try multiple locations in order of preference)
# 1. project-basics/skills/spec-author/templates/ (plugin subdirectory in project)
# 2. skills/spec-author/templates/ (plugin in root of project)
# 3. templates/ (root-level templates directory)
# 4. Current script directory/../templates (relative to script)
TEMPLATE_FILE=""
TEMPLATE_SEARCH_PATHS=(
"$PROJECT_ROOT/project-basics/skills/spec-author/templates/$TEMPLATE_NAME.md"
"$PROJECT_ROOT/skills/spec-author/templates/$TEMPLATE_NAME.md"
"$PROJECT_ROOT/templates/$TEMPLATE_NAME.md"
"$SCRIPT_DIR/../templates/$TEMPLATE_NAME.md"
)
for path in "${TEMPLATE_SEARCH_PATHS[@]}"; do
if [ -f "$path" ]; then
TEMPLATE_FILE="$path"
break
fi
done
if [ -z "$TEMPLATE_FILE" ] || [ ! -f "$TEMPLATE_FILE" ]; then
echo -e "${RED}✗ Error: Template not found${NC}"
echo "Looked in:"
for path in "${TEMPLATE_SEARCH_PATHS[@]}"; do
echo " - $path"
done
echo ""
echo "Run 'list-templates.sh' to see available templates"
exit 1
fi
# Get the folder name for this spec type
SPEC_FOLDER=$(get_spec_folder "$TEMPLATE_NAME")
if [ -z "$SPEC_FOLDER" ]; then
echo -e "${RED}✗ Error: Unknown template type: $TEMPLATE_NAME${NC}"
echo "Run 'list-templates.sh' to see available templates"
exit 1
fi
# Ensure specs type directory exists
SPEC_TYPE_DIR="$SPECS_DIR/$SPEC_FOLDER"
mkdir -p "$SPEC_TYPE_DIR"
# Build output path
OUTPUT_PATH="$SPEC_TYPE_DIR/$SPEC_ID.md"
# Check if output file already exists
if [ -f "$OUTPUT_PATH" ]; then
echo -e "${YELLOW}⚠ File already exists: $OUTPUT_PATH${NC}"
read -p "Overwrite? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Cancelled"
exit 0
fi
fi
# Copy template to output location
cp "$TEMPLATE_FILE" "$OUTPUT_PATH"
# Get current date
CURRENT_DATE=$(date +%Y-%m-%d)
# Fill in some default values in the new spec
sed -i '' "s/\[Date\]/$CURRENT_DATE/g" "$OUTPUT_PATH" 2>/dev/null || sed -i "s/\[Date\]/$CURRENT_DATE/g" "$OUTPUT_PATH"
echo -e "${GREEN}✓ Spec created successfully!${NC}"
echo ""
echo "File: $OUTPUT_PATH"
echo "Template: $(basename "$TEMPLATE_FILE")"
echo "ID: $SPEC_ID"
echo ""
echo "Next steps:"
echo "1. Open the file: $OUTPUT_PATH"
echo "2. Fill in the ID and descriptive information"
echo "3. Complete all TODO sections (marked with TODO)"
echo "4. Remove placeholder text in [brackets]"
echo ""
echo "To check what needs to be completed:"
echo " ./scripts/check-completeness.sh $OUTPUT_PATH"
echo ""
echo "To validate the spec:"
echo " ./scripts/validate-spec.sh $OUTPUT_PATH"