Address PR #1125 review feedback - both fetches now start simultaneously
via Promise.all instead of sequential-then-parallel.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add systemMessage field to HookResult so SessionStart can display a
colored timeline directly to the user in the CLI. The handler now
parallel-fetches both markdown (for Claude context) and ANSI-colored
(for user display) timelines, appending a viewer URL link.
Also update default settings to hide verbose token columns (read/work
tokens, savings amount) and disable full observation expansion, keeping
the cleaner index-only view by default.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap SDK query loop in try/finally so subprocess cleanup runs on error paths.
Swap Chroma binary check order to try project-level .bin first (common case).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Chroma requires client-side embeddings — the server is storage only.
The previous commit incorrectly removed @chroma-core/default-embed.
Uses DefaultEmbeddingFunction({ wasm: true }) which forces the WASM
backend instead of native ONNX binaries. Same model (all-MiniLM-L6-v2),
same embeddings, but works on all platforms without segfaults or
ENOENT errors (#1104, #1105, #1110).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Strip CLAUDECODE env var from SDK subprocesses to prevent "cannot be
launched inside another Claude Code session" error (Claude Code 2.1.42+)
- Lazy-load @chroma-core/default-embed to avoid eagerly pulling in
sharp native binaries at bundle startup (fixes ERR_DLOPEN_FAILED)
- Add stderr capture to SDK spawn for diagnosing future process failures
- Exclude lockfiles from marketplace rsync and delete stale lockfiles
before npm install to prevent native dep version mismatches
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded TEST-008 build ID with real package version. Add worker
filesystem path, uptime counter, and AI provider status (including last
interaction success/failure tracking) to the health endpoint response.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Missing return statement and closing brace in the programming errors
check caused a build failure after merging main.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduce timeouts to eliminate 10-30s startup delay when worker is dead
(common on WSL2 after hibernate). Add stale PID detection, graceful
error handling across all handlers, and error classification that
distinguishes worker unavailability from handler bugs.
- HEALTH_CHECK 30s→3s, new POST_SPAWN_WAIT (5s), PORT_IN_USE_WAIT (3s)
- isProcessAlive() with EPERM handling, cleanStalePidFile()
- getPluginVersion() try-catch for shutdown race (#1042)
- isWorkerUnavailableError: transport+5xx+429→exit 0, 4xx→exit 2
- No-op handler for unknown event types (#984)
- Wrap all handler fetch calls in try-catch for graceful degradation
- CLAUDE_MEM_HEALTH_TIMEOUT_MS env var override with validation
- Check CLAUDE_MEM_DATA_DIR env var before settings.json (Greptile)
- Derive project before DB check for consistent output (Greptile)
- Include project in error fallback output (Greptile)
- Set executable permission for shebang compatibility (Greptile)
Lightweight script for Claude Code statusLineCommand integration.
Returns per-project observation and prompt counts via direct SQLite
read (~15ms, no HTTP, no worker dependency).
Counts are scoped with WHERE project = ? to prevent inflated totals
from cross-project observations. Supports CLAUDE_MEM_DATA_DIR from
settings.json for custom data directory configurations.
Cherry-picked source changes from PR #657 (224 commits behind main).
Adds `claude-mem generate` and `claude-mem clean` CLI commands:
- New src/cli/claude-md-commands.ts with generateClaudeMd() and cleanClaudeMd()
- Worker service generate/clean case handlers with --dry-run support
- CLAUDE_MD logger component type
- Uses shared isDirectChild from path-utils.ts (DRY improvement over PR original)
Skipped from PR: 91 CLAUDE.md file deletions (stale), build artifacts,
.claude/plans/ dev artifact, smart-install.js shell alias auto-injection
(aggressive profile modification without consent).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bun 1.1.14+ is required because:
- `.changes` property on SQLite statements (added in 1.1.14)
- Multi-statement SQL support in db.run() (fixed in 1.0.26)
Older versions cause silent failures in database migrations.
Fixes#519🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds automatic detection and handling of Zscaler enterprise security certificates
on macOS. Combines standard certifi CA certificates with Zscaler certificates into
a single bundle, passed via SSL_CERT_FILE/REQUESTS_CA_BUNDLE/CURL_CA_BUNDLE env vars
to the chroma-mcp subprocess. Certificate bundle is cached for 24 hours. Falls back
gracefully when Zscaler is not present, with no impact on non-Zscaler environments.
Co-Authored-By: RClark4958 <rickdclark48@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gemini and OpenRouter are stateless APIs that never return session IDs.
Without synthetic IDs, PR #693's defensive memorySessionId checks throw
errors on every observation processing call for these providers.
Generates provider-prefixed IDs (gemini-/openrouter-{contentSessionId}-
{timestamp}) before the first API call, persisted to the database via
updateMemorySessionId(). Applied from PR #615 (closed due to staleness).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add restart limit (max 3 consecutive restarts) with exponential backoff
to prevent infinite generator restart loops. Also add defensive
memorySessionId checks in GeminiAgent and OpenRouterAgent before
expensive LLM calls to fail fast when session ID hasn't been captured.
Based on PR #693 by @ajbmachon (applied to current main).
Co-Authored-By: Andre Machon <ajbmachon2@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Folder CLAUDE.md generation is now gated behind the CLAUDE_MEM_FOLDER_CLAUDEMD_ENABLED
setting (default: false). The setting is exposed via the settings API and handles both
string and boolean JSON values.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add exclusion list for directories where CLAUDE.md generation breaks
toolchains: res/ (Android aapt2), .git/, build/, node_modules/,
__pycache__/. Closes issue #912. Credit to @jayvenn21.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add hasConsecutiveDuplicateSegments() check to isValidPathForClaudeMd() to reject paths
like frontend/frontend/ or src/src/ that occur when cwd already includes the directory name.
3 new tests added (46 total for claude-md-utils). Fixes#814. Credit to @Glucksberg.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents "file modified since read" errors when Claude Code is actively editing
a CLAUDE.md file by detecting CLAUDE.md paths in observation file lists and
skipping those folders during updates. Closes#859. Credit: @cheapsteak.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The startup cleanupOrphanedProcesses() only targeted chroma-mcp, leaving
orphaned mcp-server.cjs and worker-service.cjs processes undetected after
daemon crashes. Expanded to target all claude-mem process types with
30-minute age filtering and current PID exclusion. Closes PR #687 (which
had a spawnDaemon regression removing Windows WMIC support).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On Windows, when the username contains spaces (e.g., "Tafari Higgs"),
bun-runner.js fails with: Syntax Error at C:\Users\Tafari:1:2
This happens because `shell: IS_WINDOWS` (true on Windows) causes
spawn() to route through cmd.exe, which misinterprets the path at
the first space in the username directory.
Removing `shell: true` on Windows fixes the issue since spawn()
can invoke the Bun binary directly without needing a shell wrapper.
Added `windowsHide: true` to prevent a visible console window from
appearing, matching the previous hidden behavior under cmd.exe.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR #896 identified a valid XSS concern in TerminalPreview.tsx but was
broken (missing DOMPurify import and dependency). The existing
escapeXML:true on AnsiToHtml already mitigates the vector, but
DOMPurify adds defense-in-depth sanitization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On fresh installations, smart-install.js installs Bun to ~/.bun/bin/bun
but Bun isn't in PATH until terminal restart. Subsequent hooks fail
because they try to run `bun ...` directly.
This fix introduces bun-runner.js - a Node.js script that finds Bun
in common install locations (not just PATH) and runs commands with it.
All hooks now use `node bun-runner.js ...` instead of `bun ...`.
The bun-runner checks:
- PATH (via which/where)
- ~/.bun/bin/bun (default install location)
- /usr/local/bin/bun
- /opt/homebrew/bin/bun (macOS Homebrew)
- /home/linuxbrew/.linuxbrew/bin/bun (Linuxbrew)
- Windows: %LOCALAPPDATA%\bun or fallback paths
Fixes#818
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Includes PR #745 isolated credentials fix - prevents API key hijacking
from random project .env files by using centralized credentials from
~/.claude-mem/.env
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: add idle timeout to prevent zombie observer processes
Root cause fix for zombie observer accumulation. The SessionQueueProcessor
iterator now exits gracefully after 3 minutes of inactivity instead of
waiting forever for messages.
Changes:
- Add IDLE_TIMEOUT_MS constant (3 minutes)
- waitForMessage() now returns boolean and accepts timeout parameter
- createIterator() tracks lastActivityTime and exits on idle timeout
- Graceful exit via return (not throw) allows SDK to complete cleanly
This addresses the root cause that PR #848 worked around with pattern
matching. Observer processes now self-terminate, preventing accumulation
when session-complete hooks don't fire.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: trigger abort on idle timeout to actually kill subprocess
The previous implementation only returned from the iterator on idle timeout,
but this doesn't terminate the Claude subprocess - it just stops yielding
messages. The subprocess stays alive as a zombie because:
1. Returning from createIterator() ends the generator
2. The SDK closes stdin via transport.endInput()
3. But the subprocess may not exit on stdin EOF
4. No abort signal is sent to kill it
Fix: Add onIdleTimeout callback that SessionManager uses to call
session.abortController.abort(). This sends SIGTERM to the subprocess
via the SDK's ProcessTransport abort handler.
Verified by Codex analysis of the SDK internals:
- abort() triggers ProcessTransport abort handler → SIGTERM
- transport.close() sends SIGTERM → escalates to SIGKILL after 5s
- Just closing stdin is NOT sufficient to guarantee subprocess exit
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: add idle timeout to prevent zombie observer processes
Also cleaned up hooks.json to remove redundant start commands.
The hook command handler now auto-starts the worker if not running,
which is how it should have been since we changed to auto-start.
This maintenance change was done manually.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: resolve race condition in session queue idle timeout detection
- Reset timer on spurious wakeup when queue is empty but duration check fails
- Use optional chaining for onIdleTimeout callback
- Include threshold value in idle timeout log message for better diagnostics
- Add comprehensive unit tests for SessionQueueProcessor
Fixes PR #856 review feedback.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: migrate installer to Setup hook
- Add plugin/scripts/setup.sh for one-time dependency setup
- Add Setup hook to hooks.json (triggers via claude --init)
- Remove smart-install.js from SessionStart hook
- Keep smart-install.js as manual fallback for Windows/auto-install
Setup hook handles:
- Bun detection with fallback locations
- uv detection (optional, for Chroma)
- Version marker to skip redundant installs
- Clear error messages with install instructions
* feat: add np for one-command npm releases
- Add np as dev dependency
- Add release, release:patch, release:minor, release:major scripts
- Add prepublishOnly hook to run build before publish
- Configure np (no yarn, include all contents, run tests)
* fix: reduce PostToolUse hook timeout to 30s
PostToolUse runs on every tool call, 120s was excessive and could cause
hangs. Reduced to 30s for responsive behavior.
* docs: add PR shipping report
Analyzed 6 PRs for shipping readiness:
- #856: Ready to merge (idle timeout fix)
- #700, #722, #657: Have conflicts, need rebase
- #464: Contributor PR, too large (15K+ lines)
- #863: Needs manual review
Includes shipping strategy and conflict resolution order.
* MAESTRO: Verify PR #856 test suite passes
All 797 tests pass (3 skipped, 0 failures). The 11 SessionQueueProcessor
idle timeout tests all pass with 20 expect() assertions verified.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* MAESTRO: Verify PR #856 build passes
- Ran npm run build successfully with no TypeScript errors
- All artifacts generated (worker-service, mcp-server, context-generator, viewer UI)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* MAESTRO: Code review PR #856 implementation verified
Verified all requirements in SessionQueueProcessor.ts:
- IDLE_TIMEOUT_MS = 180000ms (3 minutes)
- waitForMessage() accepts timeout parameter
- lastActivityTime reset on spurious wakeup (race condition fix)
- Graceful exit logs include thresholdMs parameter
- 11 comprehensive test cases in SessionQueueProcessor.test.ts
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: bigph00t <166455923+bigph00t@users.noreply.github.com>
Co-authored-by: root <root@srv1317155.hstgr.cloud>
The previous approach (PR #837) set CLAUDE_CONFIG_DIR to isolate observer
sessions from `claude --resume`. However, this broke authentication because
Claude Code stores credentials in the config directory.
This fix uses the SDK's `cwd` option instead:
- Observer sessions run with cwd=~/.claude-mem/observer-sessions/
- Project name = path.basename(cwd) = "observer-sessions"
- Sessions won't appear when running `claude --resume` from actual projects
- Authentication works because ~/.claude/ config is preserved
Changes:
- ProcessRegistry.ts: Remove CLAUDE_CONFIG_DIR override from spawn
- SDKAgent.ts: Add cwd option to query() pointing to observer dir
- paths.ts: Rename OBSERVER_CONFIG_DIR to OBSERVER_SESSIONS_DIR
Fixes regression from #837
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>