@@ -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+
9591033run_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
10571139run_post_session_tasks () {
@@ -1093,6 +1175,13 @@ if [ -z "$session_id" ]; then
10931175 exit $opencode_exit
10941176fi
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
10971186memory_written_during_session=0
10981187if has_new_memories; then
0 commit comments