From 955b6905cca4d3bade99bd1f9ba4520d117c372c Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 1 Jan 2026 23:12:01 -0800 Subject: [PATCH] test: add agent file update tests and fix section ordering bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 33 tests covering: - Basic functionality (tech/change entries) - Missing section handling - Timestamp updates - Idempotency (no duplicates) - Change entry limits (max 2 kept) - Database entries - Tech entry placement - Edge cases (empty, NEEDS CLARIFICATION, EOF) - format_technology_stack function Bug fixed: Recent Changes section was skipped when preceded by Active Technologies section. The ## header was caught by generic "close tech section on any ##" logic before reaching Recent Changes handling. Reordered conditions to check for Recent Changes first. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .beads/issues.jsonl | 2 +- .../scripts/bash/tests/test-agent-update.sh | 511 ++++++++++++++++++ .specify/scripts/bash/update-agent-context.sh | 36 +- 3 files changed, 536 insertions(+), 13 deletions(-) create mode 100755 .specify/scripts/bash/tests/test-agent-update.sh diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index e247a85..1922e96 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -84,7 +84,7 @@ {"id":"skills-gq9","title":"Define structured skill reference schema","description":"Replace simple skill: string with structured object.\n\nCurrent (too weak):\n skill: worklog\n\nProposed:\n skill:\n id: worklog\n ref: \"git+file://...#worklog@abc123\"\n inputs:\n session: \"{{session}}\"\n expects:\n files: [\"docs/worklogs/{{session}}.org\"]\n\nFrom orch consensus: both GPT and Gemini flagged this as critical gap.\nNo mechanism to pass args from molecule to skill.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-23T19:49:30.529899123-05:00","updated_at":"2025-12-28T22:46:28.371352259-05:00","closed_at":"2025-12-28T22:46:28.371352259-05:00","close_reason":"Deferred: structured schema was for molecule→skill integration. Current approach (agent reads SKILL.md directly) works well. Skills as entrypoints are simpler than protos. Revisit if programmatic workflows become active.","dependencies":[{"issue_id":"skills-gq9","depends_on_id":"skills-oes","type":"blocks","created_at":"2025-12-23T19:50:10.337111856-05:00","created_by":"daemon"},{"issue_id":"skills-gq9","depends_on_id":"skills-8y6","type":"blocks","created_at":"2025-12-23T19:50:10.388301727-05:00","created_by":"daemon"}]} {"id":"skills-gvj","title":"Orch-in-the-Middle: LSP proxy for multi-model refactors","description":"Write an LSP proxy (Go/Rust) that:\n- Intercepts rename/code-action requests from editor\n- Sends to Orch for multi-model proposals\n- Validates proposals against real headless LSP\n- Returns winning WorkspaceEdit to editor\n\nGet consensus refactoring inside VS Code/Neovim by configuring LSP server path in home-manager.","status":"closed","priority":4,"issue_type":"feature","created_at":"2025-12-24T02:29:56.623189042-05:00","updated_at":"2025-12-29T14:37:35.360129462-05:00","closed_at":"2025-12-29T14:37:35.360129462-05:00","close_reason":"Parked: waiting on gastown (Steve Yegge's orchestration layer for beads). Revisit when gastown lands."} {"id":"skills-h9f","title":"spec-review: Balance negativity bias in prompts","description":"'Be critical' and 'devil's advocate' can bias toward over-flagging without acknowledging what's good.\n\nAdd:\n- 'List top 3 strongest parts of the document'\n- 'Call out where document is sufficiently clear/testable'\n- Categorize :against concerns as confirmed/plausible/rejected","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-15T00:23:26.418087998-08:00","updated_at":"2025-12-15T14:07:39.520818417-08:00","closed_at":"2025-12-15T14:07:39.520818417-08:00"} -{"id":"skills-hgm","title":"Add tests for agent file update logic","description":"File: .specify/scripts/bash/update-agent-context.sh (lines 360-499)\n\nCritical logic with NO test coverage:\n- Malformed agent files (missing sections)\n- Multiple section headers on same line\n- Empty file handling\n- Timestamp update verification\n- State machine correctness\n\nRisk: HIGH - corrupts agent context files on failure\n\nFix:\n- Create test fixtures for various file states\n- Test each state transition\n- Verify idempotency\n\nSeverity: HIGH","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-24T02:51:00.793493549-05:00","updated_at":"2025-12-24T02:51:00.793493549-05:00"} +{"id":"skills-hgm","title":"Add tests for agent file update logic","description":"File: .specify/scripts/bash/update-agent-context.sh (lines 360-499)\n\nCritical logic with NO test coverage:\n- Malformed agent files (missing sections)\n- Multiple section headers on same line\n- Empty file handling\n- Timestamp update verification\n- State machine correctness\n\nRisk: HIGH - corrupts agent context files on failure\n\nFix:\n- Create test fixtures for various file states\n- Test each state transition\n- Verify idempotency\n\nSeverity: HIGH","status":"in_progress","priority":2,"issue_type":"task","created_at":"2025-12-24T02:51:00.793493549-05:00","updated_at":"2026-01-02T00:55:27.102270945-05:00"} {"id":"skills-hh2","title":"skill: rename_symbol with LSP + validation","description":"Skill that performs safe renames:\n1. Uses LSP textDocument/rename\n2. Runs formatters\n3. Checks LSP diagnostics post-rename\n4. Opens bead if errors remain\n5. Updates doc references using hover/signatureHelp\n\nInput: new name, scope. Output: clean rename or bead with issues.","status":"open","priority":3,"issue_type":"task","created_at":"2025-12-24T02:29:56.87156069-05:00","updated_at":"2025-12-24T02:29:56.87156069-05:00","dependencies":[{"issue_id":"skills-hh2","depends_on_id":"skills-gga","type":"blocks","created_at":"2025-12-24T02:30:06.583813579-05:00","created_by":"daemon"}]} {"id":"skills-hhz","title":"Add doc-review skill","description":"Create skill for doc-review CLI tool (~/proj/doc-review). Tool lints markdown docs for AI agent consumption using Vale + LLM hybrid architecture. Needs: 1) flake.nix in doc-review project, 2) skill SKILL.md, 3) register in availableSkills","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T11:24:41.321478346-05:00","created_by":"dan","updated_at":"2025-12-31T00:00:30.74314365-05:00","closed_at":"2025-12-31T00:00:30.74314365-05:00","close_reason":"doc-review skill created in skills/doc-review/SKILL.md"} {"id":"skills-hin","title":"ADR: Skills and Molecules Integration Design","description":"Write Architecture Decision Record documenting:\n- Current state (skills via Nix/direnv, molecules via beads)\n- Decision to link via skill: references\n- Wisp trace format spec\n- Elevation pipeline design\n- Anti-patterns to avoid\n\nLocation: docs/adr/001-skills-molecules-integration.md\n\nMigrated from dotfiles-dn8 (was in_progress).\n\n## Current State\n- ADR-001 drafted (high-level integration)\n- ADR-002, 003, 004 drafted and revised (manifest, versioning, security)\n- Orch consensus feedback incorporated\n\n## Parked\nDeferring finalization until we see Steve Yegge's new orchestration work and how it might inform our design.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-23T19:20:47.568903148-05:00","updated_at":"2025-12-28T23:27:42.117722575-05:00","closed_at":"2025-12-28T23:27:42.117722575-05:00","close_reason":"Parked: ADR updated to 'Parked' status. Current simpler approach (skills as standalone, agent judgment) works well. Molecules not actively used. Revisit when orchestration needs grow."} diff --git a/.specify/scripts/bash/tests/test-agent-update.sh b/.specify/scripts/bash/tests/test-agent-update.sh new file mode 100755 index 0000000..6c4df02 --- /dev/null +++ b/.specify/scripts/bash/tests/test-agent-update.sh @@ -0,0 +1,511 @@ +#!/usr/bin/env bash +# Tests for update_existing_agent_file function +# Run: bash .specify/scripts/bash/tests/test-agent-update.sh + +set -uo pipefail +# Note: not using -e so we can continue after failed assertions + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PASSED=0 +FAILED=0 + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color + +# Test fixtures directory +FIXTURES_DIR="$SCRIPT_DIR/fixtures/agent-update" +mkdir -p "$FIXTURES_DIR" + +# Mock logging functions (silence in tests) +log_info() { :; } +log_error() { echo "ERROR: $1" >&2; } +log_warning() { :; } +log_success() { :; } + +# Extract format_technology_stack function +eval "$(sed -n '/^format_technology_stack()/,/^}/p' "$SCRIPT_DIR/../update-agent-context.sh")" + +# Extract update_existing_agent_file function - use more specific pattern +# The function ends with a single } on its own line before the next function +eval "$(awk '/^update_existing_agent_file\(\)/,/^}$/ {print; if (/^}$/) exit}' "$SCRIPT_DIR/../update-agent-context.sh")" + +# Test helper: compare files +assert_file_eq() { + local description="$1" + local expected_file="$2" + local actual_file="$3" + + if diff -q "$expected_file" "$actual_file" > /dev/null 2>&1; then + echo -e "${GREEN}PASS${NC}: $description" + ((PASSED++)) + else + echo -e "${RED}FAIL${NC}: $description" + echo " Expected:" + cat "$expected_file" | sed 's/^/ /' + echo " Actual:" + cat "$actual_file" | sed 's/^/ /' + echo " Diff:" + diff "$expected_file" "$actual_file" | sed 's/^/ /' || true + ((FAILED++)) + fi +} + +# Test helper: check file contains pattern +assert_contains() { + local description="$1" + local pattern="$2" + local file="$3" + + if grep -q "$pattern" "$file" 2>/dev/null; then + echo -e "${GREEN}PASS${NC}: $description" + ((PASSED++)) + else + echo -e "${RED}FAIL${NC}: $description" + echo " Pattern not found: '$pattern'" + echo " File contents:" + cat "$file" | sed 's/^/ /' + ((FAILED++)) + fi +} + +# Test helper: check file does NOT contain pattern +assert_not_contains() { + local description="$1" + local pattern="$2" + local file="$3" + + if ! grep -q "$pattern" "$file" 2>/dev/null; then + echo -e "${GREEN}PASS${NC}: $description" + ((PASSED++)) + else + echo -e "${RED}FAIL${NC}: $description" + echo " Pattern found but should not be: '$pattern'" + echo " File contents:" + cat "$file" | sed 's/^/ /' + ((FAILED++)) + fi +} + +# Test helper: count occurrences +assert_count() { + local description="$1" + local expected="$2" + local pattern="$3" + local file="$4" + + local actual + actual=$(grep -c "$pattern" "$file" 2>/dev/null || echo "0") + + if [[ "$actual" == "$expected" ]]; then + echo -e "${GREEN}PASS${NC}: $description" + ((PASSED++)) + else + echo -e "${RED}FAIL${NC}: $description" + echo " Expected count: $expected" + echo " Actual count: $actual" + echo " Pattern: '$pattern'" + ((FAILED++)) + fi +} + +# Setup test file +setup_test_file() { + local content="$1" + local test_file + test_file=$(mktemp) + echo -e "$content" > "$test_file" + echo "$test_file" +} + +# Cleanup +cleanup_test_file() { + rm -f "$1" +} + +echo "=== Agent File Update Tests ===" +echo "" + +# --- Basic Functionality --- +echo "## Basic Functionality" + +# Test: Normal update with both sections +NEW_LANG="Python 3.11" +NEW_FRAMEWORK="FastAPI" +NEW_DB="" +CURRENT_BRANCH="feature-auth" + +test_file=$(setup_test_file "# Project + +## Active Technologies +- JavaScript + React (main) + +## Recent Changes +- old-feature: Added logging + +## Other Section +Some content") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_contains "Adds new tech entry" "Python 3.11 + FastAPI (feature-auth)" "$test_file" +assert_contains "Adds new change entry" "feature-auth: Added Python 3.11 + FastAPI" "$test_file" +assert_contains "Preserves existing tech entry" "JavaScript + React (main)" "$test_file" +assert_contains "Preserves other sections" "## Other Section" "$test_file" + +cleanup_test_file "$test_file" + +# --- Missing Sections --- +echo "" +echo "## Missing Sections" + +# Test: Missing Active Technologies section +NEW_LANG="Rust" +NEW_FRAMEWORK="" +NEW_DB="" +CURRENT_BRANCH="add-rust" + +test_file=$(setup_test_file "# Project + +## Some Other Section +Content here + +## Recent Changes +- old: stuff") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_contains "Creates Active Technologies section" "## Active Technologies" "$test_file" +assert_contains "Adds tech to new section" "Rust (add-rust)" "$test_file" + +cleanup_test_file "$test_file" + +# Test: Missing Recent Changes section +NEW_LANG="Go" +NEW_FRAMEWORK="" +NEW_DB="" +CURRENT_BRANCH="add-go" + +test_file=$(setup_test_file "# Project + +## Active Technologies +- Python (main)") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_contains "Creates Recent Changes section" "## Recent Changes" "$test_file" +assert_contains "Adds change to new section" "add-go: Added Go" "$test_file" + +cleanup_test_file "$test_file" + +# Test: Both sections missing +NEW_LANG="TypeScript" +NEW_FRAMEWORK="Express" +NEW_DB="" +CURRENT_BRANCH="add-ts" + +test_file=$(setup_test_file "# Project + +Just some content here.") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_contains "Creates Active Technologies when missing" "## Active Technologies" "$test_file" +assert_contains "Creates Recent Changes when missing" "## Recent Changes" "$test_file" +assert_contains "Adds tech entry" "TypeScript + Express (add-ts)" "$test_file" +assert_contains "Adds change entry" "add-ts: Added TypeScript + Express" "$test_file" + +cleanup_test_file "$test_file" + +# --- Timestamp Updates --- +echo "" +echo "## Timestamp Updates" + +NEW_LANG="" +NEW_FRAMEWORK="" +NEW_DB="" +CURRENT_BRANCH="update-test" + +test_file=$(setup_test_file "# Project + +**Last updated**: 2023-06-01 + +## Active Technologies +- Python (main)") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_contains "Updates timestamp" "2024-01-15" "$test_file" +assert_not_contains "Old timestamp removed" "2023-06-01" "$test_file" + +cleanup_test_file "$test_file" + +# --- Idempotency --- +echo "" +echo "## Idempotency" + +# Test: Don't add duplicate tech entries +NEW_LANG="Python" +NEW_FRAMEWORK="Django" +NEW_DB="" +CURRENT_BRANCH="feature-x" + +test_file=$(setup_test_file "# Project + +## Active Technologies +- Python + Django (feature-x) + +## Recent Changes +- feature-x: Added Python + Django") + +update_existing_agent_file "$test_file" "2024-01-15" + +# Check tech section specifically - should only have one tech entry line +assert_count "No duplicate tech entry in Active Technologies" "1" "^- Python + Django (feature-x)$" "$test_file" + +cleanup_test_file "$test_file" + +# --- Change Entry Limits --- +echo "" +echo "## Change Entry Limits (max 2 kept)" + +NEW_LANG="Rust" +NEW_FRAMEWORK="" +NEW_DB="" +CURRENT_BRANCH="new-feature" + +test_file=$(setup_test_file "# Project + +## Recent Changes +- old-1: First old change +- old-2: Second old change +- old-3: Third old change +- old-4: Fourth old change + +## Other Section") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_contains "New change added first" "new-feature: Added Rust" "$test_file" +assert_contains "Keeps first old change" "old-1: First old change" "$test_file" +assert_contains "Keeps second old change" "old-2: Second old change" "$test_file" +assert_not_contains "Removes third old change" "old-3:" "$test_file" +assert_not_contains "Removes fourth old change" "old-4:" "$test_file" + +cleanup_test_file "$test_file" + +# --- Database Entries --- +echo "" +echo "## Database Entries" + +NEW_LANG="" +NEW_FRAMEWORK="" +NEW_DB="PostgreSQL" +CURRENT_BRANCH="add-db" + +test_file=$(setup_test_file "# Project + +## Active Technologies +- Python (main) + +## Recent Changes +- old: stuff") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_contains "Adds database entry to tech section" "PostgreSQL (add-db)" "$test_file" +assert_contains "Adds database to change entry" "add-db: Added PostgreSQL" "$test_file" + +cleanup_test_file "$test_file" + +# Test: DB with N/A value not added +NEW_LANG="" +NEW_FRAMEWORK="" +NEW_DB="N/A" +CURRENT_BRANCH="no-db" + +test_file=$(setup_test_file "# Project + +## Active Technologies +- Python (main)") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_not_contains "N/A database not added" "N/A (no-db)" "$test_file" + +cleanup_test_file "$test_file" + +# --- Tech Entry Placement --- +echo "" +echo "## Tech Entry Placement" + +# Test: Tech entries added before next section header +NEW_LANG="Java" +NEW_FRAMEWORK="" +NEW_DB="" +CURRENT_BRANCH="add-java" + +test_file=$(setup_test_file "## Active Technologies +- Python (main) +## Next Section +content") + +update_existing_agent_file "$test_file" "2024-01-15" + +# The Java entry should appear between Python and Next Section +assert_contains "Tech entry added to section" "Java (add-java)" "$test_file" + +# Verify order: Java should come after Python line +if grep -n "Python" "$test_file" | head -1 | cut -d: -f1 > /tmp/python_line && \ + grep -n "Java" "$test_file" | head -1 | cut -d: -f1 > /tmp/java_line; then + python_line=$(cat /tmp/python_line) + java_line=$(cat /tmp/java_line) + if [[ "$java_line" -gt "$python_line" ]]; then + echo -e "${GREEN}PASS${NC}: Tech entry appears after existing entries" + ((PASSED++)) + else + echo -e "${RED}FAIL${NC}: Tech entry appears after existing entries" + echo " Java at line $java_line, Python at line $python_line" + ((FAILED++)) + fi + rm -f /tmp/python_line /tmp/java_line +fi + +cleanup_test_file "$test_file" + +# Test: Tech entries added before blank line in section +NEW_LANG="Ruby" +NEW_FRAMEWORK="" +NEW_DB="" +CURRENT_BRANCH="add-ruby" + +test_file=$(setup_test_file "## Active Technologies +- Python (main) + +## Other Section") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_contains "Tech entry added before blank line" "Ruby (add-ruby)" "$test_file" + +cleanup_test_file "$test_file" + +# --- Edge Cases --- +echo "" +echo "## Edge Cases" + +# Test: Empty NEW_LANG and NEW_FRAMEWORK (no tech to add) +NEW_LANG="" +NEW_FRAMEWORK="" +NEW_DB="" +CURRENT_BRANCH="no-tech" + +test_file=$(setup_test_file "# Project + +## Active Technologies +- Python (main) + +## Recent Changes +- old: change") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_not_contains "No empty tech entry added" "( no-tech)" "$test_file" + +cleanup_test_file "$test_file" + +# Test: NEEDS CLARIFICATION values not added +NEW_LANG="NEEDS CLARIFICATION" +NEW_FRAMEWORK="" +NEW_DB="NEEDS CLARIFICATION" +CURRENT_BRANCH="unclear" + +test_file=$(setup_test_file "# Project + +## Active Technologies +- Python (main)") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_not_contains "NEEDS CLARIFICATION language not added" "NEEDS CLARIFICATION" "$test_file" + +cleanup_test_file "$test_file" + +# Test: File ending with tech section (no next header) +NEW_LANG="Scala" +NEW_FRAMEWORK="" +NEW_DB="" +CURRENT_BRANCH="add-scala" + +test_file=$(setup_test_file "# Project + +## Active Technologies +- Python (main)") + +update_existing_agent_file "$test_file" "2024-01-15" + +assert_contains "Tech added to section at EOF" "Scala (add-scala)" "$test_file" + +cleanup_test_file "$test_file" + +# --- Format Technology Stack --- +echo "" +echo "## format_technology_stack Function" + +result=$(format_technology_stack "Python" "Flask") +if [[ "$result" == "Python + Flask" ]]; then + echo -e "${GREEN}PASS${NC}: format_technology_stack with lang and framework" + ((PASSED++)) +else + echo -e "${RED}FAIL${NC}: format_technology_stack with lang and framework" + echo " Expected: 'Python + Flask'" + echo " Actual: '$result'" + ((FAILED++)) +fi + +result=$(format_technology_stack "Python" "") +if [[ "$result" == "Python" ]]; then + echo -e "${GREEN}PASS${NC}: format_technology_stack with lang only" + ((PASSED++)) +else + echo -e "${RED}FAIL${NC}: format_technology_stack with lang only" + echo " Expected: 'Python'" + echo " Actual: '$result'" + ((FAILED++)) +fi + +result=$(format_technology_stack "" "") +if [[ "$result" == "" ]]; then + echo -e "${GREEN}PASS${NC}: format_technology_stack with nothing" + ((PASSED++)) +else + echo -e "${RED}FAIL${NC}: format_technology_stack with nothing" + echo " Expected: ''" + echo " Actual: '$result'" + ((FAILED++)) +fi + +result=$(format_technology_stack "NEEDS CLARIFICATION" "Flask") +if [[ "$result" == "Flask" ]]; then + echo -e "${GREEN}PASS${NC}: format_technology_stack filters NEEDS CLARIFICATION" + ((PASSED++)) +else + echo -e "${RED}FAIL${NC}: format_technology_stack filters NEEDS CLARIFICATION" + echo " Expected: 'Flask'" + echo " Actual: '$result'" + ((FAILED++)) +fi + +# --- Summary --- +echo "" +echo "=== Summary ===" +echo -e "Passed: ${GREEN}$PASSED${NC}" +echo -e "Failed: ${RED}$FAILED${NC}" + +# Cleanup fixtures +rm -rf "$FIXTURES_DIR" + +if [[ $FAILED -gt 0 ]]; then + exit 1 +fi diff --git a/.specify/scripts/bash/update-agent-context.sh b/.specify/scripts/bash/update-agent-context.sh index 2a44c68..c218467 100755 --- a/.specify/scripts/bash/update-agent-context.sh +++ b/.specify/scripts/bash/update-agent-context.sh @@ -412,6 +412,27 @@ update_existing_agent_file() { local file_ended=false while IFS= read -r line || [[ -n "$line" ]]; do + # Handle Recent Changes section FIRST (before generic ## handling) + # This ensures ## Recent Changes is processed correctly even when in_tech_section=true + if [[ "$line" == "## Recent Changes" ]]; then + # Close tech section if we were in it + if [[ $in_tech_section == true ]]; then + if [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then + printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file" + tech_entries_added=true + fi + in_tech_section=false + fi + echo "$line" >> "$temp_file" + # Add new change entry right after the heading + if [[ -n "$new_change_entry" ]]; then + echo "$new_change_entry" >> "$temp_file" + fi + in_changes_section=true + changes_entries_added=true + continue + fi + # Handle Active Technologies section if [[ "$line" == "## Active Technologies" ]]; then echo "$line" >> "$temp_file" @@ -435,18 +456,9 @@ update_existing_agent_file() { echo "$line" >> "$temp_file" continue fi - - # Handle Recent Changes section - if [[ "$line" == "## Recent Changes" ]]; then - echo "$line" >> "$temp_file" - # Add new change entry right after the heading - if [[ -n "$new_change_entry" ]]; then - echo "$new_change_entry" >> "$temp_file" - fi - in_changes_section=true - changes_entries_added=true - continue - elif [[ $in_changes_section == true ]] && [[ "$line" =~ ^##[[:space:]] ]]; then + + # Handle Recent Changes section content + if [[ $in_changes_section == true ]] && [[ "$line" =~ ^##[[:space:]] ]]; then echo "$line" >> "$temp_file" in_changes_section=false continue