test: add agent file update tests and fix section ordering bug

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 <noreply@anthropic.com>
This commit is contained in:
dan 2026-01-01 23:12:01 -08:00
parent 23b374e5bf
commit 955b6905cc
3 changed files with 536 additions and 13 deletions

View file

@ -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-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-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-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-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-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."} {"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."}

View file

@ -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

View file

@ -412,6 +412,27 @@ update_existing_agent_file() {
local file_ended=false local file_ended=false
while IFS= read -r line || [[ -n "$line" ]]; do 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 # Handle Active Technologies section
if [[ "$line" == "## Active Technologies" ]]; then if [[ "$line" == "## Active Technologies" ]]; then
echo "$line" >> "$temp_file" echo "$line" >> "$temp_file"
@ -436,17 +457,8 @@ update_existing_agent_file() {
continue continue
fi fi
# Handle Recent Changes section # Handle Recent Changes section content
if [[ "$line" == "## Recent Changes" ]]; then if [[ $in_changes_section == true ]] && [[ "$line" =~ ^##[[:space:]] ]]; 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
echo "$line" >> "$temp_file" echo "$line" >> "$temp_file"
in_changes_section=false in_changes_section=false
continue continue