···
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"
# Ensure log and history directories exist
mkdir -p "${HISTORY_DIR}"
+
mkdir -p "$(dirname "${TODO_FILE}")"
···
log DEBUG "Rotated old log files"
+
# Initialize TODO.md file if it doesn't exist
+
if [ ! -f "$TODO_FILE" ]; then
+
cat > "$TODO_FILE" << 'EOF'
+
# Slopper Development TODOs
+
## Pending Setup Improvements
+
log DEBUG "Initialized TODO file: $TODO_FILE"
+
# Add a TODO item to the file
+
local timestamp="$(date '+%Y-%m-%d')"
+
# Find the appropriate section and add the item
+
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"
+
# Use awk to insert the item after the section header
+
awk -v section="$section_line" -v item="- [ ] [$timestamp $session_id] $description" '
+
' "$TODO_FILE" > "$TODO_FILE.tmp" && mv "$TODO_FILE.tmp" "$TODO_FILE"
+
log INFO "Added TODO: $description"
+
# Mark a TODO item as completed
+
local timestamp="$(date '+%Y-%m-%d %H:%M')"
+
if [ ! -f "$TODO_FILE" ]; then
+
log WARN "TODO file does not exist"
+
# 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
+
completed_items[++completed_count] = "- [x] " substr($0, 7) " (completed " timestamp ")"
+
in_completed && !moved && completed_count > 0 {
+
for (i = 1; i <= completed_count; i++) {
+
print completed_items[i]
+
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
+
if [ ! -f "$TODO_FILE" ]; then
+
grep "^- \[ \]" "$TODO_FILE" || true
+
# Parse Claude suggestions and add them to TODO.md
+
process_claude_suggestions_to_todos() {
+
local suggestions_file="$1"
+
if [ ! -f "$suggestions_file" ] || [ ! -s "$suggestions_file" ]; then
+
log WARN "No suggestions file to process"
+
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
+
# 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
+
if [[ "$item" =~ (fix|bug|error|issue) ]]; then
+
elif [[ "$item" =~ (add|implement|feature|new) ]]; then
+
elif [[ "$item" =~ (install|setup|configure|environment) ]]; then
+
add_todo_item "$category" "$item" "$session_id"
+
done < "$suggestions_file"
# Function to check if devcontainer CLI is available
check_devcontainer_cli() {
if ! command -v npx &> /dev/null; then
···
# Execute Claude with the prompt in non-interactive mode
log INFO "Executing Claude prompt..."
···
# Run Claude in non-interactive mode
claude_output=$(npx @devcontainers/cli exec --workspace-folder "${WORKSPACE}" -- \
+
bash -c "cd /workspace && claude --dangerously-skip-permissions < '$prompt_file'" 2>&1) || exit_code=$?
···
if [ "$output_size" -gt 0 ]; then
+
# Output is already on host via bind mount, display it and add to TODO.md
echo "=== Claude Analysis and Suggestions ==="
cat "$claude_output_host"
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"
log WARN "Claude output file is empty or missing"
log DEBUG "Attempting to show stderr from Claude command..."
···
+
# Show TODO.md contents
+
log INFO "Displaying current TODOs"
+
if [ ! -f "$TODO_FILE" ]; then
+
echo "No TODO file found. Run with --ocaml mode first to generate suggestions."
+
# Clear completed TODOs from TODO.md
+
log INFO "Clearing completed TODOs"
+
if [ ! -f "$TODO_FILE" ]; then
+
log WARN "No TODO file found"
+
# Create a new file without completed items
+
BEGIN { in_completed = 0; skip_empty = 0 }
+
/^##/ && !/^## Completed/ {
+
in_completed && /^- \[x\]/ { next }
+
in_completed && /^[[:space:]]*$/ && skip_empty { next }
+
in_completed { skip_empty = 0 }
+
' "$TODO_FILE" > "$TODO_FILE.tmp" && mv "$TODO_FILE.tmp" "$TODO_FILE"
+
log INFO "Completed TODOs cleared from $TODO_FILE"
+
# Implement pending TODOs non-interactively
+
mode_implement_todos() {
+
log INFO "Implementing pending TODOs"
+
if ! check_claude_cli; then
+
if [ ! -f "$TODO_FILE" ]; then
+
echo "No TODO file found. Run with --ocaml mode first to generate suggestions."
+
pending_todos=$(get_pending_todos)
+
if [ -z "$pending_todos" ]; then
+
echo "No pending TODOs to implement."
+
local total_todos=$(echo "$pending_todos" | wc -l)
+
# 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)"
+
log INFO "Found $total_todos pending TODOs to implement"
+
# Process each TODO item
+
while IFS= read -r todo_line; do
+
line_num=$((line_num + 1))
+
if [ -z "$todo_line" ]; then
+
# Extract the description (everything after the checkbox and metadata)
+
if [[ "$todo_line" =~ \[[0-9-]+\ [^]]+\][[:space:]]*(.+)$ ]]; then
+
description="${BASH_REMATCH[1]}"
+
description=$(echo "$todo_line" | sed 's/^- \[ \][[:space:]]*//')
+
if [ -z "$description" ]; then
+
log WARN "Could not parse TODO description from: $todo_line"
+
echo "=== Implementing TODO $line_num/$total_todos ==="
+
echo "Description: $description"
+
# 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
+
claude_output=$(npx @devcontainers/cli exec --workspace-folder "${WORKSPACE}" -- \
+
bash -c "cd /workspace && claude --dangerously-skip-permissions << 'EOF'
+
EOF" 2>&1) || claude_exit_code=$?
+
if [ $claude_exit_code -eq 0 ]; then
+
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"
+
echo "Implementation failed:"
+
log ERROR "Failed to implement: $description"
+
# Brief pause between implementations
+
done <<< "$pending_todos"
+
echo "=== Implementation Summary ==="
+
echo "Total TODOs processed: $total_todos"
+
echo "Successfully implemented: $implemented"
+
if [ $implemented -gt 0 ]; then
+
echo "Updated TODO file: $TODO_FILE"
+
if [ $failed -eq 0 ]; then
+
log INFO "All TODO implementations completed successfully"
+
log WARN "Some TODO implementations failed"
···
-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
-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)
SLOPPER_WORKSPACE Default workspace directory
···
./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
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
SLOPPER_WORKSPACE=/project slopper -e "refactor all Python files"
···
+
[ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; }
+
[ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; }
+
[ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; }
···
log ERROR "Invalid mode: $MODE"