fix: respect CLAUDE_CONFIG_DIR in hooks for multi-profile setups#290
fix: respect CLAUDE_CONFIG_DIR in hooks for multi-profile setups#290gjaya79 wants to merge 2 commits into
Conversation
Hooks hardcoded ~/.claude paths, ignoring the CLAUDE_CONFIG_DIR environment variable. This broke setups where users run multiple Claude Code profiles with separate config directories (e.g., CLAUDE_CONFIG_DIR=~/.claude-personal vs ~/.claude-work). All path resolution now checks process.env.CLAUDE_CONFIG_DIR first, falling back to ~/.claude when unset. Affected files: - session-helpers.mjs: added getClaudeConfigDir(), used in getSessionDBPath, getSessionEventsPath, getCleanupFlagPath - pretooluse.mjs: self-heal block (settings.json, installed_plugins) - sessionstart.mjs: CLAUDE.md paths, debug log path - precompact.mjs: debug log path Fixes mksglu#289
|
Thank you @gjaya79 for identifying this issue and putting together the initial fix! 🙏 We've implemented a broader solution directly on What we shippedInstead of patching Verified env vars from upstream source code:
VS Code Copilot, Cursor, and Kiro were verified to have no config dir override env vars. Key improvements over this PR
The underlying issue you identified was absolutely correct — hardcoded Closing in favor of the merged implementation. Thank you for the contribution! |
1. Timeline sort: ContentStore results get timestamp fallback (new Date()) 2. Read path no longer mutates state: knowledge-reuse write removed from ctx_search (read tool should not write) 3. configDir: use CLAUDE_CONFIG_DIR env var + absolute path (fixes #290 regression) 4. SessionDB: open once before query loop, close in finally (was per-query) 5. Auto-memory: 1MB file size guard on readFileSync 6. Debug logging: all catch blocks log with DEBUG=context-mode env var Removes 3 knowledge-reuse tests that validated deleted write-on-read behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: unified persistent memory & timeline search (#363) Two pillars for session continuity after compaction: Pillar 1 — Unified Timeline Search: - ctx_search gains sort="timeline" mode searching 3 sources chronologically - ContentStore (current session) + SessionDB (prior sessions) + auto-memory - Default sort="relevance" preserves current behavior exactly - New searchAllSources() in src/search/unified.ts - SessionDB.searchEvents() with project_dir filter + LIKE escaping - searchAutoMemory() with adapter-aware dash-separated paths - FTS5 schema migration: 4 new UNINDEXED columns (source_category, session_id, event_id, timestamp) Pillar 2 — Auto-Injection on Compaction: - buildAutoInjection() fires ONLY on SessionStart(source="compact") - <behavioral_directive> for roles, <rules> for decisions, <active_skills> for skills - 500 token hard cap with priority-based overflow strategy - Never fires mid-session — context-mode does not pollute the context it protects Static Reinforcement (~99 tokens, session start only): - 12 adapter configs: Session Continuity + MEMORY sections (4 tiers by hook support) - routing-block.mjs: <session_continuity> tag + tool hierarchy 0. MEMORY - ctx_search tool description: SESSION STATE reminder Bug Fixes: - snapshot.ts: add missing case "role" + buildRolesSection() - extract.ts: skill priority P3 → P2 - pi-extension.ts: minPriority 2 → 3 12 New Categories: Phase 1: user-prompt, compaction, rejected-approach, session-resume, constraint, knowledge-reuse Phase 2: agent-finding, error-resolution, external-ref, blocked-on, iteration-loop, latency 8 review rounds, 16+ engineers per round, TDD-first implementation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: move rejected-approach from pretooluse to posttooluse via marker file PreToolUse cannot safely load SessionDB (native module loading breaks hook stdout on CI). Use tmpdir marker file pattern (same as latency) instead: pretooluse writes marker, posttooluse reads and writes event. Also implements knowledge-reuse event (search_hit_prior) with sessionId wiring and 3 new tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: wire searchAllSources into ctx_search handler + skip empty guard for timeline Two critical wiring bugs found by final review: 1. searchAllSources was imported but never called — sort="timeline" silently fell back to ContentStore-only search 2. Empty-index guard blocked timeline mode even when SessionDB had data Now sort="timeline" creates a read-only SessionDB connection and calls searchAllSources() for unified 3-source search. Default sort="relevance" unchanged — calls store.searchWithFallback() directly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: correct tool name prefixes in qwen-code, openclaw, kilo adapter configs - qwen-code: bare ctx_* → mcp__context-mode__ctx_* (22 refs) - openclaw: bare ctx_search → context-mode__ctx_search (line 49) - kilo: bare ctx_search → context-mode_ctx_search (line 49) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR review — 6 blockers resolved 1. Timeline sort: ContentStore results get timestamp fallback (new Date()) 2. Read path no longer mutates state: knowledge-reuse write removed from ctx_search (read tool should not write) 3. configDir: use CLAUDE_CONFIG_DIR env var + absolute path (fixes #290 regression) 4. SessionDB: open once before query loop, close in finally (was per-query) 5. Auto-memory: 1MB file size guard on readFileSync 6. Debug logging: all catch blocks log with DEBUG=context-mode env var Removes 3 knowledge-reuse tests that validated deleted write-on-read behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: timeline timestamp correctness + output format + CI fix 1. auto-memory: set timestamp from file mtime (was missing entirely) 2. ContentStore: use sessionStartTime instead of new Date() per-result 3. Normalize SQLite datetime format to ISO before sort 4. Output headers show origin + timestamp: [prior-session | 2026-04-27 14:30 | source] 5. pretooluse.mjs: move marker writes BEFORE stdout (fixes macOS CI timeout) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: macOS CI + auto-memory match quality + snippet boundaries 1. macOS CI: test sentinel path uses /tmp (matching sentinelDir()) instead of tmpdir() which returns /var/folders/... on macOS — fixes isMCPReady() returning false in CI, causing all redirect assertions to fail 2. Auto-memory: raise minimum term length from 2 to 3 chars, use word boundary regex instead of String.includes() (prevents "if" matching "specific", "definition", etc.) 3. Snippet extraction: walk to nearest paragraph boundary (\n\n) instead of cutting mid-word at arbitrary byte offset Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: surface real timestamps from FTS5 chunks for correct timeline sort ContentStore search results now carry actual indexing timestamps instead of falling back to Date.now(). Changes: 1. store.ts: add chunks.timestamp to all 12 search SQL SELECT statements 2. store.ts: populate timestamp on INSERT with new Date().toISOString() 3. types.ts: add timestamp to SearchResult interface 4. unified.ts: use r.timestamp from ContentStore, fallback sessionStartTime Timeline sort now produces correct chronological ordering across all 3 sources (ContentStore indexed_at, SessionDB created_at, auto-memory mtime). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove session bundle files from PR Session bundles (session-db, session-extract, session-snapshot) are CI-generated artifacts. Only server.bundle.mjs and cli.bundle.mjs belong in commits. CI will regenerate session bundles on merge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove PRD from PR — belongs in issues, not in repo Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Fixes #289
Hooks hardcoded
~/.claudepaths viajoin(homedir(), ".claude", ...), ignoring theCLAUDE_CONFIG_DIRenvironment variable. This broke multi-profile setups where users launch Claude Code with different config directories:All path resolution now checks
process.env.CLAUDE_CONFIG_DIRfirst, falling back to~/.claudewhen unset. No behavior change for single-profile users.Changes
session-helpers.mjs: AddedgetClaudeConfigDir()helper. UpdatedgetSessionDBPath(),getSessionEventsPath(),getCleanupFlagPath()to use it for Claude opts.pretooluse.mjs: Self-heal block now resolvesconfigBasefrom env var forsettings.jsonandinstalled_plugins.jsonpaths.sessionstart.mjs: CLAUDE.md discovery and debug log path respect the env var.precompact.mjs: Debug log path respects the env var.Test plan
CLAUDE_CONFIG_DIR=~/.claude-testand verify session DB is created under~/.claude-test/context-mode/sessions/~/.claude/settings.jsonandinstalled_plugins.json