feat: Live Context System with Distributed CLAUDE.md Generation (#556)
* docs: add folder index generator plan RFC for auto-generating folder-level CLAUDE.md files with observation timelines. Includes IDE symlink support and root CLAUDE.md integration. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: implement folder index generator (Phase 1) Add automatic CLAUDE.md generation for folders containing observed files. This enables IDE context providers to access relevant memory observations. Core modules: - FolderDiscovery: Extract folders from observation file paths - FolderTimelineCompiler: Compile chronological timeline per folder - ClaudeMdGenerator: Write CLAUDE.md with tag-based content replacement - FolderIndexOrchestrator: Coordinate regeneration on observation save Integration: - Event-driven regeneration after observation save in ResponseProcessor - HTTP endpoints for folder discovery, timeline, and manual generation - Settings for enabling/configuring folder index behavior The <claude-mem-context> tag wrapping ensures: - Manual CLAUDE.md content is preserved - Auto-generated content won't be recursively observed - Clean separation between user and system content 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add updateFolderClaudeMd function to CursorHooksInstaller Adds function to update CLAUDE.md files for folders touched by observations. Uses existing /api/search/by-file endpoint, preserves content outside <claude-mem-context> tags, and writes atomically via temp file + rename. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: hook updateFolderClaudeMd into ResponseProcessor Calls updateFolderClaudeMd after observation save to update folder-level CLAUDE.md files. Uses fire-and-forget pattern with error logging. Extracts file paths from saved observations and workspace path from registry. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add timeline formatting for folder CLAUDE.md files Implements formatTimelineForClaudeMd function that transforms API response into compact markdown table format. Converts emojis to text labels, handles ditto marks for timestamps, and groups under "Recent" header. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: remove old folder-index implementation Deletes redundant folder-index services that were replaced by the simpler updateFolderClaudeMd approach in CursorHooksInstaller.ts. Removed: - src/services/folder-index/ directory (5 files) - FolderIndexRoutes.ts - folder-index settings from SettingsDefaultsManager - folder-index route registration from worker-service 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add worktree-aware project filtering for unified timelines Detect git worktrees and show both parent repo and worktree observations in the session start timeline. When running in a worktree, the context now includes observations from both projects, interleaved chronologically. - Add detectWorktree() utility to identify worktree directories - Add getProjectContext() to return parent + worktree projects - Update context hook to pass multi-project queries - Add queryObservationsMulti() and querySummariesMulti() for IN clauses - Maintain backward compatibility with single-project queries 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * fix: restructure logging to prove session correctness and reduce noise Add critical logging at each stage of the session lifecycle to prove the session ID chain (contentSessionId → sessionDbId → memorySessionId) stays aligned. New logs include CREATED, ENQUEUED, CLAIMED, MEMORY_ID_CAPTURED, STORING, and STORED. Move intermediate migration and backfill progress logs to DEBUG level to reduce noise, keeping only essential initialization and completion logs at INFO level. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * refactor: extract folder CLAUDE.md utils to shared location Moves folder CLAUDE.md utilities from CursorHooksInstaller to a new shared utils file. Removes Cursor registry dependency - file paths from observations are already absolute, no workspace lookup needed. New file: src/utils/claude-md-utils.ts - replaceTaggedContent() - preserves user content outside tags - writeClaudeMdToFolder() - atomic writes with tag preservation - formatTimelineForClaudeMd() - API response to compact markdown - updateFolderClaudeMdFiles() - orchestrates folder updates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: trigger folder CLAUDE.md updates when observations are saved The folder CLAUDE.md update was previously only triggered in syncAndBroadcastSummary, but summaries run with observationCount=0 (observations are saved separately). Moved the update logic to syncAndBroadcastObservations where file paths are available. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * all the claudes * test: add unit tests for claude-md-utils pure functions Add 11 tests covering replaceTaggedContent and formatTimelineForClaudeMd: - replaceTaggedContent: empty content, tag replacement, appending, partial tags - formatTimelineForClaudeMd: empty input, parsing, ditto marks, session IDs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: add integration tests for file operation functions Add 9 tests for writeClaudeMdToFolder and updateFolderClaudeMdFiles: - writeClaudeMdToFolder: folder creation, content preservation, nested dirs, atomic writes - updateFolderClaudeMdFiles: empty skip, fetch/write, deduplication, error handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: add unit tests for timeline-formatting utilities Add 14 tests for extractFirstFile and groupByDate functions: - extractFirstFile: relative paths, fallback to files_read, null handling, invalid JSON - groupByDate: empty arrays, date grouping, chronological sorting, item preservation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: rebuild plugin scripts with merged features * docs: add project-specific CLAUDE.md with architecture and development notes * fix: exclude project root from auto-generated CLAUDE.md updates Skip folders containing .git directory when auto-updating subfolder CLAUDE.md files. This ensures: 1. Root CLAUDE.md remains user-managed and untouched by the system 2. SessionStart context injection stays pristine throughout the session 3. Subfolder CLAUDE.md files continue to receive live context updates 4. Cleaner separation between user-authored root docs and auto-generated folder indexes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: prevent crash from resuming stale SDK sessions on worker restart When the worker restarts, it was incorrectly passing the `resume` parameter to INIT prompts (lastPromptNumber=1) when a memorySessionId existed from a previous SDK session. This caused "Claude Code process exited with code 1" crashes because the SDK tried to resume into a session that no longer exists. Root cause: The resume condition only checked `hasRealMemorySessionId` but did not verify that this was a CONTINUATION prompt (lastPromptNumber > 1). Fix: Add `session.lastPromptNumber > 1` check to the resume condition: - Before: `...(hasRealMemorySessionId && { resume: session.memorySessionId })` - After: `...(hasRealMemorySessionId && session.lastPromptNumber > 1 && { resume: ... })` Also added: - Enhanced debug logging that warns when skipping resume for INIT prompts - Unit tests in tests/sdk-agent-resume.test.ts (9 test cases) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: properly handle Chroma MCP connection errors Previously, ensureCollection() caught ALL errors from chroma_get_collection_info and assumed they meant "collection doesn't exist", triggering unnecessary collection creation attempts. Connection errors like "Not connected" or "MCP error -32000: Connection closed" would cascade into failed creation attempts. Similarly, queryChroma() would silently return empty results when the MCP call failed, masking the underlying connection problem. Changes: - ensureCollection(): Detect connection errors and re-throw immediately instead of attempting collection creation - queryChroma(): Wrap MCP call in try-catch and throw connection errors instead of returning empty results - Both methods reset connection state (connected=false, client=null) on connection errors so subsequent operations can attempt to reconnect 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * pushed * fix: scope regenerate-claude-md.ts to current working directory Critical bug fix: The script was querying ALL observations from the database across ALL projects ever recorded (1396+ folders), then attempting to write CLAUDE.md files everywhere including other projects, non-existent paths, and ignored directories. Changes: - Use git ls-files to discover folders (respects .gitignore automatically) - Filter database query to current project only (by folder name) - Use relative paths for database queries (matches storage format) - Add --clean flag to remove auto-generated CLAUDE.md files - Add fallback directory walker for non-git repos Now correctly scopes to 26 folders with observations instead of 1396+. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs and adjustments * fix: cleanup mode strips tags instead of deleting files blindly The cleanup mode was incorrectly deleting entire files that contained <claude-mem-context> tags. The correct behavior (per original design): 1. Strip the <claude-mem-context>...</claude-mem-context> section 2. If empty after stripping → delete the file 3. If has remaining content → save the stripped version Now properly preserves user content in CLAUDE.md files while removing only the auto-generated sections. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * deleted some files * chore: regenerate folder CLAUDE.md files with fixed script Regenerated 23 folder CLAUDE.md files using the corrected script that: - Scopes to current working directory only - Uses git ls-files to respect .gitignore - Filters by project name 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Update CLAUDE.md files for January 5, 2026 - Regenerated and staged 23 CLAUDE.md files with a mix of new and modified content. - Fixed cleanup mode to properly strip tags instead of deleting files blindly. - Cleaned up empty CLAUDE.md files from various directories, including ~/.claude and ~/Scripts. - Conducted dry-run cleanup that identified a significant reduction in auto-generated CLAUDE.md files. - Removed the isAutoGeneratedClaudeMd function due to incorrect file deletion behavior. * feat: use settings for observation limit in batch regeneration script Replace hard-coded limit of 10 with configurable CLAUDE_MEM_CONTEXT_OBSERVATIONS setting (default: 50). This allows users to control how many observations appear in folder CLAUDE.md files. Changes: - Import SettingsDefaultsManager and load settings at script startup - Use OBSERVATION_LIMIT constant derived from settings at both call sites - Remove stale default parameter from findObservationsByFolder function 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: use settings for observation limit in event-driven updates Replace hard-coded limit of 10 in updateFolderClaudeMdFiles with configurable CLAUDE_MEM_CONTEXT_OBSERVATIONS setting (default: 50). Changes: - Import SettingsDefaultsManager and os module - Load settings at function start (once, not in loop) - Use limit from settings in API call 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Implement configurable observation limits and enhance search functionality - Added configurable observation limits to batch regeneration scripts. - Enhanced SearchManager to handle folder queries and normalize parameters. - Introduced methods to check for direct child files in observations and sessions. - Updated SearchOptions interface to include isFolder flag for filtering. - Improved code quality with comprehensive reviews and anti-pattern checks. - Cleaned up auto-generated CLAUDE.md files across various directories. - Documented recent changes and improvements in CLAUDE.md files. * build asset * Project Context from Claude-Mem auto-added (can be auto removed at any time) * CLAUDE.md updates * fix: resolve CLAUDE.md files to correct directory in worktree setups When using git worktrees, CLAUDE.md files were being written relative to the worker's process.cwd() instead of the actual project directory. This fix threads the project's cwd from message processing through to the file writing utilities, ensuring CLAUDE.md files are created in the correct project directory regardless of where the worker was started. Changes: - Add projectRoot parameter to updateFolderClaudeMdFiles for path resolution - Thread projectRoot through ResponseProcessor call chain - Track lastCwd from messages in SDKAgent, GeminiAgent, OpenRouterAgent - Add tests for relative/absolute path handling with projectRoot 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * more project context updates * context updates * fix: preserve actual dates in folder CLAUDE.md generation Previously, formatTimelineForClaudeMd used today's date for all observations because the API only returned time (e.g., "4:30 PM") without date information. This caused all historical observations to appear as if they happened today. Changes: - SearchManager.findByFile now groups results by date with headers (e.g., "### Jan 4, 2026") matching formatSearchResults behavior - formatTimelineForClaudeMd now parses these date headers and uses the correct date when constructing epochs for date grouping The timeline dates are critical for claude-mem context - LLMs need accurate temporal context to understand when work happened. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * build: update worker assets with date parsing fix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * claude-mem context: Fixed critical date parsing bug in PR #556 * fix: address PR #556 review items - Use getWorkerHost() instead of hard-coded 127.0.0.1 in claude-md-utils - Add error message and stack details to FOLDER_INDEX logging - Add 5 new tests for worktree/projectRoot path resolution 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Refactor CLAUDE documentation across multiple components and tests - Updated CLAUDE.md files in src/ui/viewer, src/ui/viewer/constants, src/ui/viewer/hooks, tests/server, tests/worker/agents, and plans to reflect recent changes and improvements. - Removed outdated entries and consolidated recent activities for clarity. - Enhanced documentation for hooks, settings, and pagination implementations. - Streamlined test suite documentation for server and worker agents, indicating recent test audits and cleanup efforts. - Adjusted plans to remove obsolete entries and focus on current implementation strategies. * docs: comprehensive v9.0 documentation audit and updates - Add usage/folder-context to docs.json navigation (was documented but hidden!) - Update introduction.mdx with v9.0 release notes (Live Context, Worktree Support, Windows Fixes) - Add CLAUDE_MEM_WORKER_HOST setting to configuration.mdx - Add Folder Context Files section with link to detailed docs - Document worktree support in folder-context.mdx - Update terminology from "mem-search skill" to "MCP tools" throughout active docs - Update Search Pipeline in architecture/overview.mdx - Update usage/getting-started.mdx with MCP tools terminology - Update usage/claude-desktop.mdx title and terminology - Update hooks-architecture.mdx reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add recent activity log for worker CLI with detailed entries * chore: update CLAUDE.md context files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add brainstorming report for CLAUDE.md distribution architecture --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
<claude-mem-context>
|
||||
# Recent Activity
|
||||
|
||||
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
||||
|
||||
### Dec 10, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #23673 | 8:36 PM | ✅ | Add Project Filter Parameter to Session and Prompt Hydration in Search | ~306 |
|
||||
| #23596 | 5:54 PM | ⚖️ | Import/Export Bug Fix Priority and Scope | ~415 |
|
||||
| #23595 | 5:53 PM | 🔴 | SearchManager Returns Wrong Format for Empty Results | ~320 |
|
||||
| #23594 | " | 🔵 | SearchManager Search Method Control Flow | ~313 |
|
||||
| #23591 | 5:51 PM | 🔵 | SearchManager JSON Response Structure | ~231 |
|
||||
| #23590 | " | 🔵 | Import/Export Feature Status Review | ~490 |
|
||||
| #23583 | 5:50 PM | 🔵 | SearchManager Hybrid Search Architecture | ~495 |
|
||||
|
||||
### Dec 13, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #25191 | 8:04 PM | 🔵 | ChromaSync Instantiated in DatabaseManager Constructor | ~315 |
|
||||
|
||||
### Dec 14, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #26263 | 8:32 PM | 🔵 | SearchManager Timeline Methods Use Rich Formatting, Search Method Uses Flat Tables | ~464 |
|
||||
| #26243 | 8:29 PM | 🔵 | FormattingService Provides Basic Table Format Without Dates or File Grouping | ~390 |
|
||||
| #26240 | " | 🔵 | SearchManager Formats Results as Tables, Timeline Uses Rich Date-Grouped Format | ~416 |
|
||||
| #26108 | 7:43 PM | ✅ | changes() Method Format Logic Removed | ~401 |
|
||||
| #26107 | " | ✅ | changes() Method Format Parameter Removed | ~317 |
|
||||
| #26106 | 7:42 PM | ✅ | decisions() Method Format Logic Removed | ~405 |
|
||||
| #26105 | " | ✅ | decisions() Method Format Parameter Removed | ~310 |
|
||||
| #26104 | " | ✅ | Main search() Method Format Handling Removed | ~430 |
|
||||
| #26103 | 7:41 PM | ✅ | FormattingService.ts Rewritten to Table Format | ~457 |
|
||||
| #26102 | " | 🔵 | SearchManager.ts Format Parameter Removal Status | ~478 |
|
||||
|
||||
### Dec 15, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #27043 | 6:04 PM | 🔵 | Subagent confirms no version switcher UI exists, only orphaned backend infrastructure | ~539 |
|
||||
| #27041 | 6:03 PM | 🔵 | Branch switching code isolated to two backend files, no frontend UI components | ~473 |
|
||||
| #27037 | 6:02 PM | 🔵 | Branch switching functionality exists in SettingsRoutes with UI switcher removal intent | ~463 |
|
||||
|
||||
### Dec 16, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #27727 | 5:45 PM | 🔵 | SearchManager returns raw data arrays when format=json is specified | ~349 |
|
||||
|
||||
### Dec 17, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #28473 | 4:25 PM | 🔵 | PaginationHelper LIMIT+1 Trick and Project Path Sanitization | ~499 |
|
||||
| #28458 | 4:24 PM | 🔵 | SDK Agent Observer-Only Event-Driven Query Loop | ~513 |
|
||||
| #28455 | " | 🔵 | Event-Driven Session Manager with Zero-Latency Queuing | ~566 |
|
||||
|
||||
### Dec 18, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #29240 | 12:12 AM | 🔵 | SDK Agent Event-Driven Query Loop with Tool Restrictions | ~507 |
|
||||
|
||||
### Dec 20, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #31100 | 8:01 PM | 🔵 | Summary and Memory Message Generation in SDK Agent | ~324 |
|
||||
|
||||
### Dec 25, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #32616 | 8:43 PM | 🔵 | Comprehensive analysis of "enable billing" setting and its impact on rate limiting | ~533 |
|
||||
| #32599 | 8:40 PM | 🔄 | Added validation and explicit default for Gemini model configuration | ~393 |
|
||||
| #32598 | " | 🔵 | Gemini configuration loaded from settings or environment variables | ~363 |
|
||||
| #32591 | 8:38 PM | 🔴 | Removed Unsupported Gemini Model from Agent | ~282 |
|
||||
| #32583 | " | 🔵 | Gemini Agent Implementation Details | ~434 |
|
||||
| #32543 | 7:29 PM | 🔄 | Rate limiting applied conditionally based on billing status | ~164 |
|
||||
| #32542 | " | 🔄 | Query Gemini now accepts billing status | ~163 |
|
||||
| #32541 | " | 🔄 | Gemini config now includes billing status | ~182 |
|
||||
| #32540 | " | 🔄 | Rate limiting logic refactored for Gemini billing | ~164 |
|
||||
|
||||
### Dec 26, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #32949 | 10:55 PM | 🔵 | Complete settings persistence flow for Xiaomi MIMO v2 Flash model | ~320 |
|
||||
| #32948 | 10:53 PM | 🔵 | OpenRouterAgent uses CLAUDE_MEM_OPENROUTER_MODEL setting with Xiaomi as default | ~183 |
|
||||
|
||||
### Dec 27, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #33215 | 9:06 PM | 🔵 | SessionManager Implements Event-Driven Lifecycle with Database-First Persistence and Auto-Initialization | ~853 |
|
||||
| #33214 | " | 🔵 | SDKAgent Implements Event-Driven Query Loop with Init/Continuation Prompt Selection | ~769 |
|
||||
|
||||
### Dec 28, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #33551 | 11:00 PM | 🔵 | GeminiAgent Does Not Implement Resume Functionality | ~307 |
|
||||
| #33550 | " | 🔵 | OpenRouterAgent Does Not Implement Resume Functionality | ~294 |
|
||||
| #33549 | 10:59 PM | 🔴 | SDKAgent Now Checks memorySessionId Differs From contentSessionId Before Resume | ~419 |
|
||||
| #33547 | " | 🔵 | All Agents Call storeObservation with contentSessionId Instead of memorySessionId | ~407 |
|
||||
| #33543 | 10:56 PM | 🔵 | SDKAgent Already Implements Memory Session ID Capture and Resume Logic | ~467 |
|
||||
| #33542 | " | 🔵 | SessionManager Already Uses Renamed Session ID Fields | ~390 |
|
||||
|
||||
### Dec 30, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #34504 | 2:31 PM | 🔵 | SDKAgent V2 Message Handling and Processing Flow Detailed | ~583 |
|
||||
| #34459 | 2:23 PM | 🔵 | Complete SDKAgent V2 Architecture with Comprehensive Message Processing | ~619 |
|
||||
| #34453 | 2:21 PM | 🔵 | Memory Agent Configured as Observer-Only | ~379 |
|
||||
|
||||
### Jan 4, 2026
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36853 | 1:49 AM | 🔵 | GeminiAgent Implementation Reviewed for Model Support | ~555 |
|
||||
</claude-mem-context>
|
||||
@@ -173,7 +173,14 @@ export class GeminiAgent {
|
||||
}
|
||||
|
||||
// Process pending messages
|
||||
// Track cwd from messages for CLAUDE.md generation
|
||||
let lastCwd: string | undefined;
|
||||
|
||||
for await (const message of this.sessionManager.getMessageIterator(session.sessionDbId)) {
|
||||
// Capture cwd from each message for worktree support
|
||||
if (message.cwd) {
|
||||
lastCwd = message.cwd;
|
||||
}
|
||||
// Capture earliest timestamp BEFORE processing (will be cleared after)
|
||||
// This ensures backlog messages get their original timestamps, not current time
|
||||
const originalTimestamp = session.earliestPendingTimestamp;
|
||||
@@ -217,7 +224,8 @@ export class GeminiAgent {
|
||||
worker,
|
||||
tokensUsed,
|
||||
originalTimestamp,
|
||||
'Gemini'
|
||||
'Gemini',
|
||||
lastCwd
|
||||
);
|
||||
|
||||
} else if (message.type === 'summarize') {
|
||||
@@ -253,7 +261,8 @@ export class GeminiAgent {
|
||||
worker,
|
||||
tokensUsed,
|
||||
originalTimestamp,
|
||||
'Gemini'
|
||||
'Gemini',
|
||||
lastCwd
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,8 @@ export class OpenRouterAgent {
|
||||
worker,
|
||||
tokensUsed,
|
||||
null,
|
||||
'OpenRouter'
|
||||
'OpenRouter',
|
||||
undefined // No lastCwd yet - before message processing
|
||||
);
|
||||
} else {
|
||||
logger.warn('SDK', 'Empty OpenRouter init response - session may lack context', {
|
||||
@@ -130,8 +131,15 @@ export class OpenRouterAgent {
|
||||
});
|
||||
}
|
||||
|
||||
// Track lastCwd from messages for CLAUDE.md generation
|
||||
let lastCwd: string | undefined;
|
||||
|
||||
// Process pending messages
|
||||
for await (const message of this.sessionManager.getMessageIterator(session.sessionDbId)) {
|
||||
// Capture cwd from messages for proper worktree support
|
||||
if (message.cwd) {
|
||||
lastCwd = message.cwd;
|
||||
}
|
||||
// Capture earliest timestamp BEFORE processing (will be cleared after)
|
||||
const originalTimestamp = session.earliestPendingTimestamp;
|
||||
|
||||
@@ -174,7 +182,8 @@ export class OpenRouterAgent {
|
||||
worker,
|
||||
tokensUsed,
|
||||
originalTimestamp,
|
||||
'OpenRouter'
|
||||
'OpenRouter',
|
||||
lastCwd
|
||||
);
|
||||
|
||||
} else if (message.type === 'summarize') {
|
||||
@@ -210,7 +219,8 @@ export class OpenRouterAgent {
|
||||
worker,
|
||||
tokensUsed,
|
||||
originalTimestamp,
|
||||
'OpenRouter'
|
||||
'OpenRouter',
|
||||
lastCwd
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ export class SDKAgent {
|
||||
* @param worker WorkerService reference for spinner control (optional)
|
||||
*/
|
||||
async startSession(session: ActiveSession, worker?: WorkerRef): Promise<void> {
|
||||
// Track cwd from messages for CLAUDE.md generation (worktree support)
|
||||
// Uses mutable object so generator updates are visible in response processing
|
||||
const cwdTracker = { lastCwd: undefined as string | undefined };
|
||||
|
||||
// Find Claude executable
|
||||
const claudePath = this.findClaudeExecutable();
|
||||
|
||||
@@ -61,10 +65,13 @@ export class SDKAgent {
|
||||
];
|
||||
|
||||
// Create message generator (event-driven)
|
||||
const messageGenerator = this.createMessageGenerator(session);
|
||||
const messageGenerator = this.createMessageGenerator(session, cwdTracker);
|
||||
|
||||
// CRITICAL: Only resume if memorySessionId exists (was captured from a previous SDK response).
|
||||
// memorySessionId starts as NULL and is captured on first SDK message.
|
||||
// CRITICAL: Only resume if:
|
||||
// 1. memorySessionId exists (was captured from a previous SDK response)
|
||||
// 2. lastPromptNumber > 1 (this is a continuation within the same SDK session)
|
||||
// On worker restart or crash recovery, memorySessionId may exist from a previous
|
||||
// SDK session but we must NOT resume because the SDK context was lost.
|
||||
// NEVER use contentSessionId for resume - that would inject messages into the user's transcript!
|
||||
const hasRealMemorySessionId = !!session.memorySessionId;
|
||||
|
||||
@@ -77,11 +84,17 @@ export class SDKAgent {
|
||||
lastPromptNumber: session.lastPromptNumber
|
||||
});
|
||||
|
||||
// SESSION ALIGNMENT LOG: Resume decision proof - show if we're resuming with correct memorySessionId
|
||||
// Debug-level alignment logs for detailed tracing
|
||||
if (session.lastPromptNumber > 1) {
|
||||
logger.info('SDK', `[ALIGNMENT] Resume Decision | contentSessionId=${session.contentSessionId} | memorySessionId=${session.memorySessionId} | prompt#=${session.lastPromptNumber} | hasRealMemorySessionId=${hasRealMemorySessionId} | resumeWith=${hasRealMemorySessionId ? session.memorySessionId : 'NONE (fresh SDK session)'}`);
|
||||
const willResume = hasRealMemorySessionId;
|
||||
logger.debug('SDK', `[ALIGNMENT] Resume Decision | contentSessionId=${session.contentSessionId} | memorySessionId=${session.memorySessionId} | prompt#=${session.lastPromptNumber} | hasRealMemorySessionId=${hasRealMemorySessionId} | willResume=${willResume} | resumeWith=${willResume ? session.memorySessionId : 'NONE'}`);
|
||||
} else {
|
||||
logger.info('SDK', `[ALIGNMENT] First Prompt | contentSessionId=${session.contentSessionId} | prompt#=${session.lastPromptNumber} | Will capture memorySessionId from first SDK response`);
|
||||
// INIT prompt - never resume even if memorySessionId exists (stale from previous session)
|
||||
const hasStaleMemoryId = hasRealMemorySessionId;
|
||||
logger.debug('SDK', `[ALIGNMENT] First Prompt (INIT) | contentSessionId=${session.contentSessionId} | prompt#=${session.lastPromptNumber} | hasStaleMemoryId=${hasStaleMemoryId} | action=START_FRESH | Will capture new memorySessionId from SDK response`);
|
||||
if (hasStaleMemoryId) {
|
||||
logger.warn('SDK', `Skipping resume for INIT prompt despite existing memorySessionId=${session.memorySessionId} - SDK context was lost (worker restart or crash recovery)`);
|
||||
}
|
||||
}
|
||||
|
||||
// Run Agent SDK query loop
|
||||
@@ -90,8 +103,10 @@ export class SDKAgent {
|
||||
prompt: messageGenerator,
|
||||
options: {
|
||||
model: modelId,
|
||||
// Resume with captured memorySessionId (null on first prompt, real ID on subsequent)
|
||||
...(hasRealMemorySessionId && { resume: session.memorySessionId }),
|
||||
// Only resume if BOTH: (1) we have a memorySessionId AND (2) this isn't the first prompt
|
||||
// On worker restart, memorySessionId may exist from a previous SDK session but we
|
||||
// need to start fresh since the SDK context was lost
|
||||
...(hasRealMemorySessionId && session.lastPromptNumber > 1 && { resume: session.memorySessionId }),
|
||||
disallowedTools,
|
||||
abortController: session.abortController,
|
||||
pathToClaudeCodeExecutable: claudePath
|
||||
@@ -109,12 +124,20 @@ export class SDKAgent {
|
||||
session.sessionDbId,
|
||||
message.session_id
|
||||
);
|
||||
logger.info('SDK', 'Captured memory session ID', {
|
||||
sessionDbId: session.sessionDbId,
|
||||
// Verify the update by reading back from DB
|
||||
const verification = this.dbManager.getSessionStore().getSessionById(session.sessionDbId);
|
||||
const dbVerified = verification?.memory_session_id === message.session_id;
|
||||
logger.info('SESSION', `MEMORY_ID_CAPTURED | sessionDbId=${session.sessionDbId} | memorySessionId=${message.session_id} | dbVerified=${dbVerified}`, {
|
||||
sessionId: session.sessionDbId,
|
||||
memorySessionId: message.session_id
|
||||
});
|
||||
// SESSION ALIGNMENT LOG: Memory session ID captured - now contentSessionId→memorySessionId mapping is complete
|
||||
logger.info('SDK', `[ALIGNMENT] Captured | contentSessionId=${session.contentSessionId} → memorySessionId=${message.session_id} | Future prompts will resume with this ID`);
|
||||
if (!dbVerified) {
|
||||
logger.error('SESSION', `MEMORY_ID_MISMATCH | sessionDbId=${session.sessionDbId} | expected=${message.session_id} | got=${verification?.memory_session_id}`, {
|
||||
sessionId: session.sessionDbId
|
||||
});
|
||||
}
|
||||
// Debug-level alignment log for detailed tracing
|
||||
logger.debug('SDK', `[ALIGNMENT] Captured | contentSessionId=${session.contentSessionId} → memorySessionId=${message.session_id} | Future prompts will resume with this ID`);
|
||||
}
|
||||
|
||||
// Handle assistant messages
|
||||
@@ -177,7 +200,8 @@ export class SDKAgent {
|
||||
worker,
|
||||
discoveryTokens,
|
||||
originalTimestamp,
|
||||
'SDK'
|
||||
'SDK',
|
||||
cwdTracker.lastCwd
|
||||
);
|
||||
}
|
||||
|
||||
@@ -224,8 +248,16 @@ export class SDKAgent {
|
||||
* - Each user message is added to session.conversationHistory
|
||||
* - This allows provider switching (Claude→Gemini) with full context
|
||||
* - SDK manages its own internal state, but we mirror it for interop
|
||||
*
|
||||
* CWD TRACKING:
|
||||
* - cwdTracker is a mutable object shared with startSession
|
||||
* - As messages with cwd are processed, cwdTracker.lastCwd is updated
|
||||
* - This enables processAgentResponse to use the correct cwd for CLAUDE.md
|
||||
*/
|
||||
private async *createMessageGenerator(session: ActiveSession): AsyncIterableIterator<SDKUserMessage> {
|
||||
private async *createMessageGenerator(
|
||||
session: ActiveSession,
|
||||
cwdTracker: { lastCwd: string | undefined }
|
||||
): AsyncIterableIterator<SDKUserMessage> {
|
||||
// Load active mode
|
||||
const mode = ModeManager.getInstance().getActiveMode();
|
||||
|
||||
@@ -261,6 +293,11 @@ export class SDKAgent {
|
||||
|
||||
// Consume pending messages from SessionManager (event-driven, no polling)
|
||||
for await (const message of this.sessionManager.getMessageIterator(session.sessionDbId)) {
|
||||
// Capture cwd from each message for worktree support
|
||||
if (message.cwd) {
|
||||
cwdTracker.lastCwd = message.cwd;
|
||||
}
|
||||
|
||||
if (message.type === 'observation') {
|
||||
// Update last prompt number
|
||||
if (message.prompt_number !== undefined) {
|
||||
|
||||
@@ -71,6 +71,12 @@ export class SearchManager {
|
||||
private normalizeParams(args: any): any {
|
||||
const normalized: any = { ...args };
|
||||
|
||||
// Map filePath to files (API uses filePath, internal uses files)
|
||||
if (normalized.filePath && !normalized.files) {
|
||||
normalized.files = normalized.filePath;
|
||||
delete normalized.filePath;
|
||||
}
|
||||
|
||||
// Parse comma-separated concepts into array
|
||||
if (normalized.concepts && typeof normalized.concepts === 'string') {
|
||||
normalized.concepts = normalized.concepts.split(',').map((s: string) => s.trim()).filter(Boolean);
|
||||
@@ -101,6 +107,13 @@ export class SearchManager {
|
||||
delete normalized.dateEnd;
|
||||
}
|
||||
|
||||
// Parse isFolder boolean from string
|
||||
if (normalized.isFolder === 'true') {
|
||||
normalized.isFolder = true;
|
||||
} else if (normalized.isFolder === 'false') {
|
||||
normalized.isFolder = false;
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
@@ -301,7 +314,7 @@ export class SearchManager {
|
||||
for (const result of dayResults) {
|
||||
let file = 'General';
|
||||
if (result.type === 'observation') {
|
||||
file = extractFirstFile(result.data.files_modified, cwd);
|
||||
file = extractFirstFile(result.data.files_modified, cwd, result.data.files_read);
|
||||
}
|
||||
if (!resultsByFile.has(file)) {
|
||||
resultsByFile.set(file, []);
|
||||
@@ -577,7 +590,7 @@ export class SearchManager {
|
||||
lines.push('');
|
||||
} else if (item.type === 'observation') {
|
||||
const obs = item.data as ObservationSearchResult;
|
||||
const file = extractFirstFile(obs.files_modified, cwd);
|
||||
const file = extractFirstFile(obs.files_modified, cwd, obs.files_read);
|
||||
|
||||
if (file !== currentFile) {
|
||||
if (tableOpen) {
|
||||
@@ -1079,7 +1092,9 @@ export class SearchManager {
|
||||
*/
|
||||
async findByFile(args: any): Promise<any> {
|
||||
const normalized = this.normalizeParams(args);
|
||||
const { files: filePath, ...filters } = normalized;
|
||||
const { files: rawFilePath, ...filters } = normalized;
|
||||
// Handle both string and array (normalizeParams may split on comma)
|
||||
const filePath = Array.isArray(rawFilePath) ? rawFilePath[0] : rawFilePath;
|
||||
let observations: ObservationSearchResult[] = [];
|
||||
let sessions: SessionSummarySearchResult[] = [];
|
||||
|
||||
@@ -1138,24 +1153,57 @@ export class SearchManager {
|
||||
};
|
||||
}
|
||||
|
||||
// Format as table
|
||||
const header = `Found ${totalResults} result(s) for file "${filePath}"\n\n${this.formatter.formatTableHeader()}`;
|
||||
const formattedResults: string[] = [];
|
||||
// Combine observations and sessions with timestamps for date grouping
|
||||
const combined: Array<{
|
||||
type: 'observation' | 'session';
|
||||
data: ObservationSearchResult | SessionSummarySearchResult;
|
||||
epoch: number;
|
||||
created_at: string;
|
||||
}> = [
|
||||
...observations.map(obs => ({
|
||||
type: 'observation' as const,
|
||||
data: obs,
|
||||
epoch: obs.created_at_epoch,
|
||||
created_at: obs.created_at
|
||||
})),
|
||||
...sessions.map(sess => ({
|
||||
type: 'session' as const,
|
||||
data: sess,
|
||||
epoch: sess.created_at_epoch,
|
||||
created_at: sess.created_at
|
||||
}))
|
||||
];
|
||||
|
||||
// Add observations
|
||||
observations.forEach((obs, i) => {
|
||||
formattedResults.push(this.formatter.formatObservationIndex(obs, i));
|
||||
});
|
||||
// Sort by date (most recent first)
|
||||
combined.sort((a, b) => b.epoch - a.epoch);
|
||||
|
||||
// Add sessions
|
||||
sessions.forEach((session, i) => {
|
||||
formattedResults.push(this.formatter.formatSessionIndex(session, i + observations.length));
|
||||
});
|
||||
// Group by date for proper timeline rendering
|
||||
const resultsByDate = groupByDate(combined, item => item.created_at);
|
||||
|
||||
// Format with date headers for proper date parsing by folder CLAUDE.md generator
|
||||
const lines: string[] = [];
|
||||
lines.push(`Found ${totalResults} result(s) for file "${filePath}"`);
|
||||
lines.push('');
|
||||
|
||||
for (const [day, dayResults] of resultsByDate) {
|
||||
lines.push(`### ${day}`);
|
||||
lines.push('');
|
||||
lines.push(this.formatter.formatTableHeader());
|
||||
|
||||
for (const result of dayResults) {
|
||||
if (result.type === 'observation') {
|
||||
lines.push(this.formatter.formatObservationIndex(result.data as ObservationSearchResult, 0));
|
||||
} else {
|
||||
lines.push(this.formatter.formatSessionIndex(result.data as SessionSummarySearchResult, 0));
|
||||
}
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: 'text' as const,
|
||||
text: header + '\n' + formattedResults.join('\n')
|
||||
text: lines.join('\n')
|
||||
}]
|
||||
};
|
||||
}
|
||||
@@ -1519,7 +1567,7 @@ export class SearchManager {
|
||||
} else if (item.type === 'observation') {
|
||||
// Render observation in table
|
||||
const obs = item.data as ObservationSearchResult;
|
||||
const file = extractFirstFile(obs.files_modified, cwd);
|
||||
const file = extractFirstFile(obs.files_modified, cwd, obs.files_read);
|
||||
|
||||
// Check if we need a new file section
|
||||
if (file !== currentFile) {
|
||||
@@ -1749,7 +1797,7 @@ export class SearchManager {
|
||||
} else if (item.type === 'observation') {
|
||||
// Render observation in table
|
||||
const obs = item.data as ObservationSearchResult;
|
||||
const file = extractFirstFile(obs.files_modified, cwd);
|
||||
const file = extractFirstFile(obs.files_modified, cwd, obs.files_read);
|
||||
|
||||
// Check if we need a new file section
|
||||
if (file !== currentFile) {
|
||||
|
||||
@@ -48,7 +48,7 @@ export class SessionManager {
|
||||
* Initialize a new session or return existing one
|
||||
*/
|
||||
initializeSession(sessionDbId: number, currentUserPrompt?: string, promptNumber?: number): ActiveSession {
|
||||
logger.info('SESSION', 'initializeSession called', {
|
||||
logger.debug('SESSION', 'initializeSession called', {
|
||||
sessionDbId,
|
||||
promptNumber,
|
||||
has_currentUserPrompt: !!currentUserPrompt
|
||||
@@ -57,7 +57,7 @@ export class SessionManager {
|
||||
// Check if already active
|
||||
let session = this.sessions.get(sessionDbId);
|
||||
if (session) {
|
||||
logger.info('SESSION', 'Returning cached session', {
|
||||
logger.debug('SESSION', 'Returning cached session', {
|
||||
sessionDbId,
|
||||
contentSessionId: session.contentSessionId,
|
||||
lastPromptNumber: session.lastPromptNumber
|
||||
@@ -99,7 +99,7 @@ export class SessionManager {
|
||||
// Fetch from database
|
||||
const dbSession = this.dbManager.getSessionById(sessionDbId);
|
||||
|
||||
logger.info('SESSION', 'Fetched session from database', {
|
||||
logger.debug('SESSION', 'Fetched session from database', {
|
||||
sessionDbId,
|
||||
content_session_id: dbSession.content_session_id,
|
||||
memory_session_id: dbSession.memory_session_id
|
||||
@@ -142,7 +142,7 @@ export class SessionManager {
|
||||
currentProvider: null // Will be set when generator starts
|
||||
};
|
||||
|
||||
logger.info('SESSION', 'Creating new session object', {
|
||||
logger.debug('SESSION', 'Creating new session object', {
|
||||
sessionDbId,
|
||||
contentSessionId: dbSession.content_session_id,
|
||||
memorySessionId: dbSession.memory_session_id || '(none - fresh session)',
|
||||
@@ -199,10 +199,10 @@ export class SessionManager {
|
||||
|
||||
try {
|
||||
const messageId = this.getPendingStore().enqueue(sessionDbId, session.contentSessionId, message);
|
||||
logger.debug('SESSION', `Observation persisted to DB`, {
|
||||
sessionId: sessionDbId,
|
||||
messageId,
|
||||
tool: data.tool_name
|
||||
const queueDepth = this.getPendingStore().getPendingCount(sessionDbId);
|
||||
const toolSummary = logger.formatTool(data.tool_name, data.tool_input);
|
||||
logger.info('QUEUE', `ENQUEUED | sessionDbId=${sessionDbId} | messageId=${messageId} | type=observation | tool=${toolSummary} | depth=${queueDepth}`, {
|
||||
sessionId: sessionDbId
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('SESSION', 'Failed to persist observation to DB', {
|
||||
@@ -215,15 +215,6 @@ export class SessionManager {
|
||||
// Notify generator immediately (zero latency)
|
||||
const emitter = this.sessionQueues.get(sessionDbId);
|
||||
emitter?.emit('message');
|
||||
|
||||
// Format tool name for logging
|
||||
const toolSummary = logger.formatTool(data.tool_name, data.tool_input);
|
||||
|
||||
logger.info('SESSION', `Observation queued`, {
|
||||
sessionId: sessionDbId,
|
||||
tool: toolSummary,
|
||||
hasGenerator: !!session.generatorPromise
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,9 +239,9 @@ export class SessionManager {
|
||||
|
||||
try {
|
||||
const messageId = this.getPendingStore().enqueue(sessionDbId, session.contentSessionId, message);
|
||||
logger.debug('SESSION', `Summarize persisted to DB`, {
|
||||
sessionId: sessionDbId,
|
||||
messageId
|
||||
const queueDepth = this.getPendingStore().getPendingCount(sessionDbId);
|
||||
logger.info('QUEUE', `ENQUEUED | sessionDbId=${sessionDbId} | messageId=${messageId} | type=summarize | depth=${queueDepth}`, {
|
||||
sessionId: sessionDbId
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('SESSION', 'Failed to persist summarize to DB', {
|
||||
@@ -261,11 +252,6 @@ export class SessionManager {
|
||||
|
||||
const emitter = this.sessionQueues.get(sessionDbId);
|
||||
emitter?.emit('message');
|
||||
|
||||
logger.info('SESSION', `Summarize queued`, {
|
||||
sessionId: sessionDbId,
|
||||
hasGenerator: !!session.generatorPromise
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<claude-mem-context>
|
||||
# Recent Activity
|
||||
|
||||
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
||||
|
||||
*No recent activity*
|
||||
</claude-mem-context>
|
||||
@@ -14,6 +14,7 @@
|
||||
import { logger } from '../../../utils/logger.js';
|
||||
import { parseObservations, parseSummary, type ParsedObservation, type ParsedSummary } from '../../../sdk/parser.js';
|
||||
import { updateCursorContextForProject } from '../../worker-service.js';
|
||||
import { updateFolderClaudeMdFiles } from '../../../utils/claude-md-utils.js';
|
||||
import { getWorkerPort } from '../../../shared/worker-utils.js';
|
||||
import type { ActiveSession } from '../../worker-types.js';
|
||||
import type { DatabaseManager } from '../DatabaseManager.js';
|
||||
@@ -50,7 +51,8 @@ export async function processAgentResponse(
|
||||
worker: WorkerRef | undefined,
|
||||
discoveryTokens: number,
|
||||
originalTimestamp: number | null,
|
||||
agentName: string
|
||||
agentName: string,
|
||||
projectRoot?: string
|
||||
): Promise<void> {
|
||||
// Add assistant response to shared conversation history for provider interop
|
||||
if (text) {
|
||||
@@ -72,6 +74,12 @@ export async function processAgentResponse(
|
||||
throw new Error('Cannot store observations: memorySessionId not yet captured');
|
||||
}
|
||||
|
||||
// Log pre-storage with session ID chain for verification
|
||||
logger.info('DB', `STORING | sessionDbId=${session.sessionDbId} | memorySessionId=${session.memorySessionId} | obsCount=${observations.length} | hasSummary=${!!summaryForStore}`, {
|
||||
sessionId: session.sessionDbId,
|
||||
memorySessionId: session.memorySessionId
|
||||
});
|
||||
|
||||
// ATOMIC TRANSACTION: Store observations + summary ONCE
|
||||
// Messages are already deleted from queue on claim, so no completion tracking needed
|
||||
const result = sessionStore.storeObservations(
|
||||
@@ -84,12 +92,10 @@ export async function processAgentResponse(
|
||||
originalTimestamp ?? undefined
|
||||
);
|
||||
|
||||
// Log what was saved
|
||||
logger.info('SDK', `${agentName} observations and summary saved atomically`, {
|
||||
// Log storage result with IDs for end-to-end traceability
|
||||
logger.info('DB', `STORED | sessionDbId=${session.sessionDbId} | memorySessionId=${session.memorySessionId} | obsCount=${result.observationIds.length} | obsIds=[${result.observationIds.join(',')}] | summaryId=${result.summaryId || 'none'}`, {
|
||||
sessionId: session.sessionDbId,
|
||||
observationCount: result.observationIds.length,
|
||||
hasSummary: !!result.summaryId,
|
||||
atomicTransaction: true
|
||||
memorySessionId: session.memorySessionId
|
||||
});
|
||||
|
||||
// AFTER transaction commits - async operations (can fail safely without data loss)
|
||||
@@ -100,7 +106,8 @@ export async function processAgentResponse(
|
||||
dbManager,
|
||||
worker,
|
||||
discoveryTokens,
|
||||
agentName
|
||||
agentName,
|
||||
projectRoot
|
||||
);
|
||||
|
||||
// Sync and broadcast summary if present
|
||||
@@ -152,7 +159,8 @@ async function syncAndBroadcastObservations(
|
||||
dbManager: DatabaseManager,
|
||||
worker: WorkerRef | undefined,
|
||||
discoveryTokens: number,
|
||||
agentName: string
|
||||
agentName: string,
|
||||
projectRoot?: string
|
||||
): Promise<void> {
|
||||
for (let i = 0; i < observations.length; i++) {
|
||||
const obsId = result.observationIds[i];
|
||||
@@ -204,6 +212,25 @@ async function syncAndBroadcastObservations(
|
||||
created_at_epoch: result.createdAtEpoch
|
||||
});
|
||||
}
|
||||
|
||||
// Update folder CLAUDE.md files for touched folders (fire-and-forget)
|
||||
// This runs per-observation batch to ensure folders are updated as work happens
|
||||
const allFilePaths: string[] = [];
|
||||
for (const obs of observations) {
|
||||
allFilePaths.push(...(obs.files_modified || []));
|
||||
allFilePaths.push(...(obs.files_read || []));
|
||||
}
|
||||
|
||||
if (allFilePaths.length > 0) {
|
||||
updateFolderClaudeMdFiles(
|
||||
allFilePaths,
|
||||
session.project,
|
||||
getWorkerPort(),
|
||||
projectRoot
|
||||
).catch(error => {
|
||||
logger.warn('FOLDER_INDEX', 'CLAUDE.md update failed (non-critical)', { project: session.project }, error as Error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<claude-mem-context>
|
||||
# Recent Activity
|
||||
|
||||
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
||||
|
||||
### Dec 7, 2025
|
||||
|
||||
**SessionEventBroadcaster.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #21829 | 11:05 PM | 🔄 | Massive refactor adds 8,671 lines and removes 5,585 lines across 60 files | ~619 |
|
||||
| #21824 | 10:59 PM | 🔵 | SessionEventBroadcaster methods called 7 times across SessionRoutes and SessionCompletionHandler | ~398 |
|
||||
| #21822 | " | 🔵 | SessionEventBroadcaster instantiated in WorkerService and injected into routes and handlers | ~372 |
|
||||
| #21816 | 10:58 PM | 🔵 | SessionEventBroadcaster provides semantic SSE event broadcasting | ~398 |
|
||||
| #21807 | 10:49 PM | ⚖️ | KISS Audit Identified 587 Lines of Ceremonial Complexity | ~699 |
|
||||
| #21796 | 10:46 PM | 🔵 | SessionEventBroadcaster Duplicates Processing Status Updates | ~388 |
|
||||
| #21743 | 10:16 PM | 🟣 | Created SessionEventBroadcaster for Semantic Session Event Broadcasting | ~514 |
|
||||
|
||||
### Dec 8, 2025
|
||||
|
||||
**SessionEventBroadcaster.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #22107 | 6:47 PM | 🔵 | SessionEventBroadcaster Has observation_queued But No observation_completed Event | ~429 |
|
||||
| #22049 | 6:04 PM | 🔵 | broadcastProcessingStatus method synchronizes queue state across six system components | ~477 |
|
||||
| #22043 | 6:02 PM | 🔵 | SessionEventBroadcaster provides semantic event broadcasting with SSE and processing status updates | ~449 |
|
||||
| #22036 | 6:00 PM | 🔵 | Found processing_status tracking across UI, hooks, and event systems | ~312 |
|
||||
|
||||
### Dec 11, 2025
|
||||
|
||||
**SessionEventBroadcaster.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #23962 | 1:59 PM | 🔵 | Services Layer Implements Full Backend Architecture | ~490 |
|
||||
|
||||
### Dec 20, 2025
|
||||
|
||||
**session-events.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #30609 | 5:01 PM | 🔄 | Phase 4: Eliminated Over-Engineering in Hook/Worker System | ~504 |
|
||||
| #30567 | 4:56 PM | 🟣 | Session Event Broadcasting Utilities | ~313 |
|
||||
|
||||
**SessionEventBroadcaster.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #30593 | 4:59 PM | 🔄 | Deleted SessionEventBroadcaster Class File | ~298 |
|
||||
| #30548 | 4:53 PM | 🔵 | SessionEventBroadcaster SSE Notification Layer | ~338 |
|
||||
|
||||
### Dec 25, 2025
|
||||
|
||||
**SessionEventBroadcaster.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #32597 | 8:40 PM | 🔵 | Identified session completion mechanism and potential method discrepancy | ~470 |
|
||||
| #32580 | 8:22 PM | 🔵 | Grep for resetStuckMessages and processing | ~242 |
|
||||
|
||||
### Dec 28, 2025
|
||||
|
||||
**SessionEventBroadcaster.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #33439 | 10:15 PM | 🔄 | Extended Session ID Renaming to Additional Codebase Components | ~352 |
|
||||
| #33328 | 3:10 PM | 🟣 | Merged centralized logger and session continuity diagnostics to main | ~397 |
|
||||
| #33280 | 3:07 PM | 🔄 | Logger coverage refactor for background services | ~428 |
|
||||
|
||||
### Dec 30, 2025
|
||||
|
||||
**SessionEventBroadcaster.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #34550 | 4:53 PM | 🔵 | Phase 2 Review Reveals Critical Incomplete Error Handling | ~577 |
|
||||
|
||||
### Dec 31, 2025
|
||||
|
||||
**SessionEventBroadcaster.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #34558 | 2:32 PM | 🔵 | Code Quality Fix Plan Created for Seven Identified Issues | ~629 |
|
||||
|
||||
### Jan 2, 2026
|
||||
|
||||
**SessionEventBroadcaster.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #35951 | 4:42 PM | 🔵 | Multi-Layer Service Architecture Discovery | ~395 |
|
||||
</claude-mem-context>
|
||||
@@ -0,0 +1,58 @@
|
||||
<claude-mem-context>
|
||||
# Recent Activity
|
||||
|
||||
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
||||
|
||||
### Dec 28, 2025
|
||||
|
||||
**BaseRouteHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #33396 | 9:53 PM | ✅ | Queue refactoring touched 12 files with net addition of 1021 lines | ~402 |
|
||||
| #33336 | 3:36 PM | 🔴 | Fixed Windows Worker Crashes and Headers Already Sent Errors | ~351 |
|
||||
| #33259 | 2:46 PM | 🔴 | Windows Worker Stability Pull Request Created | ~386 |
|
||||
| #33258 | 2:38 PM | 🔴 | Added headersSent Guard to Error Handler | ~338 |
|
||||
| #33256 | 2:36 PM | ⚖️ | Implementation Plan for Windows Worker Issues | ~471 |
|
||||
|
||||
### Jan 1, 2026
|
||||
|
||||
**middleware.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #35614 | 10:57 PM | 🔴 | Suppressed /api/logs endpoint logging to reduce noise | ~252 |
|
||||
| #35612 | " | ✅ | HTTP logging middleware excludes /api/logs polling endpoint | ~262 |
|
||||
| #35611 | " | 🔵 | HTTP Middleware Architecture in Worker Service | ~360 |
|
||||
|
||||
**BaseRouteHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #35433 | 8:43 PM | 🔵 | Try-Catch Block Distribution Across Services | ~372 |
|
||||
|
||||
### Jan 2, 2026
|
||||
|
||||
**middleware.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #35951 | 4:42 PM | 🔵 | Multi-Layer Service Architecture Discovery | ~395 |
|
||||
|
||||
### Jan 3, 2026
|
||||
|
||||
**middleware.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36689 | 11:56 PM | 🔵 | PR #538 Review Findings - Modular Architecture Refactor | ~590 |
|
||||
|
||||
### Jan 5, 2026
|
||||
|
||||
**BaseRouteHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #37665 | 5:52 PM | 🔵 | Codebase uses dependency injection and lazy initialization patterns to avoid circular dependencies | ~548 |
|
||||
| #37662 | " | 🔵 | BaseRouteHandler imports logger demonstrating HTTP layer dependency on logger | ~367 |
|
||||
|
||||
**middleware.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #37626 | 5:35 PM | 🔵 | FormatTool Function Usage Across Codebase | ~493 |
|
||||
| #37537 | 4:45 PM | 🔵 | Middleware formatTool Call Confirmed as Critical Crash Point | ~361 |
|
||||
</claude-mem-context>
|
||||
@@ -0,0 +1,97 @@
|
||||
<claude-mem-context>
|
||||
# Recent Activity
|
||||
|
||||
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
||||
|
||||
### Dec 5, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #20734 | 9:08 PM | 🔵 | SearchRoutes Context Injection Endpoint with Dynamic Import | ~614 |
|
||||
| #20548 | 8:21 PM | 🔵 | Context generator imported from services directory in worker | ~334 |
|
||||
| #20547 | " | 🔵 | Context injection route implementation in SearchRoutes.ts | ~289 |
|
||||
|
||||
### Dec 7, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #21742 | 10:16 PM | 🔵 | SessionRoutes Analysis: Identified 10+ Scattered Broadcast Calls | ~540 |
|
||||
|
||||
### Dec 8, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #22301 | 9:44 PM | 🔵 | Privacy Validation in Observation Processing | ~399 |
|
||||
| #22296 | 9:43 PM | 🔵 | SessionRoutes HTTP Endpoints and SDK Agent Lifecycle | ~442 |
|
||||
| #22222 | 8:29 PM | 🔵 | Found waiting logic in SessionRoutes but it may not be working correctly | ~359 |
|
||||
| #22005 | 5:40 PM | 🔵 | handleObservationsByClaudeId Current Implementation | ~443 |
|
||||
| #22004 | " | 🔵 | Legacy Observation Handling Pattern Identified | ~337 |
|
||||
| #22003 | " | 🔵 | SessionRoutes Architecture Confirmed | ~354 |
|
||||
| #21969 | 5:22 PM | 🟣 | Worker Routes Pass tool_use_id to SessionManager Queue | ~290 |
|
||||
| #21968 | " | ✅ | Worker Endpoint Extracts toolUseId from Observation Request | ~243 |
|
||||
| #21962 | 5:21 PM | 🟣 | Implemented handleGetObservationsForToolUse Endpoint Handler | ~325 |
|
||||
| #21961 | " | 🟣 | Added GET Endpoint for Fetching Observations by Tool Use ID | ~272 |
|
||||
| #21951 | 5:18 PM | 🔵 | Worker SessionRoutes Architecture and Endpoints Reviewed | ~418 |
|
||||
| #21948 | 5:09 PM | 🟣 | Implemented PreToolUse Endpoint Handler | ~334 |
|
||||
| #21947 | 5:07 PM | 🟣 | Added PreToolUse Route Registration | ~287 |
|
||||
|
||||
### Dec 9, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #23143 | 6:42 PM | ✅ | Updated Skip Tools Logic to Use USER_SETTINGS_PATH Constant | ~150 |
|
||||
| #23142 | " | ✅ | Fixed Settings Path Import in SessionRoutes | ~148 |
|
||||
| #23140 | 6:41 PM | 🟣 | Implemented Skip Tools Filtering in Observations Endpoint | ~386 |
|
||||
| #23138 | " | ✅ | Added SettingsDefaultsManager and Paths Imports to SessionRoutes | ~222 |
|
||||
| #23136 | " | 🔵 | SessionRoutes handleObservationsByClaudeId Handler Structure | ~329 |
|
||||
| #23007 | 4:02 PM | 🔵 | Settings Write Implementation Using Nested Schema | ~398 |
|
||||
| #22859 | 2:28 PM | 🔴 | Fixed Python Version Validation to Support 3.10+ | ~322 |
|
||||
| #22854 | 2:27 PM | 🔵 | Located Python Version Validation Regex in SettingsRoutes | ~316 |
|
||||
|
||||
### Dec 10, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #23593 | 5:52 PM | 🔵 | SearchRoutes Handler Pattern | ~268 |
|
||||
| #23588 | 5:51 PM | 🔵 | Search Routes HTTP API Integration | ~281 |
|
||||
|
||||
### Dec 14, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #26253 | 8:31 PM | 🔵 | SearchRoutes Confirms Context Endpoints Use generateContext, Search Uses SearchManager | ~397 |
|
||||
| #25689 | 4:23 PM | 🔵 | SessionRoutes queueSummarize receives messages but doesn't persist them to database | ~496 |
|
||||
|
||||
### Dec 15, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #27043 | 6:04 PM | 🔵 | Subagent confirms no version switcher UI exists, only orphaned backend infrastructure | ~539 |
|
||||
| #27041 | 6:03 PM | 🔵 | Branch switching code isolated to two backend files, no frontend UI components | ~473 |
|
||||
| #27037 | 6:02 PM | 🔵 | Branch switching functionality exists in SettingsRoutes with UI switcher removal intent | ~463 |
|
||||
|
||||
### Dec 16, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #27414 | 3:25 PM | 🔵 | Batch Observations Endpoint Already Implemented | ~330 |
|
||||
|
||||
### Dec 19, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #30077 | 8:05 PM | 🔵 | SessionRoutes HTTP API Manages SDK Agent Lifecycle and Message Queue | ~516 |
|
||||
|
||||
### Dec 26, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #32949 | 10:55 PM | 🔵 | Complete settings persistence flow for Xiaomi MIMO v2 Flash model | ~320 |
|
||||
| #32939 | 10:53 PM | 🔵 | Settings API routes handle model configuration persistence | ~288 |
|
||||
|
||||
### Dec 30, 2025
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #34491 | 2:28 PM | 🔵 | SessionRoutes Implements Multi-Provider Agent Management | ~635 |
|
||||
</claude-mem-context>
|
||||
@@ -195,31 +195,46 @@ export class SearchRoutes extends BaseRouteHandler {
|
||||
|
||||
/**
|
||||
* Context injection endpoint for hooks
|
||||
* GET /api/context/inject?project=...&colors=true
|
||||
* GET /api/context/inject?projects=...&colors=true
|
||||
* GET /api/context/inject?project=...&colors=true (legacy, single project)
|
||||
*
|
||||
* Returns pre-formatted context string ready for display.
|
||||
* Use colors=true for ANSI-colored terminal output.
|
||||
*
|
||||
* For worktrees, pass comma-separated projects (e.g., "main,worktree-branch")
|
||||
* to get a unified timeline from both parent and worktree.
|
||||
*/
|
||||
private handleContextInject = this.wrapHandler(async (req: Request, res: Response): Promise<void> => {
|
||||
const projectName = req.query.project as string;
|
||||
// Support both legacy `project` and new `projects` parameter
|
||||
const projectsParam = (req.query.projects as string) || (req.query.project as string);
|
||||
const useColors = req.query.colors === 'true';
|
||||
|
||||
if (!projectName) {
|
||||
this.badRequest(res, 'Project parameter is required');
|
||||
if (!projectsParam) {
|
||||
this.badRequest(res, 'Project(s) parameter is required');
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse comma-separated projects list
|
||||
const projects = projectsParam.split(',').map(p => p.trim()).filter(Boolean);
|
||||
|
||||
if (projects.length === 0) {
|
||||
this.badRequest(res, 'At least one project is required');
|
||||
return;
|
||||
}
|
||||
|
||||
// Import context generator (runs in worker, has access to database)
|
||||
const { generateContext } = await import('../../../context-generator.js');
|
||||
|
||||
// Use project name as CWD (generateContext uses path.basename to get project)
|
||||
const cwd = `/context/${projectName}`;
|
||||
// Use first project name as CWD (for display purposes)
|
||||
const primaryProject = projects[projects.length - 1]; // Last is the current/primary project
|
||||
const cwd = `/context/${primaryProject}`;
|
||||
|
||||
// Generate context
|
||||
// Generate context with all projects
|
||||
const contextText = await generateContext(
|
||||
{
|
||||
session_id: 'context-inject-' + Date.now(),
|
||||
cwd: cwd
|
||||
cwd: cwd,
|
||||
projects: projects
|
||||
},
|
||||
useColors
|
||||
);
|
||||
|
||||
@@ -560,31 +560,23 @@ export class SessionRoutes extends BaseRouteHandler {
|
||||
// Step 1: Create/get SDK session (idempotent INSERT OR IGNORE)
|
||||
const sessionDbId = store.createSDKSession(contentSessionId, project, prompt);
|
||||
|
||||
logger.info('HTTP', 'SessionRoutes: createSDKSession returned', {
|
||||
sessionDbId,
|
||||
contentSessionId
|
||||
});
|
||||
|
||||
// SESSION ALIGNMENT LOG: DB lookup proof - show content→memory mapping
|
||||
// Verify session creation with DB lookup
|
||||
const dbSession = store.getSessionById(sessionDbId);
|
||||
const memorySessionId = dbSession?.memory_session_id || null;
|
||||
const hasCapturedMemoryId = !!memorySessionId;
|
||||
const isNewSession = !dbSession?.memory_session_id;
|
||||
logger.info('SESSION', `CREATED | contentSessionId=${contentSessionId} → sessionDbId=${sessionDbId} | isNew=${isNewSession} | project=${project}`, {
|
||||
sessionId: sessionDbId
|
||||
});
|
||||
|
||||
// Step 2: Get next prompt number from user_prompts count
|
||||
const currentCount = store.getPromptNumberFromUserPrompts(contentSessionId);
|
||||
const promptNumber = currentCount + 1;
|
||||
|
||||
logger.info('HTTP', 'SessionRoutes: Calculated promptNumber', {
|
||||
sessionDbId,
|
||||
promptNumber,
|
||||
currentCount
|
||||
});
|
||||
|
||||
// SESSION ALIGNMENT LOG: For prompt > 1, prove we looked up memorySessionId from contentSessionId
|
||||
// Debug-level alignment logs for detailed tracing
|
||||
const memorySessionId = dbSession?.memory_session_id || null;
|
||||
if (promptNumber > 1) {
|
||||
logger.info('HTTP', `[ALIGNMENT] DB Lookup Proof | contentSessionId=${contentSessionId} → memorySessionId=${memorySessionId || '(not yet captured)'} | prompt#=${promptNumber} | hasCapturedMemoryId=${hasCapturedMemoryId}`);
|
||||
logger.debug('HTTP', `[ALIGNMENT] DB Lookup Proof | contentSessionId=${contentSessionId} → memorySessionId=${memorySessionId || '(not yet captured)'} | prompt#=${promptNumber}`);
|
||||
} else {
|
||||
logger.info('HTTP', `[ALIGNMENT] New Session | contentSessionId=${contentSessionId} | prompt#=${promptNumber} | memorySessionId will be captured on first SDK response`);
|
||||
logger.debug('HTTP', `[ALIGNMENT] New Session | contentSessionId=${contentSessionId} | prompt#=${promptNumber} | memorySessionId will be captured on first SDK response`);
|
||||
}
|
||||
|
||||
// Step 3: Strip privacy tags from prompt
|
||||
@@ -610,10 +602,10 @@ export class SessionRoutes extends BaseRouteHandler {
|
||||
// Step 5: Save cleaned user prompt
|
||||
store.saveUserPrompt(contentSessionId, promptNumber, cleanedPrompt);
|
||||
|
||||
logger.info('SESSION', 'Session initialized via HTTP', {
|
||||
// Debug-level log since CREATED already logged the key info
|
||||
logger.debug('SESSION', 'User prompt saved', {
|
||||
sessionId: sessionDbId,
|
||||
promptNumber,
|
||||
project
|
||||
promptNumber
|
||||
});
|
||||
|
||||
res.json({
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<claude-mem-context>
|
||||
# Recent Activity
|
||||
|
||||
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
||||
|
||||
### Jan 3, 2026
|
||||
|
||||
**ResultFormatter.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36670 | 11:37 PM | ✅ | Resolved merge conflicts by accepting branch changes for 39 files | ~435 |
|
||||
| #36540 | 9:39 PM | 🟣 | ResultFormatter Test Suite Created | ~424 |
|
||||
| #36533 | 9:35 PM | 🔵 | ResultFormatter for Unified Search Result Display | ~598 |
|
||||
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
|
||||
|
||||
**SearchOrchestrator.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36545 | 9:41 PM | 🟣 | Phase 3 Search Strategy Test Suite Completion | ~564 |
|
||||
| #36544 | 9:40 PM | 🟣 | Phase 3 Search Strategy Test Suite Complete | ~449 |
|
||||
| #36543 | " | 🟣 | Phase 3 Search Strategy Tests Completed | ~458 |
|
||||
| #36541 | 9:39 PM | 🟣 | SearchOrchestrator Test Suite Implementation | ~588 |
|
||||
| #36531 | 9:34 PM | 🔵 | SearchOrchestrator Strategy Selection Logic | ~334 |
|
||||
| #36529 | " | 🔵 | Search Module Architecture Discovery | ~302 |
|
||||
|
||||
**types.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36538 | 9:38 PM | 🟣 | SQLiteSearchStrategy Test Suite Created | ~527 |
|
||||
| #36537 | " | 🟣 | HybridSearchStrategy Test Suite Created | ~435 |
|
||||
| #36536 | " | 🟣 | ChromaSearchStrategy Test Suite Created | ~430 |
|
||||
| #36523 | 9:34 PM | 🔴 | Fixed TypeScript Type Import Issues in Worker Services | ~386 |
|
||||
| #36519 | " | 🔴 | Fixed Type Import Issues Preventing Worker Tests | ~308 |
|
||||
| #36516 | 9:33 PM | 🔴 | Fixed TypeScript Type Import Issues in Worker Search Modules | ~377 |
|
||||
|
||||
**index.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36527 | 9:34 PM | 🔵 | Search Strategy Architecture Analysis for Phase 3 Testing | ~486 |
|
||||
| #36421 | 8:58 PM | 🔄 | Search Module Public API Organization | ~393 |
|
||||
|
||||
### Jan 5, 2026
|
||||
|
||||
**ResultFormatter.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #37968 | 8:22 PM | 🔵 | ResultFormatter Uses Epoch Timestamps from Database | ~364 |
|
||||
</claude-mem-context>
|
||||
@@ -62,10 +62,8 @@ export class ResultFormatter {
|
||||
for (const result of dayResults) {
|
||||
let file = 'General';
|
||||
if (result.type === 'observation') {
|
||||
file = extractFirstFile(
|
||||
(result.data as ObservationSearchResult).files_modified,
|
||||
cwd
|
||||
);
|
||||
const obs = result.data as ObservationSearchResult;
|
||||
file = extractFirstFile(obs.files_modified, cwd, obs.files_read);
|
||||
}
|
||||
if (!resultsByFile.has(file)) {
|
||||
resultsByFile.set(file, []);
|
||||
|
||||
@@ -216,7 +216,7 @@ export class TimelineBuilder {
|
||||
|
||||
} else if (item.type === 'observation') {
|
||||
const obs = item.data as ObservationSearchResult;
|
||||
const file = extractFirstFile(obs.files_modified, cwd);
|
||||
const file = extractFirstFile(obs.files_modified, cwd, obs.files_read);
|
||||
|
||||
if (file !== currentFile) {
|
||||
if (tableOpen) {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<claude-mem-context>
|
||||
# Recent Activity
|
||||
|
||||
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
||||
|
||||
### Jan 3, 2026
|
||||
|
||||
**DateFilter.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36670 | 11:37 PM | ✅ | Resolved merge conflicts by accepting branch changes for 39 files | ~435 |
|
||||
| #36523 | 9:34 PM | 🔴 | Fixed TypeScript Type Import Issues in Worker Services | ~386 |
|
||||
| #36519 | " | 🔴 | Fixed Type Import Issues Preventing Worker Tests | ~308 |
|
||||
| #36516 | 9:33 PM | 🔴 | Fixed TypeScript Type Import Issues in Worker Search Modules | ~377 |
|
||||
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
|
||||
|
||||
**ProjectFilter.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36529 | 9:34 PM | 🔵 | Search Module Architecture Discovery | ~302 |
|
||||
</claude-mem-context>
|
||||
@@ -0,0 +1,45 @@
|
||||
<claude-mem-context>
|
||||
# Recent Activity
|
||||
|
||||
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
||||
|
||||
### Jan 3, 2026
|
||||
|
||||
**SearchStrategy.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36670 | 11:37 PM | ✅ | Resolved merge conflicts by accepting branch changes for 39 files | ~435 |
|
||||
| #36534 | 9:35 PM | 🔵 | SearchStrategy Interface Pattern | ~341 |
|
||||
| #36523 | 9:34 PM | 🔴 | Fixed TypeScript Type Import Issues in Worker Services | ~386 |
|
||||
| #36519 | " | 🔴 | Fixed Type Import Issues Preventing Worker Tests | ~308 |
|
||||
| #36516 | 9:33 PM | 🔴 | Fixed TypeScript Type Import Issues in Worker Search Modules | ~377 |
|
||||
| #36449 | 9:02 PM | 🔵 | Search Strategy Base Implementation | ~410 |
|
||||
| #36419 | 8:57 PM | 🔵 | Search Strategy Interface Pattern | ~380 |
|
||||
|
||||
**SQLiteSearchStrategy.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36545 | 9:41 PM | 🟣 | Phase 3 Search Strategy Test Suite Completion | ~564 |
|
||||
| #36544 | 9:40 PM | 🟣 | Phase 3 Search Strategy Test Suite Complete | ~449 |
|
||||
| #36538 | 9:38 PM | 🟣 | SQLiteSearchStrategy Test Suite Created | ~527 |
|
||||
| #36527 | 9:34 PM | 🔵 | Search Strategy Architecture Analysis for Phase 3 Testing | ~486 |
|
||||
| #36526 | " | 🔵 | SQLite Search Strategy Architecture | ~439 |
|
||||
| #36451 | 9:02 PM | 🔵 | SQLite Search Strategy Implementation | ~453 |
|
||||
|
||||
**ChromaSearchStrategy.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36543 | 9:40 PM | 🟣 | Phase 3 Search Strategy Tests Completed | ~458 |
|
||||
| #36536 | 9:38 PM | 🟣 | ChromaSearchStrategy Test Suite Created | ~430 |
|
||||
| #36530 | 9:34 PM | 🔵 | Chroma Vector Search Strategy Architecture | ~508 |
|
||||
| #36529 | " | 🔵 | Search Module Architecture Discovery | ~302 |
|
||||
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
|
||||
|
||||
**HybridSearchStrategy.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #36537 | 9:38 PM | 🟣 | HybridSearchStrategy Test Suite Created | ~435 |
|
||||
| #36532 | 9:34 PM | 🔵 | HybridSearchStrategy Four-Step Pattern | ~333 |
|
||||
| #36528 | " | 🔵 | Hybrid Search Strategy Combining Metadata Filtering with Semantic Ranking | ~525 |
|
||||
| #36459 | 9:03 PM | 🔵 | Hybrid Search Strategy with Four-Step Algorithm | ~530 |
|
||||
</claude-mem-context>
|
||||
@@ -0,0 +1,103 @@
|
||||
<claude-mem-context>
|
||||
# Recent Activity
|
||||
|
||||
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
||||
|
||||
### Dec 7, 2025
|
||||
|
||||
**SessionCompletionHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #21829 | 11:05 PM | 🔄 | Massive refactor adds 8,671 lines and removes 5,585 lines across 60 files | ~619 |
|
||||
| #21825 | 11:00 PM | 🔵 | SessionCompletionHandler methods called 3 times in SessionRoutes | ~342 |
|
||||
| #21824 | 10:59 PM | 🔵 | SessionEventBroadcaster methods called 7 times across SessionRoutes and SessionCompletionHandler | ~398 |
|
||||
| #21822 | " | 🔵 | SessionEventBroadcaster instantiated in WorkerService and injected into routes and handlers | ~372 |
|
||||
| #21818 | 10:58 PM | 🔵 | SessionCompletionHandler is instantiated in SessionRoutes | ~282 |
|
||||
| #21817 | " | 🔵 | SessionCompletionHandler consolidates session completion logic | ~414 |
|
||||
| #21807 | 10:49 PM | ⚖️ | KISS Audit Identified 587 Lines of Ceremonial Complexity | ~699 |
|
||||
| #21794 | 10:46 PM | 🔵 | SessionCompletionHandler Consolidates Duplicate Completion Logic | ~341 |
|
||||
| #21764 | 10:23 PM | ✅ | Phase 4 Build and Deployment Successful | ~376 |
|
||||
| #21759 | 10:21 PM | 🟣 | SessionCompletionHandler Service Created | ~426 |
|
||||
|
||||
### Dec 11, 2025
|
||||
|
||||
**SessionCompletionHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #23962 | 1:59 PM | 🔵 | Services Layer Implements Full Backend Architecture | ~490 |
|
||||
|
||||
### Dec 14, 2025
|
||||
|
||||
**SessionCompletionHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #26088 | 7:32 PM | 🔵 | API Endpoint Architecture Discovery | ~416 |
|
||||
|
||||
### Dec 20, 2025
|
||||
|
||||
**SessionCompletionHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #30725 | 5:12 PM | 🔵 | Revealed extensive work-in-progress changes across hook and worker systems | ~479 |
|
||||
| #30569 | 4:56 PM | 🔄 | SessionCompletionHandler Broadcasting Implementation | ~264 |
|
||||
| #30568 | " | 🔄 | SessionCompletionHandler Event Broadcasting Refactor | ~282 |
|
||||
| #30566 | " | 🔵 | Session Completion Handler Consolidation | ~323 |
|
||||
|
||||
### Dec 24, 2025
|
||||
|
||||
**SessionCompletionHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #32350 | 8:42 PM | 🔵 | Detailed Cleanup Hook Evolution Documentation Retrieved | ~597 |
|
||||
| #32316 | 8:41 PM | 🔄 | Removed markSessionComplete method from DatabaseManager | ~251 |
|
||||
| #32194 | 7:42 PM | 🔵 | Session completion handler implementation analysis | ~329 |
|
||||
| #32193 | " | 🔵 | Session completion endpoint usage across codebase | ~278 |
|
||||
| #32182 | 7:15 PM | 🔄 | Removed markSessionComplete database call from session completion flow | ~316 |
|
||||
| #32179 | 7:11 PM | 🔄 | SessionCompletionHandler switched to direct SQL query | ~273 |
|
||||
| #32153 | 6:40 PM | 🔵 | Session Identifier Architecture Across Codebase | ~529 |
|
||||
|
||||
### Dec 25, 2025
|
||||
|
||||
**SessionCompletionHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #32597 | 8:40 PM | 🔵 | Identified session completion mechanism and potential method discrepancy | ~470 |
|
||||
| #32456 | 5:41 PM | ✅ | Completed merge of main branch into feature/titans-phase1-3 | ~354 |
|
||||
| #32198 | 7:41 PM | 🔄 | Removed redundant SessionEnd cleanup hook | ~317 |
|
||||
|
||||
### Dec 27, 2025
|
||||
|
||||
**SessionCompletionHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #33099 | 7:10 PM | 🔵 | SessionCompletionHandler Manual Session Termination Flow | ~348 |
|
||||
|
||||
### Dec 28, 2025
|
||||
|
||||
**SessionCompletionHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #33328 | 3:10 PM | 🟣 | Merged centralized logger and session continuity diagnostics to main | ~397 |
|
||||
| #33280 | 3:07 PM | 🔄 | Logger coverage refactor for background services | ~428 |
|
||||
|
||||
### Dec 30, 2025
|
||||
|
||||
**SessionCompletionHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #34388 | 1:40 PM | 🔵 | SessionCompletionHandler Relies on SessionManager Abort Without Process Cleanup | ~309 |
|
||||
|
||||
### Dec 31, 2025
|
||||
|
||||
**SessionCompletionHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #34707 | 4:45 PM | 🔵 | SessionCompletionHandler Aborts SDK Agent During Cleanup | ~291 |
|
||||
|
||||
### Jan 2, 2026
|
||||
|
||||
**SessionCompletionHandler.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #35951 | 4:42 PM | 🔵 | Multi-Layer Service Architecture Discovery | ~395 |
|
||||
</claude-mem-context>
|
||||
@@ -0,0 +1,77 @@
|
||||
<claude-mem-context>
|
||||
# Recent Activity
|
||||
|
||||
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
||||
|
||||
### Dec 7, 2025
|
||||
|
||||
**PrivacyCheckValidator.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #21829 | 11:05 PM | 🔄 | Massive refactor adds 8,671 lines and removes 5,585 lines across 60 files | ~619 |
|
||||
| #21820 | 10:59 PM | 🔵 | PrivacyCheckValidator used twice in SessionRoutes for observation and summarize endpoints | ~303 |
|
||||
| #21814 | 10:58 PM | 🔵 | PrivacyCheckValidator centralizes user prompt privacy validation | ~359 |
|
||||
| #21807 | 10:49 PM | ⚖️ | KISS Audit Identified 587 Lines of Ceremonial Complexity | ~699 |
|
||||
| #21797 | 10:46 PM | 🔵 | PrivacyCheckValidator Implements Single Validation Method | ~349 |
|
||||
| #21770 | 10:36 PM | 🟣 | Implemented PrivacyCheckValidator for Centralized Privacy Validation | ~318 |
|
||||
|
||||
### Dec 8, 2025
|
||||
|
||||
**PrivacyCheckValidator.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #22274 | 9:22 PM | 🔵 | Event-Driven Architecture for SDK Response Coordination Fully Mapped | ~1136 |
|
||||
| #22270 | 9:12 PM | 🔵 | DRY violations identified in endless-mode-v7.1 branch | ~553 |
|
||||
|
||||
### Dec 9, 2025
|
||||
|
||||
**PrivacyCheckValidator.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #22808 | 2:01 PM | 🔵 | Logger Utility Pattern Identified | ~300 |
|
||||
| #22750 | 1:27 PM | 🔵 | PrivacyCheckValidator Centralizes Privacy Logic | ~450 |
|
||||
|
||||
### Dec 11, 2025
|
||||
|
||||
**PrivacyCheckValidator.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #23962 | 1:59 PM | 🔵 | Services Layer Implements Full Backend Architecture | ~490 |
|
||||
|
||||
### Dec 20, 2025
|
||||
|
||||
**PrivacyCheckValidator.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #30609 | 5:01 PM | 🔄 | Phase 4: Eliminated Over-Engineering in Hook/Worker System | ~504 |
|
||||
| #30598 | 5:00 PM | 🔄 | Removed PrivacyCheckValidator module | ~201 |
|
||||
| #30549 | 4:53 PM | 🔵 | PrivacyCheckValidator for User Prompt Filtering | ~325 |
|
||||
|
||||
### Dec 24, 2025
|
||||
|
||||
**PrivacyCheckValidator.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #32153 | 6:40 PM | 🔵 | Session Identifier Architecture Across Codebase | ~529 |
|
||||
|
||||
### Dec 25, 2025
|
||||
|
||||
**PrivacyCheckValidator.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #32580 | 8:22 PM | 🔵 | Grep for resetStuckMessages and processing | ~242 |
|
||||
|
||||
### Dec 28, 2025
|
||||
|
||||
**PrivacyCheckValidator.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #33439 | 10:15 PM | 🔄 | Extended Session ID Renaming to Additional Codebase Components | ~352 |
|
||||
|
||||
### Jan 2, 2026
|
||||
|
||||
**PrivacyCheckValidator.ts**
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #35951 | 4:42 PM | 🔵 | Multi-Layer Service Architecture Discovery | ~395 |
|
||||
</claude-mem-context>
|
||||
Reference in New Issue
Block a user