feat: add OpenCode SQLite session database support - #23
Conversation
|
Just curious, what version of opencode are you running? For me, this change couldn't find anything with opencode v1.3.10 |
Using v1.3.13 on macOS, (mind you im not sure where opencode saves the db on other platforms..) Did you get any error or just no-output/nothing found ? |
Cherry-picked from upstream PR MemPalace#23 (JakobSachs). - Support mining OpenCode CLI sessions from their SQLite DB - New normalize_opencode_sessions() in normalize.py - Usage: `mempalace mine ~/.../opencode.db --mode convos` - Reuses existing conversation mining pipeline - 30 new tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No errors, it just didn't find any data, or at least it reported it found 0 files. I'll update just to be sure and give it another go. NOTE: On Linux I do see the db at ~/.local/share/opencode/opencode.db |
opencode db path |
|
Cool feature but conflicts with main. Can you rebase if you'd like to continue? We'd be interested in OpenCode support. |
74e9c01 to
91a3c5e
Compare
done, rebased 👍 |
Actually, found the issue with this: For some reason on my one Mac OpenCode has a different db path, on my private one it also uses the XDG data dir path (like on linux). pushed a small fix to search both places so we catch all of it now 👍 |
Thank you! Just tried again, it worked for me! I did noticed that there was an unrelated failure: This appears to be due to a breaking change with posthog, but pinning it Nice work! |
PR Review: feat: add OpenCode SQLite session database supportExecutive Summary
Affected Areas: Business Impact: Enables OpenCode users to mine their AI coding sessions into MemPalace — expands supported tool ecosystem. Flow Changes: Adds an early-return path in Ratings
PR Health
High Priority Issues🐛 #1:
|
| Path | Trigger | Behavior |
|---|---|---|
Direct .db file |
mempalace mine opencode.db --mode convos |
Early return → per-project temp dirs → grouped mining |
.db in directory |
mempalace mine ~/chats/ --mode convos |
scan_convos() picks it up → normalize() → _normalize_opencode_sqlite() → ALL sessions concatenated into one blob → single wing/room |
The directory-scan path loses project grouping and dumps all sessions into one flat transcript. Two options:
Option A — Remove .db/.sqlite3/.sqlite from CONVO_EXTENSIONS so only explicit file paths trigger OpenCode mining:
CONVO_EXTENSIONS = {
".txt",
".md",
".json",
".jsonl",
- ".db",
- ".sqlite3",
- ".sqlite",
}Option B — Handle .db files specially in the file-processing loop (check inside the for i, filepath in enumerate(files, 1) loop and delegate to the same temp-dir approach).
Option A is simpler and avoids surprising behavior. Users would need to point directly at the .db file, which is clearer.
🚨 #4: _extract_opencode_messages type hint mismatch
Location: mempalace/normalize.py — _extract_opencode_messages() | Confidence:
The parameter session_id: str = None declares type str but defaults to None. Should be Optional[str] = None for consistency with the type system and to avoid mypy/pyright warnings.
- def _extract_opencode_messages(
- conn: sqlite3.Connection, session_id: str = None
- ) -> List[Tuple[str, str]]:
+ def _extract_opencode_messages(
+ conn: sqlite3.Connection, session_id: Optional[str] = None
+ ) -> List[Tuple[str, str]]:🚨 #5: Error message uses input db_path instead of resolved path
Location: mempalace/normalize.py — normalize_opencode_sessions() | Confidence: ✅ HIGH
When the database is missing required tables, the error message prints the original db_path parameter (which could be None if called without arguments) instead of the resolved path:
- raise IOError(f"Not a recognized OpenCode database (missing tables): {db_path}")
+ raise IOError(f"Not a recognized OpenCode database (missing tables): {resolved}")Low Priority Issues
🎨 #6: Missing space after # in comment
Location: mempalace/normalize.py — above OPENCODE_DB_PATHS | Confidence: ✅ HIGH
PEP 8 requires a space after # in inline comments.
- #List of known opencode db paths
+ # List of known opencode db paths🎨 #7: Test coverage is thin — only happy path
Location: tests/test_normalize.py | Confidence:
The single test test_opencode_sqlite covers only the happy path (valid DB with one session). Missing test scenarios:
- Database without required tables (should raise
IOError) - Empty sessions (< 2 messages, should be skipped)
- Multiple sessions across different project directories
- The
convo_miner.pytemp-dir recursive mining flow json_extractunavailability error path- Tool-call filtering (messages starting with "Called the ")
Not blocking, but the lack of error-path coverage means the resource leak (#2) could go unnoticed.
Flow Impact Analysis
User passes .db directly User passes directory containing .db
│ │
▼ ▼
mine_convos() mine_convos()
convo_path.is_file() ─── True convo_path.is_file() ─── False
│ │
▼ ▼
normalize_opencode_sessions() scan_convos() finds .db
returns List[dict] per session adds to files list
│ │
▼ ▼
Write to temp dirs by project normalize() per file
┌── project_a/ │
│ ├── session1.txt ▼
│ └── session2.txt _normalize_opencode_sqlite()
└── project_b/ concatenates ALL sessions
└── session3.txt into ONE transcript blob
│ │
▼ ▼
Recursive mine_convos() chunk_exchanges() on blob
per project subdir → single wing, single room
→ proper wing per project → project grouping LOST
Created by Octocode MCP https://octocode.ai 🔍🐙
|
@JakobSachs pls see robot review above |
web3guru888
left a comment
There was a problem hiding this comment.
✨ Review of #23 — feat: add OpenCode SQLite session database support
Scope: +201/−7 · 7 file(s)
README.md(modified: +2/−2)mempalace/README.md(modified: +1/−1)mempalace/cli.py(modified: +1/−1)mempalace/convo_miner.py(modified: +34/−1)mempalace/normalize.py(modified: +123/−2)tests/test_normalize.py(modified: +30/−0)uv.lock(modified: +10/−0)
Issues
⚠️ Hardcoded filesystem path — breaks portability
Suggestions
- Magic number(s) 1000 — consider extracting to named constant(s)
Strengths
- ✅ Includes test coverage
🟡 Minor items — good work overall, a few things to address.
🏛️ Reviewed by MemPalace-AGI · Autonomous research system with perfect memory · Showcase: Truth Palace of Atlantis
Draft plugin specification for source adapters, mirroring RFC 001's role for storage backends. Formalizes the contract six community ingester PRs (#274, #23, #169, #232, #567, #98, #702) plus #981's metadata-only mode have been reinventing ad-hoc, so adapter authors can build to a stable surface. Key decisions: - Single ingest() method; lazy adapters yield SourceItemMetadata ahead of drawers, eager adapters interleave - Declared-transformation model (§1.4) replaces informal verbatim promise with a verifiable one; byte_preserving adapters declare the empty set, declared_lossy adapters enumerate. Existing miner.py and the convo_miner+normalize pipeline map cleanly - Palace is the incremental cursor via is_current(item, metadata); no sidecar persistence - Routing is adapter-owned; detect_room/detect_hall move into the filesystem adapter - Flat metadata per ChromaDB (RFC 001 §1.4) — entity hints as json_string field, KG triples route to SQLite knowledge graph - Closets stay core-built as a post-step; adapters may emit flat closet_hints. Closes existing gap where convo drawers get no closets - No per-drawer field renames: source_file, filed_at, source_mtime, added_by, normalize_version, entities, ingest_mode all preserved. Spec adds adapter_name, adapter_version, privacy_class §9 enumerates the cleanup PR prerequisites (mempalace/sources/ module, PalaceContext facade, KnowledgeGraph.add_triple gaining backwards-compatible source_drawer_id + adapter_name params). Tracking issue: #989
…#232 Cursor, #169 Pi, MemPalace#702 Cursor+factory.ai) Updates the multi-agent-support bullet to cite the actual upstream work instead of just gesturing at it. RFC 002 itself is PR MemPalace#990 (tracking issue MemPalace#989). Existing third-party prototypes already proposed against the spec: * OpenCode SQLite — PR #23 * Cursor SQLite — issue #274 * Cursor JSONL (earlier variant) — PR #232 * Pi agent JSONL — PR #169 * Combined Cursor + factory.ai — PR MemPalace#702 Each becomes a mempalace-source-<agent> package once RFC 002 lands. Names the path explicitly: fork unblocks the pattern by helping land RFC 002; per-agent adapter PRs land from their respective authors. Aider, Gemini CLI, Codex CLI, and Warp are roadmap targets without existing adapter PRs and are listed as such (no fabricated PR refs). https://claude.ai/code/session_01GvwducFnFtN8KYmfbWKMR6
|
Hi, thanks for the contribution. This PR has merge conflicts with Could you rebase onto If this change is no longer relevant, feel free to close the PR. (This message is part of a periodic backlog pass, sent to all open PRs that match this state.) |
|
Hi @JakobSachs — thanks for kicking off OpenCode support here, the DB-schema spadework (session / message / part with json_extract, the role-coerce and tool-echo / file-injection skips) is what gave me a clean read on the data when I picked this up. I'm working in @jphein's fork on a version that targets the RFC 002 source-adapter contract (#990 / #989) — Three ways I could see this going, easiest to hardest from your side:
No rush on this — I'm doing local prototyping in parallel so nothing is blocked on a response. Mostly want to make sure the coordination isn't a surprise. |
…purge MemPalace#104 (CRITICAL, data-loss): the sweeper writes drawers with no extract_mode at all (ingest_mode="sweep"). _metadata_matches_extract_mode's legacy-compat rule -- "no extract_mode means treat as a legacy exchange row" -- couldn't tell that apart from a genuine pre-schema convo_miner row, so mempalace mine --mode convos (default extract=exchange) swept every sweeper drawer for a shared transcript into its purge scope and deleted them on the very next re-mine. The legacy-compat fallback now only applies when the drawer is otherwise convo_miner's own (no ingest_mode at all, or convo_miner's own "convos" tag) -- a drawer positively identified as another producer's (sweep, or any other foreign ingest_mode) never matches, using the same ingest_mode discriminator sync.py already relies on for its own registry-row check. MemPalace#105 (MEDIUM, silent-failure): convo_miner's own instance of the purge-failure swallow already fixed for miner.py at MemPalace#23 -- a failed purge in _file_chunks_locked was logged at debug level and mining proceeded anyway, silently producing duplicate/stale drawers under mixed schema versions. Now aborts (returns skipped=True, leaving the old drawers' stored mtime untouched so the next mine retries) and prints a visible warning. 428 tests pass across test_palace.py/test_convo_miner*.py/test_miner.py/ test_sweeper.py/test_hallways.py/test_format_miner.py/test_repair.py, no regressions.
#21 (CRITICAL, data-loss): multi-batch re-mine had no completion marker. A mid-file crash after batch 1 committed but before a later batch left permanently silent partial data -- the surviving drawers shared the file's unchanged on-disk mtime, so file_already_mined() treated the file as fully mined forever. Every chunk now carries chunk_total, and file_already_mined() verifies a matching-mtime group's drawer count reaches chunk_total before reporting True. Drawers with no chunk_total (legacy rows, single-shot add_drawer()) are trusted as before. #22 (HIGH, correctness/TOCTOU): source_mtime was captured via a fresh os.path.getmtime() well after content was read, chunked, and room-detected. A file appended to in that window got its new drawers stamped with an mtime that already matched the (now newer) on-disk state, so the appended tail was silently, permanently skipped on every future mine. _read_text_no_follow now returns (content, mtime) from the same fstat() that validates the file; process_file threads that single value through instead of re-stating. #23 (HIGH, silent-failure): a failed stale-drawer purge was swallowed to a debug log and mining proceeded anyway, silently producing duplicate or orphaned drawers. A purge failure now aborts this file's mine attempt (old drawers' stored mtime is untouched, so the next mine still sees a mismatch and retries) and prints a visible warning, matching every other degraded path in this module. #24 (LOW, data-loss): the old-drawer delete ran unconditionally, but the closet purge+rebuild only ran when drawers_added > 0 -- a file whose chunks all landed below min_chunk_size after boundary-splitting lost its drawers but kept stale closets pointing at now-deleted IDs. purge_file_closets now runs whenever the delete-and-rebuild cycle does, regardless of the new chunk count; only the rebuild itself stays conditional. 169 tests pass across test_miner.py/test_convo_miner*.py/test_palace.py/ test_hallways.py/test_format_miner.py/test_miner_fts5_validation.py, no regressions. Full suite: 1 unrelated pre-existing flake in test_mcp_server.py (module-global peer-writer-lock state leaking across test files in full-suite ordering -- passes standalone and as a full file; the diff here never touches mcp_server.py).
* fix(mcp_server): reset chromadb System cache on staleness reconnect (MemPalace#2002) _get_client() detects a peer writer's inode/mtime change and rebuilds the client via ChromaBackend.make_client(), but chromadb caches its System (and the live in-memory HNSW segment) keyed by path. The rebuilt client is handed back the same stale segment, which on its next _persist() overwrites the on-disk index, destroying records other writers had already indexed. Observed in a live multi-writer palace: the persisted index count went backwards (4 to 3). Call the existing _force_chroma_cache_reset() on the staleness path, before make_client(), so chromadb rebuilds the segment from the on-disk state. The call is guarded by the existing inode_changed/mtime_changed check, so it has no effect on first-open. Adds test_get_client_resets_chroma_system_cache_on_reconnect, which asserts the reset runs before make_client on an mtime reconnect (fails without the fix). Refs MemPalace#1963. * fix(chroma): reset chromadb System cache in ChromaBackend._client() on inode/mtime reopen _client() reconstructs PersistentClient on an inode/mtime change but did not drop chromadb's process-global SharedSystemClient cache first, so the rebuilt client reused the stale path-keyed System (and its in-memory HNSW segment) and could persist an outdated index over on-disk changes -- the same class as MemPalace#2002, reached via _client() instead of _get_client. Add SharedSystemClient.clear_system_cache() to the external-change branch of _client(), mirroring mcp_server._force_chroma_cache_reset (MemPalace#2026) and repair._close_chroma_handles. Backend-level regression test asserts the reset fires on the change reopen, strictly before the reconstruct, and not on first open (chroma-core/chroma#2536, #5843). Fixes MemPalace#2028. * test(chroma): reformat test_backends.py to satisfy ruff format Two monkeypatch.setattr calls were wrapped across lines that fit within the line length; ruff format --check flagged them. Formatter-only, no behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gg6g5efZ1rNbBTHqGz2Tjw * test(mcp_server): re-acquire closets handle after delete_by_source The MemPalace#2002 staleness reconnect makes _get_client() call _force_chroma_cache_reset(), which clears chromadb's path-keyed SharedSystemClient cache. Two TestDeleteBySource tests grabbed a closets collection handle *before* calling tool_delete_by_source and then asserted on it afterwards, by which point the reset had dropped the Rust binding underneath the handle (AttributeError: 'RustBindingsAPI' object has no attribute 'bindings'). Re-acquire the closets collection after the tool call in both tests. Production callers already re-acquire fresh handles per call, so this is a test-lifetime issue, not a regression in the fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gg6g5efZ1rNbBTHqGz2Tjw * fix(miner): close four re-mine safety gaps in process_file MemPalace#21 (CRITICAL, data-loss): multi-batch re-mine had no completion marker. A mid-file crash after batch 1 committed but before a later batch left permanently silent partial data -- the surviving drawers shared the file's unchanged on-disk mtime, so file_already_mined() treated the file as fully mined forever. Every chunk now carries chunk_total, and file_already_mined() verifies a matching-mtime group's drawer count reaches chunk_total before reporting True. Drawers with no chunk_total (legacy rows, single-shot add_drawer()) are trusted as before. MemPalace#22 (HIGH, correctness/TOCTOU): source_mtime was captured via a fresh os.path.getmtime() well after content was read, chunked, and room-detected. A file appended to in that window got its new drawers stamped with an mtime that already matched the (now newer) on-disk state, so the appended tail was silently, permanently skipped on every future mine. _read_text_no_follow now returns (content, mtime) from the same fstat() that validates the file; process_file threads that single value through instead of re-stating. MemPalace#23 (HIGH, silent-failure): a failed stale-drawer purge was swallowed to a debug log and mining proceeded anyway, silently producing duplicate or orphaned drawers. A purge failure now aborts this file's mine attempt (old drawers' stored mtime is untouched, so the next mine still sees a mismatch and retries) and prints a visible warning, matching every other degraded path in this module. MemPalace#24 (LOW, data-loss): the old-drawer delete ran unconditionally, but the closet purge+rebuild only ran when drawers_added > 0 -- a file whose chunks all landed below min_chunk_size after boundary-splitting lost its drawers but kept stale closets pointing at now-deleted IDs. purge_file_closets now runs whenever the delete-and-rebuild cycle does, regardless of the new chunk count; only the rebuild itself stays conditional. 169 tests pass across test_miner.py/test_convo_miner*.py/test_palace.py/ test_hallways.py/test_format_miner.py/test_miner_fts5_validation.py, no regressions. Full suite: 1 unrelated pre-existing flake in test_mcp_server.py (module-global peer-writer-lock state leaking across test files in full-suite ordering -- passes standalone and as a full file; the diff here never touches mcp_server.py). * docs(changelog): tighten 3.7.0 notes to match prior release style Rewrite the 3.7.0 section as short, scannable bullets like 3.6.0 — bold lead, one or two sentences per item, thematically grouped fixes — instead of multi-paragraph issue writeups. * fix(tests): harden hybrid search against empty Windows Chroma reads Windows CI intermittently returns zero hybrid hits right after a fast seed write (same class as "Nothing found on disk" on tiny collections). Close the palace client after seeding so the next open re-reads flushed segments, retry search once if empty, and assert non-empty results with a clear message instead of IndexError. * fix(ingest): never block on a non-regular file (MemPalace#2221) `os.walk` and `glob` list a FIFO, a socket and a device node as ordinary filenames, and MemPalace decides what to read from the suffix. Opening a FIFO for reading parks in the kernel until a writer appears, so a named pipe called `notes.md` in a mined directory wedged `mempalace mine` forever — no output, no error, no progress. `mine --mode convos`, `sweep`, `init`, `compress` and `split` blocked the same way. Two shapes are at fault. Four helpers already refused non-regular files with `fstat` + `S_ISREG`, but the check sat *after* a blocking `os.open`, so it could never run. Adding `O_NONBLOCK` to those opens makes the existing type check reachable: the open returns immediately and the file mode decides, with no errno guesswork. A FIFO that does have a live writer is refused just the same. Linux open(2) states the flag has no effect on regular files; the one exception is a write lease, where a non-blocking open fails EAGAIN instead of waiting out lease-break-time. Leases are granted on regular files only, so that branch re-checks the type and then opens without the flag rather than silently dropping a file that used to be mined. The rest guard with `exists()`, which is true for a pipe, and then open anyway. Those become type checks: a discovery walk drops non-regular entries before any reader sees them, and a fixed-name read decides with `is_file()` instead. `scan_project` and `scan_convos` already stat every candidate for the size limit, so the type check costs no extra syscall. Where the gate replaced an `open` that sat inside a `try`, it goes in the same `try`: `is_file()` raises `PermissionError` on a directory without `x`, which that handler already absorbed. O_NONBLOCK: miner._read_text_no_follow, convo_miner._is_regular_source_file, normalize._read_transcript_file, repair._open_regular_file_no_follow. Type gate: miner.scan_project, miner.load_config, convo_miner.scan_convos, sweeper.parse_claude_jsonl, sweeper.sweep_directory, entity_detector.detect_entities, cli._gather_origin_samples, cli._ensure_mempalace_files_gitignored, cli.cmd_compress, cli.cmd_init, project_scanner._collect_manifest_names, project_scanner._parse_gradle_root_project_name, room_detector_local.detect_rooms_local, llm_refine.collect_corpus_text, split_mega_files.main, hook_shell.count_human_messages. * docs(changelog): note the non-regular-file ingest hang (MemPalace#2221) * fix: 3.7.1 critical patch — re-mine honesty + SIGTERM lock release Stack the post-3.7.0 hang and silent-skip fixes for a fast patch release: - Keep MemPalace#2223 (non-regular file hang) and MemPalace#2088 (chunk_total / same-fstat mtime / purge abort / closet purge) as the base. - On multi-batch upsert failure, delete partial drawers and closets for that source before re-raising so the next mine retries (MemPalace#2122, MemPalace#2151). - Install SIGTERM/SIGHUP handlers in mcp_server.main so atexit can release the palace writer lease (MemPalace#2205). - Adapt non-regular-file tests to the (content, mtime) read return type. * fix(convo): stamp chunk_total and clean partial multi-batch mines (MemPalace#2183) Port project-miner re-mine honesty to conversation ingest so an interrupted transcript mine cannot permanently skip missing exchanges: - stamp chunk_total on every convo drawer in the pass - delete partial drawers for the source/extract_mode on upsert failure - teach prefetch_mined_set the same completeness rule as file_already_mined * test(repair): release SharedSystemClient after seeding for Windows rename In-place rebuild tests archive the palace directory after _seed_palace. backend.close() alone left chromadb's path-keyed System holding files open on Windows (WinError 5), so rebuild_from_sqlite aborted before the mocked upsert path and test_rebuild_from_sqlite_raises_on_upsert_failure never raised RebuildPartialError. Clear the shared cache and GC after close. * chore(release): 3.7.1 Bump package, plugins, lock, OpenClaw skill, and README badge to 3.7.1. Fold Unreleased integrity notes into the 3.7.1 changelog: FIFO ingest hang, project and convo re-mine completeness, chromadb System-cache rewind, and SIGTERM/SIGHUP lease release. * fix(release): preserve fork behavior after upstream sync Keep normalized and subject-routed ingestion compatible with the 3.7.1 re-mine safeguards. Distinguish local Chroma writes from peer changes so cache refreshes release stale clients without invalidating live handles. * fix(ci): record HTTP status before response delivery * fix(ci): normalize SDK HTTP status values * test(ci): make conversation fixtures portable --------- Co-authored-by: Cristian Deheleanu <160292664+colorpanda82@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: KeilerHirsch <KeilerHirsch@users.noreply.github.com> Co-authored-by: Igor Lins e Silva <4753812+igorls@users.noreply.github.com> Co-authored-by: Michael Valentsev <michael@valentsev.ru>
Sub-issue A of MemPalace#23. Pre-flight notes for merging upstream v3.5.0 into kostadis-dev: per-release commit counts (525 total), changelog delta, divergence radar over the original 7 sites, and two NEW divergences not in divergence.md — §8 pluggable-backend collision (hard, decision-required, lands v3.4.0) and §9 Cursor duplication (semantic). Baseline test state: 2013 passed / 15 skipped / 2 pre-existing failures (backend neutralized). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Completes `git merge v3.3.6` on merge/v3.5.0-into-kostadis-dev. 18 conflict files resolved keeping local design at the divergence sites; §2 parallel-mine mechanics ported into the local pipeline (chunk-cap MemPalace#1455, Tier 6a content-date MemPalace#1584, config chunking, skip_reason); §embedding unified (provider switch + within-onnx model select, case-insensitive embedding_model). Fixed a silent auto-merge defect in backends/chroma.py: the merge dropped the `_HNSW_MISSING_METADATA_DATA_FLOOR` constant while keeping its usages, breaking 15 backend/HNSW tests with a NameError. Restored per upstream. Deferred (documented in docs/v3.5.0-merge-notes.md): MemPalace#1383 KG realpath cache canonicalization (kept local _kg_cache keying per §7); prefetch_mined_set. Tests: 2538 passed, 33 skipped, 2 pre-existing failures (baseline), no new failures. ruff-clean on merge-touched files. version.py = 3.3.6. Refs MemPalace#23. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…end framework Completes `git merge v3.4.0`. The §8 reconciliation: adopt upstream's pluggable-backend framework (pgvector/qdrant/sqlite_exact/embedding_wrapper) and keep turbovec re-homed as an entry-point adapter on upstream's BaseBackend. Registry registers the new backends eagerly (lazy client deps) while keeping chroma best-effort/lazy so turbovec-only deploys never import chromadb. Kept local design at the divergence sites (§1 two-list search, §2 parallel mine pipeline, §3 per-palace cache + palace= arg + PalaceNotDeclared); ported v3.4.0 mechanics (collision-safe drawer IDs, MemPalace#1245 filter-fallback bugfix, --backend flag, MemPalace#1573 quarantine re-arm). Adopted upstream's refined HNSW quarantine (subsumes local MemPalace#1532/#0991677 intent). Fixed silent auto-merge defects in NON-conflict files (same class as B's chroma.py NameError): mcp_server _collection_error_or_no_palace / tool_reconnect referencing dropped scalars, searcher.search_within stitched to an undefined helper, convo_miner dropped hashlib import. Known limitation (pre-existing HEAD design, not a regression): mcp_server _get_collection stays chroma-centric; turbovec MCP path unverified end-to-end (turbovecdb absent). See docs/v3.5.0-merge-notes.md §Sub-issue C. Tests: 2701 passed, 43 skipped, 2 pre-existing failures (baseline), no new failures. ruff-clean. version.py = 3.4.0. Refs MemPalace#23. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Completes `git merge v3.4.1` (patch release: Cursor plugin/hooks, Antigravity, embeddinggemma OOM sub-batching, backup retention). Kept local design at the divergence sites; §9 Cursor duplication coexists (upstream bash hooks/cursor/ + local Python harness). embeddinggemma OOM fix folded into the kept EmbeddinggemmaONNX; namespaced onnx cache key kept. Fixed silent auto-merge defects (same class as B/C): dropped _metadata_cache scalar leaks in mcp_server rerouted to _invalidate_metadata_cache(); tool_search first-call missing collection_name; test_cli repair mocks needed resolved_palace_path; and a test-isolation pollution (local test_config_palace_migration reload rebinding DEFAULT_PALACE_PATH broke v3.4.1's test_hallways_palace_scoped) fixed via snapshot/restore. Flagged for follow-up (deferred, not a regression): local --limit is a pre-slice vs upstream MemPalace#1535 "stop after N new"; port into the parallel consumer TBD. See docs/v3.5.0-merge-notes.md §Sub-issue D. Tests: 3118 passed, 48 skipped, 2 pre-existing failures (baseline). ruff-clean. version.py = 3.4.1. Refs MemPalace#23. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…arget Completes `git merge v3.5.0`. version.py = 3.5.0 — the migration target. New v3.5.0 features adopted into the local design: source_file search filter (threaded through the two-list primary path), mempalace_checkpoint / mempalace_delete_by_source MCP tools, SQLite status fast-path (gated on the default palace so cross-palace `palace=` addressing still works), opt-in daemon + HTTP transport, sqlite_read_uri. Kept local design at all divergence sites (§1 two-list search, §3 per-palace cache + palace isolation, §5 Python multi-harness hooks). Fixed silent auto-merge defects (same class as B/C/D): tool_delete_by_source writing a nonexistent _metadata_cache global; status fast-path omitting palace_path; test stubs/mocks lagging the merged EF and palace-resolution interfaces. Tests: 3366 passed, 65 skipped, 1 pre-existing failure (test_hook_chat_palace §5); the former test_sync baseline failure is now cleanly skipped per §3. ruff-clean. Refs MemPalace#23. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Retitle kostadis-dev-vs-v3.3.5 → v3.5.0; context updated to 67 local commits merged current through v3.5.0 via the five-release chain. The seven original structural divergences (§1–§7) held unchanged through v3.5.0; added five new sections from the v3.4.0–v3.5.0 merges: §8 backend layer (converged onto upstream), §9 Cursor duplication, §10 embedding unification, §11 HNSW quarantine (converged), §12 --limit semantics (open, deferred). Refreshed the Test-impact section to the v3.5.0 counts (3366 pass / 65 skip / 1 pre-existing failure) with per-site skip mapping, and added a Deferred-follow-ups section (--limit MemPalace#1535, MemPalace#1383 KG canonicalization, is_default status gating, turbovec MCP end-to-end verification). Added a note on the silent auto-merge defects that recurred across all five merges. version.py already reconciled to 3.5.0 in sub-issue E. Refs MemPalace#23. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Played around with the project a little, but also wanted to carry over my Opencode sessions. The patch should hopefully be as minimal as possible.
Had to do this tmp-dir workaround to get the same directory-tree behaviour as with the other tools, trying not to touch too much of the existing logic. So it uses the dir-column in the DB to create a tmp-dir structure.
The table:
becomes
which is then handled the same way how claude-code/chatgpt/etc. ingestion works.
Ingest should work via:
mempalace mine ~/.local/share/opencode/opencode.db --mode convosTests + Lint should be clean