this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

more slop

+387 -3
+387 -3
slopper
··· 26 26 WORKSPACE="${SLOPPER_WORKSPACE:-$(pwd)}" 27 27 # For OCaml mode, use workspace-local .slopper directory to work with container mount 28 28 HISTORY_DIR="${WORKSPACE}/.slopper/history" 29 + TODO_FILE="${WORKSPACE}/.slopper/TODO.md" 29 30 FORCE_REBUILD=false 30 31 QUIET=false 31 32 MODE="" 32 33 EXEC_PROMPT="" 34 + TODO_LIMIT="" 33 35 34 36 # Ensure log and history directories exist 35 37 mkdir -p "${LOG_DIR}" 36 38 mkdir -p "${HISTORY_DIR}" 39 + mkdir -p "$(dirname "${TODO_FILE}")" 37 40 38 41 # Logging function 39 42 log() { ··· 75 78 log DEBUG "Rotated old log files" 76 79 } 77 80 81 + # Initialize TODO.md file if it doesn't exist 82 + init_todo_file() { 83 + if [ ! -f "$TODO_FILE" ]; then 84 + cat > "$TODO_FILE" << 'EOF' 85 + # Slopper Development TODOs 86 + 87 + ## Pending Setup Improvements 88 + 89 + ## Pending Code Fixes 90 + 91 + ## Pending Features 92 + 93 + ## Completed 94 + EOF 95 + log DEBUG "Initialized TODO file: $TODO_FILE" 96 + fi 97 + } 98 + 99 + # Add a TODO item to the file 100 + add_todo_item() { 101 + local category="$1" 102 + local description="$2" 103 + local session_id="$3" 104 + local timestamp="$(date '+%Y-%m-%d')" 105 + 106 + init_todo_file 107 + 108 + # Find the appropriate section and add the item 109 + local section_line 110 + case "$category" in 111 + "setup"|"Setup") 112 + section_line="## Pending Setup Improvements" 113 + ;; 114 + "fix"|"Fix"|"fixes"|"Fixes") 115 + section_line="## Pending Code Fixes" 116 + ;; 117 + "feature"|"Feature"|"features"|"Features") 118 + section_line="## Pending Features" 119 + ;; 120 + *) 121 + section_line="## Pending Setup Improvements" 122 + ;; 123 + esac 124 + 125 + # Use awk to insert the item after the section header 126 + awk -v section="$section_line" -v item="- [ ] [$timestamp $session_id] $description" ' 127 + $0 == section { 128 + print $0 129 + print item 130 + next 131 + } 132 + { print } 133 + ' "$TODO_FILE" > "$TODO_FILE.tmp" && mv "$TODO_FILE.tmp" "$TODO_FILE" 134 + 135 + log INFO "Added TODO: $description" 136 + } 137 + 138 + # Mark a TODO item as completed 139 + complete_todo_item() { 140 + local description="$1" 141 + local timestamp="$(date '+%Y-%m-%d %H:%M')" 142 + 143 + if [ ! -f "$TODO_FILE" ]; then 144 + log WARN "TODO file does not exist" 145 + return 1 146 + fi 147 + 148 + # Move completed item to Completed section 149 + awk -v desc="$description" -v timestamp="$timestamp" ' 150 + BEGIN { in_completed = 0; moved = 0 } 151 + /^## Completed/ { in_completed = 1; print; next } 152 + /^##/ && !/^## Completed/ { in_completed = 0; print; next } 153 + /^- \[ \].*/ && index($0, desc) > 0 && !moved { 154 + # Add to completed section 155 + if (!in_completed) { 156 + completed_items[++completed_count] = "- [x] " substr($0, 7) " (completed " timestamp ")" 157 + } 158 + moved = 1 159 + next 160 + } 161 + in_completed && !moved && completed_count > 0 { 162 + for (i = 1; i <= completed_count; i++) { 163 + print completed_items[i] 164 + } 165 + completed_count = 0 166 + } 167 + { print } 168 + END { 169 + if (completed_count > 0) { 170 + for (i = 1; i <= completed_count; i++) { 171 + print completed_items[i] 172 + } 173 + } 174 + } 175 + ' "$TODO_FILE" > "$TODO_FILE.tmp" && mv "$TODO_FILE.tmp" "$TODO_FILE" 176 + 177 + log INFO "Marked TODO as completed: $description" 178 + } 179 + 180 + # Get pending TODO items 181 + get_pending_todos() { 182 + if [ ! -f "$TODO_FILE" ]; then 183 + return 0 184 + fi 185 + 186 + grep "^- \[ \]" "$TODO_FILE" || true 187 + } 188 + 189 + # Parse Claude suggestions and add them to TODO.md 190 + process_claude_suggestions_to_todos() { 191 + local suggestions_file="$1" 192 + local session_id="$2" 193 + 194 + if [ ! -f "$suggestions_file" ] || [ ! -s "$suggestions_file" ]; then 195 + log WARN "No suggestions file to process" 196 + return 0 197 + fi 198 + 199 + log INFO "Processing Claude suggestions and adding to TODO.md..." 200 + 201 + # Simple parsing - look for bullet points or numbered lists 202 + # This is a basic implementation - could be enhanced with better parsing 203 + while IFS= read -r line; do 204 + # Skip empty lines and headers 205 + if [[ -z "$line" || "$line" =~ ^[[:space:]]*$ || "$line" =~ ^[[:space:]]*[=#-] ]]; then 206 + continue 207 + fi 208 + 209 + # Look for lines that seem like actionable items 210 + if [[ "$line" =~ ^[[:space:]]*[-*][[:space:]]+(.+)$ ]] || 211 + [[ "$line" =~ ^[[:space:]]*[0-9]+\.[[:space:]]+(.+)$ ]]; then 212 + 213 + local item="${BASH_REMATCH[1]}" 214 + 215 + # Categorize the item based on keywords 216 + local category="setup" 217 + if [[ "$item" =~ (fix|bug|error|issue) ]]; then 218 + category="fix" 219 + elif [[ "$item" =~ (add|implement|feature|new) ]]; then 220 + category="feature" 221 + elif [[ "$item" =~ (install|setup|configure|environment) ]]; then 222 + category="setup" 223 + fi 224 + 225 + add_todo_item "$category" "$item" "$session_id" 226 + fi 227 + done < "$suggestions_file" 228 + } 229 + 78 230 # Function to check if devcontainer CLI is available 79 231 check_devcontainer_cli() { 80 232 if ! command -v npx &> /dev/null; then ··· 179 331 fi 180 332 181 333 # Execute Claude with the prompt in non-interactive mode 182 - # Using --yes to skip unsafe operation confirmations 183 334 log INFO "Executing Claude prompt..." 184 335 185 336 local claude_output ··· 191 342 192 343 # Run Claude in non-interactive mode 193 344 claude_output=$(npx @devcontainers/cli exec --workspace-folder "${WORKSPACE}" -- \ 194 - bash -c "cd /workspace && claude --yes < '$prompt_file'" 2>&1) || exit_code=$? 345 + bash -c "cd /workspace && claude --dangerously-skip-permissions < '$prompt_file'" 2>&1) || exit_code=$? 195 346 196 347 rm -f "$prompt_file" 197 348 ··· 474 625 fi 475 626 476 627 if [ "$output_size" -gt 0 ]; then 477 - # Output is already on host via bind mount, just display it 628 + # Output is already on host via bind mount, display it and add to TODO.md 478 629 echo "" 479 630 echo "=== Claude Analysis and Suggestions ===" 480 631 cat "$claude_output_host" 481 632 echo "" 482 633 echo "Analysis saved to: $claude_output_host" 634 + 635 + # Process suggestions and add to TODO.md 636 + process_claude_suggestions_to_todos "$claude_output_host" "$session_id" 637 + echo "Suggestions added to TODO.md: $TODO_FILE" 483 638 else 484 639 log WARN "Claude output file is empty or missing" 485 640 log DEBUG "Attempting to show stderr from Claude command..." ··· 517 672 fi 518 673 } 519 674 675 + # Show TODO.md contents 676 + mode_show_todos() { 677 + log INFO "Displaying current TODOs" 678 + 679 + if [ ! -f "$TODO_FILE" ]; then 680 + echo "No TODO file found. Run with --ocaml mode first to generate suggestions." 681 + exit 0 682 + fi 683 + 684 + cat "$TODO_FILE" 685 + exit 0 686 + } 687 + 688 + # Clear completed TODOs from TODO.md 689 + mode_clear_todos() { 690 + log INFO "Clearing completed TODOs" 691 + 692 + if [ ! -f "$TODO_FILE" ]; then 693 + log WARN "No TODO file found" 694 + exit 0 695 + fi 696 + 697 + # Create a new file without completed items 698 + awk ' 699 + BEGIN { in_completed = 0; skip_empty = 0 } 700 + /^## Completed/ { 701 + in_completed = 1 702 + print $0 703 + skip_empty = 1 704 + next 705 + } 706 + /^##/ && !/^## Completed/ { 707 + in_completed = 0 708 + skip_empty = 0 709 + print 710 + next 711 + } 712 + in_completed && /^- \[x\]/ { next } 713 + in_completed && /^[[:space:]]*$/ && skip_empty { next } 714 + in_completed { skip_empty = 0 } 715 + { print } 716 + ' "$TODO_FILE" > "$TODO_FILE.tmp" && mv "$TODO_FILE.tmp" "$TODO_FILE" 717 + 718 + log INFO "Completed TODOs cleared from $TODO_FILE" 719 + exit 0 720 + } 721 + 722 + # Implement pending TODOs non-interactively 723 + mode_implement_todos() { 724 + log INFO "Implementing pending TODOs" 725 + 726 + check_devcontainer_cli 727 + ensure_devcontainer 728 + 729 + if ! check_claude_cli; then 730 + stop_devcontainer 731 + exit 1 732 + fi 733 + 734 + if [ ! -f "$TODO_FILE" ]; then 735 + echo "No TODO file found. Run with --ocaml mode first to generate suggestions." 736 + stop_devcontainer 737 + exit 0 738 + fi 739 + 740 + # Get pending TODOs 741 + local pending_todos 742 + pending_todos=$(get_pending_todos) 743 + 744 + if [ -z "$pending_todos" ]; then 745 + echo "No pending TODOs to implement." 746 + stop_devcontainer 747 + exit 0 748 + fi 749 + 750 + local total_todos=$(echo "$pending_todos" | wc -l) 751 + local implemented=0 752 + local failed=0 753 + 754 + # Apply limit if specified 755 + if [ -n "$TODO_LIMIT" ] && [ "$TODO_LIMIT" -gt 0 ]; then 756 + pending_todos=$(echo "$pending_todos" | head -n "$TODO_LIMIT") 757 + total_todos=$(echo "$pending_todos" | wc -l) 758 + log INFO "Processing first $total_todos TODOs (limited by --limit $TODO_LIMIT)" 759 + fi 760 + 761 + log INFO "Found $total_todos pending TODOs to implement" 762 + 763 + # Process each TODO item 764 + local line_num=0 765 + while IFS= read -r todo_line; do 766 + line_num=$((line_num + 1)) 767 + 768 + if [ -z "$todo_line" ]; then 769 + continue 770 + fi 771 + 772 + # Extract the description (everything after the checkbox and metadata) 773 + local description 774 + if [[ "$todo_line" =~ \[[0-9-]+\ [^]]+\][[:space:]]*(.+)$ ]]; then 775 + description="${BASH_REMATCH[1]}" 776 + else 777 + # Fallback parsing 778 + description=$(echo "$todo_line" | sed 's/^- \[ \][[:space:]]*//') 779 + fi 780 + 781 + if [ -z "$description" ]; then 782 + log WARN "Could not parse TODO description from: $todo_line" 783 + continue 784 + fi 785 + 786 + echo "" 787 + echo "=== Implementing TODO $line_num/$total_todos ===" 788 + echo "Description: $description" 789 + echo "" 790 + 791 + # Create focused implementation prompt 792 + local impl_prompt="Implement this specific task: $description 793 + 794 + Please make the necessary changes to implement this requirement. Focus on: 795 + 1. Making the minimal necessary changes 796 + 2. Following existing code patterns and conventions 797 + 3. Testing that the implementation works 798 + 4. Providing clear output about what was changed 799 + 800 + If this is a setup/configuration task, make the changes to the appropriate files. 801 + If this is a code fix, identify and fix the specific issue. 802 + If this is a feature implementation, add the functionality as described." 803 + 804 + log INFO "Implementing: $description" 805 + 806 + # Run Claude implementation inside devcontainer 807 + # Use a heredoc to pass the prompt directly to claude inside the container 808 + local claude_exit_code=0 809 + local claude_output 810 + 811 + claude_output=$(npx @devcontainers/cli exec --workspace-folder "${WORKSPACE}" -- \ 812 + bash -c "cd /workspace && claude --dangerously-skip-permissions << 'EOF' 813 + $impl_prompt 814 + EOF" 2>&1) || claude_exit_code=$? 815 + 816 + if [ $claude_exit_code -eq 0 ]; then 817 + echo "$claude_output" 818 + echo "" 819 + log INFO "Successfully implemented: $description" 820 + 821 + # Mark as completed in TODO.md 822 + complete_todo_item "$description" 823 + implemented=$((implemented + 1)) 824 + 825 + # Optional: Create a git commit for this change 826 + if command -v git &>/dev/null; then 827 + local commit_msg="slopper: implement TODO - $description" 828 + if npx @devcontainers/cli exec --workspace-folder "${WORKSPACE}" -- \ 829 + bash -c "cd /workspace && git add -A && git diff --cached --quiet || git commit -m '$commit_msg'" 2>/dev/null; then 830 + log DEBUG "Created commit for TODO implementation" 831 + fi 832 + fi 833 + else 834 + echo "Implementation failed:" 835 + echo "$claude_output" 836 + echo "" 837 + log ERROR "Failed to implement: $description" 838 + failed=$((failed + 1)) 839 + fi 840 + 841 + # Brief pause between implementations 842 + sleep 1 843 + 844 + done <<< "$pending_todos" 845 + 846 + echo "" 847 + echo "=== Implementation Summary ===" 848 + echo "Total TODOs processed: $total_todos" 849 + echo "Successfully implemented: $implemented" 850 + echo "Failed: $failed" 851 + echo "" 852 + 853 + if [ $implemented -gt 0 ]; then 854 + echo "Updated TODO file: $TODO_FILE" 855 + fi 856 + 857 + stop_devcontainer 858 + 859 + if [ $failed -eq 0 ]; then 860 + log INFO "All TODO implementations completed successfully" 861 + exit 0 862 + else 863 + log WARN "Some TODO implementations failed" 864 + exit 1 865 + fi 866 + } 867 + 520 868 # Help function 521 869 show_help() { 522 870 cat << EOF ··· 530 878 -s, --shell Open interactive shell in devcontainer (default) 531 879 -c, --claude Start interactive Claude session 532 880 -o, --ocaml OCaml development mode with history logging 881 + --implement-todos Implement pending TODOs from TODO.md non-interactively 882 + --show-todos Display current TODO.md contents 883 + --clear-todos Clear completed TODOs from TODO.md 533 884 534 885 OPTIONS: 535 886 -f, --force Force rebuild devcontainer from scratch ··· 537 888 -q, --quiet Minimal output (errors only) 538 889 -h, --help Show this help message 539 890 --debug Enable debug output 891 + --limit N Limit number of TODOs to implement (for --implement-todos) 540 892 541 893 ENVIRONMENT: 542 894 SLOPPER_WORKSPACE Default workspace directory ··· 550 902 Automation: 551 903 ./slopper -e "fix the bug in main.ml" # CI/CD code fixes 552 904 ./slopper -e "write tests for module X" # Automated test generation 905 + ./slopper --implement-todos # Implement all pending TODO suggestions 906 + ./slopper --implement-todos --limit 3 # Implement first 3 TODOs 553 907 554 908 Maintenance: 555 909 0 3 * * * slopper -u -q # Cron: nightly container updates 556 910 ./slopper -f -s # Force rebuild after config changes 911 + ./slopper --show-todos # View current TODO list 912 + ./slopper --clear-todos # Clean up completed TODOs 557 913 558 914 Scripting: 559 915 SLOPPER_WORKSPACE=/project slopper -e "refactor all Python files" ··· 599 955 MODE="ocaml" 600 956 shift 601 957 ;; 958 + --implement-todos) 959 + [ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; } 960 + MODE="implement_todos" 961 + shift 962 + ;; 963 + --show-todos) 964 + [ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; } 965 + MODE="show_todos" 966 + shift 967 + ;; 968 + --clear-todos) 969 + [ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; } 970 + MODE="clear_todos" 971 + shift 972 + ;; 973 + --limit) 974 + TODO_LIMIT="$2" 975 + shift 2 976 + ;; 602 977 -f|--force) 603 978 FORCE_REBUILD=true 604 979 shift ··· 656 1031 ;; 657 1032 ocaml) 658 1033 mode_ocaml 1034 + ;; 1035 + implement_todos) 1036 + mode_implement_todos 1037 + ;; 1038 + show_todos) 1039 + mode_show_todos 1040 + ;; 1041 + clear_todos) 1042 + mode_clear_todos 659 1043 ;; 660 1044 *) 661 1045 log ERROR "Invalid mode: $MODE"