My agentic slop goes here. Not intended for anyone else!

more slop

Changed files
+387 -3
+387 -3
slopper
···
WORKSPACE="${SLOPPER_WORKSPACE:-$(pwd)}"
# For OCaml mode, use workspace-local .slopper directory to work with container mount
HISTORY_DIR="${WORKSPACE}/.slopper/history"
+
TODO_FILE="${WORKSPACE}/.slopper/TODO.md"
FORCE_REBUILD=false
QUIET=false
MODE=""
EXEC_PROMPT=""
+
TODO_LIMIT=""
# Ensure log and history directories exist
mkdir -p "${LOG_DIR}"
mkdir -p "${HISTORY_DIR}"
+
mkdir -p "$(dirname "${TODO_FILE}")"
# Logging function
log() {
···
log DEBUG "Rotated old log files"
}
+
# Initialize TODO.md file if it doesn't exist
+
init_todo_file() {
+
if [ ! -f "$TODO_FILE" ]; then
+
cat > "$TODO_FILE" << 'EOF'
+
# Slopper Development TODOs
+
+
## Pending Setup Improvements
+
+
## Pending Code Fixes
+
+
## Pending Features
+
+
## Completed
+
EOF
+
log DEBUG "Initialized TODO file: $TODO_FILE"
+
fi
+
}
+
+
# Add a TODO item to the file
+
add_todo_item() {
+
local category="$1"
+
local description="$2"
+
local session_id="$3"
+
local timestamp="$(date '+%Y-%m-%d')"
+
+
init_todo_file
+
+
# Find the appropriate section and add the item
+
local section_line
+
case "$category" in
+
"setup"|"Setup")
+
section_line="## Pending Setup Improvements"
+
;;
+
"fix"|"Fix"|"fixes"|"Fixes")
+
section_line="## Pending Code Fixes"
+
;;
+
"feature"|"Feature"|"features"|"Features")
+
section_line="## Pending Features"
+
;;
+
*)
+
section_line="## Pending Setup Improvements"
+
;;
+
esac
+
+
# Use awk to insert the item after the section header
+
awk -v section="$section_line" -v item="- [ ] [$timestamp $session_id] $description" '
+
$0 == section {
+
print $0
+
print item
+
next
+
}
+
{ print }
+
' "$TODO_FILE" > "$TODO_FILE.tmp" && mv "$TODO_FILE.tmp" "$TODO_FILE"
+
+
log INFO "Added TODO: $description"
+
}
+
+
# Mark a TODO item as completed
+
complete_todo_item() {
+
local description="$1"
+
local timestamp="$(date '+%Y-%m-%d %H:%M')"
+
+
if [ ! -f "$TODO_FILE" ]; then
+
log WARN "TODO file does not exist"
+
return 1
+
fi
+
+
# Move completed item to Completed section
+
awk -v desc="$description" -v timestamp="$timestamp" '
+
BEGIN { in_completed = 0; moved = 0 }
+
/^## Completed/ { in_completed = 1; print; next }
+
/^##/ && !/^## Completed/ { in_completed = 0; print; next }
+
/^- \[ \].*/ && index($0, desc) > 0 && !moved {
+
# Add to completed section
+
if (!in_completed) {
+
completed_items[++completed_count] = "- [x] " substr($0, 7) " (completed " timestamp ")"
+
}
+
moved = 1
+
next
+
}
+
in_completed && !moved && completed_count > 0 {
+
for (i = 1; i <= completed_count; i++) {
+
print completed_items[i]
+
}
+
completed_count = 0
+
}
+
{ print }
+
END {
+
if (completed_count > 0) {
+
for (i = 1; i <= completed_count; i++) {
+
print completed_items[i]
+
}
+
}
+
}
+
' "$TODO_FILE" > "$TODO_FILE.tmp" && mv "$TODO_FILE.tmp" "$TODO_FILE"
+
+
log INFO "Marked TODO as completed: $description"
+
}
+
+
# Get pending TODO items
+
get_pending_todos() {
+
if [ ! -f "$TODO_FILE" ]; then
+
return 0
+
fi
+
+
grep "^- \[ \]" "$TODO_FILE" || true
+
}
+
+
# Parse Claude suggestions and add them to TODO.md
+
process_claude_suggestions_to_todos() {
+
local suggestions_file="$1"
+
local session_id="$2"
+
+
if [ ! -f "$suggestions_file" ] || [ ! -s "$suggestions_file" ]; then
+
log WARN "No suggestions file to process"
+
return 0
+
fi
+
+
log INFO "Processing Claude suggestions and adding to TODO.md..."
+
+
# Simple parsing - look for bullet points or numbered lists
+
# This is a basic implementation - could be enhanced with better parsing
+
while IFS= read -r line; do
+
# Skip empty lines and headers
+
if [[ -z "$line" || "$line" =~ ^[[:space:]]*$ || "$line" =~ ^[[:space:]]*[=#-] ]]; then
+
continue
+
fi
+
+
# Look for lines that seem like actionable items
+
if [[ "$line" =~ ^[[:space:]]*[-*][[:space:]]+(.+)$ ]] ||
+
[[ "$line" =~ ^[[:space:]]*[0-9]+\.[[:space:]]+(.+)$ ]]; then
+
+
local item="${BASH_REMATCH[1]}"
+
+
# Categorize the item based on keywords
+
local category="setup"
+
if [[ "$item" =~ (fix|bug|error|issue) ]]; then
+
category="fix"
+
elif [[ "$item" =~ (add|implement|feature|new) ]]; then
+
category="feature"
+
elif [[ "$item" =~ (install|setup|configure|environment) ]]; then
+
category="setup"
+
fi
+
+
add_todo_item "$category" "$item" "$session_id"
+
fi
+
done < "$suggestions_file"
+
}
+
# Function to check if devcontainer CLI is available
check_devcontainer_cli() {
if ! command -v npx &> /dev/null; then
···
fi
# Execute Claude with the prompt in non-interactive mode
-
# Using --yes to skip unsafe operation confirmations
log INFO "Executing Claude prompt..."
local claude_output
···
# Run Claude in non-interactive mode
claude_output=$(npx @devcontainers/cli exec --workspace-folder "${WORKSPACE}" -- \
-
bash -c "cd /workspace && claude --yes < '$prompt_file'" 2>&1) || exit_code=$?
+
bash -c "cd /workspace && claude --dangerously-skip-permissions < '$prompt_file'" 2>&1) || exit_code=$?
rm -f "$prompt_file"
···
fi
if [ "$output_size" -gt 0 ]; then
-
# Output is already on host via bind mount, just display it
+
# Output is already on host via bind mount, display it and add to TODO.md
echo ""
echo "=== Claude Analysis and Suggestions ==="
cat "$claude_output_host"
echo ""
echo "Analysis saved to: $claude_output_host"
+
+
# Process suggestions and add to TODO.md
+
process_claude_suggestions_to_todos "$claude_output_host" "$session_id"
+
echo "Suggestions added to TODO.md: $TODO_FILE"
else
log WARN "Claude output file is empty or missing"
log DEBUG "Attempting to show stderr from Claude command..."
···
fi
}
+
# Show TODO.md contents
+
mode_show_todos() {
+
log INFO "Displaying current TODOs"
+
+
if [ ! -f "$TODO_FILE" ]; then
+
echo "No TODO file found. Run with --ocaml mode first to generate suggestions."
+
exit 0
+
fi
+
+
cat "$TODO_FILE"
+
exit 0
+
}
+
+
# Clear completed TODOs from TODO.md
+
mode_clear_todos() {
+
log INFO "Clearing completed TODOs"
+
+
if [ ! -f "$TODO_FILE" ]; then
+
log WARN "No TODO file found"
+
exit 0
+
fi
+
+
# Create a new file without completed items
+
awk '
+
BEGIN { in_completed = 0; skip_empty = 0 }
+
/^## Completed/ {
+
in_completed = 1
+
print $0
+
skip_empty = 1
+
next
+
}
+
/^##/ && !/^## Completed/ {
+
in_completed = 0
+
skip_empty = 0
+
print
+
next
+
}
+
in_completed && /^- \[x\]/ { next }
+
in_completed && /^[[:space:]]*$/ && skip_empty { next }
+
in_completed { skip_empty = 0 }
+
{ print }
+
' "$TODO_FILE" > "$TODO_FILE.tmp" && mv "$TODO_FILE.tmp" "$TODO_FILE"
+
+
log INFO "Completed TODOs cleared from $TODO_FILE"
+
exit 0
+
}
+
+
# Implement pending TODOs non-interactively
+
mode_implement_todos() {
+
log INFO "Implementing pending TODOs"
+
+
check_devcontainer_cli
+
ensure_devcontainer
+
+
if ! check_claude_cli; then
+
stop_devcontainer
+
exit 1
+
fi
+
+
if [ ! -f "$TODO_FILE" ]; then
+
echo "No TODO file found. Run with --ocaml mode first to generate suggestions."
+
stop_devcontainer
+
exit 0
+
fi
+
+
# Get pending TODOs
+
local pending_todos
+
pending_todos=$(get_pending_todos)
+
+
if [ -z "$pending_todos" ]; then
+
echo "No pending TODOs to implement."
+
stop_devcontainer
+
exit 0
+
fi
+
+
local total_todos=$(echo "$pending_todos" | wc -l)
+
local implemented=0
+
local failed=0
+
+
# Apply limit if specified
+
if [ -n "$TODO_LIMIT" ] && [ "$TODO_LIMIT" -gt 0 ]; then
+
pending_todos=$(echo "$pending_todos" | head -n "$TODO_LIMIT")
+
total_todos=$(echo "$pending_todos" | wc -l)
+
log INFO "Processing first $total_todos TODOs (limited by --limit $TODO_LIMIT)"
+
fi
+
+
log INFO "Found $total_todos pending TODOs to implement"
+
+
# Process each TODO item
+
local line_num=0
+
while IFS= read -r todo_line; do
+
line_num=$((line_num + 1))
+
+
if [ -z "$todo_line" ]; then
+
continue
+
fi
+
+
# Extract the description (everything after the checkbox and metadata)
+
local description
+
if [[ "$todo_line" =~ \[[0-9-]+\ [^]]+\][[:space:]]*(.+)$ ]]; then
+
description="${BASH_REMATCH[1]}"
+
else
+
# Fallback parsing
+
description=$(echo "$todo_line" | sed 's/^- \[ \][[:space:]]*//')
+
fi
+
+
if [ -z "$description" ]; then
+
log WARN "Could not parse TODO description from: $todo_line"
+
continue
+
fi
+
+
echo ""
+
echo "=== Implementing TODO $line_num/$total_todos ==="
+
echo "Description: $description"
+
echo ""
+
+
# Create focused implementation prompt
+
local impl_prompt="Implement this specific task: $description
+
+
Please make the necessary changes to implement this requirement. Focus on:
+
1. Making the minimal necessary changes
+
2. Following existing code patterns and conventions
+
3. Testing that the implementation works
+
4. Providing clear output about what was changed
+
+
If this is a setup/configuration task, make the changes to the appropriate files.
+
If this is a code fix, identify and fix the specific issue.
+
If this is a feature implementation, add the functionality as described."
+
+
log INFO "Implementing: $description"
+
+
# Run Claude implementation inside devcontainer
+
# Use a heredoc to pass the prompt directly to claude inside the container
+
local claude_exit_code=0
+
local claude_output
+
+
claude_output=$(npx @devcontainers/cli exec --workspace-folder "${WORKSPACE}" -- \
+
bash -c "cd /workspace && claude --dangerously-skip-permissions << 'EOF'
+
$impl_prompt
+
EOF" 2>&1) || claude_exit_code=$?
+
+
if [ $claude_exit_code -eq 0 ]; then
+
echo "$claude_output"
+
echo ""
+
log INFO "Successfully implemented: $description"
+
+
# Mark as completed in TODO.md
+
complete_todo_item "$description"
+
implemented=$((implemented + 1))
+
+
# Optional: Create a git commit for this change
+
if command -v git &>/dev/null; then
+
local commit_msg="slopper: implement TODO - $description"
+
if npx @devcontainers/cli exec --workspace-folder "${WORKSPACE}" -- \
+
bash -c "cd /workspace && git add -A && git diff --cached --quiet || git commit -m '$commit_msg'" 2>/dev/null; then
+
log DEBUG "Created commit for TODO implementation"
+
fi
+
fi
+
else
+
echo "Implementation failed:"
+
echo "$claude_output"
+
echo ""
+
log ERROR "Failed to implement: $description"
+
failed=$((failed + 1))
+
fi
+
+
# Brief pause between implementations
+
sleep 1
+
+
done <<< "$pending_todos"
+
+
echo ""
+
echo "=== Implementation Summary ==="
+
echo "Total TODOs processed: $total_todos"
+
echo "Successfully implemented: $implemented"
+
echo "Failed: $failed"
+
echo ""
+
+
if [ $implemented -gt 0 ]; then
+
echo "Updated TODO file: $TODO_FILE"
+
fi
+
+
stop_devcontainer
+
+
if [ $failed -eq 0 ]; then
+
log INFO "All TODO implementations completed successfully"
+
exit 0
+
else
+
log WARN "Some TODO implementations failed"
+
exit 1
+
fi
+
}
+
# Help function
show_help() {
cat << EOF
···
-s, --shell Open interactive shell in devcontainer (default)
-c, --claude Start interactive Claude session
-o, --ocaml OCaml development mode with history logging
+
--implement-todos Implement pending TODOs from TODO.md non-interactively
+
--show-todos Display current TODO.md contents
+
--clear-todos Clear completed TODOs from TODO.md
OPTIONS:
-f, --force Force rebuild devcontainer from scratch
···
-q, --quiet Minimal output (errors only)
-h, --help Show this help message
--debug Enable debug output
+
--limit N Limit number of TODOs to implement (for --implement-todos)
ENVIRONMENT:
SLOPPER_WORKSPACE Default workspace directory
···
Automation:
./slopper -e "fix the bug in main.ml" # CI/CD code fixes
./slopper -e "write tests for module X" # Automated test generation
+
./slopper --implement-todos # Implement all pending TODO suggestions
+
./slopper --implement-todos --limit 3 # Implement first 3 TODOs
Maintenance:
0 3 * * * slopper -u -q # Cron: nightly container updates
./slopper -f -s # Force rebuild after config changes
+
./slopper --show-todos # View current TODO list
+
./slopper --clear-todos # Clean up completed TODOs
Scripting:
SLOPPER_WORKSPACE=/project slopper -e "refactor all Python files"
···
MODE="ocaml"
shift
;;
+
--implement-todos)
+
[ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; }
+
MODE="implement_todos"
+
shift
+
;;
+
--show-todos)
+
[ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; }
+
MODE="show_todos"
+
shift
+
;;
+
--clear-todos)
+
[ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; }
+
MODE="clear_todos"
+
shift
+
;;
+
--limit)
+
TODO_LIMIT="$2"
+
shift 2
+
;;
-f|--force)
FORCE_REBUILD=true
shift
···
;;
ocaml)
mode_ocaml
+
;;
+
implement_todos)
+
mode_implement_todos
+
;;
+
show_todos)
+
mode_show_todos
+
;;
+
clear_todos)
+
mode_clear_todos
;;
*)
log ERROR "Invalid mode: $MODE"