···
WORKSPACE="${SLOPPER_WORKSPACE:-$(pwd)}"
# For OCaml mode, use workspace-local .slopper directory to work with container mount
HISTORY_DIR="${WORKSPACE}/.slopper/history"
29
+
TODO_FILE="${WORKSPACE}/.slopper/TODO.md"
# Ensure log and history directories exist
mkdir -p "${HISTORY_DIR}"
39
+
mkdir -p "$(dirname "${TODO_FILE}")"
···
log DEBUG "Rotated old log files"
81
+
# Initialize TODO.md file if it doesn't exist
83
+
if [ ! -f "$TODO_FILE" ]; then
84
+
cat > "$TODO_FILE" << 'EOF'
85
+
# Slopper Development TODOs
87
+
## Pending Setup Improvements
89
+
## Pending Code Fixes
95
+
log DEBUG "Initialized TODO file: $TODO_FILE"
99
+
# Add a TODO item to the file
101
+
local category="$1"
102
+
local description="$2"
103
+
local session_id="$3"
104
+
local timestamp="$(date '+%Y-%m-%d')"
108
+
# Find the appropriate section and add the item
110
+
case "$category" in
112
+
section_line="## Pending Setup Improvements"
114
+
"fix"|"Fix"|"fixes"|"Fixes")
115
+
section_line="## Pending Code Fixes"
117
+
"feature"|"Feature"|"features"|"Features")
118
+
section_line="## Pending Features"
121
+
section_line="## Pending Setup Improvements"
125
+
# Use awk to insert the item after the section header
126
+
awk -v section="$section_line" -v item="- [ ] [$timestamp $session_id] $description" '
133
+
' "$TODO_FILE" > "$TODO_FILE.tmp" && mv "$TODO_FILE.tmp" "$TODO_FILE"
135
+
log INFO "Added TODO: $description"
138
+
# Mark a TODO item as completed
139
+
complete_todo_item() {
140
+
local description="$1"
141
+
local timestamp="$(date '+%Y-%m-%d %H:%M')"
143
+
if [ ! -f "$TODO_FILE" ]; then
144
+
log WARN "TODO file does not exist"
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 ")"
161
+
in_completed && !moved && completed_count > 0 {
162
+
for (i = 1; i <= completed_count; i++) {
163
+
print completed_items[i]
165
+
completed_count = 0
169
+
if (completed_count > 0) {
170
+
for (i = 1; i <= completed_count; i++) {
171
+
print completed_items[i]
175
+
' "$TODO_FILE" > "$TODO_FILE.tmp" && mv "$TODO_FILE.tmp" "$TODO_FILE"
177
+
log INFO "Marked TODO as completed: $description"
180
+
# Get pending TODO items
181
+
get_pending_todos() {
182
+
if [ ! -f "$TODO_FILE" ]; then
186
+
grep "^- \[ \]" "$TODO_FILE" || true
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"
194
+
if [ ! -f "$suggestions_file" ] || [ ! -s "$suggestions_file" ]; then
195
+
log WARN "No suggestions file to process"
199
+
log INFO "Processing Claude suggestions and adding to TODO.md..."
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
209
+
# Look for lines that seem like actionable items
210
+
if [[ "$line" =~ ^[[:space:]]*[-*][[:space:]]+(.+)$ ]] ||
211
+
[[ "$line" =~ ^[[:space:]]*[0-9]+\.[[:space:]]+(.+)$ ]]; then
213
+
local item="${BASH_REMATCH[1]}"
215
+
# Categorize the item based on keywords
216
+
local category="setup"
217
+
if [[ "$item" =~ (fix|bug|error|issue) ]]; then
219
+
elif [[ "$item" =~ (add|implement|feature|new) ]]; then
221
+
elif [[ "$item" =~ (install|setup|configure|environment) ]]; then
225
+
add_todo_item "$category" "$item" "$session_id"
227
+
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
182
-
# Using --yes to skip unsafe operation confirmations
log INFO "Executing Claude prompt..."
···
# Run Claude in non-interactive mode
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=$?
···
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
echo "=== Claude Analysis and Suggestions ==="
cat "$claude_output_host"
echo "Analysis saved to: $claude_output_host"
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"
log WARN "Claude output file is empty or missing"
log DEBUG "Attempting to show stderr from Claude command..."
···
675
+
# Show TODO.md contents
676
+
mode_show_todos() {
677
+
log INFO "Displaying current TODOs"
679
+
if [ ! -f "$TODO_FILE" ]; then
680
+
echo "No TODO file found. Run with --ocaml mode first to generate suggestions."
688
+
# Clear completed TODOs from TODO.md
689
+
mode_clear_todos() {
690
+
log INFO "Clearing completed TODOs"
692
+
if [ ! -f "$TODO_FILE" ]; then
693
+
log WARN "No TODO file found"
697
+
# Create a new file without completed items
699
+
BEGIN { in_completed = 0; skip_empty = 0 }
706
+
/^##/ && !/^## Completed/ {
712
+
in_completed && /^- \[x\]/ { next }
713
+
in_completed && /^[[:space:]]*$/ && skip_empty { next }
714
+
in_completed { skip_empty = 0 }
716
+
' "$TODO_FILE" > "$TODO_FILE.tmp" && mv "$TODO_FILE.tmp" "$TODO_FILE"
718
+
log INFO "Completed TODOs cleared from $TODO_FILE"
722
+
# Implement pending TODOs non-interactively
723
+
mode_implement_todos() {
724
+
log INFO "Implementing pending TODOs"
726
+
check_devcontainer_cli
727
+
ensure_devcontainer
729
+
if ! check_claude_cli; then
734
+
if [ ! -f "$TODO_FILE" ]; then
735
+
echo "No TODO file found. Run with --ocaml mode first to generate suggestions."
740
+
# Get pending TODOs
741
+
local pending_todos
742
+
pending_todos=$(get_pending_todos)
744
+
if [ -z "$pending_todos" ]; then
745
+
echo "No pending TODOs to implement."
750
+
local total_todos=$(echo "$pending_todos" | wc -l)
751
+
local implemented=0
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)"
761
+
log INFO "Found $total_todos pending TODOs to implement"
763
+
# Process each TODO item
765
+
while IFS= read -r todo_line; do
766
+
line_num=$((line_num + 1))
768
+
if [ -z "$todo_line" ]; then
772
+
# Extract the description (everything after the checkbox and metadata)
774
+
if [[ "$todo_line" =~ \[[0-9-]+\ [^]]+\][[:space:]]*(.+)$ ]]; then
775
+
description="${BASH_REMATCH[1]}"
778
+
description=$(echo "$todo_line" | sed 's/^- \[ \][[:space:]]*//')
781
+
if [ -z "$description" ]; then
782
+
log WARN "Could not parse TODO description from: $todo_line"
787
+
echo "=== Implementing TODO $line_num/$total_todos ==="
788
+
echo "Description: $description"
791
+
# Create focused implementation prompt
792
+
local impl_prompt="Implement this specific task: $description
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
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."
804
+
log INFO "Implementing: $description"
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
811
+
claude_output=$(npx @devcontainers/cli exec --workspace-folder "${WORKSPACE}" -- \
812
+
bash -c "cd /workspace && claude --dangerously-skip-permissions << 'EOF'
814
+
EOF" 2>&1) || claude_exit_code=$?
816
+
if [ $claude_exit_code -eq 0 ]; then
817
+
echo "$claude_output"
819
+
log INFO "Successfully implemented: $description"
821
+
# Mark as completed in TODO.md
822
+
complete_todo_item "$description"
823
+
implemented=$((implemented + 1))
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"
834
+
echo "Implementation failed:"
835
+
echo "$claude_output"
837
+
log ERROR "Failed to implement: $description"
838
+
failed=$((failed + 1))
841
+
# Brief pause between implementations
844
+
done <<< "$pending_todos"
847
+
echo "=== Implementation Summary ==="
848
+
echo "Total TODOs processed: $total_todos"
849
+
echo "Successfully implemented: $implemented"
850
+
echo "Failed: $failed"
853
+
if [ $implemented -gt 0 ]; then
854
+
echo "Updated TODO file: $TODO_FILE"
859
+
if [ $failed -eq 0 ]; then
860
+
log INFO "All TODO implementations completed successfully"
863
+
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
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
-f, --force Force rebuild devcontainer from scratch
···
-q, --quiet Minimal output (errors only)
-h, --help Show this help message
--debug Enable debug output
891
+
--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
905
+
./slopper --implement-todos # Implement all pending TODO suggestions
906
+
./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
911
+
./slopper --show-todos # View current TODO list
912
+
./slopper --clear-todos # Clean up completed TODOs
SLOPPER_WORKSPACE=/project slopper -e "refactor all Python files"
···
959
+
[ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; }
960
+
MODE="implement_todos"
964
+
[ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; }
969
+
[ -n "$MODE" ] && { log ERROR "Multiple modes specified"; exit 1; }
···
1036
+
mode_implement_todos
log ERROR "Invalid mode: $MODE"