Skip to content

Commit 26f3d7b

Browse files
authored
fix: clean up forked sessions after extraction and auto-dream (#14)
1 parent cc511cd commit 26f3d7b

3 files changed

Lines changed: 173 additions & 7 deletions

File tree

bin/opencode-memory

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,80 @@ rollback_consolidation_lock() {
956956
set_file_mtime_secs "$path" "$prior_mtime"
957957
}
958958

959+
cleanup_forked_sessions() {
960+
local before_json="$1"
961+
962+
if ! command -v python3 >/dev/null 2>&1; then
963+
return 0
964+
fi
965+
966+
local after_json
967+
after_json=$(get_session_list_json 10 2>/dev/null || true)
968+
969+
if [ -z "$before_json" ] || [ -z "$after_json" ]; then
970+
return 0
971+
fi
972+
973+
local fork_ids
974+
fork_ids=$(python3 - "$before_json" "$after_json" "$WORKING_DIR" "$PROJECT_SCOPE_DIR" <<'PY'
975+
import json
976+
import os
977+
import sys
978+
979+
def parse(raw):
980+
try:
981+
data = json.loads(raw)
982+
return data if isinstance(data, list) else []
983+
except Exception:
984+
return []
985+
986+
before_raw, after_raw, workdir, project_dir = sys.argv[1:5]
987+
before = parse(before_raw)
988+
after = parse(after_raw)
989+
990+
before_ids = {item.get("id") for item in before if item.get("id")}
991+
workdir = os.path.realpath(workdir)
992+
project_dir = os.path.realpath(project_dir)
993+
994+
for item in after:
995+
sid = item.get("id", "")
996+
if not sid or sid in before_ids:
997+
continue
998+
directory = item.get("directory", "")
999+
if not directory:
1000+
continue
1001+
d = os.path.realpath(directory)
1002+
if d in (workdir, project_dir):
1003+
print(sid)
1004+
PY
1005+
) || return 0
1006+
1007+
while IFS= read -r fork_id; do
1008+
[ -n "$fork_id" ] || continue
1009+
if "$REAL_OPENCODE" session delete "$fork_id" >/dev/null 2>&1; then
1010+
log "Cleaned up forked session $fork_id"
1011+
fi
1012+
done <<< "$fork_ids"
1013+
}
1014+
1015+
session_has_conversation() {
1016+
local session_id="$1"
1017+
local transcript_file
1018+
transcript_file="$(get_transcripts_dir)/${session_id}.jsonl"
1019+
1020+
if [ -f "$transcript_file" ]; then
1021+
local line_count
1022+
line_count=$(wc -l < "$transcript_file")
1023+
# Empty sessions have at most 1 line (the initial user entry with no content).
1024+
# Real sessions have 3+ lines (user + tool_use + tool_result at minimum).
1025+
[ "$line_count" -gt 1 ]
1026+
return $?
1027+
fi
1028+
1029+
# Transcript not found — assume content exists to avoid skipping a valid session.
1030+
return 0
1031+
}
1032+
9591033
run_extraction_if_needed() {
9601034
local session_id="$1"
9611035
local memory_written_during_session="$2"
@@ -985,13 +1059,17 @@ run_extraction_if_needed() {
9851059
fi
9861060
cmd+=("$EXTRACT_PROMPT")
9871061

1062+
local pre_fork_json
1063+
pre_fork_json=$(get_session_list_json 5 2>/dev/null || true)
1064+
9881065
if "${cmd[@]}" >> "$EXTRACT_LOG_FILE" 2>&1; then
9891066
log "Memory extraction completed successfully"
9901067
else
9911068
local code=$?
9921069
log "Memory extraction failed (exit code $code). Check $EXTRACT_LOG_FILE for details"
9931070
fi
9941071

1072+
cleanup_forked_sessions "$pre_fork_json"
9951073
release_simple_lock "$EXTRACT_LOCK_FILE"
9961074
}
9971075

@@ -1043,15 +1121,19 @@ run_autodream_if_needed() {
10431121
fi
10441122
cmd+=("$AUTODREAM_PROMPT")
10451123

1124+
local pre_fork_json
1125+
pre_fork_json=$(get_session_list_json 5 2>/dev/null || true)
1126+
10461127
if "${cmd[@]}" >> "$AUTODREAM_LOG_FILE" 2>&1; then
10471128
log "Auto-dream consolidation completed successfully"
10481129
# Keep lock mtime at "now" to represent last consolidated timestamp.
10491130
else
10501131
local code=$?
10511132
log "Auto-dream consolidation failed (exit code $code). Rolling back gate timestamp"
10521133
rollback_consolidation_lock "$CONSOLIDATION_PRIOR_MTIME"
1053-
return 0
10541134
fi
1135+
1136+
cleanup_forked_sessions "$pre_fork_json"
10551137
}
10561138

10571139
run_post_session_tasks() {
@@ -1093,6 +1175,13 @@ if [ -z "$session_id" ]; then
10931175
exit $opencode_exit
10941176
fi
10951177

1178+
# Step 3.5: Skip if session had no real conversation (e.g. user opened TUI and exited)
1179+
if ! session_has_conversation "$session_id"; then
1180+
log "Session $session_id has no conversation, skipping post-session memory maintenance"
1181+
cleanup_timestamp
1182+
exit $opencode_exit
1183+
fi
1184+
10961185
# Step 4: Check whether main session already wrote memory files
10971186
memory_written_during_session=0
10981187
if has_new_memories; then

package-lock.json

Lines changed: 77 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/opencode-memory.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ JSON
270270
fi
271271
if [ "\${1:-}" = "run" ] && [ "\${2:-}" != "-s" ]; then
272272
mkdir -p "$CLAUDE_CONFIG_DIR/transcripts"
273-
printf '{"type":"user","content":"wrapped"}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_wrapped_target.jsonl"
273+
printf '{"type":"user","content":"wrapped"}\n{"type":"tool_use","content":""}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_wrapped_target.jsonl"
274274
echo "main run ok"
275275
exit 0
276276
fi
@@ -337,7 +337,7 @@ JSON
337337
fi
338338
if [ "\${1:-}" = "run" ] && [ "\${2:-}" != "-s" ]; then
339339
mkdir -p "$CLAUDE_CONFIG_DIR/transcripts"
340-
(sleep 1; printf '{"type":"user","content":"wrapped"}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_delayed_target.jsonl") &
340+
(sleep 1; printf '{"type":"user","content":"wrapped"}\n{"type":"tool_use","content":""}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_delayed_target.jsonl") &
341341
echo "main run ok"
342342
exit 0
343343
fi
@@ -542,9 +542,9 @@ JSON
542542
fi
543543
if [ "\${1:-}" = "run" ] && [ "\${2:-}" != "-s" ]; then
544544
mkdir -p "$CLAUDE_CONFIG_DIR/transcripts" "$HOME/.local/share/opencode/storage/session_diff"
545-
printf '{"type":"user","content":"wrapped"}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_wrapped_target.jsonl"
545+
printf '{"type":"user","content":"wrapped"}\n{"type":"tool_use","content":""}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_wrapped_target.jsonl"
546546
sleep 1
547-
printf '{"type":"user","content":"other"}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_other_repo.jsonl"
547+
printf '{"type":"user","content":"other"}\n{"type":"tool_use","content":""}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_other_repo.jsonl"
548548
echo "main run ok"
549549
exit 0
550550
fi
@@ -658,7 +658,7 @@ if [ "\${1:-}" = "session" ] && [ "\${2:-}" = "list" ]; then
658658
fi
659659
if [ "\${1:-}" = "run" ] && [ "\${2:-}" != "-s" ]; then
660660
mkdir -p "$CLAUDE_CONFIG_DIR/transcripts"
661-
printf '{"type":"user","content":"wrapped"}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_wrapped_target.jsonl"
661+
printf '{"type":"user","content":"wrapped"}\n{"type":"tool_use","content":""}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_wrapped_target.jsonl"
662662
echo "main run ok"
663663
exit 0
664664
fi
@@ -720,7 +720,7 @@ if [ "\${1:-}" = "session" ] && [ "\${2:-}" = "list" ]; then
720720
fi
721721
if [ "\${1:-}" = "run" ] && [ "\${2:-}" != "-s" ]; then
722722
mkdir -p "$CLAUDE_CONFIG_DIR/transcripts"
723-
printf '{"type":"user","content":"wrapped"}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_wrapped_target.jsonl"
723+
printf '{"type":"user","content":"wrapped"}\n{"type":"tool_use","content":""}\n' > "$CLAUDE_CONFIG_DIR/transcripts/ses_wrapped_target.jsonl"
724724
echo "main run ok"
725725
exit 0
726726
fi

0 commit comments

Comments
 (0)