Files
2026-07-13 12:35:03 +08:00

147 lines
4.8 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Generate standardized ArcKit document IDs
# Usage: ./generate-document-id.sh PROJECT_ID DOC_TYPE [VERSION] [OPTIONS]
#
# Options:
# --filename Return ID with .md extension (e.g., ARC-001-REQ-v1.0.md)
# --next-num DIR For multi-instance types, find next sequence number
# by scanning DIR for existing files
#
# Examples:
# ./generate-document-id.sh 001 REQ → ARC-001-REQ-v1.0
# ./generate-document-id.sh 042 HLD 2.1 → ARC-042-HLD-v2.1
# ./generate-document-id.sh 003 ATRS → ARC-003-ATRS-v1.0
# ./generate-document-id.sh 001 REQ 1.0 --filename → ARC-001-REQ-v1.0.md
# ./generate-document-id.sh 001 ADR 1.0 --filename --next-num ./decisions → ARC-001-ADR-001-v1.0.md
#
# Multi-instance types (require --next-num for sequence numbering):
# ADR, DIAG, DFD, WARD, DMC, RSCH, AWRS, AZRS, GCRS, DSCT, TNDR, CMPT, WGAM, WCLM, WVCH
set -euo pipefail
# Parse arguments
PROJECT_ID=""
DOC_TYPE=""
VERSION="1.0"
ADD_EXTENSION=false
NEXT_NUM_DIR=""
# Process positional and optional arguments
while [[ $# -gt 0 ]]; do
case $1 in
--filename)
ADD_EXTENSION=true
shift
;;
--next-num)
if [[ $# -lt 2 || "$2" == --* ]]; then
echo "Error: --next-num requires a directory argument" >&2
echo "Usage: $0 PROJECT_ID DOC_TYPE [VERSION] [--filename] [--next-num DIR]" >&2
exit 1
fi
NEXT_NUM_DIR="$2"
shift 2
;;
-*)
echo "Error: Unknown option: $1" >&2
exit 1
;;
*)
# Positional arguments
if [ -z "$PROJECT_ID" ]; then
PROJECT_ID="$1"
elif [ -z "$DOC_TYPE" ]; then
DOC_TYPE="$1"
else
VERSION="$1"
fi
shift
;;
esac
done
# Validate inputs
if [ -z "$PROJECT_ID" ]; then
echo "Error: PROJECT_ID required" >&2
echo "Usage: $0 PROJECT_ID DOC_TYPE [VERSION] [--filename] [--next-num DIR]" >&2
exit 1
fi
if [ -z "$DOC_TYPE" ]; then
echo "Error: DOC_TYPE required" >&2
echo "Usage: $0 PROJECT_ID DOC_TYPE [VERSION] [--filename] [--next-num DIR]" >&2
exit 1
fi
# Ensure PROJECT_ID is zero-padded to 3 digits
# Remove leading zeros first to avoid octal interpretation
PROJECT_ID_CLEAN=$(echo "$PROJECT_ID" | sed 's/^0*//')
PROJECT_ID_CLEAN=${PROJECT_ID_CLEAN:-0}
PROJECT_ID_PADDED=$(printf "%03d" "$PROJECT_ID_CLEAN")
# Multi-instance document types that require sequence numbers
# Keep in sync with arckit-claude/config/doc-types.mjs MULTI_INSTANCE_TYPES
MULTI_INSTANCE_TYPES="ADR DIAG DFD WARD DMC RSCH AWRS AZRS GCRS DSCT TNDR CMPT WGAM WCLM WVCH GOVR GCSR GLND"
# Check if this is a multi-instance type
is_multi_instance() {
local type="$1"
for t in $MULTI_INSTANCE_TYPES; do
if [ "$t" = "$type" ]; then
return 0
fi
done
return 1
}
# Generate document ID
if is_multi_instance "$DOC_TYPE"; then
if [ -n "$NEXT_NUM_DIR" ]; then
# Find next sequence number by scanning directory
if [ -d "$NEXT_NUM_DIR" ]; then
# Look for existing files matching pattern ARC-{PID}-{TYPE}-{NUM}-*
PATTERN="ARC-${PROJECT_ID_PADDED}-${DOC_TYPE}-"
LAST_NUM=0
shopt -s nullglob
for file in "$NEXT_NUM_DIR"/${PATTERN}*.md; do
if [ -f "$file" ]; then
# Extract the sequence number from filename
basename_file=$(basename "$file")
# Pattern: ARC-001-ADR-001-v1.0.md -> extract 001 (the sequence number)
num=$(echo "$basename_file" | sed -n "s/ARC-${PROJECT_ID_PADDED}-${DOC_TYPE}-\([0-9]*\)-.*/\1/p")
if [ -n "$num" ]; then
# Remove leading zeros for comparison
num_clean=$((10#$num))
if [ "$num_clean" -gt "$LAST_NUM" ]; then
LAST_NUM=$num_clean
fi
fi
fi
done
NEXT_NUM=$(printf "%03d" $((LAST_NUM + 1)))
else
# Directory doesn't exist yet, start at 001
NEXT_NUM="001"
fi
DOC_ID="ARC-${PROJECT_ID_PADDED}-${DOC_TYPE}-${NEXT_NUM}-v${VERSION}"
else
# No --next-num provided, require explicit sequence number
echo "Error: Multi-instance type '$DOC_TYPE' requires --next-num DIR option" >&2
echo "Usage: $0 $PROJECT_ID $DOC_TYPE $VERSION --next-num ./directory" >&2
exit 1
fi
else
# Single-instance document type
DOC_ID="ARC-${PROJECT_ID_PADDED}-${DOC_TYPE}-v${VERSION}"
fi
# Add file extension if requested
if [ "$ADD_EXTENSION" = true ]; then
DOC_ID="${DOC_ID}.md"
fi
echo "$DOC_ID"