Commit Graph

10 Commits

Author SHA1 Message Date
Jesse Vincent f156416c49 chore(dist): rebuild bundle from source
Claude-Session: https://claude.ai/code/session_0112vdwZphiWzfCYfaXMes4C
2026-09-08 18:48:09 +00:00
Jesse Vincent 34ed356167 chore(dist): rebuild bundle from source
Regenerates the committed dist from the combined source of the merged fixes, normalizing long-standing bundle drift (stale version, older vendored deps) so dist reproducibly matches src.

Claude-Session: https://claude.ai/code/session_0112vdwZphiWzfCYfaXMes4C
2026-09-08 18:06:11 +00:00
Jesse Vincent 6303454940 fix: single-instance lock for sync --background (#97)
Independent SessionStart events from multiple Claude Code sessions
each fire `episodic-memory sync --background`, which forks a detached
worker. Without coordination, N parents trigger N concurrent worker
processes racing the same archive and SQLite database.

The reentrancy guard (#87) covers same-process recursion, but it
can't stop SessionStart events from independent sessions whose envs
don't carry EPISODIC_MEMORY_SUMMARIZER_GUARD.

Reproduced locally on macOS: 3 parallel `node dist/sync-cli.js`
processes against the same TEST_ARCHIVE_DIR — worker 1 completes;
workers 2 and 3 crash with `SqliteError: database is locked`
(SQLITE_BUSY) trying to init the DB. On Windows, the reporter's
setup with ~67 worktrees instead piles up enough claude.exe children
to exhaust the desktop heap and crash with STATUS_DLL_INIT_FAILED
(0xC0000142). Same root cause; different blast radius depending on
how far the workers get before stepping on each other.

Fix: a single-instance lock around the sync worker, implemented as a
thin wrapper in src/file-lock.ts over the `proper-lockfile` package.
A first attempt at a hand-rolled openSync('wx') + PID-file protocol
had a residual race under concurrent stale-stealers that pure file
primitives cannot fully close without advisory locking.
proper-lockfile uses an atomic-mkdir + mtime-heartbeat protocol that
is race-free under that contention shape — the same approach npm
itself uses.

sync-cli.ts acquires <log-dir>/episodic-memory-sync.lock after the
source-dir check and before initDatabase(); if another live process
holds it, the worker prints "sync already running (pid X); skipping"
to stderr and exits 0. The lock releases on normal exit and on the
common signals (SIGINT/SIGTERM/SIGHUP).

Embedding migration's own lock now delegates to the generic helper;
its old export names (acquireMigrationLock, releaseMigrationLock,
MigrationLockHandle) stay for back-compat.

proper-lockfile is excluded from the esbuild bundle (runtime dep on
the same level as better-sqlite3/transformers/etc.) so the MCP
server bundle size is unchanged. The wrapper's install-health probe
(#95 Bug 1) gains proper-lockfile as a required package so a partial
extraction surfaces a useful diagnostic.

Tests:
- test/file-lock.test.ts: acquire/release, contention,
  parent-dir creation, garbage diagnostic content, I/O error
  propagation, N-concurrent-acquirers stress test, mtime-based
  stale recovery, fresh-lock-not-reclaimable. Subprocess imports
  use pathToFileURL for Windows compatibility.
- test/sync-cli-single-instance.test.ts: integration via real
  child-process spawn — two concurrent workers (one completes,
  one skips), single sequential run still works, lock released
  on normal exit, stale lock from a dead PID is reclaimable.
- Existing test/embedding-migration.test.ts continues to pass.

Closes #97.
2026-05-21 11:26:10 -07:00
Jesse Vincent a97fd5ef3b fix: harden Codex production support 2026-05-12 15:38:46 -07:00
Jesse Vincent 16a391451d build: update generated Codex support artifacts 2026-05-12 13:16:26 -07:00
Jesse Vincent ed99b57770 Release v1.2.0: bge-small-en-v1.5 encoder + auto-migration
Upgraded the embedding model from all-MiniLM-L6-v2 (Xenova transformers
2.x, ORT 1.14) to bge-small-en-v1.5 (HuggingFace transformers 4.x,
ORT 1.24). Measured +6.34 R@1 absolute improvement on a 17K-corpus
retrieval test against real production data — 46.8% to 53.1%, about
a 13.5% relative lift on "right answer first." R@5 +7.1, R@10 +6.7,
MRR +0.067.

Same 384-dim embeddings, so vec_exchanges FLOAT[384] is unchanged.
No bigger model performed better on this content — bge-base, gte-small,
nomic-embed-text-v1.5 (with and without long context), and various
prefix/HyDE/reranking combinations all tested and rejected. Cross-
encoder reranking specifically: zero measurable lift on top of bge-
small for this corpus.

Asymmetric encoding: queries get the BGE retrieval prefix
("Represent this sentence for searching relevant passages: ");
docs stay unmodified. Production was already calling generateEmbedding
directly for queries vs generateExchangeEmbedding for docs, so adding
generateQueryEmbedding splits cleanly along the existing seam.

Auto-migration:
- New embedding_version column tracks which encoder produced each row.
- sync-cli runs runMigrationBatch(500) after normal sync; batched and
  resumable via per-row version tag.
- File-based lock (~/.config/superpowers/conversation-index/
  .embedding-migration.lock) with PID-liveness for stale recovery.
  Concurrent sync processes that find the lock held just skip their
  migration phase; their next sync picks up.
- Single transaction per batch for durability. Crash mid-batch leaves
  unfinished rows tagged for migration, picked up next time.
- Search works throughout: vec_exchanges holds a mix of old- and
  new-encoder vectors during the transition window. Cosine similarity
  is mathematically defined across them; ranking degrades gracefully.
- ~7 min cumulative background work on a 30K-exchange index, spread
  across however many syncs are triggered.

Resolves #82 incidentally — the new ORT 1.24 fixes the protobuf-
parsing crash that broke Node ≤23 setups.

Tests: 10 new (3 query-prefix, 7 migration including end-to-end with
the real encoder + concurrent-lock simulation). Test count 108 → 118.
2026-05-03 17:37:44 -07:00
Jesse Vincent 37be420084 Release v1.1.2: emergency hotfix for recursive process cascade (#87, #88)
The persistSession: false fix in 1.1.0 (#83) only stopped the
SDK-spawned Claude subprocess from saving its session JSONL — it did
not stop the subprocess from firing SessionStart hooks. The plugin's
own SessionStart hook ran 'episodic-memory sync --background', which
re-summarized, which spawned another Claude subprocess, which fired
the hook again. Reporters saw hundreds of detached processes, CPU
saturated, and API quota burning. Multiple users affected.

Fix: a reentrancy-guard env var EPISODIC_MEMORY_SUMMARIZER_GUARD set
when calling the SDK's query(). The SDK passes our env to the spawned
subprocess. The sync-cli entry point checks the guard at startup and
exits silently when it's set, breaking the recursion at the only
intervention point we control.

Tests:
- getApiEnv() always sets the guard
- shouldSkipReentrantSync() reads it correctly
- Spawning dist/sync-cli.js with the guard env exits 0 without doing
  any sync work, even with --background

Anyone running 1.1.0 or 1.1.1 should upgrade immediately.
2026-05-03 11:12:06 -07:00
Jesse Vincent fc1e666993 fix: Resolve 7 open issues — file discovery, search filtering, path handling
- Fix agent definition referencing nonexistent 'show' tool (#62)
- Filter sidechain conversations from search results (#42)
- Add 'clear' to SessionStart hook matcher (#50, closes PR #51)
- Discover subagent conversation files recursively (#72)
- Support both ~/.claude/projects and ~/.claude/transcripts (#68)
- Respect CLAUDE_CONFIG_DIR env var for multiple profiles (#57)
- Surface summarization failures instead of silent Summarized: 0 (#70)
2026-03-27 17:49:38 -07:00
Jesse Vincent 80a657aac7 Add background sync mode to prevent blocking Claude startup
- Add --background flag to sync command that forks process and returns immediately
- Update SessionStart hook to use --background mode
- Maintains full synchronous mode for manual usage
- Resolves startup blocking issue while preserving async: true hook setting

Usage:
- Manual sync: episodic-memory sync (runs synchronously)
- Hook sync: episodic-memory sync --background (returns immediately)

This ensures Claude Code startup is never blocked by sync operations
while still allowing full sync functionality when run manually.
2025-10-31 14:06:56 -07:00
Jesse Vincent 024b0dfb32 Release v1.0.2: Pre-build and commit dist/ directory
Fix MCP server startup error by committing pre-built JavaScript files.
The dist/ directory is now tracked in git to ensure built files are
immediately available after plugin installation without requiring
a build step.

Changes:
- Remove dist/ from .gitignore
- Pre-build and commit all dist/ files
- Bump version to 1.0.2 in package.json, plugin.json, marketplace.json
- Update CHANGELOG.md

Fixes: Error: Cannot find module 'dist/mcp-server.js'
2025-10-23 14:56:31 -07:00