opencode-claude-memory 1.6.3 → 1.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bin/opencode-memory +119 -17
  2. package/package.json +1 -1
@@ -473,6 +473,41 @@ get_latest_session_id() {
473
473
  fi
474
474
  }
475
475
 
476
+ get_opencode_db_path() {
477
+ printf '%s\n' "$HOME/.local/share/opencode/opencode.db"
478
+ }
479
+
480
+ get_session_title_from_db() {
481
+ local session_id="$1"
482
+ local db_path
483
+ db_path=$(get_opencode_db_path)
484
+
485
+ if [ -z "$session_id" ] || [ ! -f "$db_path" ] || ! command -v python3 >/dev/null 2>&1; then
486
+ return 1
487
+ fi
488
+
489
+ python3 - "$db_path" "$session_id" <<'PY'
490
+ import sqlite3
491
+ import sys
492
+
493
+ db_path, session_id = sys.argv[1:3]
494
+
495
+ try:
496
+ conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
497
+ row = conn.execute("SELECT title FROM session WHERE id = ? LIMIT 1", (session_id,)).fetchone()
498
+ except Exception:
499
+ raise SystemExit(1)
500
+ finally:
501
+ try:
502
+ conn.close()
503
+ except Exception:
504
+ pass
505
+
506
+ if row and row[0]:
507
+ print(row[0])
508
+ PY
509
+ }
510
+
476
511
  get_session_target_id() {
477
512
  local before_json="$1"
478
513
  local started_at_ms="$2"
@@ -834,6 +869,78 @@ wait_for_session_target_id() {
834
869
  wait_for_scoped_session_id_since "$before_json" "$started_at_ms" "$TIMESTAMP_FILE" "$wait_seconds"
835
870
  }
836
871
 
872
+ get_fork_cleanup_candidate_id() {
873
+ local started_at_ms="$1"
874
+ local parent_title="$2"
875
+ local workdir="$3"
876
+ local project_dir="$4"
877
+ local db_path
878
+ db_path=$(get_opencode_db_path)
879
+
880
+ if [ -z "$started_at_ms" ] || [ -z "$parent_title" ] || [ ! -f "$db_path" ] || ! command -v python3 >/dev/null 2>&1; then
881
+ return 1
882
+ fi
883
+
884
+ python3 - "$db_path" "$started_at_ms" "$parent_title" "$workdir" "$project_dir" <<'PY'
885
+ import os
886
+ import re
887
+ import sqlite3
888
+ import sys
889
+
890
+ db_path, started_at_ms_raw, parent_title, workdir, project_dir = sys.argv[1:6]
891
+ started_at_ms = int(started_at_ms_raw or "0")
892
+ scope = {os.path.realpath(path) for path in (workdir, project_dir) if path}
893
+ title_pattern = re.compile(rf"^{re.escape(parent_title)} \(fork #\d+\)$")
894
+
895
+ try:
896
+ conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
897
+ rows = conn.execute(
898
+ "SELECT id, title, directory, time_created FROM session WHERE time_created >= ? ORDER BY time_created DESC",
899
+ (started_at_ms,),
900
+ ).fetchall()
901
+ except Exception:
902
+ raise SystemExit(1)
903
+ finally:
904
+ try:
905
+ conn.close()
906
+ except Exception:
907
+ pass
908
+
909
+ matches = []
910
+ for session_id, title, directory, time_created in rows:
911
+ if not session_id or not title or not directory or not time_created:
912
+ continue
913
+ if os.path.realpath(directory) not in scope:
914
+ continue
915
+ if not title_pattern.match(title):
916
+ continue
917
+ matches.append(session_id)
918
+
919
+ if len(matches) == 1:
920
+ print(matches[0])
921
+ PY
922
+ }
923
+
924
+ wait_for_fork_cleanup_candidate_id() {
925
+ local started_at_ms="$1"
926
+ local parent_title="$2"
927
+ local wait_seconds="${3:-5}"
928
+ local attempt=0
929
+ local session_id=""
930
+
931
+ while [ "$attempt" -lt "$wait_seconds" ]; do
932
+ session_id=$(get_fork_cleanup_candidate_id "$started_at_ms" "$parent_title" "$WORKING_DIR" "$PROJECT_SCOPE_DIR" || true)
933
+ if [ -n "$session_id" ]; then
934
+ printf '%s\n' "$session_id"
935
+ return 0
936
+ fi
937
+ sleep 1
938
+ attempt=$((attempt + 1))
939
+ done
940
+
941
+ return 1
942
+ }
943
+
837
944
  file_mtime_secs() {
838
945
  local file="$1"
839
946
  if [ ! -f "$file" ]; then
@@ -973,11 +1080,10 @@ rollback_consolidation_lock() {
973
1080
  }
974
1081
 
975
1082
  cleanup_forked_sessions() {
976
- local before_json="$1"
977
- local started_at_ms="$2"
978
- local timestamp_file="$3"
1083
+ local started_at_ms="$1"
1084
+ local parent_title="$2"
979
1085
 
980
- if [ -z "$before_json" ] || [ -z "$started_at_ms" ] || [ -z "$timestamp_file" ]; then
1086
+ if [ -z "$started_at_ms" ] || [ -z "$parent_title" ]; then
981
1087
  return 0
982
1088
  fi
983
1089
 
@@ -993,7 +1099,7 @@ PY
993
1099
  fi
994
1100
 
995
1101
  local fork_id
996
- fork_id=$(wait_for_scoped_session_id_since "$before_json" "$started_at_ms" "$timestamp_file" "$SESSION_WAIT_SECONDS" 0 || true)
1102
+ fork_id=$(wait_for_fork_cleanup_candidate_id "$started_at_ms" "$parent_title" "$SESSION_WAIT_SECONDS" || true)
997
1103
 
998
1104
  [ -n "$fork_id" ] || return 0
999
1105
 
@@ -1040,6 +1146,9 @@ run_extraction_if_needed() {
1040
1146
  log "Extracting memories from session $session_id..."
1041
1147
  log "Extraction log: $EXTRACT_LOG_FILE"
1042
1148
 
1149
+ local parent_session_title
1150
+ parent_session_title=$(get_session_title_from_db "$session_id" || true)
1151
+
1043
1152
  local cmd=("$REAL_OPENCODE" run -s "$session_id" --fork --dir "$WORKING_DIR")
1044
1153
  if [ -n "$EXTRACT_MODEL" ]; then
1045
1154
  cmd+=(-m "$EXTRACT_MODEL")
@@ -1049,10 +1158,6 @@ run_extraction_if_needed() {
1049
1158
  fi
1050
1159
  cmd+=("$EXTRACT_PROMPT")
1051
1160
 
1052
- local pre_fork_json
1053
- pre_fork_json=$(get_session_list_json "$AUTODREAM_SCAN_LIMIT" 2>/dev/null || true)
1054
- local fork_timestamp_file
1055
- fork_timestamp_file=$(mktemp)
1056
1161
  local fork_started_at_ms
1057
1162
  fork_started_at_ms=$(( $(date +%s) * 1000 ))
1058
1163
 
@@ -1063,8 +1168,7 @@ run_extraction_if_needed() {
1063
1168
  log "Memory extraction failed (exit code $code). Check $EXTRACT_LOG_FILE for details"
1064
1169
  fi
1065
1170
 
1066
- cleanup_forked_sessions "$pre_fork_json" "$fork_started_at_ms" "$fork_timestamp_file"
1067
- rm -f "$fork_timestamp_file"
1171
+ cleanup_forked_sessions "$fork_started_at_ms" "$parent_session_title"
1068
1172
  release_simple_lock "$EXTRACT_LOCK_FILE"
1069
1173
  }
1070
1174
 
@@ -1107,6 +1211,9 @@ run_autodream_if_needed() {
1107
1211
  log "Auto-dream firing (${hours_since}h since last consolidation, ${touched_count} sessions touched)"
1108
1212
  log "Auto-dream log: $AUTODREAM_LOG_FILE"
1109
1213
 
1214
+ local parent_session_title
1215
+ parent_session_title=$(get_session_title_from_db "$session_id" || true)
1216
+
1110
1217
  local cmd=("$REAL_OPENCODE" run -s "$session_id" --fork --dir "$WORKING_DIR")
1111
1218
  if [ -n "$AUTODREAM_MODEL" ]; then
1112
1219
  cmd+=(-m "$AUTODREAM_MODEL")
@@ -1116,10 +1223,6 @@ run_autodream_if_needed() {
1116
1223
  fi
1117
1224
  cmd+=("$AUTODREAM_PROMPT")
1118
1225
 
1119
- local pre_fork_json
1120
- pre_fork_json=$(get_session_list_json "$AUTODREAM_SCAN_LIMIT" 2>/dev/null || true)
1121
- local fork_timestamp_file
1122
- fork_timestamp_file=$(mktemp)
1123
1226
  local fork_started_at_ms
1124
1227
  fork_started_at_ms=$(( $(date +%s) * 1000 ))
1125
1228
 
@@ -1132,8 +1235,7 @@ run_autodream_if_needed() {
1132
1235
  rollback_consolidation_lock "$CONSOLIDATION_PRIOR_MTIME"
1133
1236
  fi
1134
1237
 
1135
- cleanup_forked_sessions "$pre_fork_json" "$fork_started_at_ms" "$fork_timestamp_file"
1136
- rm -f "$fork_timestamp_file"
1238
+ cleanup_forked_sessions "$fork_started_at_ms" "$parent_session_title"
1137
1239
  }
1138
1240
 
1139
1241
  run_post_session_tasks() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-claude-memory",
3
- "version": "1.6.3",
3
+ "version": "1.6.4",
4
4
  "type": "module",
5
5
  "description": "Claude Code-compatible memory compatibility layer for OpenCode — zero config, local-first, no migration",
6
6
  "main": "dist/index.js",