Commit Graph

767 Commits

Author SHA1 Message Date
Alex Newman a60f79c44d feat: file-size threshold and observation dedup for timeline gate
- Skip gate for files under 1,500 bytes — timeline (~370 tokens) costs
  more than just reading small files directly
- Deduplicate observations by memory_session_id (one per session)
- Rank by specificity: files_modified > files_read, fewer tagged files > many
- Fetch 40 candidates, dedup/score down to 15 for display
- Reduce default by-file query limit from 30 to 15

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 13:29:28 -07:00
Alex Newman 17fa383450 Merge main into thedotmack/file-read-timeline-inject
# Conflicts:
#	plugin/scripts/mcp-server.cjs
#	plugin/scripts/worker-service.cjs
2026-04-05 21:37:45 -07:00
Alex Newman 18aa5dc4e7 chore: bump version to 11.0.1
Publish to npm / publish (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 21:08:32 -07:00
Alex Newman 0f9745535a fix: disable semantic inject by default — experimental feature not ready for all users
The per-prompt Chroma vector search injection on UserPromptSubmit adds latency
and context noise. Disable by default while we iterate on a more precise
file-context approach. Users can still opt in via CLAUDE_MEM_SEMANTIC_INJECT=true.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 21:05:03 -07:00
Alex Newman d3262ae1f4 chore: rebuild after merge from main
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 03:01:41 -07:00
Alex Newman 2b8fbcf50e Merge main into thedotmack/file-read-timeline-inject
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 03:00:06 -07:00
Cyrus David Pastelero 0099a196c5 fix: replace GNU sort -V with POSIX-portable version sort
sort -V is a GNU extension not available on macOS/BSD sort. Replaced
with sed 's/^v//' | sort -t. -k1,1n -k2,2n -k3,3n which strips the
'v' prefix, sorts numerically by major.minor.patch, then re-prepends
'v' for the final path. Works on both GNU and BSD sort.
2026-04-05 15:07:35 +08:00
Cyrus David Pastelero 41010c527d fix: resolve node not found on nvm/homebrew installations
Prepend a PATH export to every hook command that invokes node, so that
/bin/sh can locate the binary when Node.js is managed by nvm or
installed via Homebrew. Falls back gracefully when nvm is not present.

Closes #1598
2026-04-05 14:57:04 +08:00
Alex Newman a7ebc35ee0 chore: bump version to 11.0.0
Publish to npm / publish (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 19:39:28 -07:00
Alex Newman 9063c5d8a7 fix: block memory agent prose-skip responses at prompt and runtime levels
Observer prompt now explicitly requires XML observation blocks or empty
responses — prose explanations like "Skipping" are discarded. ResponseProcessor
logs a warning when non-XML content is received. Recording focus expanded to
include concrete debugging findings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 19:39:01 -07:00
Alex Newman 3b34feb779 chore: rebuild plugin artifacts for v10.7.2 with Alessandro's stability PRs (#1607)
Rebuilt worker-service, mcp-server, and viewer-bundle to include:
- SIGTERM drain for orphaned pending messages (#1567)
- Multi-machine sync script (#1570)
- 3 upstream bug fixes: summarize loop, ChromaSync duplicates, TOCTOU port check (#1566)
- Semantic context injection via Chroma (#1568)
- Tier routing by queue complexity (#1569)
- Architecture overview + production guide docs (#1574)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 19:36:32 -07:00
Alex Newman b385570884 chore: bump version to 10.7.2
Publish to npm / publish (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 19:22:50 -07:00
Alex Newman 29ef3f5603 fix: downgrade concept-type cleanup log from error to debug (#1606)
The parser correctly strips observation types from concepts arrays when the
LLM ignores the prompt instruction. This is routine data normalization, not
an error — downgrade to debug to reduce log noise.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 19:21:38 -07:00
Alex Newman bedca129ac chore: bump version to 10.7.1
Publish to npm / publish (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 18:59:00 -07:00
Alex Newman c5129ed016 chore: bump version to 10.7.0
Publish to npm / publish (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 14:58:05 -07:00
Alex Newman 2495f98496 refactor: consolidate MCP factory, add non-TTY support, auto-detect transcript watchers
- Phase 1: Replace 5 duplicate MCP installers with config-driven factory, extract
  shared context-injection and json-utils utilities, fix process.execPath usage
- Phase 2: Add non-TTY fallback for @clack/prompts to prevent ENOENT in CI/Docker
- Phase 3: Wire GeminiCliHooksInstaller through hook command framework with adapter
- Phase 4: Auto-start transcript watchers on worker boot when config exists

Net -107 lines via DRY consolidation of duplicated installer logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:35:55 -07:00
Alex Newman a2ac116aac fix: move summary wait + session-complete into Stop hook to prevent lost summaries
SessionEnd has a 1.5s hardcoded cap from Claude Code (CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS),
making it unsuitable for waiting on async work. Previously, the Stop hook would fire-and-forget
the summarize request, then SessionEnd would immediately call deleteSession — aborting the SDK
agent mid-summary.

Now the Stop hook (120s timeout, no cap) owns the full lifecycle:
1. Queue summarize request
2. Poll new GET /api/sessions/status endpoint until queue drains
3. Call /api/sessions/complete after summary finishes

SessionEnd is now a true fire-and-forget fallback (process.exit(0) immediately).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 14:05:53 -07:00
Alex Newman 8265fc7aa1 Merge remote-tracking branch 'origin/thedotmack/npx-gemini-cli' into thedotmack/npx-gemini-cli
Resolve merge conflicts in adapter index, gemini-cli adapter, and rebuilt CJS artifacts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:47:49 -07:00
Alex Newman 76a880a3d6 feat: update install CLI, ESM compat, and Gemini CLI docs
Fixes CursorHooksInstaller ESM compatibility, updates install command
with improved path resolution, and refreshes built plugin artifacts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 12:38:45 -07:00
Octopus c4146cca67 fix: provide empty JSON fallback when stdin is not piped (fixes #1560) 2026-04-03 10:03:29 +08:00
Alex Newman a66b98bcdd fix: strip <system-reminder> tags from persisted memory and DRY up regex
System reminders (CLAUDE.md contents, deferred tool lists) were being
stored in memory observations. Add system-reminder to the tag stripping
pipeline alongside <private> and <system_instruction>, and extract the
duplicated regex into a shared SYSTEM_REMINDER_REGEX constant.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:25:13 -07:00
Jarvis bd47a919a8 fix: use cmd /c to execute bun.cmd on Windows
Instead of using shell:true with spawn(), use cmd.exe as the command
with /c flag to properly execute bun.cmd on Windows.

Without this, spawn() with shell:true fails because cmd.exe doesn't
know how to handle the bun shell script directly.

Fixes: Stop hook "Failed to start Bun: spawn bun ENOENT"
2026-04-02 13:06:12 +08:00
Jarvis 4d4b0a2f24 fix: prefer bun.cmd over bun shell script on Windows
Windows npm installs both bun (shell script) and bun.cmd (batch file).
When spawning bun, cmd.exe cannot execute the shell script directly.
This change makes findBun() return the full path to bun.cmd on Windows.

Fixes: Stop hook "spawn bun ENOENT" on Windows
2026-04-02 13:00:15 +08:00
Jarvis 472d302133 fix: add shell:true on Windows to spawn bun from npm
Windows npm installs bun as a shell script (C:\Users\...\AppData\Roaming\npm\bun),
not a native executable. Without shell:true, spawn() fails with ENOENT
when trying to execute it.

Fixes Stop hook failure: "Failed to start Bun: spawn bun ENOENT"
2026-04-02 12:50:56 +08:00
Alex Newman 303aafa64b chore: rebuild after merge from main
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 16:11:49 -07:00
Alex Newman 67645041fa Merge main into thedotmack/file-read-timeline-inject
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 16:11:41 -07:00
Ousama Ben Younes d8eb2fa9f9 fix: resolve hook failures when CLAUDE_PLUGIN_ROOT is not injected (#1533)
The fallback path for CLAUDE_PLUGIN_ROOT was pointing to the old
marketplaces install location which no longer exists. Hooks now first
try to find the latest versioned cache directory
(~/.claude/plugins/cache/thedotmack/claude-mem/<version>/) using ls -dt,
with the marketplaces path kept as a final fallback.

This mirrors the self-resolution pattern already used in bun-runner.js
(resolve(__bun_runner_dirname, '..')) but at the shell level, so node
can find bun-runner.js in the first place.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 07:01:37 +00:00
Oracle Public Cloud User 4589b34eab fix: decouple mcp health from loopback self-check 2026-03-30 16:37:56 +00:00
Ryan Malia b0f1a458cf fix: log warning when readiness times out on reused-worker path (#1491)
Mirror the fresh-spawn path's timeout logging for debugging parity.
CodeRabbit nitpick on PR #1491.

Co-Authored-By: CC <noreply@anthropic.com>
2026-03-30 03:47:08 -07:00
Ryan Malia 83f61177c7 fix: address CodeRabbit review feedback on PR #1491
- Update POST_SPAWN_WAIT test assertion from 5000 to 15000 to match
  the constant change in hook-constants.ts
- Remove redundant readPidFile() from aggressiveStartupCleanup() —
  start() writes the new PID before this runs, so it always returns
  process.pid (already protected)
- Add waitForReadiness() to the reused-worker path in
  ensureWorkerStarted() to prevent concurrent hooks from racing
  past a cold-starting worker's initialization guard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 03:43:36 -07:00
Ryan Malia 88b47f9e9c fix: prevent worker daemon from being killed by its own hooks (#1490)
Three independent fixes for worker daemon instability:

1. Remove version mismatch auto-restart from ensureWorkerStarted() (#1435).
   The marketplace bundle ships with __DEFAULT_PACKAGE_VERSION__ unbaked,
   causing BUILT_IN_VERSION to fall back to "development". This creates a
   100% reproducible mismatch on every hook call, killing a healthy worker
   and often failing to restart. Same pattern across #566, #665, #667,
   #669, #689, #1124, #1145 (8+ releases).

2. Add process.ppid and PID-file PID to aggressiveStartupCleanup()
   exclusions (#1426). Without this, a newly spawned daemon SIGKILLs
   the hook process that spawned it and any already-running worker
   the PID file points to.

3. Increase POST_SPAWN_WAIT from 5s to 15s (#1423). The 5s timeout was
   sized for Linux (<1s startup) but macOS ARM64 cold starts take 6-8s
   with Chroma enabled.
2026-03-30 03:43:36 -07:00
Alex Newman ddb57ea598 chore: bump version to 10.6.3
Publish to npm / publish (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 19:49:24 -07:00
Alex Newman 0321f4266d fix: remove import.meta.url banner from CJS files run by Node.js
The MCP server (#!/usr/bin/env node) and context generator run under
Node.js, where import.meta.url throws SyntaxError in CJS mode. Only
the worker-service needs the banner since it runs under Bun.

CJS files under Node.js already have __dirname/__filename natively.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 18:32:43 -07:00
Alex Newman 07ab7000a8 fix: patch 7 critical bugs affecting all non-dev-machine users and Windows
1. Fix esbuild inlining build-machine __dirname as string literal — use
   CJS-compatible runtime banner with require("node:url").fileURLToPath
   across worker-service, mcp-server, and context-generator builds.

2. Fix isMainModule check missing .cjs extension and Windows backslash
   path normalization.

3. Wrap extractLastMessage in try-catch to prevent infinite Stop hook
   feedback loop on malformed transcripts (exit 0 instead of exit 2).

4. Replace heavy SessionEnd hook (Node→Bun→1.7MB CJS→HTTP) with
   lightweight inline node -e one-liner (~200ms vs >1s).

5. Add 7 Gemini/OpenRouter error patterns to unrecoverablePatterns
   circuit breaker to prevent 77K+ retry loops on expired API keys.

6. Preserve CLAUDE_CODE_OAUTH_TOKEN and CLAUDE_CODE_GIT_BASH_PATH in
   sanitizeEnv instead of stripping them with the CLAUDE_CODE_ prefix.

7. Use PowerShell -EncodedCommand for spawnDaemon to fix path quoting
   when Windows usernames contain spaces.

Closes #1515, #1495, #1475, #1465, #1500, #1513, #1512, #1450, #1460,
#1486, #1449, #1481, #1451, #1480, #1453, #1445

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 15:20:29 -07:00
nimesh-kumar-sh a48bf89963 fix: fail worker-start hook if worker never becomes healthy
Address CodeRabbit review: add a final health check after the retry
loop so genuine worker startup failures surface as hook errors instead
of being silently masked.
2026-03-27 13:03:05 -07:00
nimesh-kumar-sh 368daddd88 fix(bun-runner): treat signal-based exits for 'start' as success
Defense-in-depth for #1505. When the 'start' subcommand forks a daemon,
the parent bun process may be killed by signal (exit > 128). If the
close handler fires, treat this as success since the daemon started fine.

Note: the primary fix is in hooks.json since the SIGKILL often kills
the entire process group before this handler fires.
2026-03-27 12:52:36 -07:00
nimesh-kumar-sh ed444dfec7 fix: SessionStart hooks fail on cold start due to worker race condition
The worker-start hook's `start` subcommand forks a daemon then SIGKILLs
its own process group, killing bun-runner.js before it can report exit 0.
Since all SessionStart hooks run in parallel, the context hook also fails
because the worker isn't listening yet.

Fix:
- worker-start: continue after the SIGKILL via `;`, poll the worker
  health endpoint until ready, then output valid JSON (exit 0)
- context: wait for worker health before attempting to fetch context

Fixes #1505
2026-03-27 12:52:02 -07:00
Conductor 5621b67ccd Saving uncommitted changes before archiving 2026-03-26 19:35:27 -07:00
huakson 4f6fb9e614 fix: address platform source review feedback
Tighten platform source persistence so legacy callers cannot silently relabel existing sessions, repair migration 24 when schema_versions drifts from the real schema, and polish the follow-up UI/error-handler review nits.

- only backfill platform_source when it is blank and raise on explicit source conflicts for an existing session
- make migration 24 verify both the sdk_sessions column and its index before treating it as applied
- expose platform_source from the functional session getters and add regression tests for source preservation and schema drift recovery
- add the required APPROVED OVERRIDE annotation for centralized HTTP error translation
- keep mobile source pills on a single horizontal row
2026-03-24 10:46:48 -03:00
huakson 2b60dd2932 feat: isolate Claude and Codex session sources
Persist platform_source across session creation, transcript ingestion, API query paths, and viewer state so Claude and Codex data can coexist without bleeding into each other.

- add platform-source normalization helpers and persist platform_source in sdk_sessions via migration 24 with backfill and indexing
- thread platformSource through CLI hooks, transcript processing, context generation, pagination, search routes, SSE payloads, and session management
- expose source-aware project catalogs, viewer tabs, context preview selectors, and source badges for observations, prompts, and summaries
- start the transcript watcher from the worker for transcript-based clients and preserve platform source during Codex ingestion
- auto-start the worker from the MCP server for MCP-only clients and tighten stdio-driven cleanup during shutdown
- keep createSDKSession backward compatible with existing custom-title callers while allowing explicit platform source forwarding
2026-03-24 08:46:18 -03:00
vnz df1fb8bb89 fix(gemini): add conversation history truncation to prevent O(N²) token cost growth
GeminiAgent sends the full conversation history with every API call,
causing quadratic token growth per session. A 100-observation session
sends ~30M cumulative input tokens. This ports the proven truncateHistory()
sliding window from OpenRouterAgent to GeminiAgent.

- Add CLAUDE_MEM_GEMINI_MAX_CONTEXT_MESSAGES (default: 20) and
  CLAUDE_MEM_GEMINI_MAX_TOKENS (default: 100000) settings
- Add truncateHistory() to GeminiAgent using shared estimateTokens()
- Always preserve at least the newest message to avoid empty API requests
- Add settings validation in SettingsRoutes (1-100 messages, 1K-1M tokens)
- Add regression tests for truncation and oversized single-prompt edge case

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 07:37:58 +01:00
Alex Newman 0524fa83cd chore: bump version to 10.6.2
Publish to npm / publish (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:14:09 -07:00
Alex Newman 4d7bec4d05 fix: stop spinner from spinning forever (#1440)
* fix: stop spinner from spinning forever due to orphaned DB messages

The activity spinner never stopped because isAnySessionProcessing() queried
ALL pending/processing messages in the database, including orphaned messages
from dead sessions that no generator would ever process.

Root cause: isAnySessionProcessing() used hasAnyPendingWork() which is a
global DB scan. Changed it to use getTotalQueueDepth() which only checks
sessions in the active in-memory Map.

Additional fixes:
- Add terminateSession() to enforce restart-or-terminate invariant
- Fix 3 zombie paths in .finally() handler that left sessions alive
- Clean up idle sessions from memory on successful completion
- Remove redundant bare isProcessing:true broadcast
- Replace inline require() with proper accessor
- Add 8 regression tests for session termination invariant

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address review findings — idle-timeout race, double broadcast, query amplification

- Move pendingCount check before idle-timeout termination to prevent
  abandoning fresh messages that arrive between idle abort and .finally()
- Move broadcastProcessingStatus() inside restart branch only — the else
  branch already broadcasts via removeSessionImmediate callback
- Compute queueDepth once in broadcastProcessingStatus() and derive
  isProcessing from it, eliminating redundant double iteration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:13:10 -07:00
Alex Newman c80763390b feat: file-read decision gate — block reads when observation history exists
Add a PreToolUse gate that blocks file reads on first attempt when rich
observation history exists, presenting the timeline as feedback. Claude
then decides: use get_observations() (skip read, save tokens) or re-read
(allowed on second attempt).

- FileReadGate: in-memory session-scoped gate with 4h TTL
- POST /api/file-context/gate endpoint in worker
- stderrMessage plumbing in hook-command for exit code 2
- file-context handler uses gate to block/allow reads

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:11:02 -07:00
Alex Newman 47d6d51030 Merge main into thedotmack/file-read-timeline-inject
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:10:26 -07:00
Alex Newman 9f529a30f5 feat: strip <system_instruction> tags before DB storage (#1398)
* feat: strip <system_instruction> tags before database storage

Extends the existing tag-stripping mechanism (used for <private> and
<claude-mem-context>) to also filter Conductor-injected system instructions,
preventing them from being persisted in the observation database.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: also strip <system-instruction> (hyphen variant) before DB storage

Conductor uses both <system_instruction> and <system-instruction> tag
formats. This adds the hyphen variant to the same stripping mechanism.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:08:25 -07:00
Alex Newman e07b13f7de fix: proper project isolation and relative path matching for file-context hook
- Use getProjectContext(cwd).allProjects for project scoping (same as SessionStart)
- Convert absolute file_path to relative using cwd (observations store relative paths)
- API accepts comma-separated projects param with IN() SQL filter
- Remove basename matching — use full relative path to avoid cross-file collisions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 15:38:53 -07:00
Alex Newman 1d48f63b99 fix: remove project filter from file-context hook — cwd != stored project name
The handler was passing input.cwd (full absolute path) as the project
filter, but observations store short project names ('san-diego', not
'/Users/.../san-diego'). This caused zero results for every query.
Removing the filter entirely is better: cross-project observations
about the same file are useful for duplicate prevention.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 15:24:34 -07:00
Alex Newman fb9d917f8a feat: inject file observation timeline on PreToolUse Read hook
When Claude reads a file, the PreToolUse hook queries for existing
observations about that file and injects the timeline into context
via additionalContext + permissionDecision: allow. This prevents
duplicate observations and saves tokens through active rediscovery.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 15:18:54 -07:00
Alex Newman d54e574251 chore: bump version to 10.6.1
Publish to npm / publish (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 14:36:23 -07:00