Files
portfolio-hub/.vendor/myagent-kit/bootstrap/install.sh
T

264 lines
8.0 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
KIT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
MERGE_COPILOT_INSTRUCTIONS=0
DRY_RUN=0
PROJECT_ROOT=""
usage() {
cat <<'EOF'
Usage: bootstrap/install.sh [PROJECT_ROOT] [--merge-copilot-instructions] [--dry-run]
Options:
--merge-copilot-instructions Opt-in: safely merge .github/copilot-instructions.md
--dry-run Print planned changes without modifying files
-h, --help Show this help message
EOF
}
log_action() {
local message="$1"
if [[ "$DRY_RUN" -eq 1 ]]; then
echo "[dry-run] $message"
else
echo "$message"
fi
}
run_or_dry() {
if [[ "$DRY_RUN" -eq 1 ]]; then
log_action "$*"
return 0
fi
"$@"
}
while [[ $# -gt 0 ]]; do
case "$1" in
--merge-copilot-instructions)
MERGE_COPILOT_INSTRUCTIONS=1
shift
;;
--dry-run)
DRY_RUN=1
shift
;;
-h|--help)
usage
exit 0
;;
-*)
echo "Unknown option: $1" >&2
usage >&2
exit 1
;;
*)
if [[ -z "$PROJECT_ROOT" ]]; then
PROJECT_ROOT="$1"
shift
else
echo "Unexpected extra argument: $1" >&2
usage >&2
exit 1
fi
;;
esac
done
PROJECT_ROOT="${PROJECT_ROOT:-$(pwd)}"
MANAGED_BEGIN='<!-- BEGIN: myagent-kit (managed - do not edit) -->'
MANAGED_END='<!-- END: myagent-kit -->'
PROJECT_BEGIN='<!-- BEGIN: project-specific (safe to edit) -->'
PROJECT_END='<!-- END: project-specific -->'
count_occurrence() {
local needle="$1"
local file="$2"
grep -cF "$needle" "$file" || true
}
build_managed_block() {
local kit_file="$1"
{
printf '%s\n' "$MANAGED_BEGIN"
cat "$kit_file"
printf '\n%s\n' "$MANAGED_END"
}
}
append_project_section_if_missing() {
local file="$1"
local project_begin_count
local project_end_count
project_begin_count="$(count_occurrence "$PROJECT_BEGIN" "$file")"
project_end_count="$(count_occurrence "$PROJECT_END" "$file")"
if [[ "$project_begin_count" -eq 0 && "$project_end_count" -eq 0 ]]; then
cat >> "$file" <<EOF
$PROJECT_BEGIN
<!-- Add host-project-specific Copilot rules here. -->
$PROJECT_END
EOF
elif [[ "$project_begin_count" -ne "$project_end_count" ]]; then
return 1
fi
}
validate_merged_copilot_file() {
local file="$1"
local managed_begin_count
local managed_end_count
local project_begin_count
local project_end_count
managed_begin_count="$(count_occurrence "$MANAGED_BEGIN" "$file")"
managed_end_count="$(count_occurrence "$MANAGED_END" "$file")"
project_begin_count="$(count_occurrence "$PROJECT_BEGIN" "$file")"
project_end_count="$(count_occurrence "$PROJECT_END" "$file")"
[[ "$managed_begin_count" -eq 1 ]] || return 1
[[ "$managed_end_count" -eq 1 ]] || return 1
[[ "$project_begin_count" -eq 1 ]] || return 1
[[ "$project_end_count" -eq 1 ]] || return 1
}
merge_copilot_instructions() {
local kit_file="$KIT_ROOT/base/.github/copilot-instructions.md"
local host_file="$PROJECT_ROOT/.github/copilot-instructions.md"
local backup_file="$host_file.bak"
local tmp_file
local managed_block
local managed_begin_count
local managed_end_count
if [[ "$MERGE_COPILOT_INSTRUCTIONS" -ne 1 ]]; then
return 0
fi
if [[ ! -f "$kit_file" ]]; then
log_action "Skipped Copilot merge: kit template not found at $kit_file"
return 0
fi
if [[ "$DRY_RUN" -eq 1 ]]; then
if [[ ! -f "$host_file" ]]; then
log_action "Would create and initialize $host_file with managed + project-specific sections"
return 0
fi
managed_begin_count="$(count_occurrence "$MANAGED_BEGIN" "$host_file")"
managed_end_count="$(count_occurrence "$MANAGED_END" "$host_file")"
log_action "Would back up $host_file to $host_file.bak"
if [[ "$managed_begin_count" -eq 1 && "$managed_end_count" -eq 1 ]]; then
log_action "Would update managed myagent-kit section in $host_file"
elif [[ "$managed_begin_count" -eq 0 && "$managed_end_count" -eq 0 ]]; then
log_action "Would append managed myagent-kit section to $host_file"
else
log_action "Would fail: malformed managed marker pair in $host_file"
return 1
fi
local project_begin_count
local project_end_count
project_begin_count="$(count_occurrence "$PROJECT_BEGIN" "$host_file")"
project_end_count="$(count_occurrence "$PROJECT_END" "$host_file")"
if [[ "$project_begin_count" -eq 0 && "$project_end_count" -eq 0 ]]; then
log_action "Would append project-specific editable section to $host_file"
elif [[ "$project_begin_count" -ne "$project_end_count" ]]; then
log_action "Would fail: malformed project-specific marker pair in $host_file"
return 1
fi
return 0
fi
managed_block="$(build_managed_block "$kit_file")"
tmp_file="$(mktemp)"
if [[ ! -f "$host_file" ]]; then
{
printf '%s\n' "$managed_block"
printf '\n%s\n' "$PROJECT_BEGIN"
printf '<!-- Add host-project-specific Copilot rules here. -->\n'
printf '%s\n' "$PROJECT_END"
} > "$host_file"
validate_merged_copilot_file "$host_file"
log_action "Created and initialized $host_file"
rm -f "$tmp_file"
return 0
fi
cp "$host_file" "$backup_file"
managed_begin_count="$(count_occurrence "$MANAGED_BEGIN" "$host_file")"
managed_end_count="$(count_occurrence "$MANAGED_END" "$host_file")"
if [[ "$managed_begin_count" -eq 1 && "$managed_end_count" -eq 1 ]]; then
awk \
-v begin="$MANAGED_BEGIN" \
-v end="$MANAGED_END" \
-v block="$managed_block" '
BEGIN {
in_block = 0
replaced = 0
}
$0 == begin {
if (!replaced) {
print block
replaced = 1
}
in_block = 1
next
}
$0 == end {
in_block = 0
next
}
!in_block {
print
}
END {
if (!replaced) {
print ""
print block
}
}
' "$host_file" > "$tmp_file"
elif [[ "$managed_begin_count" -eq 0 && "$managed_end_count" -eq 0 ]]; then
{
cat "$host_file"
printf '\n%s\n' "$managed_block"
} > "$tmp_file"
else
echo "Malformed managed marker pair in $host_file" >&2
cp "$backup_file" "$host_file"
rm -f "$tmp_file"
return 1
fi
mv "$tmp_file" "$host_file"
append_project_section_if_missing "$host_file"
validate_merged_copilot_file "$host_file"
log_action "Merged $host_file (backup: $backup_file)"
}
run_or_dry mkdir -p "$PROJECT_ROOT/.github/prompts" \
"$PROJECT_ROOT/.github/instructions" \
"$PROJECT_ROOT/.github/ISSUE_TEMPLATE"
run_or_dry cp "$KIT_ROOT/base/.github/prompts/"*.prompt.md "$PROJECT_ROOT/.github/prompts/"
run_or_dry cp "$KIT_ROOT/base/.github/instructions/"*.instructions.md "$PROJECT_ROOT/.github/instructions/"
run_or_dry cp "$KIT_ROOT/base/.github/ISSUE_TEMPLATE/"*.md "$PROJECT_ROOT/.github/ISSUE_TEMPLATE/"
if [[ -f "$KIT_ROOT/base/.github/pull_request_template.md" ]]; then
run_or_dry cp "$KIT_ROOT/base/.github/pull_request_template.md" "$PROJECT_ROOT/.github/pull_request_template.md"
fi
merge_copilot_instructions
log_action "Installed myagent-kit assets into $PROJECT_ROOT/.github"