Root cause: plugin registered as directory source in known_marketplaces.json,
which gets wiped on CLI updates. Now registers in extraKnownMarketplaces
(settings.json) as a GitHub source — same mechanism caveman/context-mode use.
Binaries install to ~/.claude-mnemonic/bin/ instead of the Claude-managed
plugins directory. Thin wrapper scripts in the repo let the marketplace
clone find them. Nothing gets cleaned up when Claude refreshes its cache.
Also fixed along the way:
- ONNX Runtime 1.24.3 → 1.26.0 (API v25 mismatch broke all embedding tests)
- Vector client leaked on DB reinit, processQueue had a race on sessionManager
- reloadConfig called os.Exit(0) bypassing graceful shutdown
- Removed dead QueryRowWithTimeout that leaked contexts
- Added tests for graph/watcher/maintenance/update (all were at 0%)
- Add server-side detection of SDK processor's internal system prompt
in handleSessionInit, since CLAUDE_MNEMONIC_INTERNAL env var is not
propagated by Claude Code to hook subprocesses
- Add cross-session duplicate detection (FindRecentPromptByTextGlobal)
to catch same prompt text arriving from different session IDs
- Add hooks, mcpServers, and commands references to plugin.json per
Claude Code plugin spec
- Remove MCP server injection from register-plugin.sh (now in plugin.json)
- Use ${CLAUDE_PLUGIN_ROOT} for statusline path instead of hardcoded path
- Add python3 fallback for plugin registration when jq is unavailable
- Replace hardcoded 1.0.0 version in findWorkerBinary with glob lookup
- Add cache copy verification in register-plugin.sh
- Add update-version Makefile target to keep metadata in sync
- [x] Add type checking and error handling for JSON type assertions in user-prompt hook
- [x] Add error handling for session update query in CreateSDKSession
- [x] Update MCP tool description to reference sqlite-vec instead of ChromaDB
- [x] Fix MinConfidence sentinel value check from 0 to -1
- [x] Pass project parameter to vector search filter in handleSearchByPrompt
- [x] Return empty map instead of nil for successful responses without JSON body
1. Version mismatch restart loop (pkg/hooks/worker.go):
- Added versionsCompatible() and extractBaseVersion() functions
- Hooks no longer restart worker when base versions match (e.g., v0.3.5-dirty ≈ v0.3.5-2-gca711a8-dirty)
2. Auto-update detection (internal/update/update.go):
- isNewerVersion() now extracts base version before comparing
- No longer always reports updates for dirty/dev builds
3. Non-blocking ChromaDB sync (internal/worker/handlers.go):
- SyncUserPrompt now runs in a goroutine with 10-second timeout
- /api/sessions/init responds immediately without waiting for ChromaDB