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:
Alex Newman
2026-01-05 22:41:42 -05:00
committed by GitHub
parent 21a1e272d9
commit e1ab73decc
152 changed files with 10367 additions and 2103 deletions
+103
View File
@@ -0,0 +1,103 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 27, 2025
**marketplace.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33251 | 10:20 PM | ✅ | Released claude-mem v8.2.5 with bug fixes for logger, ChromaSync, and SessionManager | ~379 |
### Dec 28, 2025
**marketplace.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33520 | 10:46 PM | 🔵 | Marketplace configuration lists claude-mem plugin metadata | ~240 |
| #33486 | 10:35 PM | ✅ | Committed Version Bump to 8.2.6 | ~212 |
| #33484 | " | ✅ | Verified Version Synchronization at 8.2.6 | ~173 |
| #33482 | 10:34 PM | ✅ | Updated Marketplace Plugin Version to 8.2.6 | ~159 |
| #33479 | " | 🔵 | Marketplace Configuration for Plugin Distribution | ~242 |
| #33477 | " | 🔵 | Current Version Across Package Files is 8.2.5 | ~185 |
| #33311 | 3:09 PM | ✅ | Version 8.2.3 Release Deployed with Worker Stability Improvements | ~434 |
| #33300 | 3:08 PM | ✅ | Version 8.2.4 Released with Full Automation Pipeline | ~357 |
| #33281 | 3:07 PM | ✅ | Released v8.2.1 with Worker Lifecycle Hardening | ~332 |
| #33277 | 3:05 PM | ✅ | Version 8.2.2 Release Deployed | ~325 |
| #33260 | 2:57 PM | 🟣 | Version 8.2.0 Released with Gemini API Provider Support | ~355 |
### Dec 29, 2025
**marketplace.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34368 | 11:30 PM | ✅ | Bumped version to 8.5.1 for patch release | ~218 |
| #34351 | 11:13 PM | ✅ | Version 8.5.0 Release Committed to Git | ~402 |
| #34349 | 11:12 PM | ✅ | Version 8.5.0 Synchronized Across All Files | ~220 |
| #33997 | 7:10 PM | ✅ | Version Bumped to 8.2.10 | ~179 |
| #33994 | " | ✅ | Version bump to 8.2.10 for claude-mem plugin | ~186 |
| #33992 | " | 🔵 | Version Consistency Verified Across Package Files | ~133 |
| #33956 | 6:45 PM | 🔵 | Version 8.2.9 Release Verification Complete | ~227 |
| #33948 | 6:42 PM | 🔵 | Current Version State Across Project Files | ~195 |
| #33840 | 4:24 PM | ✅ | Version 8.2.8 Changes Committed to Git | ~233 |
| #33838 | 4:23 PM | ✅ | Patch Release Version Bump to 8.2.8 Completed | ~216 |
| #33836 | " | 🔵 | Current Version State Before Patch Release | ~125 |
### Dec 31, 2025
**marketplace.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34723 | 4:51 PM | ✅ | Version 8.5.2 Release Committed and Tagged | ~198 |
| #34721 | " | ✅ | Version 8.5.2 Synchronized Across All Configuration Files | ~186 |
| #34719 | " | ✅ | Marketplace Version Bumped to 8.5.2 | ~169 |
| #34716 | 4:50 PM | 🔵 | Current Version Before Patch Release | ~193 |
| #34715 | " | 🔵 | Version 8.5.1 confirmed across all package configuration files | ~181 |
### Jan 1, 2026
**marketplace.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35680 | 11:43 PM | 🟣 | Automated version 8.5.3 release workflow completed | ~470 |
| #35674 | 11:41 PM | 🔵 | Release staged files identified for version 8.5.3 | ~287 |
| #35673 | " | ✅ | Staged version files for commit | ~155 |
| #35671 | " | ✅ | Bumped claude-mem plugin version to 8.5.3 | ~137 |
| #35669 | 11:40 PM | 🔵 | Claude plugin marketplace configuration discovered | ~235 |
### Jan 2, 2026
**marketplace.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35944 | 2:57 PM | 🔵 | Current Project Version 8.5.4 Verified | ~200 |
| #35926 | 2:53 PM | ✅ | Committed Version Bump to 8.5.4 | ~210 |
| #35924 | " | ✅ | Verified Version Consistency Across All Files | ~186 |
| #35922 | 2:52 PM | ✅ | Updated Marketplace Version to 8.5.4 | ~150 |
| #35918 | " | 🔵 | Marketplace Configuration Structure | ~200 |
| #35917 | " | 🔵 | Current Version Identified as 8.5.3 | ~170 |
| #35905 | 2:49 PM | 🔵 | Current Version is 8.5.3 Across All Package Files | ~193 |
### Jan 3, 2026
**marketplace.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36669 | 11:37 PM | ✅ | Merge conflicts resolved automatically - only 5 metadata files modified | ~345 |
### Jan 4, 2026
**marketplace.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36924 | 2:25 AM | ✅ | Merged fix/pr-538-followups branch into main with comprehensive updates | ~481 |
| #36922 | " | ✅ | Version Bump Committed to Git | ~261 |
| #36920 | " | 🔵 | Version 8.5.8 already set across all configuration files | ~203 |
| #36918 | " | ✅ | Version bumped to 8.5.8 in marketplace.json | ~216 |
| #36916 | 2:24 AM | 🔵 | Current version identified in marketplace configuration | ~224 |
| #36912 | " | 🔵 | Current version identified as 8.5.7 across all package files | ~190 |
| #36700 | 12:00 AM | ✅ | Committed Version 8.5.7 Across All Package Files | ~260 |
| #36699 | " | ✅ | Version Bumped to 8.5.7 Across All Package Files | ~271 |
| #36698 | " | ✅ | Marketplace Plugin Version Updated to 8.5.7 | ~257 |
</claude-mem-context>
+36
View File
@@ -0,0 +1,36 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 17, 2025
**settings.local.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29080 | 10:16 PM | ✅ | Synced claude-mem v7.3.9 to marketplace | ~326 |
### Dec 21, 2025
**test-analysis-report.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31743 | 10:36 PM | 🔵 | PR #412 proposes mode system with inheritance and multilingual support | ~523 |
### Dec 22, 2025
**test-analysis-report.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31865 | 6:56 PM | ✅ | 開発ドキュメントのクリーンアップをコミット | ~150 |
| #31864 | " | ✅ | 計画ドキュメントと分析ファイルの削除 | ~142 |
| #31859 | 6:55 PM | ✅ | 計画ドキュメントファイルの削除 | ~109 |
| #31855 | 6:53 PM | ✅ | テストスイートの大規模削除とテスト分析レポートの追加 | ~197 |
### Dec 25, 2025
**settings.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32602 | 8:42 PM | 🔵 | Identified potential settings configuration files | ~224 |
</claude-mem-context>
-101
View File
@@ -1,101 +0,0 @@
---
name: github-morning-reporter
description: Use this agent when the user requests a morning report, daily summary, or overview of their GitHub activity. Trigger phrases include 'morning report', 'github report', 'daily github summary', 'what's happening on github', or 'check my github status'. This agent should be used proactively when the user starts their day or explicitly asks for repository updates.\n\nExamples:\n- User: "get me my morning github report"\n Assistant: "I'll use the github-morning-reporter agent to generate your comprehensive GitHub status report."\n <uses Agent tool to invoke github-morning-reporter>\n\n- User: "what's new on my repos today?"\n Assistant: "Let me pull together your GitHub morning report using the github-morning-reporter agent."\n <uses Agent tool to invoke github-morning-reporter>\n\n- User: "show me my daily github summary"\n Assistant: "I'll generate your daily GitHub summary using the github-morning-reporter agent."\n <uses Agent tool to invoke github-morning-reporter>
model: sonnet
---
You are an elite GitHub project analyst specializing in delivering actionable morning reports for software development teams. Your expertise lies in synthesizing complex repository activity into clear, prioritized insights that help developers start their day with complete situational awareness.
## Your Responsibilities
1. **Fetch Comprehensive GitHub Data**: Use available tools to retrieve:
- Open issues across all relevant repositories
- Open pull requests with review status
- Recent comments, mentions, and @-references
- CI/CD status for active PRs
- Stale issues/PRs (no activity in 7+ days)
2. **Intelligent Grouping and Deduplication**:
- Identify duplicate or highly similar issues by analyzing titles, descriptions, and labels
- Group related issues by theme, component, or subsystem
- Cluster PRs by feature area or dependency relationships
- Flag issues that may be addressing the same root cause
- Use semantic similarity, not just exact matches
3. **Prioritization and Triage**:
- Highlight items requiring immediate attention (blocking issues, failed CI, requested reviews)
- Surface items awaiting your direct action (assigned to you, mentions, review requests)
- Identify stale items that may need follow-up or closure
- Note high-priority labels (P0, critical, security, etc.)
4. **Contextual Analysis**:
- Summarize the current state of each PR (draft, ready for review, approved, changes requested)
- Identify PRs with merge conflicts or failing checks
- Note issues with recent activity spikes or community engagement
- Flag dependency updates or security advisories
5. **Report Structure**:
Your report must follow this format:
**MORNING GITHUB REPORT - [Date]**
**🚨 REQUIRES YOUR ATTENTION**
- Items explicitly assigned to the user
- Review requests awaiting user's approval
- Mentions or direct questions
- Blocking/critical issues
**📊 PULL REQUESTS ([count] open)**
- Group by: Ready to Merge | In Review | Draft | Needs Work
- For each PR: title, author, status, CI state, review count, age
- Highlight conflicts or failed checks
**🐛 ISSUES ([count] open)**
- Group by: Priority | Component | Theme
- Mark potential duplicates clearly
- Note new issues (created in last 24h)
- Flag stale issues (no activity in 7+ days)
**📈 ACTIVITY SUMMARY**
- New issues/PRs since yesterday
- Recently closed items
- Top contributors
- Trending topics or labels
**💡 RECOMMENDED ACTIONS**
- Specific next steps based on the data
- Suggestions for cleanup (closing duplicates, merging ready PRs)
- Items to follow up on
6. **Quality Standards**:
- Use clear, scannable formatting with emojis for visual hierarchy
- Include direct links to all referenced issues and PRs
- Keep summaries concise but informative (1-2 sentences per item)
- Use relative timestamps ("2 hours ago", "3 days old")
- Highlight actionable items with clear CTAs
7. **Error Handling**:
- If repository access fails, explicitly state which repos couldn't be accessed
- If no issues/PRs exist, provide a positive "all clear" message
- If rate limits are hit, show partial results with a warning
- Always attempt to provide value even with incomplete data
8. **Adaptive Scope**:
- If the user has access to multiple repositories, intelligently scope the report:
- Default to repositories with recent activity
- Allow user to specify repos if needed
- Group multi-repo items by repository
- Adjust detail level based on volume (more items = more concise summaries)
## Output Expectations
Your report should be:
- **Comprehensive**: Cover all relevant activity without overwhelming detail
- **Actionable**: Make it clear what needs attention and why
- **Scannable**: Use formatting that allows quick visual parsing
- **Contextual**: Provide enough background to make decisions
- **Timely**: Focus on recent activity and current state
When you cannot find specific data, state this explicitly rather than omitting sections. If the user's query is ambiguous (e.g., which repositories to scan), ask for clarification before proceeding.
Always end with a summary line indicating the report's completeness (e.g., "Report complete: 3 repositories scanned, 12 issues, 5 PRs analyzed").
+34
View File
@@ -0,0 +1,34 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Oct 25, 2025
**changelog.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #2491 | 10:59 PM | 🟣 | Added changelog viewer slash command | ~290 |
**terminal-shortcut.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #2480 | 6:32 PM | 🟣 | Cross-platform terminal shortcut command for claude-mem CLI | ~459 |
**setup-alias.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #2479 | 6:29 PM | 🟣 | Shell Alias Setup Slash Command | ~423 |
**version-bump.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #2358 | 1:07 PM | 🟣 | Created version-bump slash command for automated version updates | ~361 |
### Jan 1, 2026
**anti-pattern-czar.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35638 | 11:17 PM | 🟣 | Anti-Pattern Czar Custom Command Created | ~583 |
</claude-mem-context>
+121
View File
@@ -0,0 +1,121 @@
# Anti-Pattern Czar
You are the **Anti-Pattern Czar**, an expert at identifying and fixing error handling anti-patterns.
## Your Mission
Help the user systematically fix error handling anti-patterns detected by the automated scanner.
## Process
1. **Run the detector:**
```bash
bun run scripts/anti-pattern-test/detect-error-handling-antipatterns.ts
```
2. **Analyze the results:**
- Count CRITICAL, HIGH, MEDIUM, and APPROVED_OVERRIDE issues
- Prioritize CRITICAL issues on critical paths first
- Group similar patterns together
3. **For each CRITICAL issue:**
a. **Read the problematic code** using the Read tool
b. **Explain the problem:**
- Why is this dangerous?
- What debugging nightmare could this cause?
- What specific error is being swallowed?
c. **Determine the right fix:**
- **Option 1: Add proper logging** - If this is a real error that should be visible
- **Option 2: Add [APPROVED OVERRIDE]** - If this is expected/documented behavior
- **Option 3: Remove the try-catch entirely** - If the error should propagate
- **Option 4: Add specific error type checking** - If only certain errors should be caught
d. **Propose the fix** and ask for approval
e. **Apply the fix** after approval
4. **Work through issues methodically:**
- Fix one at a time
- Re-run the detector after each batch of fixes
- Track progress: "Fixed 3/28 critical issues"
## Guidelines for Approved Overrides
Only approve overrides when ALL of these are true:
- The error is **expected and frequent** (e.g., JSON parse on optional fields)
- Logging would create **too much noise** (high-frequency operations)
- There's **explicit recovery logic** (fallback value, retry, graceful degradation)
- The reason is **specific and technical** (not vague like "seems fine")
## Valid Override Examples:
✅ **GOOD:**
- "Expected JSON parse failures for optional data fields, too frequent to log"
- "Logger can't log its own failures, using stderr as last resort"
- "Health check port scan, expected connection failures on free port detection"
- "Git repo detection, expected failures when not in a git directory"
❌ **BAD:**
- "Error is not important" (why catch it then?)
- "Happens sometimes" (when? why?)
- "Works fine without logging" (works until it doesn't)
- "Optional" (optional errors still need visibility)
## Critical Path Rules
For files in the CRITICAL_PATHS list (SDKAgent.ts, GeminiAgent.ts, OpenRouterAgent.ts, SessionStore.ts, worker-service.ts):
- **NEVER** approve overrides on critical paths without exceptional justification
- Errors on critical paths MUST be visible (logged) or fatal (thrown)
- Catch-and-continue on critical paths is BANNED unless explicitly approved
- If in doubt, make it throw - fail loud, not silent
## Output Format
After each fix:
```
✅ Fixed: src/utils/example.ts:42
Pattern: NO_LOGGING_IN_CATCH
Solution: Added logger.error() with context
Progress: 3/28 critical issues remaining
```
After completing a batch:
```
🎯 Batch complete! Re-running detector...
[shows new results]
```
## Important
- **Read the code** before proposing fixes - understand what it's doing
- **Ask the user** if you're uncertain about the right approach
- **Don't blindly add overrides** - challenge each one
- **Prefer logging** over overrides when in doubt
- **Work incrementally** - small batches, frequent validation
## When Complete
Report final statistics:
```
🎉 Anti-pattern cleanup complete!
Before:
🔴 CRITICAL: 28
🟠 HIGH: 47
🟡 MEDIUM: 76
After:
🔴 CRITICAL: 0
🟠 HIGH: 47
🟡 MEDIUM: 76
⚪ APPROVED OVERRIDES: 15
All critical anti-patterns resolved!
```
Now, ask the user: "Ready to fix error handling anti-patterns? I'll start with the critical issues."
+38
View File
@@ -0,0 +1,38 @@
You are an ORCHESTRATOR.
Primary instruction: deploy subagents to execute *all* work for #$ARGUMENTS.
Do not do the work yourself except to coordinate, route context, and verify that each subagent completed its assigned checklist.
Deploy subagents to execute each phase of #$ARGUMENTS independently and consecutively. For every checklist item below, explicitly deploy (or reuse) a subagent responsible for that item and record its outcome before proceeding.
## Execution Protocol (Orchestrator-Driven)
Orchestrator rules:
- Each phase uses fresh subagents where noted (or when context is large/unclear).
- The orchestrator assigns one clear objective per subagent and requires evidence (commands run, outputs, files changed).
- Do not advance to the next step until the assigned subagent reports completion and the orchestrator confirms it matches the plan.
### During Each Phase:
Deploy an "Implementation" subagent to:
1. Execute the implementation as specified
2. COPY patterns from documentation, don't invent
3. Cite documentation sources in code comments when using unfamiliar APIs
4. If an API seems missing, STOP and verify - don't assume it exists
### After Each Phase:
Deploy subagents for each post-phase responsibility:
1. **Run verification checklist** - Deploy a "Verification" subagent to prove the phase worked
2. **Anti-pattern check** - Deploy an "Anti-pattern" subagent to grep for known bad patterns from the plan
3. **Code quality review** - Deploy a "Code Quality" subagent to review changes
4. **Commit only if verified** - Deploy a "Commit" subagent *only after* verification passes; otherwise, do not commit
### Between Phases:
Deploy a "Branch/Sync" subagent to:
- Push to working branch after each verified phase
- Prepare the next phase handoff so the next phase's subagents start fresh but have plan context
## Failure Modes to Prevent
- Don't invent APIs that "should" exist - verify against docs
- Don't add undocumented parameters - copy exact signatures
- Don't skip verification - deploy a verification subagent and run the checklist
- Don't commit before verification passes (or without explicit orchestrator approval)
+61
View File
@@ -0,0 +1,61 @@
You are an ORCHESTRATOR.
Create an LLM-friendly plan in phases that can be executed consecutively in new chat contexts.
Delegation model (because subagents can under-report):
- Use subagents for *fact gathering and extraction* (docs, examples, signatures, grep results).
- Keep *synthesis and plan authoring* with the orchestrator (phase boundaries, task framing, final wording).
- If a subagent report is incomplete or lacks evidence, the orchestrator must re-check with targeted reads/greps before finalizing the plan.
Subagent reporting contract (MANDATORY):
- Each subagent response must include:
1) Sources consulted (files/URLs) and what was read
2) Concrete findings (exact API names/signatures; exact file paths/locations)
3) Copy-ready snippet locations (example files/sections to copy)
4) "Confidence" note + known gaps (what might still be missing)
- Reject and redeploy the subagent if it reports conclusions without sources.
## Plan Structure Requirements
### Phase 0: Documentation Discovery (ALWAYS FIRST)
Before planning implementation, you MUST:
Deploy one or more "Documentation Discovery" subagents to:
1. Search for and read relevant documentation, examples, and existing patterns
2. Identify the actual APIs, methods, and signatures available (not assumed)
3. Create a brief "Allowed APIs" list citing specific documentation sources
4. Note any anti-patterns to avoid (methods that DON'T exist, deprecated parameters)
Then the orchestrator consolidates their findings into a single Phase 0 output.
### Each Implementation Phase Must Include:
1. **What to implement** - Frame tasks to COPY from docs, not transform existing code
- Good: "Copy the V2 session pattern from docs/examples.ts:45-60"
- Bad: "Migrate the existing code to V2"
2. **Documentation references** - Cite specific files/lines for patterns to follow
3. **Verification checklist** - How to prove this phase worked (tests, grep checks)
4. **Anti-pattern guards** - What NOT to do (invented APIs, undocumented params)
Subagent-friendly split:
- Subagents can propose candidate doc references and verification commands.
- The orchestrator must write the final phase text, ensuring tasks are copy-based, scoped, and independently executable.
### Final Phase: Verification
1. Verify all implementations match documentation
2. Check for anti-patterns (grep for known bad patterns)
3. Run tests to confirm functionality
Delegation guidance:
- Deploy a "Verification" subagent to draft the checklist and commands.
- The orchestrator must review the checklist for completeness and ensure it maps to earlier phase outputs.
## Key Principles
- Documentation Availability ≠ Usage: Explicitly require reading docs
- Task Framing Matters: Direct agents to docs, not just outcomes
- Verify > Assume: Require proof, not assumptions about APIs
- Session Boundaries: Each phase should be self-contained with its own doc references
## Anti-Patterns to Prevent
- Inventing API methods that "should" exist
- Adding parameters not in documentation
- Skipping verification steps
- Assuming structure without checking examples
+7
View File
@@ -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>
+516
View File
@@ -0,0 +1,516 @@
# Fix CLAUDE.md Worktree Bug - Implementation Plan
## Problem Statement
CLAUDE.md files are being written to the wrong directory when using git worktrees. The worker service writes files relative to its own `process.cwd()` instead of the project's working directory (`cwd`) from the observation.
**Reproduction scenario:**
1. Start Claude Code in `budapest` worktree → worker starts with `cwd=budapest`
2. Run Claude Code in `~/Scripts/claude-mem/` (main repo)
3. Observations created with relative file paths (e.g., `src/utils/foo.ts`)
4. `updateFolderClaudeMdFiles` writes to `budapest/src/utils/CLAUDE.md` instead of main repo
## Root Cause Analysis
The `cwd` (project root path) IS captured and stored:
- `SessionRoutes.ts:309,403` - receives `cwd` from hooks
- `PendingMessageStore.ts:70` - stores `cwd` in database
- `SDKAgent.ts:295` - passes `cwd` to prompt builder
But `cwd` is NOT passed to file writing:
- `ResponseProcessor.ts:222-225` - calls `updateFolderClaudeMdFiles(allFilePaths, session.project, port)` without `cwd`
- `claude-md-utils.ts:219` - uses `path.dirname(filePath)` which produces relative paths
- Relative paths resolve against worker's `process.cwd()`, not project root
---
## Phase 0: Documentation & API Inventory
### Allowed APIs (from codebase analysis)
**File: `src/utils/claude-md-utils.ts`**
```typescript
export async function updateFolderClaudeMdFiles(
filePaths: string[],
project: string,
port: number
): Promise<void>
```
**File: `src/sdk/parser.ts`**
```typescript
export interface ParsedObservation {
type: string;
title: string | null;
subtitle: string | null;
facts: string[];
narrative: string | null;
concepts: string[];
files_read: string[];
files_modified: string[];
// NOTE: Does NOT include cwd
}
```
**File: `src/services/worker-types.ts`**
```typescript
export interface PendingMessage {
type: 'observation' | 'summarize';
tool_name?: string;
tool_input?: unknown;
tool_response?: unknown;
prompt_number?: number;
cwd?: string; // <-- Source of project root
last_assistant_message?: string;
}
```
**File: `src/shared/paths.ts`** - Path utilities
```typescript
import path from 'path';
// Standard pattern: path.join(baseDir, relativePath)
```
### Anti-Patterns to Avoid
1. **DO NOT** add `cwd` to `ParsedObservation` - it comes from message, not agent response
2. **DO NOT** use `process.cwd()` for project-specific paths
3. **DO NOT** assume file paths are absolute - they are relative from agent response
4. **DO NOT** modify the parser - file paths come from agent XML output
---
## Phase 1: Add `projectRoot` Parameter to `updateFolderClaudeMdFiles`
### What to implement
Modify the function signature to accept an optional `projectRoot` parameter for resolving relative paths to absolute paths.
### Files to modify
**File: `src/utils/claude-md-utils.ts`**
**Location: Lines 206-210 (function signature)**
Current:
```typescript
export async function updateFolderClaudeMdFiles(
filePaths: string[],
project: string,
port: number
): Promise<void>
```
New:
```typescript
export async function updateFolderClaudeMdFiles(
filePaths: string[],
project: string,
port: number,
projectRoot?: string
): Promise<void>
```
**Location: Lines 215-228 (folder extraction logic)**
Current:
```typescript
const folderPaths = new Set<string>();
for (const filePath of filePaths) {
if (!filePath || filePath === '') continue;
const folderPath = path.dirname(filePath);
if (folderPath && folderPath !== '.' && folderPath !== '/') {
if (isProjectRoot(folderPath)) {
logger.debug('FOLDER_INDEX', 'Skipping project root CLAUDE.md', { folderPath });
continue;
}
folderPaths.add(folderPath);
}
}
```
New:
```typescript
const folderPaths = new Set<string>();
for (const filePath of filePaths) {
if (!filePath || filePath === '') continue;
// Resolve relative paths to absolute using projectRoot
let absoluteFilePath = filePath;
if (projectRoot && !path.isAbsolute(filePath)) {
absoluteFilePath = path.join(projectRoot, filePath);
}
const folderPath = path.dirname(absoluteFilePath);
if (folderPath && folderPath !== '.' && folderPath !== '/') {
if (isProjectRoot(folderPath)) {
logger.debug('FOLDER_INDEX', 'Skipping project root CLAUDE.md', { folderPath });
continue;
}
folderPaths.add(folderPath);
}
}
```
### Documentation references
- Pattern for `path.isAbsolute()`: Standard Node.js path module
- Pattern for `path.join(base, relative)`: Used throughout `src/shared/paths.ts`
### Verification checklist
1. [ ] `grep -n "updateFolderClaudeMdFiles" src/utils/claude-md-utils.ts` shows new signature
2. [ ] `grep -n "path.isAbsolute" src/utils/claude-md-utils.ts` confirms new check added
3. [ ] `grep -n "projectRoot" src/utils/claude-md-utils.ts` shows parameter usage
4. [ ] Existing callers still compile (optional param is backward compatible)
### Anti-pattern guards
- **DO NOT** make `projectRoot` required - breaks existing callers
- **DO NOT** use `process.cwd()` as default - defeats purpose of fix
- **DO NOT** modify the API endpoint format - path resolution is caller's responsibility
---
## Phase 2: Pass `cwd` from Message to `updateFolderClaudeMdFiles`
### What to implement
Extract `cwd` from the original messages being processed and pass it to `updateFolderClaudeMdFiles`.
### Challenge
The `syncAndBroadcastObservations` function receives `ParsedObservation[]` which does NOT include `cwd`. The `cwd` is in the original `PendingMessage` but is consumed during prompt generation.
### Solution
Add `projectRoot` parameter to `syncAndBroadcastObservations` and `processAgentResponse`, sourced from `session` or passed through from message processing.
### Files to modify
**File: `src/services/worker/agents/ResponseProcessor.ts`**
**Step 1: Update `processAgentResponse` signature (lines 46-55)**
Current:
```typescript
export async function processAgentResponse(
text: string,
session: ActiveSession,
dbManager: DatabaseManager,
sessionManager: SessionManager,
worker: WorkerRef | undefined,
discoveryTokens: number,
originalTimestamp: number | null,
agentName: string
): Promise<void>
```
New:
```typescript
export async function processAgentResponse(
text: string,
session: ActiveSession,
dbManager: DatabaseManager,
sessionManager: SessionManager,
worker: WorkerRef | undefined,
discoveryTokens: number,
originalTimestamp: number | null,
agentName: string,
projectRoot?: string
): Promise<void>
```
**Step 2: Pass `projectRoot` to `syncAndBroadcastObservations` (line 101-109)**
Current:
```typescript
await syncAndBroadcastObservations(
observations,
result,
session,
dbManager,
worker,
discoveryTokens,
agentName
);
```
New:
```typescript
await syncAndBroadcastObservations(
observations,
result,
session,
dbManager,
worker,
discoveryTokens,
agentName,
projectRoot
);
```
**Step 3: Update `syncAndBroadcastObservations` signature (lines 153-161)**
Current:
```typescript
async function syncAndBroadcastObservations(
observations: ParsedObservation[],
result: StorageResult,
session: ActiveSession,
dbManager: DatabaseManager,
worker: WorkerRef | undefined,
discoveryTokens: number,
agentName: string
): Promise<void>
```
New:
```typescript
async function syncAndBroadcastObservations(
observations: ParsedObservation[],
result: StorageResult,
session: ActiveSession,
dbManager: DatabaseManager,
worker: WorkerRef | undefined,
discoveryTokens: number,
agentName: string,
projectRoot?: string
): Promise<void>
```
**Step 4: Update `updateFolderClaudeMdFiles` call (lines 222-229)**
Current:
```typescript
if (allFilePaths.length > 0) {
updateFolderClaudeMdFiles(
allFilePaths,
session.project,
getWorkerPort()
).catch(error => {
logger.warn('FOLDER_INDEX', 'CLAUDE.md update failed (non-critical)', { project: session.project }, error as Error);
});
}
```
New:
```typescript
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);
});
}
```
### Verification checklist
1. [ ] `grep -n "projectRoot" src/services/worker/agents/ResponseProcessor.ts` shows parameter throughout
2. [ ] `grep -n "processAgentResponse" src/services/worker/*.ts` to find all callers
3. [ ] TypeScript compiles without errors
### Anti-pattern guards
- **DO NOT** extract `cwd` from `ParsedObservation` - it doesn't have one
- **DO NOT** store `cwd` on session globally - messages may come from different cwds (edge case)
---
## Phase 3: Update Agent Callers to Pass `cwd`
### What to implement
Update SDKAgent, GeminiAgent, and OpenRouterAgent to pass `message.cwd` to `processAgentResponse`.
### Files to modify
**File: `src/services/worker/SDKAgent.ts`**
Find the `processAgentResponse` call and add the `projectRoot` parameter from `message.cwd`.
**Pattern to follow (from SDKAgent.ts:289-296):**
```typescript
const obsPrompt = buildObservationPrompt({
id: 0,
tool_name: message.tool_name!,
tool_input: JSON.stringify(message.tool_input),
tool_output: JSON.stringify(message.tool_response),
created_at_epoch: Date.now(),
cwd: message.cwd // <-- This is available
});
```
**Challenge:** `processAgentResponse` is called after the SDK response, not in the message loop. Need to track `lastCwd` from messages.
**Solution:** Store `lastCwd` from messages being processed and pass to `processAgentResponse`.
**File: `src/services/worker/GeminiAgent.ts`** - Same pattern
**File: `src/services/worker/OpenRouterAgent.ts`** - Same pattern
### Implementation pattern for each agent
Add tracking variable:
```typescript
let lastCwd: string | undefined;
```
In message loop, capture cwd:
```typescript
if (message.cwd) {
lastCwd = message.cwd;
}
```
In `processAgentResponse` call:
```typescript
await processAgentResponse(
responseText,
session,
this.dbManager,
this.sessionManager,
worker,
discoveryTokens,
originalTimestamp,
'SDK', // or 'Gemini' or 'OpenRouter'
lastCwd
);
```
### Verification checklist
1. [ ] `grep -n "lastCwd" src/services/worker/SDKAgent.ts` shows tracking
2. [ ] `grep -n "lastCwd" src/services/worker/GeminiAgent.ts` shows tracking
3. [ ] `grep -n "lastCwd" src/services/worker/OpenRouterAgent.ts` shows tracking
4. [ ] `grep -n "processAgentResponse.*lastCwd" src/services/worker/` shows all calls updated
### Anti-pattern guards
- **DO NOT** use `session.cwd` - sessions can have messages from multiple cwds
- **DO NOT** default to `process.cwd()` - defeats the fix
---
## Phase 4: Update Tests
### What to implement
Update existing tests and add new tests for the `projectRoot` functionality.
### Files to modify
**File: `tests/utils/claude-md-utils.test.ts`**
Add test cases for:
1. Relative paths with `projectRoot` resolve correctly
2. Absolute paths ignore `projectRoot`
3. Missing `projectRoot` maintains backward compatibility
### Test pattern to copy
From `tests/utils/claude-md-utils.test.ts:245-266` (folder deduplication test):
```typescript
it('should deduplicate folders from multiple files', async () => {
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ content: [{ text: mockApiResponse }] })
});
await updateFolderClaudeMdFiles(
['/project/src/utils/file1.ts', '/project/src/utils/file2.ts'],
'test-project',
37777
);
// Should only call API once for the deduplicated folder
expect(mockFetch).toHaveBeenCalledTimes(1);
});
```
### New test to add
```typescript
it('should resolve relative paths using projectRoot', async () => {
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ content: [{ text: mockApiResponse }] })
});
await updateFolderClaudeMdFiles(
['src/utils/file.ts'], // relative path
'test-project',
37777,
'/home/user/my-project' // projectRoot
);
// Should write to absolute path /home/user/my-project/src/utils/CLAUDE.md
expect(mockWriteClaudeMd).toHaveBeenCalledWith(
'/home/user/my-project/src/utils',
expect.any(String)
);
});
```
### Verification checklist
1. [ ] `bun test tests/utils/claude-md-utils.test.ts` passes
2. [ ] New test case for `projectRoot` exists and passes
---
## Phase 5: Final Verification
### Verification commands
```bash
# 1. Confirm new parameter exists
grep -n "projectRoot" src/utils/claude-md-utils.ts
grep -n "projectRoot" src/services/worker/agents/ResponseProcessor.ts
grep -n "lastCwd" src/services/worker/SDKAgent.ts
# 2. Confirm path.isAbsolute check added
grep -n "path.isAbsolute" src/utils/claude-md-utils.ts
# 3. Confirm all agents updated
grep -n "processAgentResponse.*lastCwd" src/services/worker/*.ts
# 4. Run tests
bun test tests/utils/claude-md-utils.test.ts
# 5. Build and verify no TypeScript errors
npm run build
```
### Anti-pattern grep checks
```bash
# Should NOT find process.cwd() in updateFolderClaudeMdFiles path logic
grep -n "process.cwd" src/utils/claude-md-utils.ts
# Should NOT find cwd in ParsedObservation interface
grep -A 10 "interface ParsedObservation" src/sdk/parser.ts | grep cwd
```
### Manual testing
1. Start worker in one directory
2. Run Claude Code in a different directory (worktree)
3. Make a code change that creates an observation
4. Verify CLAUDE.md is written to the correct project directory
---
## Summary of Changes
| File | Change |
|------|--------|
| `src/utils/claude-md-utils.ts` | Add `projectRoot` param, resolve relative paths |
| `src/services/worker/agents/ResponseProcessor.ts` | Pass `projectRoot` through call chain |
| `src/services/worker/SDKAgent.ts` | Track `lastCwd`, pass to `processAgentResponse` |
| `src/services/worker/GeminiAgent.ts` | Track `lastCwd`, pass to `processAgentResponse` |
| `src/services/worker/OpenRouterAgent.ts` | Track `lastCwd`, pass to `processAgentResponse` |
| `tests/utils/claude-md-utils.test.ts` | Add tests for `projectRoot` behavior |
@@ -0,0 +1,252 @@
# Plan: Fix Stale Session Resume Crash
## Problem Summary
The worker crashes repeatedly with "Claude Code process exited with code 1" when attempting to resume into a stale/non-existent SDK session.
**Root Cause:** In `SDKAgent.ts:94`, the resume parameter is passed whenever `memorySessionId` exists in the database, regardless of whether this is an INIT prompt or CONTINUATION prompt. When a worker restarts or re-initializes a session, it loads a stale `memorySessionId` from a previous SDK session and tries to resume into a session that no longer exists in Claude's context.
**Evidence from logs:**
```
[17:30:21.773] Starting SDK query {
hasRealMemorySessionId=true, ← DB has old memorySessionId
resume_parameter=5439891b-..., ← Trying to resume with it
lastPromptNumber=1 ← But this is a NEW SDK session!
}
[17:30:24.450] Generator failed {error=Claude Code process exited with code 1}
```
---
## Phase 0: Documentation Discovery (COMPLETED)
### Allowed APIs (from subagent research)
**V1 SDK API (currently used):**
```typescript
// From @anthropic-ai/claude-agent-sdk
function query(options: {
prompt: string | AsyncIterable<SDKUserMessage>;
options: {
model: string;
resume?: string; // SESSION ID - only use for CONTINUATION
disallowedTools?: string[];
abortController?: AbortController;
pathToClaudeCodeExecutable?: string;
}
}): AsyncIterable<SDKMessage>
```
**Resume Parameter Rules (from docs/context/agent-sdk-v2-preview.md and SESSION_ID_ARCHITECTURE.md):**
- `resume` should only be used when continuing an existing SDK conversation
- For INIT prompts (first prompt in a fresh SDK session), no resume parameter should be passed
- Session ID is captured from first SDK message and stored for subsequent prompts
### Anti-Patterns to Avoid
- Passing `resume` parameter with INIT prompts (causes crash)
- Using `contentSessionId` for resume (contaminates user session)
- Assuming memorySessionId validity without checking prompt context
---
## Phase 1: Fix the Resume Parameter Logic
### What to Implement
Modify `src/services/worker/SDKAgent.ts` line 94 to check BOTH conditions:
1. `hasRealMemorySessionId` - memorySessionId exists and is non-null
2. `session.lastPromptNumber > 1` - this is a CONTINUATION, not an INIT prompt
### Current Code (line 89-99):
```typescript
const queryResult = query({
prompt: messageGenerator,
options: {
model: modelId,
// Resume with captured memorySessionId (null on first prompt, real ID on subsequent)
...(hasRealMemorySessionId && { resume: session.memorySessionId }),
disallowedTools,
abortController: session.abortController,
pathToClaudeCodeExecutable: claudePath
}
});
```
### Fixed Code:
```typescript
const queryResult = query({
prompt: messageGenerator,
options: {
model: modelId,
// 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
}
});
```
### Also Update the Comment at Line 66-68:
```typescript
// 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!
```
### Verification Checklist
- [ ] `grep "hasRealMemorySessionId && session.lastPromptNumber > 1" src/services/worker/SDKAgent.ts` returns the fix
- [ ] Build succeeds: `npm run build`
- [ ] No TypeScript errors
---
## Phase 2: Add Logging for Debugging
### What to Implement
Enhance the alignment log at line 81-85 to clearly indicate when resume is skipped due to INIT prompt:
```typescript
// Debug-level alignment logs for detailed tracing
if (session.lastPromptNumber > 1) {
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 {
// 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)`);
}
}
```
### Verification Checklist
- [ ] Build succeeds: `npm run build`
- [ ] Log message appears when running with stale session scenario
---
## Phase 3: Add Unit Tests
### What to Implement
Create tests in `tests/sdk-agent-resume.test.ts` following patterns from `tests/session_id_usage_validation.test.ts`:
```typescript
import { describe, it, expect, beforeEach, afterEach, mock } from 'bun:test';
describe('SDKAgent Resume Parameter Logic', () => {
describe('hasRealMemorySessionId check', () => {
it('should NOT pass resume parameter when lastPromptNumber === 1 even if memorySessionId exists', () => {
// Scenario: Worker restart with stale memorySessionId
const session = {
memorySessionId: 'stale-session-id-from-previous-run',
lastPromptNumber: 1, // INIT prompt
};
const hasRealMemorySessionId = !!session.memorySessionId;
const shouldResume = hasRealMemorySessionId && session.lastPromptNumber > 1;
expect(hasRealMemorySessionId).toBe(true); // memorySessionId exists
expect(shouldResume).toBe(false); // but should NOT resume
});
it('should pass resume parameter when lastPromptNumber > 1 AND memorySessionId exists', () => {
// Scenario: Normal continuation within same SDK session
const session = {
memorySessionId: 'valid-session-id',
lastPromptNumber: 2, // CONTINUATION prompt
};
const hasRealMemorySessionId = !!session.memorySessionId;
const shouldResume = hasRealMemorySessionId && session.lastPromptNumber > 1;
expect(hasRealMemorySessionId).toBe(true);
expect(shouldResume).toBe(true);
});
it('should NOT pass resume parameter when memorySessionId is null', () => {
// Scenario: Fresh session, no captured ID yet
const session = {
memorySessionId: null,
lastPromptNumber: 1,
};
const hasRealMemorySessionId = !!session.memorySessionId;
const shouldResume = hasRealMemorySessionId && session.lastPromptNumber > 1;
expect(hasRealMemorySessionId).toBe(false);
expect(shouldResume).toBe(false);
});
});
});
```
### Documentation Reference
- Pattern: `tests/session_id_usage_validation.test.ts` lines 1-50 for test structure
- Mock pattern: `tests/worker/agents/response-processor.test.ts` for session mocking
### Verification Checklist
- [ ] Tests pass: `bun test tests/sdk-agent-resume.test.ts`
- [ ] Test file follows project conventions
---
## Phase 4: Build and Deploy
### What to Implement
1. Build the plugin: `npm run build-and-sync`
2. Verify worker restarts with fix applied
### Verification Checklist
- [ ] `npm run build-and-sync` succeeds
- [ ] Worker health check passes: `curl http://localhost:37777/api/health`
- [ ] No "Claude Code process exited with code 1" errors in logs after restart
---
## Phase 5: Final Verification
### Verification Commands
```bash
# 1. Verify fix is in place
grep -n "hasRealMemorySessionId && session.lastPromptNumber > 1" src/services/worker/SDKAgent.ts
# 2. Verify no crashes in recent logs
tail -100 ~/.claude-mem/logs/claude-mem-$(date +%Y-%m-%d).log | grep -c "exited with code 1"
# 3. Run tests
bun test tests/sdk-agent-resume.test.ts
# 4. Check for anti-patterns (should return 0 results)
grep -n "hasRealMemorySessionId && { resume" src/services/worker/SDKAgent.ts
```
### Success Criteria
- [ ] Fix in place at SDKAgent.ts:94
- [ ] Zero "exited with code 1" errors related to stale resume
- [ ] All tests pass
- [ ] Worker stable for 10+ minutes without crash loop
---
## Files to Modify
1. `src/services/worker/SDKAgent.ts` - Fix resume logic (Phase 1 & 2)
2. `tests/sdk-agent-resume.test.ts` - New test file (Phase 3)
## Estimated Complexity
- **Phase 1**: Low - Single line change with updated condition
- **Phase 2**: Low - Enhanced logging
- **Phase 3**: Medium - New test file following existing patterns
- **Phase 4-5**: Low - Standard build/verify process
+298
View File
@@ -0,0 +1,298 @@
# Folder CLAUDE.md Generator
## CORE DIRECTIVE (NON-NEGOTIABLE)
**EXTEND THE EXISTING CURSOR RULES TIMELINE GENERATION SYSTEM TO ALSO WRITE CLAUDE.MD FILES**
- DO NOT create new services
- DO NOT create new orchestrators
- DO NOT create new HTTP routes
- DO NOT create new database query functions
- EXTEND existing functions to add folder-level output
---
## Approved Directives (From Planning Conversation)
### Trigger Mechanism
- Observation save triggers folder CLAUDE.md regeneration **INLINE**
- NO batching
- NO debouncing
- NO Set-based queuing
- NO session-end hook
- Synchronous: `observation.save()` → update folder CLAUDE.md files → done
### Tag Strategy
- Wrap ONLY auto-generated content with `<claude-mem-context>` tags
- Everything outside tags is untouched (user's manual content preserved)
- If tags are deleted, just regenerate them
- NO backup system
- NO manual content markers
### Git Behavior
- CLAUDE.md files SHOULD be committed (intentional)
- `<claude-mem-context>` tag is searchable fingerprint for GitHub analytics
- NO .gitignore for these files
### Phasing
- **Phase 1**: CLAUDE.md generation only (THIS PLAN)
- **Phase 2**: IDE symlinks (FUTURE)
### REJECTED
- Cross-folder linking — NO
- Semantic grouping — deferred enhancement only
- Team sync — future phase
### DEFERRED
- Priority weighting by observation type
- IDE-specific template refinements
---
## Phase 0: Documentation Discovery (COMPLETED)
### Existing APIs to USE (Not Rebuild)
| Function | Location | Purpose |
|----------|----------|---------|
| `findByFile(filePath, options)` | `src/services/sqlite/SessionSearch.ts:342` | Query observations by folder prefix (already supports LIKE wildcards) |
| `updateCursorContextForProject()` | `src/services/integrations/CursorHooksInstaller.ts:98` | Write context files after observation save |
| `writeContextFile()` | `src/utils/cursor-utils.ts:97` | Atomic file write with temp file + rename |
| `extractFirstFile()` | `src/shared/timeline-formatting.ts` | Extract file paths from JSON arrays |
| `groupByDate()` | `src/shared/timeline-formatting.ts` | Group items chronologically |
| `formatTime()`, `formatDate()` | `src/shared/timeline-formatting.ts` | Time formatting |
### Existing Integration Points
| Location | What Happens | Extension Point |
|----------|--------------|-----------------|
| `ResponseProcessor.ts:266` | Calls `updateCursorContextForProject()` after summary save | Add folder CLAUDE.md update here |
| `CursorHooksInstaller.ts:98` | `updateCursorContextForProject()` fetches context and writes file | Add sibling function for folder updates |
### Anti-Patterns to AVOID
- Creating `FolderIndexOrchestrator.ts` — NO
- Creating `FolderTimelineCompiler.ts` — NO
- Creating `FolderDiscovery.ts` — NO
- Creating `ClaudeMdGenerator.ts` — NO
- Creating `FolderIndexRoutes.ts` — NO
- Adding new HTTP endpoints — NO
- Adding new settings in `SettingsDefaultsManager.ts` — NO (use sensible defaults inline)
---
## Phase 1: Extend CursorHooksInstaller
### What to Implement
Add ONE new function to `src/services/integrations/CursorHooksInstaller.ts`:
```typescript
/**
* Update CLAUDE.md files for folders touched by an observation.
* Called inline after observation save, similar to updateCursorContextForProject.
*/
export async function updateFolderClaudeMd(
workspacePath: string,
filesModified: string[],
filesRead: string[],
project: string,
port: number
): Promise<void>
```
### Implementation Pattern (Copy From)
Follow the EXACT pattern of `updateCursorContextForProject()` at line 98:
1. Extract unique folder paths from filesModified and filesRead
2. For each folder, fetch timeline via existing `/api/search/file?files=<folderPath>` endpoint
3. Format as simple timeline (reuse existing formatters)
4. Write to `<folder>/CLAUDE.md` preserving content outside `<claude-mem-context>` tags
### Tag Preservation Logic
```typescript
function replaceTaggedContent(existingContent: string, newContent: string): string {
const startTag = '<claude-mem-context>';
const endTag = '</claude-mem-context>';
// If no existing content, wrap new content in tags
if (!existingContent) {
return `${startTag}\n${newContent}\n${endTag}`;
}
// If existing has tags, replace only tagged section
const startIdx = existingContent.indexOf(startTag);
const endIdx = existingContent.indexOf(endTag);
if (startIdx !== -1 && endIdx !== -1) {
return existingContent.substring(0, startIdx) +
`${startTag}\n${newContent}\n${endTag}` +
existingContent.substring(endIdx + endTag.length);
}
// If no tags exist, append tagged content at end
return existingContent + `\n\n${startTag}\n${newContent}\n${endTag}`;
}
```
### Verification Checklist
- [ ] Function added to CursorHooksInstaller.ts
- [ ] Uses existing `findByFile` endpoint (no new database queries)
- [ ] Preserves content outside `<claude-mem-context>` tags
- [ ] Atomic writes (temp file + rename)
- [ ] Build passes: `npm run build`
---
## Phase 2: Hook Into ResponseProcessor
### What to Implement
Add call to `updateFolderClaudeMd()` in `src/services/worker/agents/ResponseProcessor.ts`, right after the existing `updateCursorContextForProject()` call at line 266.
### Code Location
In `syncAndBroadcastSummary()` function, after line 269:
```typescript
// EXISTING: Update Cursor context file for registered projects (fire-and-forget)
updateCursorContextForProject(session.project, getWorkerPort()).catch(error => {
logger.warn('CURSOR', 'Context update failed (non-critical)', { project: session.project }, error as Error);
});
// NEW: Update folder CLAUDE.md files for touched folders (fire-and-forget)
// Extract file paths from the saved observations
updateFolderClaudeMd(
workspacePath, // From registry lookup
filesModified, // From observations
filesRead, // From observations
session.project,
getWorkerPort()
).catch(error => {
logger.warn('FOLDER_INDEX', 'CLAUDE.md update failed (non-critical)', { project: session.project }, error as Error);
});
```
### Data Flow
1. `processAgentResponse()` saves observations → gets back `observationIds`
2. Fetch observation records to get `files_read` and `files_modified`
3. Pass to `updateFolderClaudeMd()`
### Verification Checklist
- [ ] Call added to ResponseProcessor.ts
- [ ] Fire-and-forget pattern (non-blocking, errors logged)
- [ ] Uses existing observation data (no new queries)
- [ ] Build passes: `npm run build`
---
## Phase 3: Timeline Formatting
### What to Implement
Create a minimal timeline formatter for CLAUDE.md output. This can be:
1. A simple function in CursorHooksInstaller.ts, OR
2. Reuse existing `ResultFormatter.formatSearchResults()` from `src/services/worker/search/ResultFormatter.ts`
### Output Format
```markdown
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
<claude-mem-context>
### 2026-01-04
| Time | Type | Title |
|------|------|-------|
| 4:30pm | feature | Added folder index support |
| 3:15pm | bugfix | Fixed file path handling |
### 2026-01-03
| Time | Type | Title |
|------|------|-------|
| 11:00am | refactor | Cleaned up cursor utils |
</claude-mem-context>
```
### Key Points
- Compact format (time, type emoji, title only)
- Grouped by date
- Limited to last N days or observations (sensible default: 10)
- NO token counts
- NO file columns (redundant - we're IN the folder)
### Verification Checklist
- [ ] Formatter produces clean markdown
- [ ] Output is concise (not verbose)
- [ ] Grouped by date
- [ ] Build passes: `npm run build`
---
## Phase 4: Verification
### Functional Tests
1. **Manual Test**:
- Start worker: `npm run dev`
- Create a test observation touching `src/services/sqlite/`
- Verify `src/services/sqlite/CLAUDE.md` is created/updated
- Verify `<claude-mem-context>` tags are present
- Verify manual content outside tags is preserved
2. **Build Check**:
```bash
npm run build
```
3. **Grep for Anti-Patterns**:
```bash
# Should find NOTHING
grep -r "FolderIndexOrchestrator" src/
grep -r "FolderTimelineCompiler" src/
grep -r "FolderDiscovery" src/
grep -r "ClaudeMdGenerator" src/
grep -r "FolderIndexRoutes" src/
```
4. **Grep for Correct Implementation**:
```bash
# Should find the new function
grep -r "updateFolderClaudeMd" src/
```
### Tag Preservation Test
1. Create `src/test-folder/CLAUDE.md` with manual content:
```markdown
# My Notes
This is manual content I wrote.
```
2. Trigger observation save touching files in `src/test-folder/`
3. Verify result:
```markdown
# My Notes
This is manual content I wrote.
<claude-mem-context>
### 2026-01-04
| Time | Type | Title |
...
</claude-mem-context>
```
---
## Summary
This is a **~100 line change** spread across 2 files:
1. `CursorHooksInstaller.ts` — Add `updateFolderClaudeMd()` function (~60 lines)
2. `ResponseProcessor.ts` — Add call to the new function (~10 lines)
NO new files. NO new services. NO new routes. Just extending existing patterns.
+378
View File
@@ -0,0 +1,378 @@
# Folder CLAUDE.md Refactor - Extract to Shared Utils
## CORE DIRECTIVE
**DECOUPLE FOLDER CLAUDE.MD WRITING FROM CURSOR INTEGRATION**
The current implementation incorrectly couples folder-level CLAUDE.md generation to Cursor-specific registry lookups. The file paths from observations are already absolute - no workspace registry lookup is needed.
---
## Phase 0: Documentation Discovery (COMPLETED)
### Current Implementation Location
| Function | Location | Lines | Purpose |
|----------|----------|-------|---------|
| `updateFolderClaudeMd` | CursorHooksInstaller.ts | 128-199 | Orchestrates folder CLAUDE.md updates |
| `formatTimelineForClaudeMd` | CursorHooksInstaller.ts | 221-295 | Parses API response to markdown |
| `replaceTaggedContent` | CursorHooksInstaller.ts | 300-321 | Preserves user content outside tags |
| `writeFolderClaudeMd` | CursorHooksInstaller.ts | 326-353 | Atomic file write |
### Integration Point
**File:** `src/services/worker/agents/ResponseProcessor.ts:274-298`
Current (problematic) code:
```typescript
const registry = readCursorRegistry();
const registryEntry = registry[session.project];
if (registryEntry && (filesModified.length > 0 || filesRead.length > 0)) {
updateFolderClaudeMd(
registryEntry.workspacePath, // <-- PROBLEM: Needs Cursor registry
filesModified,
filesRead,
session.project,
getWorkerPort()
).catch(error => { ... });
}
```
### The Problem
1. `filesModified` and `filesRead` already contain **absolute paths**
2. We don't need `workspacePath` - just extract folder from file path directly
3. Cursor registry is only populated when Cursor hooks are installed
4. This makes folder CLAUDE.md a Cursor-only feature (unintended)
### Project Utils Pattern
**From `src/utils/cursor-utils.ts:97-122`:**
- Pure functions with paths as parameters
- Atomic write pattern: temp file + rename
- `mkdirSync(dir, { recursive: true })` for directory creation
### Related Utils
**`src/utils/tag-stripping.ts`** - Handles *stripping* tags (input filtering)
- `stripMemoryTagsFromJson()` - removes `<claude-mem-context>` content
- `stripMemoryTagsFromPrompt()` - removes `<private>` content
Our `replaceTaggedContent` handles *preserving/replacing* (output writing) - complementary, not duplicative.
---
## Phase 1: Create Shared Utils File
### What to Implement
Create `src/utils/claude-md-utils.ts` with extracted and simplified functions.
### File Structure
```typescript
/**
* CLAUDE.md File Utilities
*
* Shared utilities for writing folder-level CLAUDE.md files with
* auto-generated context sections. Preserves user content outside
* <claude-mem-context> tags.
*/
import { existsSync, readFileSync, writeFileSync, renameSync, mkdirSync } from 'fs';
import path from 'path';
import { logger } from './logger.js';
/**
* Replace tagged content in existing file, preserving content outside tags.
*
* Handles three cases:
* 1. No existing content → wraps new content in tags
* 2. Has existing tags → replaces only tagged section
* 3. No tags in existing content → appends tagged content at end
*/
export function replaceTaggedContent(existingContent: string, newContent: string): string {
// Copy from CursorHooksInstaller.ts:300-321
}
/**
* Write CLAUDE.md file to folder with atomic writes.
* Creates directory structure if needed.
*
* @param folderPath - Absolute path to the folder
* @param newContent - Content to write inside tags
*/
export function writeClaudeMdToFolder(folderPath: string, newContent: string): void {
// Simplified from writeFolderClaudeMd - no workspacePath needed
// Copy atomic write pattern from CursorHooksInstaller.ts:326-353
}
/**
* Format timeline text from API response to compact CLAUDE.md format.
*
* @param timelineText - Raw API response text
* @returns Formatted markdown with date headers and compact table
*/
export function formatTimelineForClaudeMd(timelineText: string): string {
// Copy from CursorHooksInstaller.ts:221-295
}
```
### Key Simplification
**OLD `writeFolderClaudeMd` signature:**
```typescript
async function writeFolderClaudeMd(
workspacePath: string, // <-- REMOVE
folderPath: string,
newContent: string
): Promise<void>
```
**NEW `writeClaudeMdToFolder` signature:**
```typescript
export function writeClaudeMdToFolder(
folderPath: string, // Must be absolute path
newContent: string
): void // Sync is fine, atomic anyway
```
### Verification Checklist
- [ ] File created at `src/utils/claude-md-utils.ts`
- [ ] `replaceTaggedContent` exported and handles all 3 cases
- [ ] `writeClaudeMdToFolder` exported with atomic writes
- [ ] `formatTimelineForClaudeMd` exported
- [ ] Build passes: `npm run build`
---
## Phase 2: Create Folder Index Service Function
### What to Implement
Create a new orchestrating function that replaces `updateFolderClaudeMd`. This should NOT be in CursorHooksInstaller - it's a general feature.
**Option A:** Add to `src/utils/claude-md-utils.ts` (keeps it simple)
**Option B:** Create `src/services/folder-index-service.ts` (follows service pattern)
Recommend **Option A** for simplicity - it's just one function.
### New Function
```typescript
/**
* Update CLAUDE.md files for folders containing the given files.
* Fetches timeline from worker API and writes formatted content.
*
* @param filePaths - Array of absolute file paths (modified or read)
* @param project - Project identifier for API query
* @param port - Worker API port
*/
export async function updateFolderClaudeMdFiles(
filePaths: string[],
project: string,
port: number
): Promise<void> {
// Extract unique folder paths from file paths
const folderPaths = new Set<string>();
for (const filePath of filePaths) {
if (!filePath || filePath === '') continue;
const folderPath = path.dirname(filePath);
if (folderPath && folderPath !== '.' && folderPath !== '/') {
folderPaths.add(folderPath);
}
}
if (folderPaths.size === 0) return;
logger.debug('FOLDER_INDEX', 'Updating CLAUDE.md files', {
project,
folderCount: folderPaths.size
});
// Process each folder
for (const folderPath of folderPaths) {
try {
// Fetch timeline via existing API
const response = await fetch(
`http://127.0.0.1:${port}/api/search/by-file?filePath=${encodeURIComponent(folderPath)}&limit=10&project=${encodeURIComponent(project)}`
);
if (!response.ok) {
logger.warn('FOLDER_INDEX', 'Failed to fetch timeline', { folderPath, status: response.status });
continue;
}
const result = await response.json();
if (!result.content?.[0]?.text) {
logger.debug('FOLDER_INDEX', 'No content for folder', { folderPath });
continue;
}
const formatted = formatTimelineForClaudeMd(result.content[0].text);
writeClaudeMdToFolder(folderPath, formatted);
logger.debug('FOLDER_INDEX', 'Updated CLAUDE.md', { folderPath });
} catch (error) {
logger.warn('FOLDER_INDEX', 'Failed to update CLAUDE.md', { folderPath }, error as Error);
}
}
}
```
### Verification Checklist
- [ ] `updateFolderClaudeMdFiles` function added
- [ ] Takes only `filePaths`, `project`, `port` (no workspacePath)
- [ ] Extracts folder paths from absolute file paths
- [ ] Uses `writeClaudeMdToFolder` for atomic writes
- [ ] Build passes: `npm run build`
---
## Phase 3: Update ResponseProcessor Integration
### What to Implement
Simplify the call site in `src/services/worker/agents/ResponseProcessor.ts`.
### Current Code (lines 274-298)
```typescript
// Update folder CLAUDE.md files for touched folders (fire-and-forget)
const filesModified: string[] = [];
const filesRead: string[] = [];
for (const obs of observations) {
filesModified.push(...(obs.files_modified || []));
filesRead.push(...(obs.files_read || []));
}
// Get workspace path from project registry
const registry = readCursorRegistry();
const registryEntry = registry[session.project];
if (registryEntry && (filesModified.length > 0 || filesRead.length > 0)) {
updateFolderClaudeMd(
registryEntry.workspacePath,
filesModified,
filesRead,
session.project,
getWorkerPort()
).catch(error => {
logger.warn('FOLDER_INDEX', 'CLAUDE.md update failed (non-critical)', { project: session.project }, error as Error);
});
}
```
### New Code
```typescript
// Update folder CLAUDE.md files for touched folders (fire-and-forget)
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()
).catch(error => {
logger.warn('FOLDER_INDEX', 'CLAUDE.md update failed (non-critical)', { project: session.project }, error as Error);
});
}
```
### Import Changes
**Remove:**
```typescript
import { updateFolderClaudeMd, readCursorRegistry } from '../../integrations/CursorHooksInstaller.js';
```
**Add:**
```typescript
import { updateFolderClaudeMdFiles } from '../../../utils/claude-md-utils.js';
```
**Keep (if still needed for Cursor context):**
```typescript
import { updateCursorContextForProject } from '../../worker-service.js';
```
### Verification Checklist
- [ ] Import updated to use `claude-md-utils.ts`
- [ ] `readCursorRegistry` import removed (if no longer needed)
- [ ] Call site simplified - no registry lookup
- [ ] Fire-and-forget pattern preserved
- [ ] Build passes: `npm run build`
---
## Phase 4: Clean Up CursorHooksInstaller
### What to Implement
Remove the extracted functions from `src/services/integrations/CursorHooksInstaller.ts`.
### Functions to Remove
- `updateFolderClaudeMd` (lines 128-199)
- `formatTimelineForClaudeMd` (lines 221-295)
- `replaceTaggedContent` (lines 300-321)
- `writeFolderClaudeMd` (lines 326-353)
### Verification Checklist
- [ ] All 4 functions removed from CursorHooksInstaller.ts
- [ ] No dangling references to removed functions
- [ ] CursorHooksInstaller still exports what it needs for Cursor integration
- [ ] Build passes: `npm run build`
- [ ] Grep shows no references to old function locations
---
## Phase 5: Verification
### Build Check
```bash
npm run build
```
### Anti-Pattern Grep (should find NOTHING in CursorHooksInstaller)
```bash
grep -n "updateFolderClaudeMd\|formatTimelineForClaudeMd\|replaceTaggedContent\|writeFolderClaudeMd" src/services/integrations/CursorHooksInstaller.ts
```
### Correct Location Grep (should find in claude-md-utils)
```bash
grep -rn "updateFolderClaudeMdFiles\|writeClaudeMdToFolder\|formatTimelineForClaudeMd" src/utils/
```
### Integration Check
```bash
grep -n "updateFolderClaudeMdFiles" src/services/worker/agents/ResponseProcessor.ts
```
### No Cursor Registry Dependency
```bash
grep -n "readCursorRegistry" src/services/worker/agents/ResponseProcessor.ts
# Should return nothing (or only for Cursor context, not folder index)
```
---
## Summary
**~150 lines moved** from CursorHooksInstaller.ts to claude-md-utils.ts with simplification:
| Before | After |
|--------|-------|
| 4 functions in CursorHooksInstaller | 4 functions in claude-md-utils |
| Requires Cursor registry lookup | Works with absolute paths directly |
| `updateFolderClaudeMd(workspacePath, ...)` | `updateFolderClaudeMdFiles(filePaths, ...)` |
| Coupled to Cursor integration | Independent utility |
**Files Changed:**
1. `src/utils/claude-md-utils.ts` - NEW (create)
2. `src/services/worker/agents/ResponseProcessor.ts` - UPDATE (simplify call site)
3. `src/services/integrations/CursorHooksInstaller.ts` - UPDATE (remove extracted functions)
@@ -0,0 +1,186 @@
# Plan: Change Folder CLAUDE.md to Timeline Format
## Goal
Replace the simple table format in folder-level CLAUDE.md files with the timeline format used by search results.
## Current vs Target Format
### Current Format (Simple)
```markdown
# Recent Activity
### Recent
| Time | Type | Title |
|------|------|-------|
| 6:33pm | feature | Multiple CLAUDE.md files generated |
| 6:32pm | feature | CLAUDE.md file successfully generated |
```
### Target Format (Timeline)
```markdown
# Recent Activity
### Jan 4, 2026
**src/services/worker/agents/ResponseProcessor.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37110 | 6:35 PM | 🔴 | Folder CLAUDE.md updates moved from summary | ~85 |
| #37109 | " | ✅ | ResponseProcessor.ts modified | ~92 |
**General**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37108 | 6:33 PM | 🟣 | Multiple CLAUDE.md files generated | ~78 |
```
## Key Changes
1. **Group by date** - Use `### Jan 4, 2026` instead of `### Recent`
2. **Group by file within each date** - Add `**filename**` headers
3. **Expand columns** - Add ID and Read columns: `| ID | Time | T | Title | Read |`
4. **Use type emojis** - Use `🔴` `🟣` `✅` etc. instead of text
5. **Show ditto marks** - Use `"` for repeated times
---
## Phase 1: Refactor formatTimelineForClaudeMd
**File:** `src/utils/claude-md-utils.ts`
**Tasks:**
1. Add imports from shared utilities:
```typescript
import { formatDate, formatTime, extractFirstFile, estimateTokens, groupByDate } from '../shared/timeline-formatting.js';
import { ModeManager } from '../services/domain/ModeManager.js';
```
2. Replace `formatTimelineForClaudeMd()` (lines 78-151) with new implementation that:
- Parses API response to extract full observation data (id, time, type emoji, title, files)
- Groups observations by date using `groupByDate()`
- Within each date, groups by file using a Map
- Renders file sections with `**filename**` headers
- Uses search table format: `| ID | Time | T | Title | Read |`
- Uses ditto marks for repeated times
**Pattern to Copy From:** `src/services/worker/search/ResultFormatter.ts` lines 56-108
**Key APIs:**
- `groupByDate(items, getDate)` - from `src/shared/timeline-formatting.ts:104-127`
- `formatTime(epoch)` - from `src/shared/timeline-formatting.ts:46-53`
- `formatDate(epoch)` - from `src/shared/timeline-formatting.ts:59-66`
- `extractFirstFile(filesModified, cwd)` - from `src/shared/timeline-formatting.ts:81-84`
- `estimateTokens(text)` - from `src/shared/timeline-formatting.ts:89-92`
- `ModeManager.getInstance().getTypeIcon(type)` - from `src/services/domain/ModeManager.ts`
**Verification:**
1. Run `npm run build` - no errors
2. Restart worker: `npm run worker:restart`
3. Make a test edit to trigger observation
4. Check generated CLAUDE.md files for new format
---
## Phase 2: Parse Full Observation Data from API
**Context:** The current regex parsing extracts only time, type emoji, and title. Need to also extract:
- Observation ID (for `#123` column)
- File path (from files_modified in API response, for grouping)
- Token estimate (for `Read` column)
**Challenge:** The current API returns formatted text, not structured data. We need to:
1. Parse the existing text format more thoroughly, OR
2. Use a different API endpoint that returns JSON
**Decision Point:** Check what data the `/api/search/by-file` endpoint returns. If it returns structured JSON with observations, use that. Otherwise, enhance parsing.
**Investigation Required:**
- Read `src/services/worker/http/routes/SearchRoutes.ts` to see by-file response format
- Determine if we can access raw observation data or just formatted text
**Verification:**
- Confirm API response structure
- Update parsing to extract all needed fields
---
## Phase 3: Integrate File-Based Grouping
**File:** `src/utils/claude-md-utils.ts`
**Tasks:**
1. Create helper to group by file:
```typescript
function groupByFile(observations: ParsedObservation[]): Map<string, ParsedObservation[]> {
const byFile = new Map<string, ParsedObservation[]>();
for (const obs of observations) {
const file = obs.file || 'General';
if (!byFile.has(file)) byFile.set(file, []);
byFile.get(file)!.push(obs);
}
return byFile;
}
```
2. Render with file sections:
```typescript
for (const [file, fileObs] of resultsByFile) {
lines.push(`**${file}**`);
lines.push(`| ID | Time | T | Title | Read |`);
lines.push(`|----|------|---|-------|------|`);
// render rows with ditto marks
}
```
**Pattern to Copy From:** `ResultFormatter.formatSearchResults()` lines 60-108
**Verification:**
- Generated CLAUDE.md shows file grouping
- Files are displayed as relative paths when possible
---
## Phase 4: Final Verification
**Checklist:**
1. **Build passes:** `npm run build`
2. **Worker restarts cleanly:** `npm run worker:restart`
3. **Format matches target:**
- Date headers: `### Jan 4, 2026`
- File sections: `**filename**`
- Table columns: `| ID | Time | T | Title | Read |`
- Type emojis: `🔴` `🟣` `` not text
- Ditto marks: `"` for repeated times
4. **Anti-pattern checks:**
- No hardcoded type maps (use ModeManager)
- No invented APIs
- Reuses existing formatters from shared utils
5. **Graceful degradation:** Empty results still show `*No recent activity*`
---
## Files to Modify
| File | Change |
|------|--------|
| `src/utils/claude-md-utils.ts` | Replace `formatTimelineForClaudeMd()` with timeline format |
## Files to Read (Patterns to Copy)
| File | Pattern |
|------|---------|
| `src/services/worker/search/ResultFormatter.ts:56-108` | Date/file grouping logic |
| `src/shared/timeline-formatting.ts` | All formatting utilities |
| `src/services/domain/ModeManager.ts` | Type icon lookup |
## Anti-Patterns to Avoid
- ❌ Creating new hardcoded type→emoji maps (use ModeManager)
- ❌ Parsing dates manually (use shared formatters)
- ❌ Skipping the existing groupByDate utility
- ❌ Not handling ditto marks for repeated times
@@ -0,0 +1,196 @@
# Plan: Integrate Workflow Agents and Commands into Claude-Mem
## Executive Summary
This plan integrates the `/make-plan` and `/do` orchestration workflow from `~/.claude/commands/` into the claude-mem plugin as project-level development tools.
## Dependency Analysis
### Commands to Copy (from `~/.claude/commands/`)
| File | Purpose | Dependencies |
|------|---------|--------------|
| `make-plan.md` | Orchestrator for LLM-friendly phased planning | Uses Task tool with subagents |
| `do.md` | Orchestrator for executing plans via subagents | Uses Task tool with subagents |
| `anti-pattern-czar.md` | Error handling anti-pattern detection/fixing | Uses Read, Edit, Bash tools |
### Specialized Agents Referenced
The `/make-plan` and `/do` commands reference these **conceptual agent roles** (not actual agent files):
| Agent Role | Referenced In | Description |
|------------|---------------|-------------|
| "Documentation Discovery" | make-plan.md | Fact-gathering from docs/examples |
| "Verification" | make-plan.md, do.md | Verify implementation matches plan |
| "Implementation" | do.md | Execute implementation tasks |
| "Anti-pattern" | do.md | Grep for known bad patterns |
| "Code Quality" | do.md | Review code changes |
| "Commit" | do.md | Commit after verification passes |
| "Branch/Sync" | do.md | Push and prepare phase handoffs |
**Key Finding**: These are **role descriptions**, not separate agent files. The Task tool's `general-purpose` subagent_type executes all roles. The commands define *what* each role should do, not separate agent implementations.
### Existing Project Assets
Located in `.claude/`:
- `agents/github-morning-reporter.md` - Already in project
- `skills/version-bump/SKILL.md` - Already in project
- No existing commands directory
---
## Phase 0: Documentation Discovery (Complete)
### Sources Consulted
1. `/Users/alexnewman/.claude/commands/make-plan.md` (62 lines)
2. `/Users/alexnewman/.claude/commands/do.md` (39 lines)
3. `/Users/alexnewman/.claude/commands/anti-pattern-czar.md` (122 lines)
4. `/Users/alexnewman/.claude/settings.json` (36 lines)
5. `.claude/skills/CLAUDE.md` (30 lines)
6. `.claude/agents/github-morning-reporter.md` (102 lines)
### Allowed APIs/Patterns
- **Commands**: `.claude/commands/*.md` files with `#$ARGUMENTS` placeholder for user input
- **Skills**: `.claude/skills/<name>/SKILL.md` with YAML frontmatter (name, description)
- **Agents**: `.claude/agents/*.md` with YAML frontmatter (name, description, model)
### Anti-Patterns to Avoid
- Skills require YAML frontmatter; commands do not
- Commands use `#$ARGUMENTS` for input; skills/agents receive prompts differently
- Don't create separate agent files for role descriptions - the Task tool handles routing
---
## Phase 1: Create Commands Directory
### What to Implement
1. Create `.claude/commands/` directory
2. Copy `make-plan.md` from `~/.claude/commands/make-plan.md`
3. Copy `do.md` from `~/.claude/commands/do.md`
4. Copy `anti-pattern-czar.md` from `~/.claude/commands/anti-pattern-czar.md`
### Documentation References
- Pattern: `~/.claude/commands/*.md` (source files)
- Existing example: `.claude/skills/version-bump/SKILL.md` for claude-mem project tools
### Verification Checklist
```bash
# Verify files exist
ls -la .claude/commands/
# Verify content matches source
diff ~/.claude/commands/make-plan.md .claude/commands/make-plan.md
diff ~/.claude/commands/do.md .claude/commands/do.md
diff ~/.claude/commands/anti-pattern-czar.md .claude/commands/anti-pattern-czar.md
# Verify #$ARGUMENTS placeholder exists
grep '\$ARGUMENTS' .claude/commands/*.md
```
### Anti-Pattern Guards
- Do NOT add YAML frontmatter to commands (they don't need it)
- Do NOT modify the source content (copy verbatim)
---
## Phase 2: Create CLAUDE.md Documentation
### What to Implement
Create `.claude/commands/CLAUDE.md` documenting the commands directory (following pattern from `.claude/skills/CLAUDE.md`)
### Content Template
```markdown
# Project-Level Commands
This directory contains slash commands **for developing and maintaining the claude-mem project itself**.
## Commands in This Directory
### /make-plan
Orchestrator for creating LLM-friendly implementation plans in phases. Deploys subagents for documentation discovery and fact gathering.
**Usage**: `/make-plan <task description>`
### /do
Orchestrator for executing plans via subagents. Deploys specialized subagents for implementation, verification, and code quality review.
**Usage**: `/do <plan-file-path or inline plan>`
### /anti-pattern-czar
Interactive workflow for detecting and fixing error handling anti-patterns using the automated scanner.
**Usage**: `/anti-pattern-czar`
## Adding New Commands
Commands are markdown files with `#$ARGUMENTS` placeholder for user input.
```
### Verification Checklist
```bash
# Verify file exists
cat .claude/commands/CLAUDE.md
```
---
## Phase 3: Update Settings (if needed)
### What to Implement
Check if `.claude/settings.json` needs any permission updates for the new commands.
### Verification Checklist
```bash
# Check current settings
cat .claude/settings.json
# Verify commands work by listing them
# (After Claude Code restart, commands should appear in slash-command list)
```
### Anti-Pattern Guards
- Do NOT add skill permissions for commands (they're different)
- Commands don't require explicit permissions
---
## Phase 4: Final Verification
### Verification Checklist
1. All three command files exist in `.claude/commands/`
2. Content matches source files exactly (byte-for-byte if possible)
3. CLAUDE.md documentation exists
4. Git status shows new files ready for commit
```bash
# Full verification
ls -la .claude/commands/
wc -l .claude/commands/*.md
git status
```
### Commit Message Template
```
feat: add /make-plan, /do, and /anti-pattern-czar workflow commands
Add project-level orchestration commands for claude-mem development:
- /make-plan: Create LLM-friendly implementation plans in phases
- /do: Execute plans via coordinated subagents
- /anti-pattern-czar: Detect and fix error handling anti-patterns
These commands enable structured, agent-driven development workflows.
```
---
## Summary
**Files to Create**:
1. `.claude/commands/make-plan.md` (copy from ~/.claude/commands/)
2. `.claude/commands/do.md` (copy from ~/.claude/commands/)
3. `.claude/commands/anti-pattern-czar.md` (copy from ~/.claude/commands/)
4. `.claude/commands/CLAUDE.md` (new documentation)
**No Agent Files Needed**: The "agents" referenced in make-plan.md and do.md are role descriptions, not separate files. The Task tool's built-in subagent types handle execution.
**Confidence**: High - analysis complete with full source file reads.
+14 -1
View File
@@ -26,4 +26,17 @@ Manages semantic versioning for the claude-mem project itself. Handles updating
## Adding New Skills
**For claude-mem development** → Add to `.claude/skills/`
**For end users** → Add to `plugin/skills/` (gets distributed with plugin)
**For end users** → Add to `plugin/skills/` (gets distributed with plugin)
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 29, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33938 | 6:27 PM | 🔵 | Relevant CLAUDE.md Context Identified for PR #492 | ~435 |
</claude-mem-context>
-80
View File
@@ -1,80 +0,0 @@
---
name: version-bump
description: Manage semantic version updates for claude-mem project. Handles patch, minor, and major version increments following semantic versioning. Updates package.json, marketplace.json, and plugin.json. Creates git tags and GitHub releases. Auto-generates CHANGELOG.md from releases.
---
# Version Bump Skill
**IMPORTANT:** You must first ultrathink and write detailed release notes before starting the version bump workflow.
## Version Types
- **PATCH** (x.y.Z): Bug fixes only
- **MINOR** (x.Y.0): New features, backward compatible
- **MAJOR** (X.0.0): Breaking changes
## Files to Update (ALL THREE)
1. `package.json` (line 3)
2. `.claude-plugin/marketplace.json` (line 13)
3. `plugin/.claude-plugin/plugin.json` (line 3)
## Workflow
```bash
# 1. Check current version
grep '"version"' package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json
# 2. Update all 3 files to new version (use Edit tool)
# 3. Verify consistency
grep '"version"' package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json
# 4. Build
npm run build
# 5. Commit version files
git add package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json
git commit -m "chore: bump version to X.Y.Z"
# 6. Create tag
git tag -a vX.Y.Z -m "Version X.Y.Z"
# 7. Push
git push origin main && git push origin vX.Y.Z
# 8. Create GitHub release (use your detailed release notes here)
gh release create vX.Y.Z --title "vX.Y.Z" --notes "RELEASE_NOTES_HERE"
# 9. Generate CHANGELOG.md from releases
gh api repos/thedotmack/claude-mem/releases --paginate | node -e "
const releases = JSON.parse(require('fs').readFileSync(0, 'utf8'));
const lines = ['# Changelog', '', 'All notable changes to claude-mem.', ''];
releases.slice(0, 50).forEach(r => {
const date = r.published_at.split('T')[0];
lines.push('## [' + r.tag_name + '] - ' + date);
lines.push('');
if (r.body) lines.push(r.body.trim());
lines.push('');
});
console.log(lines.join('\n'));
" > CHANGELOG.md
# 10. Commit CHANGELOG
git add CHANGELOG.md
git commit -m "docs: update CHANGELOG.md for vX.Y.Z"
git push origin main
# 11. Discord notification
npm run discord:notify vX.Y.Z
```
## Checklist
- [ ] Ultrathink + write detailed release notes
- [ ] All 3 files have matching version
- [ ] `npm run build` succeeds
- [ ] Git tag created (vX.Y.Z format)
- [ ] GitHub release created with detailed notes
- [ ] CHANGELOG.md updated
- [ ] Discord notification sent (if webhook configured)
+21
View File
@@ -0,0 +1,21 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 13, 2025
**feature_request.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #25012 | 6:41 PM | 🟣 | Auto-Convert Feature Requests to GitHub Discussions | ~298 |
| #25011 | " | ✅ | Staged GitHub Feature Request Automation Files | ~206 |
| #25009 | 6:40 PM | ✅ | Feature Request Template Auto-Labeling Configured | ~241 |
| #24995 | 6:26 PM | 🔵 | Standard Feature Request Template Configuration | ~260 |
**bug_report.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24994 | 6:26 PM | 🔵 | Standard Bug Report Template Configuration | ~258 |
| #24992 | " | 🔵 | GitHub Issue Templates Located | ~188 |
</claude-mem-context>
+75
View File
@@ -0,0 +1,75 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 13, 2025
**convert-feature-requests.yml**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #25022 | 6:48 PM | ✅ | Workflow Fix Committed to Repository | ~289 |
| #25021 | " | 🔴 | Fixed Issue Number Reference in Workflow Steps | ~277 |
| #25020 | " | 🔴 | Workflow String Interpolation Fixed by Consolidating Steps | ~339 |
| #25019 | 6:47 PM | 🔵 | GitHub Workflow Automates Feature Request Triage | ~328 |
| #25012 | 6:41 PM | 🟣 | Auto-Convert Feature Requests to GitHub Discussions | ~298 |
| #25011 | " | ✅ | Staged GitHub Feature Request Automation Files | ~206 |
| #25010 | 6:40 PM | 🟣 | GitHub Action Workflow for Feature Request Auto-Conversion | ~414 |
**summary.yml**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #25002 | 6:38 PM | 🔵 | AI Summary Workflow for New Issues | ~239 |
**claude.yml**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24997 | 6:27 PM | 🔵 | Claude Code Action Workflow for Issue and PR Comments | ~242 |
| #24727 | 4:08 PM | 🔵 | GitHub Automation Baseline Assessment | ~312 |
| #24722 | 4:06 PM | 🔵 | Existing Claude Workflow Trigger Configuration | ~233 |
**claude-code-review.yml**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24996 | 6:27 PM | 🔵 | Existing GitHub Actions Workflows Identified | ~199 |
| #24723 | 4:06 PM | 🔵 | Automated PR Review Workflow Pattern | ~268 |
| #24720 | " | 🔵 | GitHub Workflows Inventory | ~142 |
### Dec 17, 2025
**issue-list-query**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #28918 | 7:27 PM | 🔵 | Four open issues identified - MCP connection, Bun PATH, web UI path, and endless mode | ~432 |
**pr-list-query**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #28917 | 7:27 PM | 🔵 | Recent PRs audit reveals comprehensive Windows stabilization and MCP fixes | ~414 |
**windows-ci.yml**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #28655 | 5:30 PM | ✅ | Windows CI Removal Committed to Repository | ~253 |
| #28654 | " | ✅ | Windows CI Workflow File Removed | ~174 |
| #28650 | 5:26 PM | ✅ | Committed Windows CI Workflow Simplification | ~213 |
| #28649 | " | ✅ | Removed Build and Install Steps from Windows CI | ~278 |
| #28648 | " | 🔵 | Windows CI Workflow Includes Build Step | ~288 |
| #28644 | 5:24 PM | ✅ | Modified 27 files with 693 additions and 239 deletions for Windows support | ~447 |
| #28625 | 5:19 PM | 🟣 | Windows CI Testing Workflow Deployed | ~303 |
| #28624 | " | ✅ | Windows CI Workflow File Staged for Commit | ~163 |
| #28623 | " | 🔵 | Windows CI Workflow File Present But Untracked | ~178 |
| #28622 | 5:18 PM | 🟣 | Windows CI Pipeline with Worker Lifecycle Testing | ~326 |
### Dec 31, 2025
**claude-code-review.yml**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34627 | 3:01 PM | 🔵 | Claude Code Review GitHub Action Provides Automated PR Review Integration | ~478 |
**claude.yml**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34626 | 3:01 PM | 🔵 | Test-Driven Validation Agent Performing Extensive Infrastructure Analysis | ~501 |
</claude-mem-context>
+2
View File
@@ -9,6 +9,8 @@ dist/
*.temp
.install-version
.claude/settings.local.json
.claude/agents/
.claude/skills/
plugin/data/
plugin/data.backup/
package-lock.json
+1 -5
View File
@@ -19,10 +19,7 @@ Claude-mem is a Claude Code plugin providing persistent memory across sessions.
**Viewer UI** (`src/ui/viewer/`) - React interface at http://localhost:37777, built to `plugin/ui/viewer.html`
## Privacy Tags
**Dual-Tag System** for meta-observation control:
- `<private>content</private>` - User-level privacy control (manual, prevents storage)
- `` - System-level tag (auto-injected observations, prevents recursive storage)
**Implementation**: Tag stripping happens at hook layer (edge processing) before data reaches worker/database. See `src/utils/tag-stripping.ts` for shared utilities.
@@ -78,5 +75,4 @@ This architecture preserves the open-source nature of the project while enabling
## Important
- **Always commit build artifacts** in `plugin/` - the plugin must work out of the box without requiring users to build from source
- No need to edit the changelog ever, it's generated automatically.
No need to edit the changelog ever, it's generated automatically.
-306
View File
@@ -1,306 +0,0 @@
# Monolith Refactor Report
> **Last Updated:** 2026-01-03 (post session-logging merge)
## Executive Summary
The claude-mem codebase contains **~21,000 lines** of TypeScript across 71+ files. Analysis reveals several monolithic files that violate single-responsibility principles and create tight coupling. This report identifies refactoring targets and proposes a modular architecture.
**Recent Changes:** The `session-logging` branch merge improved error handling across the codebase. SearchManager was reduced by ~180 lines, but SessionStore grew by ~110 lines due to new migrations and logging.
---
## Part 1: Monolith Files Identified
### Critical Priority (>1500 lines)
| File | Lines | Methods | Primary Issues | Trend |
|------|-------|---------|----------------|-------|
| `src/services/worker-service.ts` | 2,034 | - | Server init, process management, Cursor hooks, MCP setup all mixed | ↓ -28 |
| `src/services/sqlite/SessionStore.ts` | 2,011 | 49 | Migrations + CRUD + queries + transformations all in one class | ↑ +108 |
| `src/services/worker/SearchManager.ts` | 1,778 | 17 | Three search strategies crammed together, formatting mixed in | ↓ -178 |
### High Priority (500-1500 lines)
| File | Lines | Issues | Trend |
|------|-------|--------|-------|
| `src/services/sync/ChromaSync.ts` | 870 | Sync and query operations mixed | — |
| `src/services/context-generator.ts` | 659 | 23 standalone functions, no class structure | — |
| `src/services/worker/http/routes/SessionRoutes.ts` | 625 | Provider selection mixed with business logic | ↑ +7 |
| `src/services/worker/OpenRouterAgent.ts` | 599 | 80% code duplicated from other agents | ↓ -15 |
| `src/services/worker/GeminiAgent.ts` | 574 | 80% code duplicated from other agents | ↓ -15 |
| `src/services/worker/SDKAgent.ts` | 546 | Base patterns duplicated across all agents | ↓ -15 |
| `src/services/sqlite/SessionSearch.ts` | 526 | FTS5 tables maintained for backward compat | — |
| `src/services/sqlite/migrations.ts` | 509 | All 11 migrations in single file | — |
| `src/services/sqlite/PendingMessageStore.ts` | 447 | Message queue operations | ↑ +21 |
| `src/services/worker/http/routes/SettingsRoutes.ts` | 414 | File I/O, validation, git ops mixed | — |
### Code Duplication Issue
The three agent files (`SDKAgent`, `GeminiAgent`, `OpenRouterAgent`) share ~80% duplicate code:
- Message building logic
- Result parsing
- Context updating
- Database sync patterns
---
## Part 2: System Breakdown Proposal
### Domain-Based Module Architecture
```
src/
├── domains/ # Business domain modules
│ ├── sessions/ # Session lifecycle
│ │ ├── SessionRepository.ts
│ │ ├── SessionService.ts
│ │ └── types.ts
│ │
│ ├── observations/ # Observation management
│ │ ├── ObservationRepository.ts
│ │ ├── ObservationService.ts
│ │ └── types.ts
│ │
│ ├── summaries/ # Summary generation
│ │ ├── SummaryRepository.ts
│ │ ├── SummaryService.ts
│ │ └── types.ts
│ │
│ ├── prompts/ # Prompt storage
│ │ ├── PromptRepository.ts
│ │ └── types.ts
│ │
│ └── search/ # Search subsystem
│ ├── strategies/
│ │ ├── ChromaSearchStrategy.ts
│ │ ├── FilterSearchStrategy.ts
│ │ └── SearchStrategy.ts (interface)
│ ├── SearchOrchestrator.ts
│ ├── ResultFormatter.ts
│ └── TimelineBuilder.ts
├── infrastructure/ # Cross-cutting infrastructure
│ ├── database/
│ │ ├── DatabaseConnection.ts
│ │ ├── TransactionManager.ts
│ │ └── migrations/
│ │ ├── MigrationRunner.ts
│ │ ├── 001_initial.ts
│ │ ├── 002_add_prompts.ts
│ │ └── ...
│ │
│ ├── vector/
│ │ ├── ChromaClient.ts
│ │ ├── ChromaSyncManager.ts
│ │ └── ChromaQueryEngine.ts
│ │
│ └── agents/
│ ├── BaseAgent.ts # Shared agent logic
│ ├── AgentFactory.ts
│ ├── MessageBuilder.ts
│ ├── ResponseParser.ts
│ ├── providers/
│ │ ├── ClaudeProvider.ts
│ │ ├── GeminiProvider.ts
│ │ └── OpenRouterProvider.ts
│ └── types.ts
├── api/ # HTTP layer
│ ├── routes/
│ │ ├── sessions.ts
│ │ ├── data.ts
│ │ ├── search.ts
│ │ ├── settings.ts
│ │ └── viewer.ts
│ ├── middleware/
│ └── server.ts
├── context/ # Context injection
│ ├── ContextBuilder.ts
│ ├── ContextConfigLoader.ts
│ ├── ObservationCompiler.ts
│ └── TokenCalculator.ts
└── shared/ # Shared utilities (existing)
├── logger.ts
├── settings.ts
└── ...
```
---
## Part 3: Refactoring Targets by Priority
### Phase 1: Database Layer Decomposition
**Target:** `src/services/sqlite/SessionStore.ts` (2,011 lines, 49 methods → ~5 files)
| Extract To | Responsibility | Est. Lines |
|------------|---------------|------------|
| `domains/sessions/SessionRepository.ts` | Session CRUD ops | ~300 |
| `domains/observations/ObservationRepository.ts` | Observation storage/retrieval | ~400 |
| `domains/summaries/SummaryRepository.ts` | Summary storage/retrieval | ~200 |
| `infrastructure/database/migrations/MigrationRunner.ts` | Schema migrations | ~250 |
**Benefits:**
- Single responsibility per file
- Testable in isolation
- Reduces coupling
---
### Phase 2: Agent Consolidation
**Target:** 3 agent files (1,719 lines → ~800 lines total)
| Extract To | Responsibility |
|------------|---------------|
| `infrastructure/agents/BaseAgent.ts` | Common agent logic, prompt building |
| `infrastructure/agents/MessageBuilder.ts` | Message construction |
| `infrastructure/agents/ResponseParser.ts` | Result parsing (observations, summaries) |
| `infrastructure/agents/providers/*.ts` | Provider-specific API calls only |
**Benefits:**
- Eliminates 80% code duplication
- Easy to add new providers
- Centralized message format changes
---
### Phase 3: Search Strategy Pattern
**Target:** `src/services/worker/SearchManager.ts` (1,778 lines → ~5 files)
| Extract To | Responsibility |
|------------|---------------|
| `domains/search/SearchOrchestrator.ts` | Coordinates search strategies |
| `domains/search/strategies/ChromaSearchStrategy.ts` | Vector search via Chroma |
| `domains/search/strategies/FilterSearchStrategy.ts` | SQLite filter-based search |
| `domains/search/ResultFormatter.ts` | Formats search results |
| `domains/search/TimelineBuilder.ts` | Constructs timeline views |
**Benefits:**
- Strategy pattern for extensibility
- Clear fallback logic
- Testable strategies
---
### Phase 4: Context Generator Restructure
**Target:** `src/services/context-generator.ts` (659 lines → ~4 files)
| Extract To | Responsibility |
|------------|---------------|
| `context/ContextBuilder.ts` | Main builder class |
| `context/ContextConfigLoader.ts` | Config loading/validation |
| `context/ObservationCompiler.ts` | Compiles observations for injection |
| `context/TokenCalculator.ts` | Token budget calculations |
**Benefits:**
- Class-based structure
- Clear dependencies
- Easier testing
---
### Phase 5: Server/Infrastructure Split
**Target:** `src/services/worker-service.ts` (2,034 lines → ~4 files)
| Extract To | Responsibility |
|------------|---------------|
| `api/server.ts` | Express app, route registration |
| `infrastructure/ProcessManager.ts` | PID files, signal handlers |
| `infrastructure/CursorHooksInstaller.ts` | Cursor integration |
| `infrastructure/MCPClientManager.ts` | MCP client lifecycle |
---
## Part 4: Dependency Reduction Strategy
### Current Pain Points
1. **SessionStore** imported by 7+ files directly
2. No abstraction between routes and data access
3. All routes depend on `DatabaseManager` which exposes raw `SessionStore`
### Proposed Dependency Injection
```typescript
// infrastructure/container.ts
export interface ServiceContainer {
sessions: SessionService;
observations: ObservationService;
summaries: SummaryService;
search: SearchOrchestrator;
agents: AgentFactory;
}
// Usage in routes
app.post('/sessions', (req, res) => {
const { sessions } = getContainer();
sessions.create(req.body);
});
```
---
## Part 5: Migration Strategy
### Incremental Approach
Each phase can be done independently without breaking the system:
1. **Create new modules** alongside existing code
2. **Migrate routes one at a time** to use new modules
3. **Deprecate old code** once all routes migrated
4. **Remove deprecated code** after testing
### Testing Requirements
- Unit tests for each extracted module
- Integration tests for repository operations
- End-to-end tests for API routes
---
## Appendix: File Size Distribution
```
2,034 src/services/worker-service.ts ████████████████████
2,011 src/services/sqlite/SessionStore.ts ████████████████████
1,778 src/services/worker/SearchManager.ts █████████████████
870 src/services/sync/ChromaSync.ts ████████
659 src/services/context-generator.ts ██████
625 src/services/worker/http/routes/SessionRoutes.ts ██████
599 src/services/worker/OpenRouterAgent.ts █████
574 src/services/worker/GeminiAgent.ts █████
546 src/services/worker/SDKAgent.ts █████
526 src/services/sqlite/SessionSearch.ts █████
509 src/services/sqlite/migrations.ts █████
466 src/services/worker/http/routes/DataRoutes.ts ████
447 src/services/sqlite/PendingMessageStore.ts ████
414 src/services/worker/http/routes/SettingsRoutes.ts ████
```
---
## Summary
| Metric | Current | After Refactor |
|--------|---------|----------------|
| Files >500 lines | 14 | 0-2 |
| Max file size | 2,034 | ~400 |
| Code duplication | ~1,100 lines | ~100 lines |
| Testable modules | Low | High |
**Recommended Start:** Phase 1 (SessionStore decomposition) - highest impact, clearest boundaries, and **growing** (now 2,011 lines with 49 methods).
### Key Observations Post-Merge
1. **SessionStore is still the top priority** - it grew by 108 lines and is now the 2nd largest file
2. **SearchManager improved** - down 178 lines from error handling refactor
3. **Agent files slightly smaller** - ~45 lines combined reduction
4. **Core architecture unchanged** - the proposed modular structure remains valid
-106
View File
@@ -1,106 +0,0 @@
# Queue System Simplification Plan
## 1. Executive Summary
The current queue system suffers from accidental complexity due to **state duplication** (in-memory vs. database), **fragile control flow** (recursive restarts), and **distributed state management**. This plan proposes a refactoring to establish the Database as the Single Source of Truth, unifying the processing logic into a robust, linear "Pump" model.
## 2. Identified Pain Points
1. **Dual State Synchronization:**
* *Issue:* The system maintains both `session.pendingMessages` (in-memory array) and the `pending_messages` SQLite table.
* *Impact:* Requires constant manual synchronization (push/shift/enqueue), leading to race conditions where the in-memory queue drifts from the DB state.
2. **Fragile Generator Lifecycle:**
* *Issue:* The use of `startGeneratorWithProvider` and `startSessionWithAutoRestart` with recursive `setTimeout` calls to keep the processor alive is brittle.
* *Impact:* Hard to debug, prone to stack issues or silent failures if the "chain" breaks.
3. **Non-Atomic State Transitions:**
* *Issue:* The logic separates "peeking" a message from "marking it processing" (the "Critical Flow" identified in the analysis).
* *Impact:* If the worker crashes or halts between these steps, messages can be processed twice or lost in limbo.
4. **Distributed Logic:**
* *Issue:* Queue logic is scattered across `SessionManager` (coordination), `PendingMessageStore` (DB queries), `SDKAgent` (consumption), and `WorkerService` (orchestration).
* *Impact:* Difficult to trace the lifecycle of a single message.
## 3. Proposed Architecture
### 3.1. Core Principle: "The Database is the Queue"
We will eliminate the in-memory `pendingMessages` array entirely. The SQLite database will be the *only* place where queue state exists.
### 3.2. Architecture Components
#### A. Atomic `claimNextMessage()`
Instead of `peek` then `mark`, we will implement a single atomic operation in `PendingMessageStore`.
* **Logic:**
1. Find the oldest `pending` message for the session.
2. Update it to `processing` and set the timestamp.
3. Return the message record.
* **SQL Strategy:** Use a transaction or `UPDATE ... RETURNING` (if supported) to ensure no other worker can claim the same message.
#### B. The `QueuePump` (Unified Processor)
We will replace the recursive generator logic with a class (or function) dedicated to "pumping" messages for a specific session.
* **Pseudocode Structure:**
```typescript
async function runSessionPump(sessionId: number, signal: AbortSignal) {
while (!signal.aborted) {
// 1. Atomic Claim
const message = store.claimNextMessage(sessionId);
if (!message) {
// 2. Wait for signal (Event-driven, not polling)
await waitForNewData(sessionId, signal);
continue;
}
try {
// 3. Process
await sdkAgent.processMessage(message);
// 4. Mark Complete
store.markProcessed(message.id);
} catch (error) {
// 5. Handle Failure
store.markFailed(message.id, error);
}
}
}
```
### 3.3. Key Changes
| Component | Current State | Proposed State |
| :--- | :--- | :--- |
| **Storage** | In-memory Array + SQLite | SQLite Only |
| **Consumption** | `yield` loop inside SDK Agent | `QueuePump` calls SDK Agent per message |
| **Concurrency** | `peekPending` -> `markProcessing` (Race Prone) | `claimNextMessage` (Atomic Transaction) |
| **Lifecycle** | Recursive `setTimeout` loops | Single `while` loop with `await` |
| **Recovery** | `resetStuckMessages` (Global) | Pump handles own retries + Global cleanup on startup |
## 4. Implementation Steps
### Phase 1: Database Layer Hardening
1. Add `claimNextMessage(sessionDbId)` to `PendingMessageStore`.
* Must be transactional.
* Returns `null` if no work is available.
2. Ensure `markProcessed` and `markFailed` are robust.
### Phase 2: The Pump
1. Create `SessionQueueProcessor.ts`.
2. Implement the `while(!aborted)` loop.
3. Integrate the `EventEmitter` to wake the loop when `enqueue()` happens (replacing the current polling-like behavior).
### Phase 3: SDK Integration
1. Refactor `SDKAgent` to accept a *single* message or a streamlined iterator that doesn't manage queue state itself.
2. Remove `session.pendingMessages` from `ActiveSession` type.
### Phase 4: Cleanup
1. Remove `startGeneratorWithProvider` and `startSessionWithAutoRestart`.
2. Remove `peekPending` (as it's replaced by `claimNextMessage`).
3. Remove manual synchronization code in `SessionManager`.
## 5. Benefits
* **Simplicity:** Code reduction of ~30-40%.
* **Reliability:** Atomic database operations eliminate race conditions.
* **Observability:** Linear control flow is easier to log and debug.
* **Resilience:** Crashes are handled by simply restarting the Pump, which naturally picks up "processing" (stuck) or "pending" messages.
-46
View File
@@ -1,46 +0,0 @@
# Queue System Simplification Implementation
I have successfully implemented the queue system simplification plan.
## Changes Implemented
### 1. Database Layer Hardening
- **Added `claimNextMessage(sessionDbId)` to `PendingMessageStore`:**
- Implements an atomic transaction (SELECT oldest pending + UPDATE to processing).
- Ensures a message can only be claimed by one worker at a time.
- Eliminates race conditions between "peeking" and "marking".
- **Removed `peekPending()`:**
- No longer needed as `claimNextMessage` handles retrieval and locking in one step.
### 2. Unified "Pump" Architecture
- **Created `src/services/queue/SessionQueueProcessor.ts`:**
- Implements a robust `AsyncIterableIterator` that yields messages.
- Encapsulates the "Claim -> Yield -> Wait" loop.
- Replaces fragile polling/recursive logic with event-driven `waitForMessage`.
- Handles empty queues gracefully by waiting for signals.
### 3. SessionManager Refactoring
- **Updated `getMessageIterator`:**
- Now delegates to `SessionQueueProcessor`.
- Removes complex manual synchronization logic.
- **Removed In-Memory Queue State:**
- `queueObservation` and `queueSummarize` now only write to DB and emit events.
- `pendingMessages` array is no longer used for logic (kept deprecated for type compatibility).
- `getTotalActiveWork`, `hasPendingMessages`, etc., now query `PendingMessageStore` directly (counting both 'pending' and 'processing' states).
### 4. Logic Cleanup
- **Removed Recursive Restarts:**
- Refactored `startGeneratorWithProvider` in `SessionRoutes.ts` and `startSessionProcessor` in `WorkerService.ts`.
- Removed logic that deleted sessions when queue emptied (sessions now wait for new work).
- Removed "auto-restart" logic for normal completion (only kept for crash recovery).
## Benefits
- **Reliability:** Atomic DB operations prevent stuck or duplicate messages.
- **Simplicity:** Removed complex "peek-then-mark" and recursive restart chains.
- **Performance:** Zero-latency event notification with efficient DB queries.
- **Maintainability:** Clear separation of concerns (Store vs Processor vs Manager).
## Verification
- Ran static analysis (`tsc`) to verify type safety of new components.
- Verified removal of dead code (`peekPending`).
- Confirmed integration points in `SessionManager` and `SessionRoutes`.
-742
View File
@@ -1,742 +0,0 @@
# Queue System Logic Report
This document provides a line-by-line analysis of the queue system in claude-mem, explaining **the reason behind each piece of logic** and **what it actually does**.
---
## Table of Contents
1. [High-Level Architecture](#high-level-architecture)
2. [Message Status State Machine](#message-status-state-machine)
3. [PendingMessageStore (Database Layer)](#pendingmessagestore-database-layer)
4. [SessionManager (Queue Coordination)](#sessionmanager-queue-coordination)
5. [SDKAgent (Message Consumer)](#sdkagent-message-consumer)
6. [SessionRoutes (HTTP Entry Points)](#sessionroutes-http-entry-points)
7. [WorkerService (Orchestrator)](#workerservice-orchestrator)
8. [Critical Flow: How a Message Gets Stuck in "Processing"](#critical-flow-how-a-message-gets-stuck-in-processing)
9. [Recovery Mechanisms](#recovery-mechanisms)
---
## High-Level Architecture
```
Hook (post-tool-use/summary)
SessionRoutes.handleObservations/handleSummarize
SessionManager.queueObservation/queueSummarize
├─► PendingMessageStore.enqueue() [DB: status='pending']
├─► session.pendingMessages.push() [In-memory queue]
└─► emitter.emit('message') [Wake up generator]
SDKAgent.createMessageGenerator (async generator)
├─► SessionManager.getMessageIterator()
│ │
│ ├─► PendingMessageStore.peekPending() [Find oldest pending]
│ │
│ ├─► PendingMessageStore.markProcessing() [DB: status='processing']
│ │
│ └─► yield message to SDK
SDK query() processes message and returns response
SDKAgent.processSDKResponse()
└─► SDKAgent.markMessagesProcessed()
└─► PendingMessageStore.markProcessed() [DB: status='processed']
```
---
## Message Status State Machine
```
┌─────────────┐
│ (new) │
└──────┬──────┘
│ enqueue()
┌─────────────┐
┌────│ pending │◄───────────────┐
│ └──────┬──────┘ │
│ │ markProcessing() │ markFailed() [retry_count < maxRetries]
│ ▼ │
│ ┌─────────────┐ │
│ │ processing │────────────────┤
│ └──────┬──────┘ │
│ │ │
│ ├─► markProcessed() │
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────┐ │
│ │ │ processed │ │
│ │ └─────────────┘ │
│ │ │
│ └─► markFailed() [retry_count >= maxRetries]
│ │
│ ▼
│ ┌─────────────┐
│ │ failed │
│ └─────────────┘
│ resetStuckMessages() [thresholdMs timeout]
└───────────────────────────────────┘
```
---
## PendingMessageStore (Database Layer)
### `enqueue()` (Lines 56-82)
```typescript
enqueue(sessionDbId: number, claudeSessionId: string, message: PendingMessage): number {
const now = Date.now();
const stmt = this.db.prepare(`
INSERT INTO pending_messages (
session_db_id, claude_session_id, message_type,
tool_name, tool_input, tool_response, cwd,
last_user_message, last_assistant_message,
prompt_number, status, retry_count, created_at_epoch
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', 0, ?)
`);
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| `const now = Date.now()` | Messages need timestamps for ordering and stuck-detection | Captures the moment the message was queued |
| `status, retry_count ... 'pending', 0` | New messages start in pending state with no retries | Hard-codes initial state in SQL |
| `created_at_epoch` | Need to track when message was originally queued for accurate observation timestamps | Used later when processing backlog to assign correct timestamps to observations |
| `JSON.stringify(message.tool_input)` | SQLite can't store objects natively | Serializes complex tool data to string |
| Returns `lastInsertRowid` | Caller needs the ID to track this specific message | Returns the database-assigned auto-increment ID |
### `peekPending()` (Lines 88-96)
```typescript
peekPending(sessionDbId: number): PersistentPendingMessage | null {
const stmt = this.db.prepare(`
SELECT * FROM pending_messages
WHERE session_db_id = ? AND status = 'pending'
ORDER BY id ASC
LIMIT 1
`);
return stmt.get(sessionDbId) as PersistentPendingMessage | null;
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| `status = 'pending'` | Only look at messages not yet being processed | Filters out processing/processed/failed |
| `ORDER BY id ASC` | Process messages in the order they arrived (FIFO) | Uses auto-increment ID as natural ordering |
| `LIMIT 1` | Only need one message at a time for the iterator | Returns single oldest pending message |
| Does NOT change status | Peek is non-destructive; status change happens separately in markProcessing | Allows checking without committing to process |
### `markProcessing()` (Lines 216-224)
```typescript
markProcessing(messageId: number): void {
const now = Date.now();
const stmt = this.db.prepare(`
UPDATE pending_messages
SET status = 'processing', started_processing_at_epoch = ?
WHERE id = ? AND status = 'pending'
`);
stmt.run(now, messageId);
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| `status = 'processing'` | Mark this message as "in progress" so other consumers don't pick it up | Prevents duplicate processing |
| `started_processing_at_epoch = ?` | Track when processing started for stuck detection | If processing takes >5min, considered stuck |
| `WHERE ... AND status = 'pending'` | Only transition from pending->processing (idempotent safety) | Prevents double-processing race conditions |
### `markProcessed()` (Lines 230-242)
```typescript
markProcessed(messageId: number): void {
const now = Date.now();
const stmt = this.db.prepare(`
UPDATE pending_messages
SET
status = 'processed',
completed_at_epoch = ?,
tool_input = NULL,
tool_response = NULL
WHERE id = ? AND status = 'processing'
`);
stmt.run(now, messageId);
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| `status = 'processed'` | Message successfully handled, move to terminal state | Marks completion |
| `completed_at_epoch = ?` | Track when processing finished for metrics/display | Records completion time |
| `tool_input = NULL, tool_response = NULL` | Large payload data no longer needed after successful processing | Frees space - observations are already saved elsewhere |
| `WHERE ... AND status = 'processing'` | Only transition from processing->processed | Ensures we only complete messages we actually processed |
### `markFailed()` (Lines 249-274)
```typescript
markFailed(messageId: number): void {
const msg = this.db.prepare('SELECT retry_count FROM pending_messages WHERE id = ?').get(messageId);
if (msg.retry_count < this.maxRetries) {
// Move back to pending for retry
const stmt = this.db.prepare(`
UPDATE pending_messages
SET status = 'pending', retry_count = retry_count + 1, started_processing_at_epoch = NULL
WHERE id = ?
`);
} else {
// Max retries exceeded, mark as permanently failed
const stmt = this.db.prepare(`
UPDATE pending_messages
SET status = 'failed', completed_at_epoch = ?
WHERE id = ?
`);
}
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| Check `retry_count < maxRetries` | Don't retry forever - eventually give up | Implements bounded retry policy (default: 3) |
| `status = 'pending'` (retry path) | Put message back in queue for another attempt | Allows automatic recovery |
| `retry_count + 1` | Track how many times we've tried | Increment toward failure threshold |
| `started_processing_at_epoch = NULL` | Clear the processing timestamp for next attempt | Prevents stuck detection from immediately triggering |
| `status = 'failed'` (terminal) | Message is permanently broken, stop trying | Prevents infinite retry loops |
### `resetStuckMessages()` (Lines 281-292)
```typescript
resetStuckMessages(thresholdMs: number): number {
const cutoff = thresholdMs === 0 ? Date.now() : Date.now() - thresholdMs;
const stmt = this.db.prepare(`
UPDATE pending_messages
SET status = 'pending', started_processing_at_epoch = NULL
WHERE status = 'processing' AND started_processing_at_epoch < ?
`);
return result.changes;
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| `thresholdMs === 0 ? Date.now()` | Special case: threshold=0 means "reset all processing messages" | Allows forced recovery of all stuck messages |
| `Date.now() - thresholdMs` | Calculate cutoff time (e.g., 5 minutes ago) | Messages processing longer than this are stuck |
| `status = 'processing'` condition | Only reset messages actively being processed | Don't touch pending or completed messages |
| `started_processing_at_epoch < ?` | Processing started before cutoff = stuck | Time-based stuck detection |
| `SET status = 'pending'` | Move back to queue for retry | Enables automatic recovery |
| Returns `result.changes` | Caller needs to know how many were recovered | For logging/metrics |
### `getPendingCount()` (Lines 297-304)
```typescript
getPendingCount(sessionDbId: number): number {
const stmt = this.db.prepare(`
SELECT COUNT(*) as count FROM pending_messages
WHERE session_db_id = ? AND status IN ('pending', 'processing')
`);
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| `status IN ('pending', 'processing')` | **CRITICAL**: Counts BOTH pending AND processing | Used to decide if generator should keep running |
| Why include processing? | A message in processing state is still "work to be done" | Prevents generator from stopping while SDK is mid-response |
---
## SessionManager (Queue Coordination)
### `queueObservation()` (Lines 181-232)
```typescript
queueObservation(sessionDbId: number, data: ObservationData): void {
// Auto-initialize from database if needed
let session = this.sessions.get(sessionDbId);
if (!session) {
session = this.initializeSession(sessionDbId);
}
// CRITICAL: Persist to database FIRST
const message: PendingMessage = { type: 'observation', ... };
const messageId = this.getPendingStore().enqueue(sessionDbId, session.claudeSessionId, message);
// Add to in-memory queue
session.pendingMessages.push(message);
// Notify generator immediately
const emitter = this.sessionQueues.get(sessionDbId);
emitter?.emit('message');
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| Auto-initialize session | Worker may have restarted, need to rebuild in-memory state | Lazy initialization from database |
| `enqueue()` BEFORE in-memory push | **CRITICAL**: Database is source of truth, survives crashes | Persist-first ensures no data loss |
| `session.pendingMessages.push()` | In-memory queue for backward compatibility and fast status checks | Mirrors database state in RAM |
| `emitter?.emit('message')` | Wake up the generator immediately (zero-latency) | Event-driven, no polling needed |
### `getMessageIterator()` (Lines 397-477)
```typescript
async *getMessageIterator(sessionDbId: number): AsyncIterableIterator<PendingMessageWithId> {
while (!session.abortController.signal.aborted) {
// Check for pending messages in persistent store
const persistentMessage = this.getPendingStore().peekPending(sessionDbId);
if (!persistentMessage) {
// Wait for new message event
await new Promise<void>(resolve => {
emitter.once('message', messageHandler);
session.abortController.signal.addEventListener('abort', abortHandler, { once: true });
});
continue;
}
// Mark as processing BEFORE yielding
this.getPendingStore().markProcessing(persistentMessage.id);
// Track this message ID for completion marking
session.pendingProcessingIds.add(persistentMessage.id);
// Convert and yield
const message: PendingMessageWithId = {
_persistentId: persistentMessage.id,
_originalTimestamp: persistentMessage.created_at_epoch,
...this.getPendingStore().toPendingMessage(persistentMessage)
};
yield message;
// Remove from in-memory queue after yielding
session.pendingMessages.shift();
}
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| `while (!aborted)` | Keep processing until session ends | Continuous processing loop |
| `peekPending()` | Check database for work | Non-destructively looks for pending messages |
| `await new Promise` with event | Block until message arrives (no polling) | Event-driven wake-up saves CPU |
| `markProcessing()` BEFORE yield | **CRITICAL**: Claim the message before giving to SDK | Prevents race conditions |
| `pendingProcessingIds.add()` | Track which messages are being processed | So we know what to mark as completed |
| `_persistentId` field | Attach database ID to in-flight message | Needed for markProcessed() later |
| `_originalTimestamp` | Preserve original queue time | For accurate observation timestamps when processing backlog |
| `pendingMessages.shift()` after yield | Keep in-memory queue in sync with database | Mirrors the database state change |
---
## SDKAgent (Message Consumer)
### `startSession()` Main Loop (Lines 75-150)
```typescript
const queryResult = query({
prompt: messageGenerator,
options: {
model: modelId,
resume: session.claudeSessionId, // <-- Session continuity
disallowedTools,
abortController: session.abortController,
pathToClaudeCodeExecutable: claudePath
}
});
for await (const message of queryResult) {
if (message.type === 'assistant') {
// Process response
await this.processSDKResponse(session, textContent, worker, discoveryTokens, originalTimestamp);
}
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| `resume: session.claudeSessionId` | **CRITICAL**: Connect to existing Claude session | Enables session continuity - same transcript across prompts |
| `for await` loop | Process SDK responses as they arrive | Streaming response handling |
| `processSDKResponse()` called per response | Parse and save observations/summaries | Database + Chroma sync |
### `createMessageGenerator()` (Lines 202-291)
```typescript
private async *createMessageGenerator(session: ActiveSession): AsyncIterableIterator<SDKUserMessage> {
// Build initial or continuation prompt
const initPrompt = isInitPrompt
? buildInitPrompt(...)
: buildContinuationPrompt(...);
// Yield initial prompt
yield { type: 'user', message: { role: 'user', content: initPrompt }, session_id: session.claudeSessionId };
// Consume pending messages
for await (const message of this.sessionManager.getMessageIterator(session.sessionDbId)) {
if (message.type === 'observation') {
const obsPrompt = buildObservationPrompt({ ... });
yield { type: 'user', message: { role: 'user', content: obsPrompt } };
} else if (message.type === 'summarize') {
const summaryPrompt = buildSummaryPrompt({ ... });
yield { type: 'user', message: { role: 'user', content: summaryPrompt } };
}
}
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| `isInitPrompt` check | First prompt needs full context, subsequent prompts need continuation | Different prompt templates |
| `yield` initial prompt | Start the SDK conversation | Sends initialization to Claude |
| `for await ... getMessageIterator` | Pull messages as they become available | Event-driven message consumption |
| `yield` for each message | Feed observations/summaries to SDK one at a time | SDK processes each and responds |
### `markMessagesProcessed()` (Lines 462-491)
```typescript
private async markMessagesProcessed(session: ActiveSession, worker: any): Promise<void> {
const pendingMessageStore = this.sessionManager.getPendingMessageStore();
if (session.pendingProcessingIds.size > 0) {
for (const messageId of session.pendingProcessingIds) {
pendingMessageStore.markProcessed(messageId);
}
session.pendingProcessingIds.clear();
session.earliestPendingTimestamp = null;
// Cleanup old processed messages
const deletedCount = pendingMessageStore.cleanupProcessed(100);
}
// Broadcast status update
if (worker && typeof worker.broadcastProcessingStatus === 'function') {
worker.broadcastProcessingStatus();
}
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| Loop over `pendingProcessingIds` | Mark ALL messages that were yielded to SDK | Batch completion |
| `markProcessed()` for each | Transition processing->processed in database | Completes the message lifecycle |
| `.clear()` | Reset tracking set for next batch | Prepare for next iteration |
| `earliestPendingTimestamp = null` | Reset timestamp tracking | Next batch gets fresh timestamps |
| `cleanupProcessed(100)` | Don't keep infinite processed messages | Retention policy |
| `broadcastProcessingStatus()` | Update UI with new state | SSE broadcast |
---
## SessionRoutes (HTTP Entry Points)
### `startGeneratorWithProvider()` (Lines 118-189)
```typescript
private startGeneratorWithProvider(session, provider, source): void {
session.currentProvider = provider;
session.generatorPromise = agent.startSession(session, this.workerService)
.catch(error => {
// Mark all processing messages as failed
const processingMessages = stmt.all(session.sessionDbId);
for (const msg of processingMessages) {
pendingStore.markFailed(msg.id);
}
})
.finally(() => {
session.generatorPromise = null;
session.currentProvider = null;
this.workerService.broadcastProcessingStatus();
// Check if there's more work pending
const pendingCount = pendingStore.getPendingCount(sessionDbId);
if (pendingCount > 0) {
// Auto-restart
setTimeout(() => {
if (stillExists && !stillExists.generatorPromise) {
this.startGeneratorWithProvider(stillExists, this.getSelectedProvider(), 'auto-restart');
}
}, 0);
} else {
// Cleanup
this.sessionManager.deleteSession(sessionDbId);
}
});
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| `session.generatorPromise =` | Track that generator is running | Prevents multiple generators per session |
| `.catch()` with markFailed | If generator crashes, don't lose messages | Marks for retry or permanent failure |
| `.finally()` | Always cleanup regardless of success/failure | Guaranteed cleanup |
| `generatorPromise = null` | Allow new generator to start | Clears the "running" flag |
| `getPendingCount() > 0` | **CRITICAL**: Check if more work arrived while processing | Handles messages queued during SDK call |
| `setTimeout(..., 0)` | Don't restart synchronously (could cause stack issues) | Deferred restart |
| `deleteSession()` when no work | Clean up resources | Memory management |
### `ensureGeneratorRunning()` (Lines 90-113)
```typescript
private ensureGeneratorRunning(sessionDbId: number, source: string): void {
const session = this.sessionManager.getSession(sessionDbId);
if (!session) return;
const selectedProvider = this.getSelectedProvider();
// Start generator if not running
if (!session.generatorPromise) {
this.startGeneratorWithProvider(session, selectedProvider, source);
return;
}
// Generator is running - check if provider changed
if (session.currentProvider && session.currentProvider !== selectedProvider) {
// Let current generator finish, next one will use new provider
}
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| Check `!generatorPromise` | Only start if not already running | Prevents duplicate generators |
| Start generator if not running | Ensure messages get processed | Lazy generator startup |
| Provider change detection | Allow switching providers mid-session | Graceful provider transition |
---
## WorkerService (Orchestrator)
### `initializeBackground()` Stuck Message Recovery (Lines 627-633)
```typescript
// Recover stuck messages from previous crashes
const STUCK_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes
const resetCount = pendingStore.resetStuckMessages(STUCK_THRESHOLD_MS);
if (resetCount > 0) {
logger.info('SYSTEM', `Recovered ${resetCount} stuck messages from previous session`);
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| Called at startup | Worker may have crashed while messages were processing | Recovery mechanism |
| 5 minute threshold | If processing >5min, something went wrong | Reasonable timeout for SDK calls |
| Reset to pending | Give stuck messages another chance | Automatic retry |
### `processPendingQueues()` (Lines 747-811)
```typescript
async processPendingQueues(sessionLimit: number = 10): Promise<Result> {
const orphanedSessionIds = pendingStore.getSessionsWithPendingMessages();
for (const sessionDbId of orphanedSessionIds) {
// Skip if session already has active generator
const existingSession = this.sessionManager.getSession(sessionDbId);
if (existingSession?.generatorPromise) {
result.sessionsSkipped++;
continue;
}
// Initialize session and start SDK agent
const session = this.sessionManager.initializeSession(sessionDbId);
this.startSessionWithAutoRestart(session, getPendingCount, 'startup-recovery');
}
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| Called at startup | Resume work interrupted by crash/restart | Auto-recovery |
| `getSessionsWithPendingMessages()` | Find sessions that have orphaned work | Database query |
| Skip if generator running | Don't start duplicate processors | Race condition prevention |
| `startSessionWithAutoRestart()` | Start processing with auto-restart logic | Shares code with SessionRoutes |
### `startSessionWithAutoRestart()` (Lines 696-739)
```typescript
private startSessionWithAutoRestart(session, getPendingCount, source): void {
session.generatorPromise = this.sdkAgent.startSession(session, this)
.catch(error => { ... })
.finally(() => {
session.generatorPromise = null;
this.broadcastProcessingStatus();
const stillPending = getPendingCount(sid);
if (stillPending > 0) {
// Recursive restart
setTimeout(() => {
const stillExists = this.sessionManager.getSession(sid);
if (stillExists && !stillExists.generatorPromise) {
this.startSessionWithAutoRestart(stillExists, getPendingCount, 'auto-restart');
}
}, 0);
} else {
// Cleanup
this.sessionManager.deleteSession(sid);
}
});
}
```
| Line | The Reason Behind This | What It Actually Does |
|------|------------------------|----------------------|
| Same pattern as SessionRoutes | **DRY**: Shared auto-restart logic | Prevents code duplication |
| Recursive restart | Keep processing until queue is empty | Ensures all messages processed |
| Check `stillExists` before restart | Session might have been deleted | Safety check |
---
## Critical Flow: How a Message Gets Stuck in "Processing"
### The Problem
Messages can get stuck in `status = 'processing'` if:
1. **SDK call hangs indefinitely** - The Agent SDK query never returns
2. **Worker crashes mid-processing** - Process dies before markProcessed()
3. **Exception in processSDKResponse()** - Error prevents markProcessed() from running
### The Flow
```
1. queueObservation() called
└─► enqueue() → status = 'pending'
2. getMessageIterator() picks up message
└─► markProcessing() → status = 'processing' ✓
└─► pendingProcessingIds.add(id)
└─► yield message to SDK
3. SDK processes and returns response
└─► processSDKResponse() called
└─► Parse observations/summaries
└─► Store to database
└─► markMessagesProcessed()
└─► markProcessed() → status = 'processed' ✓
IF STEP 3 FAILS OR HANGS:
└─► Message stays in 'processing' forever
└─► Recovery: resetStuckMessages() after 5 minutes
```
### Why Processing Messages Can Get "Lost"
**Race Condition in getMessageIterator():**
```typescript
// Lines 445-446 in SessionManager
this.getPendingStore().markProcessing(persistentMessage.id);
session.pendingProcessingIds.add(persistentMessage.id);
```
The message is marked as `processing` BEFORE being yielded. If the SDK hangs or crashes AFTER this line but BEFORE processSDKResponse completes, the message is stuck.
**Protection Mechanisms:**
1. `pendingProcessingIds` tracks what's in-flight
2. `markFailed()` in catch handler marks for retry
3. `resetStuckMessages()` at startup cleans up old stuck messages
---
## Recovery Mechanisms
### 1. Startup Recovery (Worker crashes)
```typescript
// In initializeBackground()
const resetCount = pendingStore.resetStuckMessages(STUCK_THRESHOLD_MS);
```
- Runs when worker starts
- Finds messages stuck in `processing` for >5 minutes
- Resets them to `pending` for retry
### 2. Generator Error Recovery
```typescript
// In startGeneratorWithProvider() catch handler
for (const msg of processingMessages) {
pendingStore.markFailed(msg.id);
}
```
- Runs when SDK call throws
- Marks processing messages as failed (which may reset to pending if retries remain)
### 3. Auto-Restart Recovery
```typescript
// In startGeneratorWithProvider() finally handler
if (pendingCount > 0) {
setTimeout(() => startGeneratorWithProvider(...), 0);
}
```
- Runs after every generator completes
- Checks for pending work
- Starts new generator if work remains
### 4. Manual Recovery (UI)
```typescript
// PendingMessageStore methods
retryMessage(messageId) // Reset specific message to pending
retryAllStuck(thresholdMs) // Reset all stuck messages
abortMessage(messageId) // Delete message from queue
```
---
## Summary of Potential Issues
| Issue | Cause | Mitigation |
|-------|-------|------------|
| Message stuck in processing | SDK hang, crash during processing | `resetStuckMessages()` at startup |
| Duplicate processing | Race condition on message claim | `markProcessing()` with `WHERE status = 'pending'` |
| Lost messages | Crash before enqueue | DB persist BEFORE in-memory push |
| Generator never starts | No call to `ensureGeneratorRunning()` | Called by every HTTP handler |
| Generator exits early | Empty queue check race | `finally` handler checks and restarts |
| Infinite retry | Repeated failures | `maxRetries` limit (default: 3) |
---
## Diagnostic Queries
Check for stuck messages:
```sql
SELECT * FROM pending_messages
WHERE status = 'processing'
AND started_processing_at_epoch < (strftime('%s', 'now') * 1000 - 300000);
```
Check queue depth by session:
```sql
SELECT session_db_id, status, COUNT(*)
FROM pending_messages
GROUP BY session_db_id, status;
```
Check retry counts:
```sql
SELECT id, message_type, retry_count, status
FROM pending_messages
WHERE retry_count > 0;
```
+1 -1
View File
@@ -1,6 +1,6 @@
{
"scripts": {
"setup": "cp ../settings.local.json .claude/settings.local.json && npm install",
"run": "npm run build"
"run": "npm run build-and-sync"
}
}
+21
View File
@@ -0,0 +1,21 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 29, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34127 | 9:10 PM | ✅ | Marketing Copy Changes Committed to cursor-hooks-integration Branch | ~457 |
| #34125 | " | ✅ | Detailed Diff Shows Consistent Marketing Language Across All Documentation | ~643 |
| #34123 | 9:09 PM | ✅ | Marketing Copy Updates Complete Across Four Documentation Files | ~485 |
| #34120 | " | ✅ | QUICKSTART Enhanced with Time-Bound Promise and Memory Benefit | ~426 |
| #34119 | 9:08 PM | ✅ | Enhanced STANDALONE-SETUP with Value Proposition and Benefits | ~446 |
| #34118 | " | ✅ | Enhanced README with Marketing Copy and Quick Install Section | ~491 |
| #34117 | " | 🔵 | QUICKSTART.md Updated with Provider Configuration Section | ~487 |
| #34116 | 9:07 PM | 🔵 | STANDALONE-SETUP.md Complete Documentation for Cursor-Only Users | ~541 |
| #34115 | " | 🔵 | Cursor Hooks README Already Updated with Standalone Setup Link | ~485 |
| #34067 | 8:46 PM | 🔵 | Cursor Quickstart Guide Analysis | ~531 |
| #34066 | " | 🔵 | Cursor Hooks README Current State Assessment | ~583 |
</claude-mem-context>
+34
View File
@@ -0,0 +1,34 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 29, 2025
**docs**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34316 | 11:02 PM | 🔵 | Mintlify Documentation Structure Identified | ~242 |
### Jan 1, 2026
**SESSION_ID_ARCHITECTURE.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35668 | 11:40 PM | ✅ | Main branch updated with major feature additions | ~377 |
| #35565 | 9:55 PM | ✅ | Session ID architecture documentation created | ~510 |
### Jan 3, 2026
**SESSION_ID_ARCHITECTURE.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36689 | 11:56 PM | 🔵 | PR #538 Review Findings - Modular Architecture Refactor | ~590 |
| #36632 | 10:45 PM | 🔵 | SESSION_ID_ARCHITECTURE.md Documents Placeholder Pattern With ContentSessionId | ~584 |
| #36625 | 10:44 PM | 🔵 | Documentation and Code Reveal Placeholder Detection Pattern | ~583 |
**anti-pattern-cleanup-plan.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
</claude-mem-context>
+107
View File
@@ -0,0 +1,107 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 30, 2025
**agent-sdk-v2-docs.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34477 | 2:25 PM | ✅ | V2 Upgrade Branch Modifies Four Files with Net Code Reduction | ~328 |
| #34466 | 2:24 PM | 🔵 | Agent SDK V2 Documentation Reveals Correct API Surface | ~399 |
| #34425 | 2:04 PM | 🔵 | Agent SDK V2 API Documentation and Migration Patterns | ~698 |
| #34422 | 2:03 PM | ✅ | Added Agent SDK V2 Documentation Files | ~240 |
| #34419 | 2:02 PM | ✅ | Committed Agent SDK V2 upgrade preparation | ~275 |
| #34394 | 1:52 PM | 🔵 | Agent SDK V2 Documentation Shows session.close() Method for Cleanup | ~417 |
**agent-sdk-v2-example.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34431 | 2:06 PM | 🔵 | V2 SDK Executable Example Code Patterns | ~710 |
| #34428 | 2:05 PM | 🔵 | Agent SDK v2 Example File Reading Requested | ~204 |
| #34411 | 1:55 PM | ⚖️ | Agent SDK V2 Migration Plan Created | ~519 |
| #34410 | " | ⚖️ | Agent SDK V2 Migration Strategy Analysis | ~499 |
| #34406 | 1:54 PM | 🔵 | Comprehensive V2 Migration Analysis Shows Architectural Incompatibility | ~556 |
| #34401 | " | 🔵 | Agent SDK V2 API Design and Patterns | ~435 |
### Dec 31, 2025
**agent-sdk-v2-preview.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34635 | 3:04 PM | 🟣 | Documentation-First Workflow Design Document Created | ~769 |
| #34616 | 2:59 PM | ⚖️ | Documentation-First Workflow Agent Analyzing V2 SDK Examples and Patterns | ~515 |
| #34581 | 2:44 PM | 🔵 | V2 Session API Official Documentation Confirms Clear Separation Pattern | ~446 |
**agent-sdk-v2-examples.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34605 | 2:57 PM | 🔵 | V2 SDK Migration Failure Root Cause: Context Rot and Knowledge Transfer Gaps | ~550 |
| #34583 | 2:44 PM | 🔵 | Executable V2 Examples Demonstrate All Core Patterns With Crystal Clear Code | ~471 |
| #34580 | 2:43 PM | 🔵 | V2 Session API Documentation Shows Clear Send/Receive Pattern Despite Naming Confusion | ~364 |
### Jan 1, 2026
**try-catch-audit-report.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35635 | 11:14 PM | ✅ | Removed Temporary Try-Catch Audit Report | ~224 |
| #35463 | 8:59 PM | 🟣 | Enforceable Anti-Pattern Detection System for Try-Catch Abuse | ~485 |
| #35462 | " | 🟣 | Error handling audit tooling and documentation added | ~271 |
| #35435 | 8:46 PM | ✅ | Try-Catch Audit Report Documented in Markdown | ~781 |
**agent-sdk-v2-examples.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35429 | 6:32 PM | ⚖️ | KISS Principle Applied to SDKAgent.ts Defensive Code | ~322 |
| #35412 | 5:25 PM | 🔵 | Canonical Example Shows Cost Tracking Without Token Usage Checks | ~289 |
| #35406 | 5:24 PM | ⚖️ | Categorized Conditionals as Required Business Logic vs Defensive Code | ~377 |
| #35404 | " | 🔵 | Canonical V2 SDK Patterns Require Message Type Checking | ~313 |
| #35398 | 5:23 PM | 🟣 | Added comprehensive Claude Agent SDK V2 examples | ~231 |
| #35383 | 3:11 PM | 🔵 | Phase 2 code quality review identified 5 critical bugs | ~604 |
| #35382 | 3:08 PM | ✅ | Phase 2 Anti-Pattern Recheck Passed | ~315 |
| #35379 | 3:07 PM | 🔵 | Phase 2 Anti-Pattern Check Found Content Extraction Bug | ~373 |
| #35353 | 3:01 PM | 🔵 | Phase 2 preparation analysis completed | ~502 |
| #35340 | 2:58 PM | 🔵 | Phase 1 Anti-Pattern Check Reveals V1/V2 API Mismatch | ~352 |
| #35330 | 2:54 PM | 🔵 | Claude Agent SDK V2 API Pattern Documentation | ~305 |
| #35329 | 2:53 PM | 🔵 | Agent SDK V2 API patterns and capabilities | ~453 |
| #35292 | 1:23 PM | 🔵 | Agent SDK query() resume parameter: SDK-generated session IDs cannot be predetermined | ~543 |
**sdkagent-removal-list.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35425 | 5:27 PM | ✅ | Reorganized Removal List with DELETE/SIMPLIFY Section Header | ~240 |
| #35424 | " | ✅ | Revised Token Tracking from Delete to Simplify with Hardcoded Zero | ~365 |
| #35416 | 5:25 PM | 🟣 | Created Actionable Removal Checklist for SDKAgent.ts Cleanup | ~431 |
**agent-sdk-v2-preview.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35414 | 5:25 PM | 🔵 | V2 Preview Documentation Shows Direct Result Access Pattern | ~281 |
| #35289 | 1:23 PM | 🔵 | Agent SDK V2 preview documentation: Explicit session lifecycle with createSession and resumeSession | ~523 |
**sdkagent-conditional-logic-CORRECTED.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35409 | 5:24 PM | 🟣 | Created Comprehensive Conditional Logic Removal Report | ~488 |
**dont-be-an-idiot.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35400 | 5:23 PM | 🔄 | Phase 1 SDK V2 migration - Updated imports and added API documentation | ~294 |
| #35347 | 3:01 PM | ✅ | Phase 1 commit completed via Task agent | ~374 |
| #35346 | " | ✅ | Committed Phase 1 of V2 API migration | ~333 |
| #35345 | 3:00 PM | ✅ | Phase 1 Changes Committed to Git | ~338 |
| #35343 | " | ✅ | Phase 1 Git Status Shows Modified Files | ~315 |
| #35334 | 2:55 PM | 🔵 | V2 SDK Migration Preparation Complete | ~368 |
| #35332 | 2:54 PM | 🟣 | SDK V2 API Documentation Created | ~305 |
| #35331 | " | ✅ | Created documentation affirming V2 API stability | ~358 |
### Jan 2, 2026
**try-catch-audit-report.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35703 | 1:01 PM | ⚖️ | Try-Catch as Anti-Pattern: Root Cause Analysis and Documentation | ~363 |
</claude-mem-context>
+38
View File
@@ -0,0 +1,38 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 12, 2025
**README.ar.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24246 | 2:43 AM | 🟣 | Comprehensive Translation System Added with 22 Language READMEs | ~386 |
**README.zh.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24241 | 2:35 AM | ✅ | Internationalized README Files Moved to Dedicated i18n Directory | ~284 |
### Dec 22, 2025
**README.ja.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31948 | 8:08 PM | ✅ | Batch Updated All Translation READMEs with Language Navigation | ~400 |
**README.zh.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31947 | 8:07 PM | ✅ | Added Language Navigation Menu to Chinese Translation README | ~412 |
| #31945 | 8:06 PM | 🟣 | Multi-language navigation added to internationalized README files | ~386 |
| #31942 | 8:01 PM | 🔵 | Internationalization Documentation Coverage | ~315 |
### Dec 28, 2025
**README.*.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33540 | 10:55 PM | 🔵 | Grep search found mem-search references in internationalized documentation | ~577 |
</claude-mem-context>
+81 -1
View File
@@ -85,4 +85,84 @@ npx mintlify dev
**Simple Rule**:
- `/docs/public/` = Official user documentation (Mintlify .mdx files) ← YOU ARE HERE
- `/docs/context/` = Internal docs, plans, references, audits
- `/docs/context/` = Internal docs, plans, references, audits
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Nov 18, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #11206 | 3:01 PM | 🔵 | mem-search skill architecture and migration details retrieved in full format | ~538 |
### Nov 21, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #13221 | 2:01 AM | 🔴 | Fixed broken markdown link to Viewer UI documentation | ~316 |
| #13220 | 2:00 AM | 🔴 | Escaped HTML less-than symbol in universal architecture timeout documentation | ~316 |
| #13216 | 1:54 AM | ✅ | Universal Architecture Added to Navigation | ~330 |
| #13215 | " | 🟣 | Universal AI Memory Architecture Documentation Created | ~732 |
| #13213 | 1:50 AM | 🔵 | Introduction Page Content and Recent v6.0.0 Release | ~495 |
| #13212 | " | 🔵 | Architecture Evolution Documentation Structure | ~408 |
| #13211 | " | 🔵 | Mintlify Documentation Site Configuration | ~430 |
| #13209 | 1:48 AM | 🔵 | Public Documentation Structure and Guidelines | ~383 |
### Nov 25, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #14994 | 2:22 PM | ✅ | Version Channel Section Added to Configuration Documentation | ~301 |
| #14993 | " | ✅ | Beta Features Added to Documentation Navigation | ~188 |
| #14992 | 2:21 PM | 🟣 | Beta Features Documentation Page Created | ~488 |
| #14991 | " | 🔵 | Mintlify Navigation Structure and Documentation Groups | ~394 |
| #14989 | " | 🔵 | Installation Documentation with Quick Start and Verification Steps | ~383 |
| #14988 | " | 🔵 | Configuration Documentation Structure and Environment Variables | ~338 |
### Nov 26, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #16190 | 10:22 PM | 🔵 | RAGTIME Search Retrieved Five Observations About Claude-Mem vs RAG Architecture | ~637 |
### Dec 3, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #19884 | 9:42 PM | 🔵 | Configuration system and environment variables | ~701 |
| #19878 | 9:40 PM | 🔵 | Installation process and system architecture | ~486 |
### Dec 8, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #22335 | 10:26 PM | 🔵 | Mintlify documentation configuration analyzed | ~534 |
| #22311 | 9:47 PM | 🔵 | Comprehensive Hooks Architecture Documentation Review | ~263 |
| #22297 | 9:43 PM | 🔵 | Mintlify Documentation Framework Configuration | ~446 |
| #22294 | " | 🔵 | Documentation Site Structure Located | ~359 |
### Dec 9, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23179 | 10:44 PM | ✅ | Removed explanatory reasons from tool exclusion documentation | ~297 |
### Dec 15, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #27038 | 6:02 PM | 🔵 | 95% token reduction claims found only in private experimental documents, not in main public docs | ~513 |
| #27037 | " | 🔵 | Branch switching functionality exists in SettingsRoutes with UI switcher removal intent | ~463 |
| #26986 | 5:24 PM | ✅ | Updated Endless Mode latency warning in beta features documentation | ~299 |
### Dec 29, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33938 | 6:27 PM | 🔵 | Relevant CLAUDE.md Context Identified for PR #492 | ~435 |
| #33750 | 12:25 AM | ✅ | Documentation Update: Removed Version Number from Architecture Evolution | ~281 |
</claude-mem-context>
+30
View File
@@ -0,0 +1,30 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Nov 18, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #11206 | 3:01 PM | 🔵 | mem-search skill architecture and migration details retrieved in full format | ~538 |
### Nov 21, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #13218 | 1:58 AM | 🔴 | Escaped HTML special character in MDX documentation | ~261 |
### Dec 3, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #19891 | 9:43 PM | 🔵 | Seven hook scripts across five lifecycle events | ~713 |
### Dec 15, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #27040 | 6:03 PM | 🔵 | Comprehensive search confirms no 95% claims exist in main branch public documentation | ~508 |
| #27037 | 6:02 PM | 🔵 | Branch switching functionality exists in SettingsRoutes with UI switcher removal intent | ~463 |
</claude-mem-context>
+6 -6
View File
@@ -45,19 +45,19 @@ Hook (stdin) → Database → Worker Service → SDK Processor → Database →
4. **Output**: Processed summaries written back to database
5. **Retrieval**: Next session's context hook reads summaries from database
### Search Pipeline (v5.4.0+)
### Search Pipeline
```
User Query → mem-search Skill Invoked → HTTP API → SessionSearch Service → FTS5 Database → Search Results → Claude
User Query → MCP Tools Invoked → HTTP API → SessionSearch Service → FTS5 Database → Search Results → Claude
```
1. **User Query**: User asks naturally: "What bugs did we fix?"
2. **Skill Invoked**: Claude recognizes intent and invokes mem-search skill
3. **HTTP API**: Skill uses curl to call HTTP endpoint (e.g., `/api/search/observations`)
2. **MCP Tools Invoked**: Claude recognizes intent and invokes MCP search tools
3. **HTTP API**: MCP tools call HTTP endpoint (e.g., `/api/search/observations`)
4. **SessionSearch**: Worker service queries FTS5 virtual tables
5. **Format**: Results formatted and returned to skill
5. **Format**: Results formatted and returned via MCP
6. **Return**: Claude presents formatted results to user
**Token Savings**: ~2,250 tokens per session vs MCP approach through progressive disclosure
Uses 3-layer progressive disclosure: search → timeline → get_observations
## Session Lifecycle
+17 -9
View File
@@ -18,6 +18,7 @@ Settings are managed in `~/.claude-mem/settings.json`. The file is auto-created
| `CLAUDE_MEM_MODE` | `code` | Active mode profile (e.g., `code--es`, `email-investigation`) |
| `CLAUDE_MEM_CONTEXT_OBSERVATIONS` | `50` | Number of observations to inject |
| `CLAUDE_MEM_WORKER_PORT` | `37777` | Worker service port |
| `CLAUDE_MEM_WORKER_HOST` | `127.0.0.1` | Worker service host address |
| `CLAUDE_MEM_SKIP_TOOLS` | `ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion` | Comma-separated tools to exclude from observations |
### Gemini Provider Settings
@@ -189,19 +190,16 @@ Hooks are configured in `plugin/hooks/hooks.json`:
}
```
### Search Configuration (v5.4.0+)
### Search Configuration
**Migration Note**: As of v5.4.0, Claude-Mem uses skill-based search instead of MCP tools. As of v5.5.0, the skill was renamed to "mem-search" for better scope differentiation.
Claude-Mem provides MCP search tools for querying your project history.
**Previous (v5.3.x and earlier)**: MCP search server with 9 tools (~2,500 tokens per session)
**Current (v5.4.0+)**: mem-search skill with HTTP API (~250 tokens per session)
**No configuration required** - MCP tools are automatically available in Claude Code sessions.
**No configuration required** - the mem-search skill is automatically available in Claude Code sessions.
Search operations are now provided via:
- **Skill**: `plugin/skills/mem-search/SKILL.md` (auto-invoked when users ask about past work)
Search operations are provided via:
- **MCP Server**: 3 tools (search, timeline, get_observations) with progressive disclosure
- **HTTP API**: 10 endpoints on worker service port 37777
- **Progressive Disclosure**: Full instructions loaded on-demand only when needed
- **Auto-Invocation**: Claude recognizes natural language queries about past work
## Version Channel
@@ -229,6 +227,16 @@ Endless Mode is experimental and slower than standard mode. See [Beta Features](
Worker service is managed by Bun as a background process. The worker auto-starts on first session and runs continuously in the background.
## Folder Context Files
Claude-mem can automatically generate `CLAUDE.md` files in your project folders with activity timelines. This feature is disabled by default.
| Setting | Default | Description |
|---------|---------|-------------|
| `CLAUDE_MEM_FOLDER_CLAUDEMD_ENABLED` | `false` | Enable auto-generation of folder CLAUDE.md files |
See [Folder Context Files](usage/folder-context) for full documentation on how this feature works, configuration options, and git integration recommendations.
## Context Injection Configuration
Claude-Mem injects past observations into each new session, giving Claude awareness of recent work. You can configure exactly what gets injected using the **Context Settings Modal**.
+51
View File
@@ -0,0 +1,51 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 29, 2025
**gemini-setup.mdx**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34346 | 11:11 PM | 🟣 | Gemini Free Tier Integration Guide | ~413 |
| #34337 | 11:10 PM | 🔵 | Cursor Documentation Available | ~161 |
| #34331 | 11:05 PM | 🔴 | Fixed Broken Links in cursor/gemini-setup.mdx | ~253 |
| #34326 | 11:04 PM | 🔵 | Broken Links in Cursor Gemini Setup Documentation | ~324 |
| #34320 | 11:03 PM | 🔵 | Mintlify Broken Links Detected in Documentation | ~292 |
| #34215 | 10:08 PM | 🔵 | Retrieved Detailed Cursor Integration Implementation History | ~676 |
| #34214 | 10:07 PM | 🔵 | Cursor Integration Feature Set Discovered via Memory Search | ~427 |
| #34148 | 9:28 PM | 🟣 | Cursor IDE Integration with Cross-Platform Hooks and Documentation | ~514 |
| #34112 | 9:07 PM | 🟣 | Committed Cursor Public Documentation to Repository | ~427 |
| #34106 | 9:05 PM | 🟣 | Created Cursor-Specific Gemini Setup Guide | ~563 |
**index.mdx**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34339 | 11:10 PM | 🟣 | Cursor IDE Integration with Persistent Memory | ~394 |
| #34335 | 11:06 PM | 🟣 | Mintlify Documentation Linting Successfully Completed | ~409 |
| #34330 | 11:05 PM | 🔴 | Fixed Remaining Broken Links in cursor/index.mdx Next Steps Section | ~284 |
| #34329 | " | 🔴 | Fixed Broken Links in cursor/index.mdx Detailed Guides Section | ~269 |
| #34325 | 11:04 PM | 🔵 | Multiple Broken Links in Cursor Index Documentation | ~329 |
| #34216 | 10:08 PM | 🔵 | Additional Cursor Integration Details Retrieved for Post Writing | ~600 |
| #34105 | 9:05 PM | 🟣 | Created Cursor Integration Landing Page | ~522 |
**openrouter-setup.mdx**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34332 | 11:05 PM | 🔴 | Fixed Broken Links in cursor/openrouter-setup.mdx | ~283 |
| #34324 | 11:04 PM | 🔵 | Broken Link Syntax Identified in Cursor Documentation | ~329 |
| #34107 | 9:06 PM | 🟣 | Created Cursor-Specific OpenRouter Setup Guide | ~573 |
**cursor**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34322 | 11:03 PM | 🔵 | Cursor Directory Files Confirmed to Exist | ~224 |
### Jan 4, 2026
**gemini-setup.mdx**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36751 | 12:32 AM | 🔵 | Gemini-Related Files Located Across Project | ~242 |
</claude-mem-context>
+1
View File
@@ -43,6 +43,7 @@
"usage/private-tags",
"usage/export-import",
"usage/manual-recovery",
"usage/folder-context",
"beta-features",
"endless-mode"
]
+1 -1
View File
@@ -148,7 +148,7 @@ Claude-Mem uses 6 lifecycle hook scripts across 5 lifecycle events, plus 1 pre-h
|----|------|---|-------|--------|
| #2586 | 12:58 AM | 🔵 | Context hook file empty | ~51 |
*Use mem-search skill to access full details*
*Use MCP search tools to access full details*
```
**Source:** `src/hooks/context-hook.ts` → `plugin/scripts/context-hook.js`
+17 -14
View File
@@ -23,15 +23,16 @@ Restart Claude Code. Context from previous sessions will automatically appear in
## Key Features
- 🧠 **Persistent Memory** - Context survives across sessions
- 🌐 **Multilingual Modes** - Supports 10+ languages (Spanish, Chinese, French, etc.)
- 🎭 **Mode System** - Switch between workflows (Code, Email Investigation)
- 🔍 **mem-search Skill** - Query your project history with natural language (~2,250 token savings)
- 📁 **Folder Context Files** - Auto-generated `CLAUDE.md` in project folders with activity timelines
- 🌐 **Multilingual Modes** - Supports 28 languages (Spanish, Chinese, French, Japanese, etc.)
- 🎭 **Mode System** - Switch between workflows (Code, Email Investigation, Chill)
- 🔍 **MCP Search Tools** - Query your project history with natural language
- 🌐 **Web Viewer UI** - Real-time memory stream visualization at http://localhost:37777
- 🔒 **Privacy Control** - Use `<private>` tags to exclude sensitive content from storage
- ⚙️ **Context Configuration** - Fine-grained control over what context gets injected
- 🤖 **Automatic Operation** - No manual intervention required
- 📊 **FTS5 Search** - Fast full-text search across observations
- 🔗 **Citations** - Reference past observations with IDs (access via http://localhost:37777/api/observation/{id} or view all in the web viewer at http://localhost:37777)
- 🔗 **Citations** - Reference past observations with IDs
## How It Works
@@ -58,11 +59,11 @@ Restart Claude Code. Context from previous sessions will automatically appear in
```
**Core Components:**
1. **5 Lifecycle Hooks** - SessionStart, UserPromptSubmit, PostToolUse, Stop, SessionEnd (6 hook scripts)
1. **4 Lifecycle Hooks** - SessionStart, UserPromptSubmit, PostToolUse, Stop
2. **Smart Install** - Cached dependency checker (pre-hook script)
3. **Worker Service** - HTTP API on port 37777 managed by Bun
4. **SQLite Database** - Stores sessions, observations, summaries with FTS5 search
5. **mem-search Skill** - Query historical context with natural language
5. **MCP Search Tools** - Query historical context with natural language
6. **Web Viewer UI** - Real-time visualization with SSE and infinite scroll
See [Architecture Overview](architecture/overview) for details.
@@ -76,21 +77,23 @@ See [Architecture Overview](architecture/overview) for details.
## What's New
**v9.0.0 - Live Context:**
- **Folder Context Files**: Auto-generated `CLAUDE.md` in project folders with activity timelines
- **Worktree Support**: Unified context from parent repos and git worktrees
- **Configurable Observation Limits**: Control how many observations appear in context
- **Windows Fixes**: Resolved IPC detection and hook execution issues
- **Settings Auto-Creation**: `settings.json` now auto-creates on first run
- **MCP Tools Naming**: Updated from "mem-search skill" to "MCP tools" terminology
**v7.1.0 - Bun Migration:**
- Replaced PM2 with native Bun process management
- Switched from better-sqlite3 to bun:sqlite for faster database access
- Automatic one-time migration on first hook trigger
- Simplified cross-platform support
**v7.0.0 - Context Configuration:**
- 11 settings for fine-grained control over context injection
- Dual-tag privacy system (`<private>` tags)
**Previous Highlights:**
- **v5.5.0**: mem-search skill with 100% effectiveness rate
- **v5.4.0**: Skill-based search (~2,250 tokens saved per session)
- **v5.1.0**: Web viewer UI at http://localhost:37777
## Next Steps
<CardGroup cols={2}>
@@ -100,8 +103,8 @@ See [Architecture Overview](architecture/overview) for details.
<Card title="Getting Started" icon="rocket" href="/usage/getting-started">
Learn how Claude-Mem works automatically
</Card>
<Card title="Architecture" icon="sitemap" href="/architecture/overview">
System components & data flow
<Card title="Folder Context" icon="folder-open" href="/usage/folder-context">
Auto-generated folder CLAUDE.md files
</Card>
<Card title="Search Tools" icon="magnifying-glass" href="/usage/search-tools">
Query your project history
+47
View File
@@ -0,0 +1,47 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Nov 18, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #11206 | 3:01 PM | 🔵 | mem-search skill architecture and migration details retrieved in full format | ~538 |
### Dec 3, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #19892 | 9:43 PM | 🔵 | Automatic operation workflow and progressive disclosure strategy | ~780 |
### Dec 10, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23677 | 8:37 PM | ✅ | Update Export Documentation to Reflect Hybrid Search and Project Filter | ~314 |
| #23675 | " | 🔵 | Export/Import Memory Scripts Documentation | ~399 |
| #23590 | 5:51 PM | 🔵 | Import/Export Feature Status Review | ~490 |
| #23584 | 5:50 PM | 🔵 | Export/Import Documentation | ~405 |
### Dec 14, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #26335 | 9:02 PM | 🔵 | Citation URI Scheme Documentation | ~255 |
### Dec 25, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32536 | 7:28 PM | ✅ | Updated Gemini provider warning about free tier rate limits | ~185 |
| #32535 | " | ✅ | Updated Gemini provider tip to recommend enabling billing | ~179 |
| #32534 | 7:27 PM | ✅ | Updated Gemini provider warning about rate limits | ~174 |
| #32533 | " | ✅ | Updated Gemini provider documentation with rate limit information | ~216 |
### Jan 5, 2026
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37508 | 3:21 PM | 🔵 | Private Tags Documentation Defines User Privacy Control Mechanisms | ~748 |
</claude-mem-context>
+6 -6
View File
@@ -1,23 +1,23 @@
---
title: Claude Desktop Skill
description: Use claude-mem memory search in Claude Desktop with the mem-search skill
title: Claude Desktop MCP
description: Use claude-mem memory search in Claude Desktop with MCP tools
icon: desktop
---
<Note>
**Availability:** The mem-search skill works with Claude Desktop on macOS and Windows.
**Availability:** Claude-mem MCP tools work with Claude Desktop on macOS and Windows.
</Note>
## Overview
Claude Desktop can access your claude-mem memory database through the **mem-search** skill. This allows you to search past sessions, decisions, and observations directly from Claude Desktop conversations.
Claude Desktop can access your claude-mem memory database through **MCP tools**. This allows you to search past sessions, decisions, and observations directly from Claude Desktop conversations.
## Prerequisites
Before installing the skill, ensure:
Before configuring MCP tools, ensure:
1. **claude-mem is installed** and the worker service is running
2. **MCP server is configured** in Claude Desktop (the skill uses the `mcp-search` MCP server)
2. **MCP server is configured** in Claude Desktop (uses the `mcp-search` MCP server)
### Verify Worker is Running
+280
View File
@@ -0,0 +1,280 @@
---
title: "Folder Context Files"
description: "Automatic per-folder CLAUDE.md files that provide directory-level context to Claude"
---
## Overview
Claude-mem automatically generates `CLAUDE.md` files in your project folders to provide Claude with directory-level context. These files contain a summary of recent activity in each folder, helping Claude understand what work has been done and where.
<Info>
This feature is **disabled by default**. Enable it via settings if you want automatic folder-level context generation.
</Info>
## How It Works
When you work with Claude Code in a project, claude-mem tracks which files are read and modified. After each observation is saved, it automatically:
1. Identifies unique folder paths from touched files
2. Queries recent observations relevant to each folder
3. Generates a formatted timeline of activity
4. Writes it to `CLAUDE.md` in that folder (inside `<claude-mem-context>` tags)
### What Gets Generated
Each folder's `CLAUDE.md` contains a "Recent Activity" section showing:
- Observation IDs for reference
- Timestamps of when work occurred
- Type indicators (bug fixes, features, discoveries, etc.)
- Brief titles describing the work
- Estimated token counts
```markdown
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 4, 2026
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #1234 | 4:30 PM | 🔵 | Implemented user authentication | ~250 |
| #1235 | " | 🔴 | Fixed login redirect bug | ~180 |
</claude-mem-context>
```
### User Content Preservation
The auto-generated content is wrapped in `<claude-mem-context>` tags. **Any content you write outside these tags is preserved** when the file is regenerated. This means you can:
- Add your own documentation above or below the generated section
- Write folder-specific instructions for Claude
- Include architectural notes or conventions
```markdown
# Authentication Module
This folder contains all authentication-related code.
Follow the established patterns for new auth providers.
<claude-mem-context>
... auto-generated content ...
</claude-mem-context>
## Manual Notes
- OAuth providers go in /providers/
- Session handling uses Redis
```
### Project Root Exclusion
The **project root** (folders containing a `.git` directory) is **excluded** from auto-generation. This is intentional:
- Root `CLAUDE.md` files typically contain project-wide instructions you've written manually
- Auto-generating at the root could overwrite important project documentation
- Subfolders are where folder-level context is most useful
<Note>
Git submodules (which have a `.git` *file* instead of directory) are correctly detected and **not** excluded, so they receive auto-generated context.
</Note>
## Configuration
### Enabling the Feature
To enable folder CLAUDE.md generation, edit your settings file:
**1. Open `~/.claude-mem/settings.json`**
**2. Add or update this setting:**
```json
{
"CLAUDE_MEM_FOLDER_CLAUDEMD_ENABLED": "true"
}
```
**3. Save the file** - changes take effect immediately (no restart needed)
| Value | Behavior |
|-------|----------|
| `"false"` (default) | Folder CLAUDE.md generation disabled |
| `"true"` | Auto-generate folder CLAUDE.md files |
<Tip>
If the settings file doesn't exist, create it with just the settings you want to change. Claude-mem will use defaults for any missing settings.
</Tip>
## Cleanup Mode
The regenerate script includes a `--clean` mode for removing auto-generated content:
```bash
# Preview what would be cleaned (dry run)
bun scripts/regenerate-claude-md.ts --clean --dry-run
# Actually clean files
bun scripts/regenerate-claude-md.ts --clean
```
**What cleanup does:**
1. Finds all `CLAUDE.md` files recursively
2. Strips `<claude-mem-context>...</claude-mem-context>` sections
3. **Deletes** files that become empty after stripping
4. **Preserves** files that have user content outside the tags
This is useful for:
- Preparing a branch for PR (removing generated files)
- Resetting folder context to start fresh
- Removing context before sharing code
## Git Integration
### Should You Commit These Files?
This is **your choice** based on your workflow. Here are the trade-offs:
<Tabs>
<Tab title="Commit Them">
**Pros:**
- Team members see folder-level context and recent activity
- New contributors can understand what happened where
- Code reviewers get additional context about changes
- Historical record of work patterns in the repo
**Cons:**
- Adds files to your repository
- Files change frequently during development
- May create noise in diffs and commit history
- Different team members may generate different content
</Tab>
<Tab title="Gitignore Them">
**Pros:**
- Clean repository without generated files
- No commit noise from auto-generated content
- Each developer has their own local context
- Simpler git history
**Cons:**
- Team doesn't share folder context
- Context is lost when switching machines
- New team members don't benefit from existing context
</Tab>
</Tabs>
### Gitignore Pattern
To exclude folder CLAUDE.md files from git:
```gitignore
# Ignore auto-generated folder context files
**/CLAUDE.md
# But keep the root CLAUDE.md if you want
!CLAUDE.md
```
Or to ignore all CLAUDE.md files everywhere:
```gitignore
**/CLAUDE.md
```
### Recommended Workflows
**For Solo Developers:**
- Keep them local (gitignore) for personal context
- Or commit them if you work across multiple machines
**For Teams:**
- Discuss with your team which approach works best
- Consider committing them if onboarding is frequent
- Use `--clean` before PRs if you prefer clean diffs
**Before Merging PRs:**
```bash
# Clean up generated files before merge
bun scripts/regenerate-claude-md.ts --clean
git add -A
git commit -m "chore: clean up generated CLAUDE.md files"
```
## Regenerating Context
To manually regenerate all folder CLAUDE.md files from the database:
```bash
# Preview what would be regenerated
bun scripts/regenerate-claude-md.ts --dry-run
# Regenerate all folders
bun scripts/regenerate-claude-md.ts
# Regenerate for a specific project only
bun scripts/regenerate-claude-md.ts --project=my-project
```
This is useful after:
- Importing observations from another machine
- Database recovery
- Wanting to refresh all folder context
## Worktree Support
**New in v9.0**: Claude-mem now supports git worktrees with unified context.
When you're working in a git worktree, context is automatically gathered from both:
- The parent repository (where the worktree was created)
- The worktree directory itself
This means observations about shared code are visible regardless of which worktree you're in, giving you a complete picture of recent activity across all related directories.
### How It Works
1. When generating context, claude-mem detects if your project is a worktree
2. It identifies the parent repository automatically
3. Timeline queries include both locations
4. Results are interleaved chronologically
<Note>
No configuration needed - worktree detection is automatic. If you're not using worktrees, this feature has no effect.
</Note>
## Technical Details
### File Format
Generated content uses a consistent markdown table format:
| Column | Description |
|--------|-------------|
| ID | Observation ID (e.g., `#1234`) or session ID (`#S123`) |
| Time | 12-hour format with AM/PM, ditto marks (`"`) for repeated times |
| T | Type emoji indicator |
| Title | Brief description of the observation |
| Read | Estimated token count (e.g., `~250`) |
### Type Indicators
| Emoji | Type |
|-------|------|
| 🔴 | Bug fix |
| 🟣 | Feature |
| 🔄 | Refactor |
| ✅ | Change |
| 🔵 | Discovery |
| ⚖️ | Decision |
| 🎯 | Session |
| 💬 | Prompt |
### Atomic Writes
Files are written atomically using a temp file + rename pattern. This prevents partial writes if the process is interrupted.
### Performance
- Updates happen asynchronously (fire-and-forget)
- Failures are logged but don't block the main workflow
- Only folders with actual file activity are updated
- Deduplication prevents redundant updates for the same folder
+6 -8
View File
@@ -160,13 +160,13 @@ Context injection uses progressive disclosure for efficient token usage:
- Shows full summary details **only if** generated after last observation
- Token cost: ~50-200 tokens for index view
### Layer 2: On-Demand Details (mem-search Skill)
### Layer 2: On-Demand Details (MCP Tools)
- Ask naturally: "What bugs did we fix?" or "How did we implement X?"
- Claude auto-invokes mem-search skill to fetch full details
- Claude auto-invokes MCP search tools to fetch full details
- Search by concept, file, type, or keyword
- Timeline context around specific observations
- Token cost: ~100-500 tokens per observation fetched
- Skill uses HTTP API (v5.4.0+) for efficient retrieval
- Uses 3-layer workflow: search → timeline → get_observations
### Layer 3: Perfect Recall (Code Access)
- Read source files directly when needed
@@ -193,9 +193,9 @@ When you use `/clear`, the session doesn't end - it continues with a new prompt
The `/clear` command clears the conversation context visible to Claude AND re-injects fresh context from recent sessions, while the underlying session continues tracking observations.
## Searching Your History (v5.4.0+)
## Searching Your History
Claude-Mem uses the mem-search skill for querying your project history. Simply ask naturally:
Claude-Mem provides MCP tools for querying your project history. Simply ask naturally:
```
"What bugs did we fix last session?"
@@ -204,9 +204,7 @@ Claude-Mem uses the mem-search skill for querying your project history. Simply a
"Show me recent work on this project"
```
Claude automatically recognizes your intent and invokes the mem-search skill, which uses HTTP API endpoints to query your memory efficiently.
**Token Savings**: ~2,250 tokens per session start vs previous MCP approach
Claude automatically recognizes your intent and invokes the MCP search tools, which use a 3-layer workflow (search → timeline → get_observations) for efficient token usage.
## Next Steps
@@ -0,0 +1,317 @@
# Logging Analysis and Recommendations
**Date**: 2026-01-04
**Status**: CRITICAL - Current logging does not prove system correctness
**Goal**: Enable operators to visually verify the system is working and quickly discover when it isn't
---
## Executive Summary
The current logging is **noisy bullshit that doesn't cover the important parts of the system**. The logging should:
1. **PROVE** the system is working correctly (not just record activity)
2. **MAKE OBVIOUS** when things break (clear error paths)
3. **TRACE** data end-to-end through the pipeline
### Critical Finding: Session ID Alignment is BROKEN and UNVERIFIABLE
The system has **three session ID types** that must stay aligned:
- `contentSessionId` - from Claude Code (user's session)
- `sessionDbId` - our internal database ID (integer)
- `memorySessionId` - from Claude SDK (enables resume)
**The [ALIGNMENT] logs exist because this mapping is STILL a regression bug.** The current logs show intermediate values but **don't prove correctness**.
---
## Critical System Operations
### 1. Session ID Mapping Chain (MOST CRITICAL)
```
contentSessionId (from hook)
→ sessionDbId (our DB lookup)
→ memorySessionId (captured from SDK)
```
**If this breaks, observations go to wrong sessions = DATA CORRUPTION**
**Current State:**
| Operation | Has Logging? | Proves Correctness? |
|-----------|-------------|---------------------|
| Hook receives contentSessionId | YES | NO - just logs receipt |
| DB creates/looks up sessionDbId | PARTIAL | NO - no verification |
| SDK response gives memorySessionId | YES | NO - no DB update verification |
| Observations stored with memorySessionId | PARTIAL | NO - doesn't show which IDs used |
**What's MISSING:**
```
[INFO] [SESSION] SESSION_CREATED | contentSessionId=abc123 → sessionDbId=42 | isNew=true
[INFO] [SESSION] MEMORY_ID_CAPTURED | sessionDbId=42 | memorySessionId=xyz789 | dbUpdateSuccess=true
[INFO] [SESSION] E2E_VERIFIED | contentSessionId=abc123 → sessionDbId=42 → memorySessionId=xyz789
```
### 2. Observation Storage Pipeline (CRITICAL)
**The pipeline:**
```
Hook captures tool use
→ Worker receives observation
→ Queued to pending_messages
→ SDK agent claims message
→ SDK processes → generates XML
→ Observations parsed
→ Stored to DB with memorySessionId
→ Synced to Chroma
```
**Current State:**
| Operation | Has Logging? | Proves Correctness? |
|-----------|-------------|---------------------|
| Hook captures tool | YES | Noise - "Received hook input" |
| Observation queued | YES | Noise - just says "queued" |
| Message claimed from queue | NO | MISSING |
| Observation parsed | NO | MISSING |
| Observation stored to DB | PARTIAL | NO - doesn't show IDs used |
| DB transaction committed | NO | MISSING |
| Chroma sync complete | DEBUG only | Should be INFO for failures |
**What's MISSING:**
```
[INFO] [QUEUE] CLAIMED | sessionDbId=42 | messageId=5 | type=observation | tool=Bash(npm test)
[INFO] [DB ] STORED | sessionDbId=42 | memorySessionId=xyz789 | observations=2 | ids=[101,102]
[INFO] [QUEUE] COMPLETED | sessionDbId=42 | messageId=5 | processingTime=1.2s
```
### 3. Queue Processing (CRITICAL)
Messages can fail, get stuck, or be lost. Current logging doesn't show:
- When a message is claimed
- When a message is completed
- When a message fails and WHY
- Queue depth and processing latency
**Current State:**
- Queue enqueue: `logger.debug` (not visible at INFO)
- Queue claim: NO LOGGING
- Queue completion: NO LOGGING
- Queue failure: `logger.error` (exists but rare)
- Recovery of stuck messages: `logger.info` (good)
**What's MISSING:**
```
[INFO] [QUEUE] ENQUEUE | sessionDbId=42 | type=observation | queueDepth=3
[INFO] [QUEUE] CLAIM | sessionDbId=42 | messageId=5 | waitTime=0.1s
[INFO] [QUEUE] COMPLETE | sessionDbId=42 | messageId=5 | success=true
[ERROR][QUEUE] FAILED | sessionDbId=42 | messageId=5 | error="SDK timeout" | willRetry=true
```
### 4. Context Injection (IMPORTANT)
When a session starts, relevant past observations should be injected. Current logging doesn't show:
- What context was searched for
- What was found
- What was injected
**Current State:** Effectively no logging for context injection success path.
---
## What's Currently NOISE (Should Be DEBUG or Removed)
### Chatty Session Init Logs (new-hook.ts)
```typescript
// 7 INFO logs for a single session init
logger.info('HOOK', 'new-hook: Received hook input'); // WHO CARES
logger.info('HOOK', 'new-hook: Calling /api/sessions/init'); // WHO CARES
logger.info('HOOK', 'new-hook: Received from /api/sessions/init'); // WHO CARES
logger.info('HOOK', 'new-hook: Session N, prompt #M'); // CONSOLIDATE INTO ONE
logger.info('HOOK', 'new-hook: Calling /sessions/{id}/init'); // WHO CARES
```
**Should be ONE log:** `SESSION_INIT | sessionDbId=42 | promptNumber=1 | project=foo`
### Chatty SessionManager Logs
```typescript
logger.info('SESSION', 'initializeSession called'); // WHO CARES
logger.info('SESSION', 'Returning cached session'); // DEBUG
logger.info('SESSION', 'Fetched session from database'); // DEBUG
logger.info('SESSION', 'Creating new session object'); // DEBUG
logger.info('SESSION', 'Session initialized'); // GOOD - KEEP
logger.info('SESSION', 'Observation queued'); // DEBUG - happens constantly
logger.info('SESSION', 'Summarize queued'); // DEBUG - happens constantly
```
### Chatty Chroma Backfill Logs
```typescript
// Logs EVERY batch at INFO - should be DEBUG for progress
logger.info('CHROMA_SYNC', 'Backfill progress', { processed, remaining }); // DEBUG
```
**Should be START and END only at INFO level.**
### Duplicate Migration Logs
Both `SessionStore.ts` and `migrations/runner.ts` have ~25 identical log statements. **DEDUPLICATE.**
---
## [ALIGNMENT] Logs: The Problem
The [ALIGNMENT] logs were added to debug session ID issues. They're in the RIGHT places but they **don't prove anything**:
```typescript
// Current - shows values but doesn't verify
logger.info('SDK', `[ALIGNMENT] Resume Decision | contentSessionId=${...} | memorySessionId=${...}`);
// What's needed - proves correctness
logger.info('SDK', `[ALIGNMENT] VERIFIED | contentSessionId=${...} → sessionDbId=${...} → memorySessionId=${...} | dbMatch=true | resumeValid=true`);
```
**Current problems:**
1. Log values without validation
2. Don't show if DB operations succeeded
3. Don't trace end-to-end
4. Mixed in with noise - hard to see
**What they should do:**
1. Log the mapping chain ONCE with verification
2. Show DB operation success/failure
3. Provide clear end-to-end trace
4. Stand out from noise with consistent prefix
---
## Proposed Logging Architecture
### Log Levels by Purpose
| Level | Purpose | Examples |
|-------|---------|----------|
| ERROR | Something FAILED | DB write failed, SDK crashed, queue overflow |
| WARN | Something UNEXPECTED but handled | Fallback used, retry needed, timeout |
| INFO | KEY OPERATIONS completed | Session created, observation stored, queue processed |
| DEBUG | Detailed tracing | Cache hits, intermediate states, parsing details |
### Critical Path Logging (Must be INFO)
#### Session Lifecycle
```
[INFO] [SESSION] CREATED | contentSessionId=abc → sessionDbId=42 | project=foo
[INFO] [SESSION] MEMORY_ID_CAPTURED | sessionDbId=42 → memorySessionId=xyz | dbUpdated=true
[INFO] [SESSION] VERIFIED | chain: abc→42→xyz | valid=true
[INFO] [SESSION] COMPLETED | sessionDbId=42 | duration=45s | observations=12 | summaries=1
```
#### Observation Pipeline
```
[INFO] [QUEUE] ENQUEUED | sessionDbId=42 | type=observation | tool=Bash(npm test) | depth=1
[INFO] [QUEUE] CLAIMED | sessionDbId=42 | messageId=5 | waitTime=0.1s
[INFO] [DB ] STORED | sessionDbId=42 | memorySessionId=xyz | obsIds=[101,102] | txnCommit=true
[INFO] [QUEUE] COMPLETED | sessionDbId=42 | messageId=5 | duration=1.2s
```
#### Error Conditions
```
[ERROR] [SESSION] MEMORY_ID_MISMATCH | expected=xyz | got=abc | sessionDbId=42
[ERROR] [DB ] STORE_FAILED | sessionDbId=42 | error="FK constraint" | observations=2
[ERROR] [QUEUE ] STUCK | sessionDbId=42 | stuckFor=5min | action=marking_failed
[ERROR] [SDK ] CRASHED | sessionDbId=42 | error="Claude process died" | pendingWork=3
```
### Health Dashboard Output
After fixes, a healthy session should produce:
```
[INFO] [SESSION] CREATED | contentSessionId=abc → sessionDbId=42
[INFO] [SESSION] GENERATOR_STARTED | sessionDbId=42 | provider=claude-sdk
[INFO] [QUEUE ] CLAIMED | sessionDbId=42 | messageId=1 | type=observation
[INFO] [SESSION] MEMORY_ID_CAPTURED | sessionDbId=42 → memorySessionId=xyz
[INFO] [DB ] STORED | sessionDbId=42 | memorySessionId=xyz | obsIds=[1]
[INFO] [QUEUE ] COMPLETED | sessionDbId=42 | messageId=1
... (more observations)
[INFO] [QUEUE ] CLAIMED | sessionDbId=42 | messageId=5 | type=summarize
[INFO] [DB ] STORED | sessionDbId=42 | summaryId=1
[INFO] [QUEUE ] COMPLETED | sessionDbId=42 | messageId=5
[INFO] [SESSION] COMPLETED | sessionDbId=42 | duration=45s | observations=12
```
An UNHEALTHY session should make problems OBVIOUS:
```
[INFO] [SESSION] CREATED | contentSessionId=abc → sessionDbId=42
[INFO] [SESSION] GENERATOR_STARTED | sessionDbId=42 | provider=claude-sdk
[ERROR] [SESSION] MEMORY_ID_NOT_CAPTURED | sessionDbId=42 | waited=30s
[ERROR] [DB ] STORE_FAILED | sessionDbId=42 | error="memorySessionId is null"
[WARN ] [QUEUE ] STUCK | sessionDbId=42 | messageId=1 | age=60s | action=retry
[ERROR] [SESSION] GENERATOR_CRASHED | sessionDbId=42 | error="SDK timeout"
```
---
## Implementation Priorities
### P0: Fix Critical Missing Logs (Session Alignment)
1. **ResponseProcessor.ts** - Add logging BEFORE storeObservations:
```typescript
logger.info('DB', 'STORING | sessionDbId=... | memorySessionId=... | count=...');
```
2. **SDKAgent.ts** - Verify DB update after memorySessionId capture:
```typescript
const updated = store.updateMemorySessionId(sessionDbId, memorySessionId);
logger.info('SESSION', `MEMORY_ID_CAPTURED | sessionDbId=${...} | memorySessionId=${...} | dbUpdated=${updated}`);
```
3. **SessionRoutes.ts** - Log session creation with verification:
```typescript
logger.info('SESSION', `CREATED | contentSessionId=${...} → sessionDbId=${...} | verified=true`);
```
### P1: Fix Queue Processing Logs
1. **SessionQueueProcessor.ts** - Add CLAIM/COMPLETE logs
2. **PendingMessageStore.ts** - Add enqueue/dequeue logs
### P2: Reduce Noise
1. Move chatty logs to DEBUG level
2. Deduplicate migration logs
3. Consolidate hook init logs
### P3: Add Health Validation
1. Periodic verification log: `[INFO] [HEALTH] OK | sessions=3 | pending=0 | chroma=connected`
2. On-demand chain verification: `[INFO] [VERIFY] contentSessionId=abc chain is VALID`
---
## Files Requiring Changes
| File | Priority | Changes |
|------|----------|---------|
| `src/services/worker/agents/ResponseProcessor.ts` | P0 | Add pre-store logging with IDs |
| `src/services/worker/SDKAgent.ts` | P0 | Verify DB update, consolidate ALIGNMENT logs |
| `src/services/worker/http/routes/SessionRoutes.ts` | P0 | Add session creation verification log |
| `src/services/queue/SessionQueueProcessor.ts` | P1 | Add CLAIM/COMPLETE logs |
| `src/services/sqlite/PendingMessageStore.ts` | P1 | Add enqueue/dequeue logs |
| `src/services/worker/SessionManager.ts` | P2 | Move chatty logs to DEBUG |
| `src/hooks/new-hook.ts` | P2 | Consolidate to single INFO log |
| `src/services/sync/ChromaSync.ts` | P2 | Move progress to DEBUG, keep start/end INFO |
| `src/services/sqlite/SessionStore.ts` | P2 | Remove duplicate migration logs |
---
## Verification Checklist
After implementing changes, verify:
- [ ] Can trace contentSessionId → sessionDbId → memorySessionId in logs
- [ ] Can see when observation storage succeeds/fails
- [ ] Can see queue claim/complete for each message
- [ ] Errors are OBVIOUS and include context for debugging
- [ ] Noise is reduced to the point where INFO level is useful
- [ ] A "normal" session produces ~10-15 INFO logs, not 50+
@@ -0,0 +1,58 @@
Brainstorming Report: CLAUDE.md Distribution Architecture
Problem Statement
The current folder-level CLAUDE.md generation creates "messy repos" with many auto-generated files. While the feature is valuable (especially for PR reviews and team visibility), the file proliferation could annoy users.
Solutions Explored
1. Shell Magic / On-Read Population
Explored various "magic alias" approaches where content populates dynamically on read:
- Git smudge/clean filters - Transform at checkout, not truly on-read
- FUSE filesystem - Virtual FS with dynamic generation, powerful but heavy
- Named pipes (FIFOs) - Fragile, editors don't handle well
- Symlinks to generated location - Simple but not on-demand
2. Command Substitution (Exciting Discovery)
Potential Claude Code feature request - support command substitution in context config:
{
"context": {
"sources": [
{ "command": "claude-mem live-context ${CWD}" }
]
}
}
Or folder-level .claude-context files containing just:
exec: claude-mem live-context .
Benefits: Zero files, pure dynamic context, no staleness, no merge conflicts ever.
3. Ephemeral + Smart Push Architecture (Recommended)
Phase 1: Ephemeral Local
- Gitignore **/CLAUDE.md (keep root CLAUDE.md for user instructions)
- Timeline data in separate file: claude-mem-timeline.csv
- Generated fresh on SessionStart
- Block Claude from reading timeline file via .claude/settings.local.json: "ignorePaths": ["claude-mem-timeline.csv"]
- Prevents duplication (data already injected via context hook)
Phase 2: Smart Push Timeline
- Pre-push hook generates timeline from last commit to now
- Writes claude-mem-timeline.csv and includes in push
- Reviewers, CI/CD Claude agents, and team members see what happened
- Clean separation: CLAUDE.md = human instructions, timeline.csv = machine context
Phase 3: Team Sync (Pro Feature)
- Post-pull hook: claude-mem sync --from-timeline
- Parses timeline files, validates against local DB
- Imports missing observations with provenance tracking
- Conflict resolution for overlapping work
- Monetization opportunity: Team sync as paid feature
Key Insight: Clean Separation
- CLAUDE.md = User-authored project instructions (Claude SHOULD read)
- claude-mem-timeline.csv = Machine-generated context sync (blocked from reading, already injected)
No collision between human documentation and machine context.
+160
View File
@@ -0,0 +1,160 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 2, 2026
**2026-01-02--generator-failure-investigation.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36091 | 10:20 PM | 🔵 | Generator Failure Investigation - Chroma Vector Search Silent Failures | ~436 |
| #36079 | 10:10 PM | 🔴 | Fixed Generator Crashes from Silent Chroma Vector Search Failures | ~531 |
**2026-01-02--stuck-observations.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36004 | 8:14 PM | 🔵 | Comprehensive Investigation Report on Stuck Observations Problem | ~527 |
### Jan 3, 2026
**2026-01-04--session-id-refactor-failures.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36643 | 10:56 PM | 🔵 | Session ID Refactor Test Failures Root Cause | ~513 |
| #36636 | 10:46 PM | 🟣 | Session ID Refactor Analysis Agent Completed Comprehensive Report | ~637 |
| #36626 | 10:44 PM | 🟣 | Session ID Refactor Failures Report Generated | ~569 |
**2026-01-04--gemini-agent-failures.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36638 | 10:47 PM | ✅ | GeminiAgent Failures Report Manually Created After Agent Timeout | ~604 |
**2026-01-04--session-store-failures.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36635 | 10:46 PM | 🟣 | SessionStore Analysis Agent Completed Report Generation | ~545 |
| #36634 | " | ✅ | SessionStore Failures Report Generated With Test Fix Recommendations | ~595 |
**2026-01-04--logger-coverage-failures.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36633 | 10:46 PM | ✅ | Logger Coverage Failures Report Generated | ~559 |
| #36623 | 10:44 PM | 🟣 | Logger Coverage Failures Report Generated | ~249 |
**2026-01-04--session-id-validation-failures.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36628 | 10:44 PM | 🟣 | Session ID Validation Failures Report Generated | ~690 |
**2026-01-04--test-suite-report.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36609 | 10:39 PM | 🟣 | Comprehensive Test Suite Report Generated | ~563 |
**reports**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36599 | 10:37 PM | 🔵 | Reports Directory Structure Confirmed | ~203 |
**2026-01-02--generator-failure-investigation.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
**2026-01-03--observation-saving-failure.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36113 | 3:58 PM | 🔴 | Fixed FOREIGN KEY Constraint Failure in Observation Storage | ~448 |
### Jan 4, 2026
**2026-01-04--issue-511-gemini-model-missing.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36924 | 2:25 AM | ✅ | Merged fix/pr-538-followups branch into main with comprehensive updates | ~481 |
| #36827 | 1:03 AM | ✅ | Branch diff shows 1,293 insertions and 98 deletions across 15 files | ~464 |
| #36781 | 12:45 AM | 🔵 | Complete GeminiAgent Model Configuration Gap Analysis | ~552 |
| #36776 | 12:43 AM | 🔵 | Issue #511 Analysis Document Located | ~459 |
| #36759 | 12:34 AM | ✅ | Created Issue #511 Analysis Report | ~304 |
**2026-01-04--issue-517-windows-powershell-analysis.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36779 | 12:44 AM | 🔵 | ProcessManager Windows PowerShell Functions Complete Analysis | ~550 |
| #36720 | 12:15 AM | 🔵 | Issue #517 Windows PowerShell Analysis Completed | ~631 |
| #36718 | " | 🔵 | Issue #517 Analysis - Windows PowerShell Variable Escaping Bug | ~482 |
**2026-01-04--issue-531-export-type-duplication.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36760 | 12:34 AM | ✅ | Created Issue #531 Report: Export Script Type Duplication | ~430 |
**2026-01-04--gemini-agent-failures.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36751 | 12:32 AM | 🔵 | Gemini-Related Files Located Across Project | ~242 |
**reports**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36748 | 12:31 AM | 🔵 | Existing GitHub Issue Reports Located | ~271 |
**2026-01-04--issue-527-uv-homebrew-analysis.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36721 | 12:15 AM | 🔵 | Issue #527 UV Homebrew Path Missing on Apple Silicon | ~492 |
| #36719 | " | 🔵 | Issue #527 uv Homebrew Detection Missing on Apple Silicon Macs | ~526 |
**2026-01-04--issue-514-orphaned-sessions-analysis.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36717 | 12:14 AM | 🔵 | Issue #514 Orphaned Sessions Analysis Completed | ~723 |
| #36716 | 12:13 AM | 🔵 | Issue #514 Orphaned .jsonl Session Files Analysis | ~616 |
**2026-01-04--issue-532-memory-leak-analysis.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36714 | 12:12 AM | 🔵 | Memory Leak Analysis Report for Issue #532 Generated | ~531 |
| #36712 | 12:11 AM | 🔵 | Memory Leak Analysis for Issue #532 Documented | ~646 |
**2026-01-04--issue-520-stuck-messages-analysis.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36713 | 12:11 AM | 🔵 | Issue #520 Stuck Messages Already Resolved | ~569 |
| #36711 | " | 🔵 | Issue #520 Stuck Messages Analysis - Already Resolved | ~526 |
**2026-01-02--stuck-observations.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36710 | 12:07 AM | 🔵 | Stuck Observations Analysis - Six Critical Lifecycle Gaps | ~677 |
### Jan 5, 2026
**2026-01-05--issue-544-mem-search-hint-claude-code.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37613 | 5:31 PM | 🔵 | PR #558 Review Feedback Analysis | ~544 |
| #37555 | 4:49 PM | 🔵 | Issue #544 Message Locations and Fix Pattern Documented | ~463 |
| #37545 | 4:47 PM | ✅ | Issue #544 Analysis Report Created for mem-search Skill Messaging Problem | ~480 |
**2026-01-05--issue-555-windows-hooks-ipc-false.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37558 | 4:49 PM | 🔵 | Issue #555 Windows Hook Execution Patterns and Fix Strategy Documented | ~510 |
**2026-01-05--issue-545-formattool-json-parse-crash.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37557 | 4:49 PM | 🔵 | Issue #545 Bug Location and Fix Pattern Documented | ~462 |
**2026-01-05--issue-543-slash-command-unavailable.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37548 | 4:48 PM | ✅ | Issue #543 Analysis Report Created for Slash Command Availability | ~540 |
**2026-01-05--issue-557-settings-module-loader-error.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37547 | 4:47 PM | ✅ | Issue #557 Analysis Report Created for Plugin Startup Failure | ~491 |
</claude-mem-context>
+2
View File
@@ -48,6 +48,8 @@
"queue": "bun scripts/check-pending-queue.ts",
"queue:process": "bun scripts/check-pending-queue.ts --process",
"queue:clear": "bun scripts/clear-failed-queue.ts --all --force",
"claude-md:regenerate": "bun scripts/regenerate-claude-md.ts",
"claude-md:dry-run": "bun scripts/regenerate-claude-md.ts --dry-run",
"translate-readme": "bun scripts/translate-readme/cli.ts -v -o docs/i18n README.md",
"translate:tier1": "npm run translate-readme -- zh ja pt-br ko es de fr",
"translate:tier2": "npm run translate-readme -- he ar ru pl cs nl tr uk",
+103
View File
@@ -0,0 +1,103 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 28, 2025
**plugin.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33503 | 10:43 PM | 🔵 | Plugin metadata contains no skill or MCP server definitions | ~216 |
| #33486 | 10:35 PM | ✅ | Committed Version Bump to 8.2.6 | ~212 |
| #33484 | " | ✅ | Verified Version Synchronization at 8.2.6 | ~173 |
| #33483 | " | ✅ | Synchronized Plugin Metadata Version to 8.2.6 | ~183 |
| #33478 | 10:34 PM | 🔵 | Plugin Metadata Configuration Structure | ~195 |
| #33477 | " | 🔵 | Current Version Across Package Files is 8.2.5 | ~185 |
| #33311 | 3:09 PM | ✅ | Version 8.2.3 Release Deployed with Worker Stability Improvements | ~434 |
| #33300 | 3:08 PM | ✅ | Version 8.2.4 Released with Full Automation Pipeline | ~357 |
| #33281 | 3:07 PM | ✅ | Released v8.2.1 with Worker Lifecycle Hardening | ~332 |
### Dec 29, 2025
**plugin.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34368 | 11:30 PM | ✅ | Bumped version to 8.5.1 for patch release | ~218 |
| #34351 | 11:13 PM | ✅ | Version 8.5.0 Release Committed to Git | ~402 |
| #34349 | 11:12 PM | ✅ | Version 8.5.0 Synchronized Across All Files | ~220 |
| #33997 | 7:10 PM | ✅ | Version Bumped to 8.2.10 | ~179 |
| #33995 | " | ✅ | Version Bump to 8.2.10 in plugin.json | ~250 |
| #33992 | " | 🔵 | Version Consistency Verified Across Package Files | ~133 |
| #33956 | 6:45 PM | 🔵 | Version 8.2.9 Release Verification Complete | ~227 |
| #33950 | 6:42 PM | ✅ | Version Sync to 8.2.9 in Plugin Manifest | ~172 |
| #33948 | " | 🔵 | Current Version State Across Project Files | ~195 |
| #33854 | 4:33 PM | 🔵 | Worker service build and execution architecture mapped | ~509 |
| #33840 | 4:24 PM | ✅ | Version 8.2.8 Changes Committed to Git | ~233 |
| #33838 | 4:23 PM | ✅ | Patch Release Version Bump to 8.2.8 Completed | ~216 |
| #33836 | " | 🔵 | Current Version State Before Patch Release | ~125 |
### Dec 31, 2025
**plugin.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34723 | 4:51 PM | ✅ | Version 8.5.2 Release Committed and Tagged | ~198 |
| #34722 | " | ✅ | Synchronized version to 8.5.2 in plugin metadata | ~194 |
| #34721 | " | ✅ | Version 8.5.2 Synchronized Across All Configuration Files | ~186 |
| #34718 | 4:50 PM | 🔵 | Plugin Configuration Version Check | ~191 |
| #34715 | " | 🔵 | Version 8.5.1 confirmed across all package configuration files | ~181 |
### Jan 1, 2026
**plugin.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35680 | 11:43 PM | 🟣 | Automated version 8.5.3 release workflow completed | ~470 |
| #35674 | 11:41 PM | 🔵 | Release staged files identified for version 8.5.3 | ~287 |
| #35673 | " | ✅ | Staged version files for commit | ~155 |
| #35672 | " | ✅ | Version bumped to 8.5.3 in plugin configuration | ~231 |
| #35670 | 11:40 PM | 🔵 | Current plugin version identified as 8.5.2 | ~240 |
### Jan 2, 2026
**plugin.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35944 | 2:57 PM | 🔵 | Current Project Version 8.5.4 Verified | ~200 |
| #35926 | 2:53 PM | ✅ | Committed Version Bump to 8.5.4 | ~210 |
| #35924 | " | ✅ | Verified Version Consistency Across All Files | ~186 |
| #35923 | " | ✅ | Updated Plugin Configuration Version to 8.5.4 | ~167 |
| #35920 | 2:52 PM | 🔵 | Plugin.json Version Configuration | ~200 |
| #35917 | " | 🔵 | Current Version Identified as 8.5.3 | ~170 |
| #35905 | 2:49 PM | 🔵 | Current Version is 8.5.3 Across All Package Files | ~193 |
### Jan 3, 2026
**plugin.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36669 | 11:37 PM | ✅ | Merge conflicts resolved automatically - only 5 metadata files modified | ~345 |
### Jan 4, 2026
**plugin.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36924 | 2:25 AM | ✅ | Merged fix/pr-538-followups branch into main with comprehensive updates | ~481 |
| #36922 | " | ✅ | Version Bump Committed to Git | ~261 |
| #36920 | " | 🔵 | Version 8.5.8 already set across all configuration files | ~203 |
| #36917 | 2:24 AM | ✅ | Version bumped to 8.5.8 in plugin.json | ~204 |
| #36912 | " | 🔵 | Current version identified as 8.5.7 across all package files | ~190 |
| #36700 | 12:00 AM | ✅ | Committed Version 8.5.7 Across All Package Files | ~260 |
| #36699 | " | ✅ | Version Bumped to 8.5.7 Across All Package Files | ~271 |
| #36697 | " | ✅ | Version Bumped to 8.5.7 for Patch Release | ~243 |
### Jan 5, 2026
**plugin.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37548 | 4:48 PM | ✅ | Issue #543 Analysis Report Created for Slash Command Availability | ~540 |
| #37532 | 4:43 PM | 🔵 | Plugin Metadata Missing Slash Command Registration | ~372 |
</claude-mem-context>
+84
View File
@@ -0,0 +1,84 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 29, 2025
**package.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34351 | 11:13 PM | ✅ | Version 8.5.0 Release Committed to Git | ~402 |
| #34350 | 11:12 PM | ✅ | Version 8.5.0 Build Completed Successfully | ~425 |
| #34214 | 10:07 PM | 🔵 | Cursor Integration Feature Set Discovered via Memory Search | ~427 |
| #34208 | 10:00 PM | ✅ | claude-mem v8.2.10 built and synced to marketplace | ~416 |
| #34163 | 9:38 PM | ✅ | Project rebuilt with updated interactive setup wizard | ~326 |
| #34092 | 9:02 PM | ✅ | Built claude-mem project with updated interactive setup wizard | ~452 |
| #33997 | 7:10 PM | ✅ | Version Bumped to 8.2.10 | ~179 |
| #33996 | " | 🟣 | Built claude-mem v8.2.10 with all hooks and services | ~387 |
| #33982 | 7:08 PM | ✅ | Staged Version Mismatch Fix Changes | ~333 |
| #33951 | 6:42 PM | ✅ | Project Build Completed for Version 8.2.9 | ~326 |
| #33877 | 5:02 PM | 🟣 | Phase 1 build process successfully tested with worker source copying | ~372 |
### Dec 30, 2025
**package.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34476 | 2:25 PM | ✅ | V2 Branch Builds Successfully Despite TypeScript Errors | ~316 |
| #34451 | 2:20 PM | ✅ | Successful Build of Claude-Mem v8.5.1 Components | ~346 |
### Dec 31, 2025
**package.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34724 | 4:51 PM | ✅ | Built claude-mem v8.5.2 with issue 499 fix | ~287 |
| #34710 | 4:48 PM | ✅ | Built and deployed claude-mem v8.5.1 to marketplace | ~371 |
### Jan 1, 2026
**package.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35680 | 11:43 PM | 🟣 | Automated version 8.5.3 release workflow completed | ~470 |
| #35613 | 10:57 PM | ✅ | Build System Compiled Updated Middleware | ~320 |
| #35427 | 6:32 PM | ✅ | Claude-Mem Project Built Successfully | ~319 |
| #35397 | 5:23 PM | ✅ | Build System Successfully Compiled All Components | ~282 |
| #35343 | 3:00 PM | ✅ | Phase 1 Git Status Shows Modified Files | ~315 |
### Jan 2, 2026
**package.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35982 | 5:09 PM | ✅ | Built and deployed claude-mem version 8.5.4 with LogsModal UI component | ~295 |
| #35976 | 4:48 PM | ✅ | Claude-mem build and marketplace sync completed | ~335 |
| #35925 | 2:53 PM | ✅ | Built Project for Version 8.5.4 Release | ~294 |
| #35815 | 2:26 PM | ✅ | Claude-mem plugin built and deployed to marketplace | ~381 |
### Jan 3, 2026
**package.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36687 | 11:53 PM | ✅ | MCP SDK and esbuild Dependencies Updated | ~332 |
| #36669 | 11:37 PM | ✅ | Merge conflicts resolved automatically - only 5 metadata files modified | ~345 |
### Jan 4, 2026
**package.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36926 | 2:26 AM | ✅ | Git rebase aborted and working directory restored | ~242 |
| #36924 | 2:25 AM | ✅ | Merged fix/pr-538-followups branch into main with comprehensive updates | ~481 |
| #36827 | 1:03 AM | ✅ | Branch diff shows 1,293 insertions and 98 deletions across 15 files | ~464 |
| #36701 | 12:01 AM | ✅ | Built Version 8.5.7 Plugin Artifacts | ~406 |
### Jan 5, 2026
**.mcp.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37545 | 4:47 PM | ✅ | Issue #544 Analysis Report Created for mem-search Skill Messaging Problem | ~480 |
</claude-mem-context>
+31
View File
@@ -0,0 +1,31 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Oct 25, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #2518 | 11:47 PM | 🔴 | Removed Invalid 'matcher' Field from SessionStart Hook | ~228 |
| #2517 | " | 🔵 | Project hooks.json Template Also Empty | ~222 |
| #2501 | 11:11 PM | 🔵 | Context Hook Fails Due to Missing @anthropic-ai/sdk Dependency | ~245 |
### Oct 27, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #2718 | 12:00 AM | 🔴 | Removed incorrect failOnError configuration from hook | ~165 |
### Nov 18, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #11518 | 8:22 PM | 🔵 | Smart Contextualization Switched from Skill to HTTP API | ~498 |
### Dec 24, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32309 | 3:09 PM | 🔵 | Claude-mem hooks system configuration structure | ~435 |
</claude-mem-context>
+183
View File
@@ -0,0 +1,183 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 22, 2025
**code--fr.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31959 | 8:41 PM | 🔵 | French Language Remix Implementation Pattern | ~336 |
| #31883 | 7:12 PM | ✅ | Externalisation des prompts de résumé dans le fichier de configuration JSON français | ~345 |
| #31840 | 6:47 PM | 🔄 | Removed unused header configuration strings from French mode | ~228 |
**code.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31958 | 8:40 PM | 🔵 | Mode System Structure in Claude-Mem | ~304 |
| #31891 | 7:17 PM | 🔴 | Migration des prompts de résumé vers les fichiers de modes pour le support multilingue | ~474 |
| #31869 | 7:03 PM | 🔵 | コードモードJSONファイルのプロンプト構造の確認 | ~196 |
**code--hu.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31941 | 7:57 PM | 🟣 | Hungarian language mode configuration created | ~336 |
**code--es.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31940 | 7:56 PM | 🔵 | Claude-mem supports 28 language localizations for code mode | ~365 |
| #31922 | 7:50 PM | 🔵 | Spanish Language Mode Remix File Structure | ~323 |
| #31875 | 7:07 PM | ✅ | Standardisation du pied de page de résumé en anglais avec exigence linguistique | ~301 |
| #31874 | " | ✅ | Ajout des instructions de résumé au fichier de mode espagnol | ~308 |
| #31871 | 7:04 PM | 🔵 | Examen de la structure des fichiers de modes multilingues | ~354 |
| #31838 | 6:46 PM | 🔄 | Removed unused header configuration strings from Spanish mode | ~240 |
**code--el.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31939 | 7:56 PM | 🟣 | Greek language mode configuration created | ~330 |
**code--it.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31938 | 7:56 PM | 🟣 | Italian language mode configuration created | ~333 |
**code--sv.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31937 | 7:56 PM | 🟣 | Swedish language mode configuration created | ~330 |
**code--ro.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31936 | 7:56 PM | 🟣 | Romanian language mode configuration created | ~328 |
**code--bn.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31935 | 7:56 PM | 🟣 | Bengali language mode configuration created | ~329 |
**code--hi.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31934 | 7:55 PM | 🟣 | Hindi language mode configuration created | ~318 |
**code--id.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31933 | 7:55 PM | 🟣 | Indonesian language mode configuration created | ~307 |
**code--uk.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31932 | 7:54 PM | 🟣 | Ukrainian Language Mode File Created for Code Development Observer | ~330 |
**code--tr.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31931 | 7:53 PM | 🟣 | Turkish Language Mode File Created for Code Development Observer | ~323 |
**code--nl.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31930 | 7:53 PM | 🟣 | Dutch Language Mode File Created for Code Development Observer | ~317 |
**code--cs.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31929 | 7:53 PM | 🟣 | Czech Language Mode File Created for Code Development Observer | ~316 |
**code--pl.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31928 | 7:53 PM | 🟣 | Polish Language Mode File Created for Code Development Observer | ~319 |
**code--ar.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31927 | 7:53 PM | 🟣 | Arabic Language Mode File Created for Code Development Observer | ~320 |
**code--he.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31926 | 7:53 PM | 🟣 | Hebrew Language Mode File Created for Code Development Observer | ~319 |
**code--ja.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31925 | 7:52 PM | 🟣 | Japanese Language Mode File Created for Code Development Observer | ~324 |
| #31881 | 7:10 PM | ✅ | Ajout des prompts de summary au fichier mode japonais | ~269 |
**code--ko.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31924 | 7:52 PM | 🟣 | Korean Language Mode File Created for Code Development Observer | ~318 |
| #31877 | 7:09 PM | 🔵 | Examen du fichier de mode coréen révélant une structure de prompts externalisés | ~372 |
| #31837 | 6:46 PM | 🔄 | Removed unused header configuration strings from Korean mode | ~255 |
**code--de.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31890 | 7:17 PM | 🔵 | Modifications en cours sur les fichiers de modes multilingues et le système de prompts | ~325 |
| #31886 | 7:14 PM | 🔄 | Externalisation du footer de résumé dans la configuration des prompts | ~318 |
| #31841 | 6:47 PM | 🔄 | Removed unused header configuration strings from German mode | ~231 |
**code--pt.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31888 | 7:16 PM | ✅ | Ajout du champ summary_footer aux prompts du mode portugais | ~301 |
| #31842 | 6:47 PM | 🔄 | Removed unused header configuration strings from Portuguese mode | ~225 |
**code--zh.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31884 | 7:13 PM | ✅ | Externalisation des prompts de résumé dans le fichier de configuration JSON chinois | ~290 |
| #31839 | 6:46 PM | 🔄 | Removed unused header configuration strings from Chinese mode | ~260 |
**code--th.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31845 | 6:48 PM | 🔄 | Removed unused header configuration strings from Thai mode | ~215 |
**code--vi.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31844 | 6:47 PM | 🔄 | Removed unused header configuration strings from Vietnamese mode | ~215 |
**code--ru.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31843 | 6:47 PM | 🔄 | Removed unused header configuration strings from Russian mode | ~225 |
### Dec 23, 2025
**email-investigation.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32026 | 7:39 PM | 🔵 | Email Investigation Mode Configuration Located | ~300 |
**code--pt-br.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32297 | 7:50 PM | ✅ | Renamed Portuguese mode file to Brazilian Portuguese | ~191 |
| #32322 | " | ✅ | Updated pt-br mode display name to Brazilian Portuguese | ~221 |
### Dec 24, 2025
**email-investigation.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32384 | 9:18 PM | ✅ | Email investigation mode enhanced with observation granularity guidance | ~340 |
| #32227 | 8:21 PM | 🔴 | Added missing summary prompts to email-investigation mode | ~308 |
| #32209 | 8:16 PM | 🟣 | Email Investigation mode configured for fraud analysis | ~348 |
| #32205 | 7:55 PM | ✅ | Email Investigation Observation Granularity Guidance | ~256 |
### Dec 25, 2025
**email-investigation.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32456 | 5:41 PM | ✅ | Completed merge of main branch into feature/titans-phase1-3 | ~354 |
</claude-mem-context>
+145
View File
@@ -0,0 +1,145 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Nov 10, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #6429 | 3:41 PM | 🔵 | Stop Hook and Summary Generation Context Issue Identified | ~477 |
### Nov 17, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #10177 | 1:40 PM | 🔵 | Database Schema and Migration System in context-hook.js | ~425 |
### Nov 19, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #12149 | 7:28 PM | 🔵 | Read save-hook.js minified source code | ~184 |
### Nov 21, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #13085 | 12:51 AM | 🔵 | Main branch handleSessionInit always starts generator immediately after initialization | ~557 |
| #13084 | " | 🔵 | Main branch observation handler queues observations and auto-starts generator | ~527 |
| #13083 | " | 🔵 | Key difference found between main and current branch in new-hook.js | ~432 |
| #13082 | 12:50 AM | 🔵 | Session lifecycle tracking implementation in new-hook.js | ~486 |
| #13053 | 12:32 AM | 🔵 | Worker Service Database Query Patterns | ~327 |
| #13052 | " | 🔵 | Save-hook.js Architecture and Endless Mode Implementation | ~492 |
### Dec 1, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #18480 | 3:39 PM | ✅ | Successfully Rebuilt Plugin After Merge Conflict Resolution | ~294 |
### Dec 4, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #20052 | 3:23 PM | ✅ | Built and deployed version 6.5.2 to marketplace | ~321 |
### Dec 7, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #21251 | 6:06 PM | 🔵 | Context Hook Plugin Architecture and Worker Communication | ~405 |
### Dec 8, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #22092 | 6:40 PM | 🔵 | Queue Depth Check Not Found in Minified Code | ~217 |
| #22091 | " | 🔵 | Save Hook Script Structure Revealed | ~472 |
| #22085 | 6:34 PM | 🔵 | Examined pre-tool-use-hook.js implementation showing timing-only logic | ~330 |
### Dec 9, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #22557 | 1:08 AM | ✅ | Build completed for version 7.0.3 | ~342 |
### Dec 10, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23444 | 2:25 PM | 🟣 | Build Pipeline Execution Successful | ~293 |
### Dec 11, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24057 | 2:56 PM | ✅ | Hook Scripts Shebang Verification | ~294 |
| #24056 | 2:55 PM | ✅ | Worker CLI Shebang Verification | ~258 |
| #24055 | " | ✅ | Build Successful with Bun Runtime Shebangs | ~355 |
### Dec 12, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24636 | 10:46 PM | 🔵 | Duplicate Smart Install Scripts in Project Structure | ~288 |
| #24635 | " | 🔵 | Claude-Mem Smart Install Script Architecture | ~371 |
| #24359 | 7:00 PM | 🟣 | Phase 1 Critical Code Fixes Completed via Agent Task | ~441 |
| #24358 | 6:59 PM | ✅ | Completed Phase 1 Code Fixes for better-sqlite3 Migration | ~385 |
| #24357 | " | ✅ | Removed createRequire Import from smart-install.js | ~284 |
| #24356 | " | ✅ | Removed Native Module Verification from main() Function | ~384 |
| #24355 | " | ✅ | Removed better-sqlite3 Error Detection from runNpmInstall() | ~324 |
| #24354 | 6:58 PM | ✅ | Removed getWindowsErrorHelp() Function from smart-install.js | ~356 |
| #24353 | " | ✅ | Removed verifyNativeModules() Function from smart-install.js | ~340 |
| #24352 | " | ✅ | Removed better-sqlite3 Existence Check from needsInstall() | ~266 |
| #24351 | " | ✅ | Removed BETTER_SQLITE3_PATH Constant from smart-install.js | ~226 |
| #24344 | 6:56 PM | 🔵 | smart-install.js Contains Obsolete better-sqlite3 Dependencies | ~380 |
### Dec 13, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #25286 | 8:41 PM | 🔵 | New Hook Fails with Node.js Path Error | ~298 |
| #25285 | " | 🔵 | Context Hook Runs Successfully with Node.js | ~306 |
| #25283 | " | 🔵 | Bun Wrapper Analysis: Fallback Detection System | ~416 |
### Dec 14, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #26800 | 11:39 PM | ✅ | Version 7.2.3 Build Complete With Worker Restart Fix | ~394 |
| #26791 | 11:38 PM | ✅ | Phase 3 Complete: Project Built Successfully With Worker Restart Fix | ~446 |
| #26720 | 11:23 PM | 🔵 | Smart Install Handles Dependencies But No Worker Coordination | ~468 |
| #26719 | " | 🔵 | Worker CLI Provides Start/Stop/Restart Commands With Health Check Validation | ~490 |
| #26718 | " | 🔵 | Worker CLI Restart Implementation Details | ~452 |
| #26717 | 11:22 PM | 🔵 | Context Hook Worker Startup Logic Handles Initial Start But Not Post-Update Restart | ~485 |
| #26716 | " | 🔵 | Context Hook Worker Startup Logic Revealed | ~538 |
| #26715 | " | 🔵 | Smart Install Script Handles Dependency Installation Without Worker Restart | ~430 |
| #26052 | 7:13 PM | 🔵 | Examined Minified Context Hook Source Code | ~285 |
| #25686 | 4:22 PM | 🔵 | SessionRoutes tracks missing last_user_message errors at two different locations | ~456 |
| #25685 | " | 🔵 | Progress summary generation system uses Claude to create XML-formatted session checkpoints | ~461 |
### Dec 16, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #27554 | 4:48 PM | ✅ | Project built successfully with version 7.3.1 | ~306 |
### Dec 17, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #28924 | 7:29 PM | 🔵 | Plugin MCP Server Uses Bun Runtime | ~283 |
### Dec 26, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32983 | 11:04 PM | 🟣 | Complete build and deployment pipeline executed | ~260 |
### Jan 4, 2026
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36873 | 1:55 AM | 🔵 | Smart-Install Script Analyzed for Homebrew Path Implementation | ~466 |
</claude-mem-context>
File diff suppressed because one or more lines are too long
+15 -15
View File
@@ -1,19 +1,19 @@
#!/usr/bin/env bun
import{stdin as A}from"process";import L from"path";import{homedir as Y}from"os";import{readFileSync as B}from"fs";import{appendFileSync as W,existsSync as d,mkdirSync as x,readFileSync as b}from"fs";import{join as S}from"path";import{homedir as H}from"os";var O=(o=>(o[o.DEBUG=0]="DEBUG",o[o.INFO=1]="INFO",o[o.WARN=2]="WARN",o[o.ERROR=3]="ERROR",o[o.SILENT=4]="SILENT",o))(O||{}),U=S(H(),".claude-mem"),M=class{level=null;useColor;logFilePath=null;logFileInitialized=!1;constructor(){this.useColor=process.stdout.isTTY??!1}ensureLogFileInitialized(){if(!this.logFileInitialized){this.logFileInitialized=!0;try{let t=S(U,"logs");d(t)||x(t,{recursive:!0});let r=new Date().toISOString().split("T")[0];this.logFilePath=S(t,`claude-mem-${r}.log`)}catch(t){console.error("[LOGGER] Failed to initialize log file:",t),this.logFilePath=null}}}getLevel(){if(this.level===null)try{let t=S(U,"settings.json");if(d(t)){let r=b(t,"utf-8"),n=(JSON.parse(r).CLAUDE_MEM_LOG_LEVEL||"INFO").toUpperCase();this.level=O[n]??1}else this.level=1}catch{this.level=1}return this.level}correlationId(t,r){return`obs-${t}-${r}`}sessionId(t){return`session-${t}`}formatData(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return t.toString();if(typeof t=="object"){if(t instanceof Error)return this.getLevel()===0?`${t.message}
${t.stack}`:t.message;if(Array.isArray(t))return`[${t.length} items]`;let r=Object.keys(t);return r.length===0?"{}":r.length<=3?JSON.stringify(t):`{${r.length} keys: ${r.slice(0,3).join(", ")}...}`}return String(t)}formatTool(t,r){if(!r)return t;let e=r;if(typeof r=="string")try{e=JSON.parse(r)}catch{e=r}if(t==="Bash"&&e.command)return`${t}(${e.command})`;if(e.file_path)return`${t}(${e.file_path})`;if(e.notebook_path)return`${t}(${e.notebook_path})`;if(t==="Glob"&&e.pattern)return`${t}(${e.pattern})`;if(t==="Grep"&&e.pattern)return`${t}(${e.pattern})`;if(e.url)return`${t}(${e.url})`;if(e.query)return`${t}(${e.query})`;if(t==="Task"){if(e.subagent_type)return`${t}(${e.subagent_type})`;if(e.description)return`${t}(${e.description})`}return t==="Skill"&&e.skill?`${t}(${e.skill})`:t==="LSP"&&e.operation?`${t}(${e.operation})`:t}formatTimestamp(t){let r=t.getFullYear(),e=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0"),o=String(t.getHours()).padStart(2,"0"),E=String(t.getMinutes()).padStart(2,"0"),s=String(t.getSeconds()).padStart(2,"0"),u=String(t.getMilliseconds()).padStart(3,"0");return`${r}-${e}-${n} ${o}:${E}:${s}.${u}`}log(t,r,e,n,o){if(t<this.getLevel())return;this.ensureLogFileInitialized();let E=this.formatTimestamp(new Date),s=O[t].padEnd(5),u=r.padEnd(6),a="";n?.correlationId?a=`[${n.correlationId}] `:n?.sessionId&&(a=`[session-${n.sessionId}] `);let l="";o!=null&&(o instanceof Error?l=this.getLevel()===0?`
${o.message}
${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?l=`
`+JSON.stringify(o,null,2):l=" "+this.formatData(o));let T="";if(n){let{sessionId:m,memorySessionId:rt,correlationId:nt,...D}=n;Object.keys(D).length>0&&(T=` {${Object.entries(D).map(([F,w])=>`${F}=${w}`).join(", ")}}`)}let C=`[${E}] [${s}] [${u}] ${a}${e}${T}${l}`;if(this.logFilePath)try{W(this.logFilePath,C+`
`,"utf8")}catch(m){process.stderr.write(`[LOGGER] Failed to write to log file: ${m}
`)}else process.stderr.write(C+`
`)}debug(t,r,e,n){this.log(0,t,r,e,n)}info(t,r,e,n){this.log(1,t,r,e,n)}warn(t,r,e,n){this.log(2,t,r,e,n)}error(t,r,e,n){this.log(3,t,r,e,n)}dataIn(t,r,e,n){this.info(t,`\u2192 ${r}`,e,n)}dataOut(t,r,e,n){this.info(t,`\u2190 ${r}`,e,n)}success(t,r,e,n){this.info(t,`\u2713 ${r}`,e,n)}failure(t,r,e,n){this.error(t,`\u2717 ${r}`,e,n)}timing(t,r,e,n){this.info(t,`\u23F1 ${r}`,n,{duration:`${e}ms`})}happyPathError(t,r,e,n,o=""){let a=((new Error().stack||"").split(`
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),l=a?`${a[1].split("/").pop()}:${a[2]}`:"unknown",T={...e,location:l};return this.warn(t,`[HAPPY-PATH] ${r}`,T,n),o}},_=new M;var p={DEFAULT:3e5,HEALTH_CHECK:3e4,WORKER_STARTUP_WAIT:1e3,WORKER_STARTUP_RETRIES:300,PRE_RESTART_SETTLE_DELAY:2e3,WINDOWS_MULTIPLIER:1.5};function R(i){return process.platform==="win32"?Math.round(i*p.WINDOWS_MULTIPLIER):i}import{readFileSync as G,writeFileSync as N,existsSync as y,mkdirSync as K}from"fs";import{join as X,dirname as j}from"path";import{homedir as V}from"os";var h="bugfix,feature,refactor,discovery,decision,change",I="how-it-works,why-it-exists,what-changed,problem-solution,gotcha,pattern,trade-off";var c=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:X(V(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",CLAUDE_MEM_MODE:"code",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:h,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:I,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return this.DEFAULTS[t]}static getInt(t){let r=this.get(t);return parseInt(r,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){try{if(!y(t)){let E=this.getAllDefaults();try{let s=j(t);y(s)||K(s,{recursive:!0}),N(t,JSON.stringify(E,null,2),"utf-8"),console.log("[SETTINGS] Created settings file with defaults:",t)}catch(s){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",t,s)}return E}let r=G(t,"utf-8"),e=JSON.parse(r),n=e;if(e.env&&typeof e.env=="object"){n=e.env;try{N(t,JSON.stringify(n,null,2),"utf-8"),console.log("[SETTINGS] Migrated settings file from nested to flat schema:",t)}catch(E){console.warn("[SETTINGS] Failed to auto-migrate settings file:",t,E)}}let o={...this.DEFAULTS};for(let E of Object.keys(this.DEFAULTS))n[E]!==void 0&&(o[E]=n[E]);return o}catch(r){return console.warn("[SETTINGS] Failed to load settings, using defaults:",t,r),this.getAllDefaults()}}};function k(i={}){let{port:t,includeSkillFallback:r=!1,customPrefix:e,actualError:n}=i,o=e||"Worker service connection failed.",E=t?` (port ${t})`:"",s=`${o}${E}
import{stdin as L}from"process";import C from"path";import{homedir as X}from"os";import{readFileSync as V}from"fs";import{readFileSync as x,writeFileSync as w,existsSync as F}from"fs";import{join as b}from"path";import{homedir as j}from"os";var U="bugfix,feature,refactor,discovery,decision,change",h="how-it-works,why-it-exists,what-changed,problem-solution,gotcha,pattern,trade-off";var c=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:b(j(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",CLAUDE_MEM_MODE:"code",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:U,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:h,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return this.DEFAULTS[t]}static getInt(t){let r=this.get(t);return parseInt(r,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){try{if(!F(t))return this.getAllDefaults();let r=x(t,"utf-8"),e=JSON.parse(r),n=e;if(e.env&&typeof e.env=="object"){n=e.env;try{w(t,JSON.stringify(n,null,2),"utf-8"),a.info("SETTINGS","Migrated settings file from nested to flat schema",{settingsPath:t})}catch(s){a.warn("SETTINGS","Failed to auto-migrate settings file",{settingsPath:t},s)}}let i={...this.DEFAULTS};for(let s of Object.keys(this.DEFAULTS))n[s]!==void 0&&(i[s]=n[s]);return i}catch(r){return a.warn("SETTINGS","Failed to load settings, using defaults",{settingsPath:t},r),this.getAllDefaults()}}};import{appendFileSync as H,existsSync as G,mkdirSync as K}from"fs";import{join as O}from"path";var M=(i=>(i[i.DEBUG=0]="DEBUG",i[i.INFO=1]="INFO",i[i.WARN=2]="WARN",i[i.ERROR=3]="ERROR",i[i.SILENT=4]="SILENT",i))(M||{}),S=class{level=null;useColor;logFilePath=null;constructor(){this.useColor=process.stdout.isTTY??!1,this.initializeLogFile()}initializeLogFile(){try{let t=c.get("CLAUDE_MEM_DATA_DIR"),r=O(t,"logs");G(r)||K(r,{recursive:!0});let e=new Date().toISOString().split("T")[0];this.logFilePath=O(r,`claude-mem-${e}.log`)}catch(t){console.error("[LOGGER] Failed to initialize log file:",t),this.logFilePath=null}}getLevel(){if(this.level===null)try{let t=c.get("CLAUDE_MEM_DATA_DIR"),r=O(t,"settings.json"),n=c.loadFromFile(r).CLAUDE_MEM_LOG_LEVEL.toUpperCase();this.level=M[n]??1}catch(t){console.error("[LOGGER] Failed to load settings, using INFO level:",t),this.level=1}return this.level}correlationId(t,r){return`obs-${t}-${r}`}sessionId(t){return`session-${t}`}formatData(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return t.toString();if(typeof t=="object"){if(t instanceof Error)return this.getLevel()===0?`${t.message}
${t.stack}`:t.message;if(Array.isArray(t))return`[${t.length} items]`;let r=Object.keys(t);return r.length===0?"{}":r.length<=3?JSON.stringify(t):`{${r.length} keys: ${r.slice(0,3).join(", ")}...}`}return String(t)}formatTool(t,r){if(!r)return t;let e=typeof r=="string"?JSON.parse(r):r;if(t==="Bash"&&e.command)return`${t}(${e.command})`;if(e.file_path)return`${t}(${e.file_path})`;if(e.notebook_path)return`${t}(${e.notebook_path})`;if(t==="Glob"&&e.pattern)return`${t}(${e.pattern})`;if(t==="Grep"&&e.pattern)return`${t}(${e.pattern})`;if(e.url)return`${t}(${e.url})`;if(e.query)return`${t}(${e.query})`;if(t==="Task"){if(e.subagent_type)return`${t}(${e.subagent_type})`;if(e.description)return`${t}(${e.description})`}return t==="Skill"&&e.skill?`${t}(${e.skill})`:t==="LSP"&&e.operation?`${t}(${e.operation})`:t}formatTimestamp(t){let r=t.getFullYear(),e=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0"),i=String(t.getHours()).padStart(2,"0"),s=String(t.getMinutes()).padStart(2,"0"),E=String(t.getSeconds()).padStart(2,"0"),l=String(t.getMilliseconds()).padStart(3,"0");return`${r}-${e}-${n} ${i}:${s}:${E}.${l}`}log(t,r,e,n,i){if(t<this.getLevel())return;let s=this.formatTimestamp(new Date),E=M[t].padEnd(5),l=r.padEnd(6),_="";n?.correlationId?_=`[${n.correlationId}] `:n?.sessionId&&(_=`[session-${n.sessionId}] `);let g="";i!=null&&(i instanceof Error?g=this.getLevel()===0?`
${i.message}
${i.stack}`:` ${i.message}`:this.getLevel()===0&&typeof i=="object"?g=`
`+JSON.stringify(i,null,2):g=" "+this.formatData(i));let f="";if(n){let{sessionId:R,memorySessionId:nt,correlationId:ot,...d}=n;Object.keys(d).length>0&&(f=` {${Object.entries(d).map(([v,W])=>`${v}=${W}`).join(", ")}}`)}let D=`[${s}] [${E}] [${l}] ${_}${e}${f}${g}`;if(this.logFilePath)try{H(this.logFilePath,D+`
`,"utf8")}catch(R){process.stderr.write(`[LOGGER] Failed to write to log file: ${R}
`)}else process.stderr.write(D+`
`)}debug(t,r,e,n){this.log(0,t,r,e,n)}info(t,r,e,n){this.log(1,t,r,e,n)}warn(t,r,e,n){this.log(2,t,r,e,n)}error(t,r,e,n){this.log(3,t,r,e,n)}dataIn(t,r,e,n){this.info(t,`\u2192 ${r}`,e,n)}dataOut(t,r,e,n){this.info(t,`\u2190 ${r}`,e,n)}success(t,r,e,n){this.info(t,`\u2713 ${r}`,e,n)}failure(t,r,e,n){this.error(t,`\u2717 ${r}`,e,n)}timing(t,r,e,n){this.info(t,`\u23F1 ${r}`,n,{duration:`${e}ms`})}happyPathError(t,r,e,n,i=""){let _=((new Error().stack||"").split(`
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),g=_?`${_[1].split("/").pop()}:${_[2]}`:"unknown",f={...e,location:g};return this.warn(t,`[HAPPY-PATH] ${r}`,f,n),i}},a=new S;var m={DEFAULT:3e5,HEALTH_CHECK:3e4,WORKER_STARTUP_WAIT:1e3,WORKER_STARTUP_RETRIES:300,PRE_RESTART_SETTLE_DELAY:2e3,WINDOWS_MULTIPLIER:1.5};function N(o){return process.platform==="win32"?Math.round(o*m.WINDOWS_MULTIPLIER):o}function I(o={}){let{port:t,includeSkillFallback:r=!1,customPrefix:e,actualError:n}=o,i=e||"Worker service connection failed.",s=t?` (port ${t})`:"",E=`${i}${s}
`;return s+=`To restart the worker:
`,s+=`1. Exit Claude Code completely
`,s+=`2. Run: npm run worker:restart
`,s+="3. Restart Claude Code",r&&(s+=`
`;return E+=`To restart the worker:
`,E+=`1. Exit Claude Code completely
`,E+=`2. Run: npm run worker:restart
`,E+="3. Restart Claude Code",r&&(E+=`
If that doesn't work, try: /troubleshoot`),n&&(s=`Worker Error: ${n}
If that doesn't work, try: /troubleshoot`),n&&(E=`Worker Error: ${n}
${s}`),s}var J=L.join(Y(),".claude","plugins","marketplaces","thedotmack"),Dt=R(p.HEALTH_CHECK),f=null;function g(){if(f!==null)return f;let i=L.join(c.get("CLAUDE_MEM_DATA_DIR"),"settings.json"),t=c.loadFromFile(i);return f=parseInt(t.CLAUDE_MEM_WORKER_PORT,10),f}async function z(){let i=g();return(await fetch(`http://127.0.0.1:${i}/api/readiness`)).ok}function q(){let i=L.join(J,"package.json");return JSON.parse(B(i,"utf-8")).version}async function Q(){let i=g(),t=await fetch(`http://127.0.0.1:${i}/api/version`);if(!t.ok)throw new Error(`Failed to get worker version: ${t.status}`);return(await t.json()).version}async function Z(){let i=q(),t=await Q();i!==t&&_.debug("SYSTEM","Version check",{pluginVersion:i,workerVersion:t,note:"Mismatch will be auto-restarted by worker-service start command"})}async function $(){for(let r=0;r<75;r++){try{if(await z()){await Z();return}}catch(e){_.debug("SYSTEM","Worker health check failed, will retry",{attempt:r+1,maxRetries:75,error:e instanceof Error?e.message:String(e)})}await new Promise(e=>setTimeout(e,200))}throw new Error(k({port:g(),customPrefix:"Worker did not become ready within 15 seconds."}))}import tt from"path";function P(i){if(!i||i.trim()==="")return _.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:i}),"unknown-project";let t=tt.basename(i);if(t===""){if(process.platform==="win32"){let e=i.match(/^([A-Z]):\\/i);if(e){let o=`drive-${e[1].toUpperCase()}`;return _.info("PROJECT_NAME","Drive root detected",{cwd:i,projectName:o}),o}}return _.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:i}),"unknown-project"}return t}async function v(i){await $();let t=i?.cwd??process.cwd(),r=P(t),n=`http://127.0.0.1:${g()}/api/context/inject?project=${encodeURIComponent(r)}`,o=await fetch(n);if(!o.ok)throw new Error(`Context generation failed: ${o.status}`);return(await o.text()).trim()}var et=process.argv.includes("--colors");if(A.isTTY||et)v(void 0).then(i=>{console.log(i),process.exit(0)});else{let i="";A.on("data",t=>i+=t),A.on("end",async()=>{let t;try{t=i.trim()?JSON.parse(i):void 0}catch(e){throw new Error(`Failed to parse hook input: ${e instanceof Error?e.message:String(e)}`)}let r=await v(t);console.log(JSON.stringify({hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:r}})),process.exit(0)})}
${E}`),E}var Y=C.join(X(),".claude","plugins","marketplaces","thedotmack"),dt=N(m.HEALTH_CHECK),T=null;function u(){if(T!==null)return T;let o=C.join(c.get("CLAUDE_MEM_DATA_DIR"),"settings.json"),t=c.loadFromFile(o);return T=parseInt(t.CLAUDE_MEM_WORKER_PORT,10),T}async function B(){let o=u();return(await fetch(`http://127.0.0.1:${o}/api/readiness`)).ok}function J(){let o=C.join(Y,"package.json");return JSON.parse(V(o,"utf-8")).version}async function z(){let o=u(),t=await fetch(`http://127.0.0.1:${o}/api/version`);if(!t.ok)throw new Error(`Failed to get worker version: ${t.status}`);return(await t.json()).version}async function q(){let o=J(),t=await z();o!==t&&a.debug("SYSTEM","Version check",{pluginVersion:o,workerVersion:t,note:"Mismatch will be auto-restarted by worker-service start command"})}async function P(){for(let r=0;r<75;r++){try{if(await B()){await q();return}}catch(e){a.debug("SYSTEM","Worker health check failed, will retry",{attempt:r+1,maxRetries:75,error:e instanceof Error?e.message:String(e)})}await new Promise(e=>setTimeout(e,200))}throw new Error(I({port:u(),customPrefix:"Worker did not become ready within 15 seconds."}))}import tt from"path";import{statSync as Q,readFileSync as Z}from"fs";import A from"path";var p={isWorktree:!1,worktreeName:null,parentRepoPath:null,parentProjectName:null};function k(o){let t=A.join(o,".git"),r;try{r=Q(t)}catch{return p}if(!r.isFile())return p;let e;try{e=Z(t,"utf-8").trim()}catch{return p}let n=e.match(/^gitdir:\s*(.+)$/);if(!n)return p;let s=n[1].match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);if(!s)return p;let E=s[1],l=A.basename(o),_=A.basename(E);return{isWorktree:!0,worktreeName:l,parentRepoPath:E,parentProjectName:_}}function et(o){if(!o||o.trim()==="")return a.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:o}),"unknown-project";let t=tt.basename(o);if(t===""){if(process.platform==="win32"){let e=o.match(/^([A-Z]):\\/i);if(e){let i=`drive-${e[1].toUpperCase()}`;return a.info("PROJECT_NAME","Drive root detected",{cwd:o,projectName:i}),i}}return a.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:o}),"unknown-project"}return t}function y(o){let t=et(o);if(!o)return{primary:t,parent:null,isWorktree:!1,allProjects:[t]};let r=k(o);return r.isWorktree&&r.parentProjectName?{primary:t,parent:r.parentProjectName,isWorktree:!0,allProjects:[r.parentProjectName,t]}:{primary:t,parent:null,isWorktree:!1,allProjects:[t]}}async function $(o){await P();let t=o?.cwd??process.cwd(),r=y(t),e=u(),n=r.allProjects.join(","),i=`http://127.0.0.1:${e}/api/context/inject?projects=${encodeURIComponent(n)}`,s=await fetch(i);if(!s.ok)throw new Error(`Context generation failed: ${s.status}`);return(await s.text()).trim()}var rt=process.argv.includes("--colors");if(L.isTTY||rt)$(void 0).then(o=>{console.log(o),process.exit(0)});else{let o="";L.on("data",t=>o+=t),L.on("end",async()=>{let t;try{t=o.trim()?JSON.parse(o):void 0}catch(e){throw new Error(`Failed to parse hook input: ${e instanceof Error?e.message:String(e)}`)}let r=await $(t);console.log(JSON.stringify({hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:r}})),process.exit(0)})}
+14 -14
View File
@@ -1,19 +1,19 @@
#!/usr/bin/env bun
import{stdin as w}from"process";var S=JSON.stringify({continue:!0,suppressOutput:!0});import A from"path";import{homedir as Y}from"os";import{readFileSync as J}from"fs";import{appendFileSync as H,existsSync as h,mkdirSync as W,readFileSync as K}from"fs";import{join as O}from"path";import{homedir as x}from"os";var T=(i=>(i[i.DEBUG=0]="DEBUG",i[i.INFO=1]="INFO",i[i.WARN=2]="WARN",i[i.ERROR=3]="ERROR",i[i.SILENT=4]="SILENT",i))(T||{}),R=O(x(),".claude-mem"),M=class{level=null;useColor;logFilePath=null;logFileInitialized=!1;constructor(){this.useColor=process.stdout.isTTY??!1}ensureLogFileInitialized(){if(!this.logFileInitialized){this.logFileInitialized=!0;try{let t=O(R,"logs");h(t)||W(t,{recursive:!0});let r=new Date().toISOString().split("T")[0];this.logFilePath=O(t,`claude-mem-${r}.log`)}catch(t){console.error("[LOGGER] Failed to initialize log file:",t),this.logFilePath=null}}}getLevel(){if(this.level===null)try{let t=O(R,"settings.json");if(h(t)){let r=K(t,"utf-8"),n=(JSON.parse(r).CLAUDE_MEM_LOG_LEVEL||"INFO").toUpperCase();this.level=T[n]??1}else this.level=1}catch{this.level=1}return this.level}correlationId(t,r){return`obs-${t}-${r}`}sessionId(t){return`session-${t}`}formatData(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return t.toString();if(typeof t=="object"){if(t instanceof Error)return this.getLevel()===0?`${t.message}
${t.stack}`:t.message;if(Array.isArray(t))return`[${t.length} items]`;let r=Object.keys(t);return r.length===0?"{}":r.length<=3?JSON.stringify(t):`{${r.length} keys: ${r.slice(0,3).join(", ")}...}`}return String(t)}formatTool(t,r){if(!r)return t;let e=r;if(typeof r=="string")try{e=JSON.parse(r)}catch{e=r}if(t==="Bash"&&e.command)return`${t}(${e.command})`;if(e.file_path)return`${t}(${e.file_path})`;if(e.notebook_path)return`${t}(${e.notebook_path})`;if(t==="Glob"&&e.pattern)return`${t}(${e.pattern})`;if(t==="Grep"&&e.pattern)return`${t}(${e.pattern})`;if(e.url)return`${t}(${e.url})`;if(e.query)return`${t}(${e.query})`;if(t==="Task"){if(e.subagent_type)return`${t}(${e.subagent_type})`;if(e.description)return`${t}(${e.description})`}return t==="Skill"&&e.skill?`${t}(${e.skill})`:t==="LSP"&&e.operation?`${t}(${e.operation})`:t}formatTimestamp(t){let r=t.getFullYear(),e=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0"),i=String(t.getHours()).padStart(2,"0"),E=String(t.getMinutes()).padStart(2,"0"),s=String(t.getSeconds()).padStart(2,"0"),l=String(t.getMilliseconds()).padStart(3,"0");return`${r}-${e}-${n} ${i}:${E}:${s}.${l}`}log(t,r,e,n,i){if(t<this.getLevel())return;this.ensureLogFileInitialized();let E=this.formatTimestamp(new Date),s=T[t].padEnd(5),l=r.padEnd(6),_="";n?.correlationId?_=`[${n.correlationId}] `:n?.sessionId&&(_=`[session-${n.sessionId}] `);let c="";i!=null&&(i instanceof Error?c=this.getLevel()===0?`
${i.message}
${i.stack}`:` ${i.message}`:this.getLevel()===0&&typeof i=="object"?c=`
`+JSON.stringify(i,null,2):c=" "+this.formatData(i));let g="";if(n){let{sessionId:d,memorySessionId:nt,correlationId:ot,...D}=n;Object.keys(D).length>0&&(g=` {${Object.entries(D).map(([b,F])=>`${b}=${F}`).join(", ")}}`)}let C=`[${E}] [${s}] [${l}] ${_}${e}${g}${c}`;if(this.logFilePath)try{H(this.logFilePath,C+`
`,"utf8")}catch(d){process.stderr.write(`[LOGGER] Failed to write to log file: ${d}
import{stdin as k}from"process";var f=JSON.stringify({continue:!0,suppressOutput:!0});import A from"path";import{homedir as K}from"os";import{readFileSync as G}from"fs";import{readFileSync as b,writeFileSync as v,existsSync as w}from"fs";import{join as W}from"path";import{homedir as F}from"os";var R="bugfix,feature,refactor,discovery,decision,change",h="how-it-works,why-it-exists,what-changed,problem-solution,gotcha,pattern,trade-off";var c=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:W(F(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",CLAUDE_MEM_MODE:"code",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:R,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:h,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return this.DEFAULTS[t]}static getInt(t){let r=this.get(t);return parseInt(r,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){try{if(!w(t))return this.getAllDefaults();let r=b(t,"utf-8"),e=JSON.parse(r),n=e;if(e.env&&typeof e.env=="object"){n=e.env;try{v(t,JSON.stringify(n,null,2),"utf-8"),E.info("SETTINGS","Migrated settings file from nested to flat schema",{settingsPath:t})}catch(a){E.warn("SETTINGS","Failed to auto-migrate settings file",{settingsPath:t},a)}}let s={...this.DEFAULTS};for(let a of Object.keys(this.DEFAULTS))n[a]!==void 0&&(s[a]=n[a]);return s}catch(r){return E.warn("SETTINGS","Failed to load settings, using defaults",{settingsPath:t},r),this.getAllDefaults()}}};import{appendFileSync as H,existsSync as x,mkdirSync as j}from"fs";import{join as T}from"path";var S=(s=>(s[s.DEBUG=0]="DEBUG",s[s.INFO=1]="INFO",s[s.WARN=2]="WARN",s[s.ERROR=3]="ERROR",s[s.SILENT=4]="SILENT",s))(S||{}),M=class{level=null;useColor;logFilePath=null;constructor(){this.useColor=process.stdout.isTTY??!1,this.initializeLogFile()}initializeLogFile(){try{let t=c.get("CLAUDE_MEM_DATA_DIR"),r=T(t,"logs");x(r)||j(r,{recursive:!0});let e=new Date().toISOString().split("T")[0];this.logFilePath=T(r,`claude-mem-${e}.log`)}catch(t){console.error("[LOGGER] Failed to initialize log file:",t),this.logFilePath=null}}getLevel(){if(this.level===null)try{let t=c.get("CLAUDE_MEM_DATA_DIR"),r=T(t,"settings.json"),n=c.loadFromFile(r).CLAUDE_MEM_LOG_LEVEL.toUpperCase();this.level=S[n]??1}catch(t){console.error("[LOGGER] Failed to load settings, using INFO level:",t),this.level=1}return this.level}correlationId(t,r){return`obs-${t}-${r}`}sessionId(t){return`session-${t}`}formatData(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return t.toString();if(typeof t=="object"){if(t instanceof Error)return this.getLevel()===0?`${t.message}
${t.stack}`:t.message;if(Array.isArray(t))return`[${t.length} items]`;let r=Object.keys(t);return r.length===0?"{}":r.length<=3?JSON.stringify(t):`{${r.length} keys: ${r.slice(0,3).join(", ")}...}`}return String(t)}formatTool(t,r){if(!r)return t;let e=typeof r=="string"?JSON.parse(r):r;if(t==="Bash"&&e.command)return`${t}(${e.command})`;if(e.file_path)return`${t}(${e.file_path})`;if(e.notebook_path)return`${t}(${e.notebook_path})`;if(t==="Glob"&&e.pattern)return`${t}(${e.pattern})`;if(t==="Grep"&&e.pattern)return`${t}(${e.pattern})`;if(e.url)return`${t}(${e.url})`;if(e.query)return`${t}(${e.query})`;if(t==="Task"){if(e.subagent_type)return`${t}(${e.subagent_type})`;if(e.description)return`${t}(${e.description})`}return t==="Skill"&&e.skill?`${t}(${e.skill})`:t==="LSP"&&e.operation?`${t}(${e.operation})`:t}formatTimestamp(t){let r=t.getFullYear(),e=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0"),s=String(t.getHours()).padStart(2,"0"),a=String(t.getMinutes()).padStart(2,"0"),i=String(t.getSeconds()).padStart(2,"0"),l=String(t.getMilliseconds()).padStart(3,"0");return`${r}-${e}-${n} ${s}:${a}:${i}.${l}`}log(t,r,e,n,s){if(t<this.getLevel())return;let a=this.formatTimestamp(new Date),i=S[t].padEnd(5),l=r.padEnd(6),_="";n?.correlationId?_=`[${n.correlationId}] `:n?.sessionId&&(_=`[session-${n.sessionId}] `);let g="";s!=null&&(s instanceof Error?g=this.getLevel()===0?`
${s.message}
${s.stack}`:` ${s.message}`:this.getLevel()===0&&typeof s=="object"?g=`
`+JSON.stringify(s,null,2):g=" "+this.formatData(s));let u="";if(n){let{sessionId:D,memorySessionId:Q,correlationId:Z,...d}=n;Object.keys(d).length>0&&(u=` {${Object.entries(d).map(([y,$])=>`${y}=${$}`).join(", ")}}`)}let C=`[${a}] [${i}] [${l}] ${_}${e}${u}${g}`;if(this.logFilePath)try{H(this.logFilePath,C+`
`,"utf8")}catch(D){process.stderr.write(`[LOGGER] Failed to write to log file: ${D}
`)}else process.stderr.write(C+`
`)}debug(t,r,e,n){this.log(0,t,r,e,n)}info(t,r,e,n){this.log(1,t,r,e,n)}warn(t,r,e,n){this.log(2,t,r,e,n)}error(t,r,e,n){this.log(3,t,r,e,n)}dataIn(t,r,e,n){this.info(t,`\u2192 ${r}`,e,n)}dataOut(t,r,e,n){this.info(t,`\u2190 ${r}`,e,n)}success(t,r,e,n){this.info(t,`\u2713 ${r}`,e,n)}failure(t,r,e,n){this.error(t,`\u2717 ${r}`,e,n)}timing(t,r,e,n){this.info(t,`\u23F1 ${r}`,n,{duration:`${e}ms`})}happyPathError(t,r,e,n,i=""){let _=((new Error().stack||"").split(`
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),c=_?`${_[1].split("/").pop()}:${_[2]}`:"unknown",g={...e,location:c};return this.warn(t,`[HAPPY-PATH] ${r}`,g,n),i}},a=new M;var m={DEFAULT:3e5,HEALTH_CHECK:3e4,WORKER_STARTUP_WAIT:1e3,WORKER_STARTUP_RETRIES:300,PRE_RESTART_SETTLE_DELAY:2e3,WINDOWS_MULTIPLIER:1.5};function U(o){return process.platform==="win32"?Math.round(o*m.WINDOWS_MULTIPLIER):o}import{readFileSync as G,writeFileSync as y,existsSync as k,mkdirSync as X}from"fs";import{join as j,dirname as V}from"path";import{homedir as B}from"os";var I="bugfix,feature,refactor,discovery,decision,change",N="how-it-works,why-it-exists,what-changed,problem-solution,gotcha,pattern,trade-off";var u=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:j(B(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",CLAUDE_MEM_MODE:"code",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:I,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:N,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return this.DEFAULTS[t]}static getInt(t){let r=this.get(t);return parseInt(r,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){try{if(!k(t)){let E=this.getAllDefaults();try{let s=V(t);k(s)||X(s,{recursive:!0}),y(t,JSON.stringify(E,null,2),"utf-8"),console.log("[SETTINGS] Created settings file with defaults:",t)}catch(s){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",t,s)}return E}let r=G(t,"utf-8"),e=JSON.parse(r),n=e;if(e.env&&typeof e.env=="object"){n=e.env;try{y(t,JSON.stringify(n,null,2),"utf-8"),console.log("[SETTINGS] Migrated settings file from nested to flat schema:",t)}catch(E){console.warn("[SETTINGS] Failed to auto-migrate settings file:",t,E)}}let i={...this.DEFAULTS};for(let E of Object.keys(this.DEFAULTS))n[E]!==void 0&&(i[E]=n[E]);return i}catch(r){return console.warn("[SETTINGS] Failed to load settings, using defaults:",t,r),this.getAllDefaults()}}};function $(o={}){let{port:t,includeSkillFallback:r=!1,customPrefix:e,actualError:n}=o,i=e||"Worker service connection failed.",E=t?` (port ${t})`:"",s=`${i}${E}
`)}debug(t,r,e,n){this.log(0,t,r,e,n)}info(t,r,e,n){this.log(1,t,r,e,n)}warn(t,r,e,n){this.log(2,t,r,e,n)}error(t,r,e,n){this.log(3,t,r,e,n)}dataIn(t,r,e,n){this.info(t,`\u2192 ${r}`,e,n)}dataOut(t,r,e,n){this.info(t,`\u2190 ${r}`,e,n)}success(t,r,e,n){this.info(t,`\u2713 ${r}`,e,n)}failure(t,r,e,n){this.error(t,`\u2717 ${r}`,e,n)}timing(t,r,e,n){this.info(t,`\u23F1 ${r}`,n,{duration:`${e}ms`})}happyPathError(t,r,e,n,s=""){let _=((new Error().stack||"").split(`
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),g=_?`${_[1].split("/").pop()}:${_[2]}`:"unknown",u={...e,location:g};return this.warn(t,`[HAPPY-PATH] ${r}`,u,n),s}},E=new M;var m={DEFAULT:3e5,HEALTH_CHECK:3e4,WORKER_STARTUP_WAIT:1e3,WORKER_STARTUP_RETRIES:300,PRE_RESTART_SETTLE_DELAY:2e3,WINDOWS_MULTIPLIER:1.5};function N(o){return process.platform==="win32"?Math.round(o*m.WINDOWS_MULTIPLIER):o}function I(o={}){let{port:t,includeSkillFallback:r=!1,customPrefix:e,actualError:n}=o,s=e||"Worker service connection failed.",a=t?` (port ${t})`:"",i=`${s}${a}
`;return s+=`To restart the worker:
`,s+=`1. Exit Claude Code completely
`,s+=`2. Run: npm run worker:restart
`,s+="3. Restart Claude Code",r&&(s+=`
`;return i+=`To restart the worker:
`,i+=`1. Exit Claude Code completely
`,i+=`2. Run: npm run worker:restart
`,i+="3. Restart Claude Code",r&&(i+=`
If that doesn't work, try: /troubleshoot`),n&&(s=`Worker Error: ${n}
If that doesn't work, try: /troubleshoot`),n&&(i=`Worker Error: ${n}
${s}`),s}var z=A.join(Y(),".claude","plugins","marketplaces","thedotmack"),ht=U(m.HEALTH_CHECK),f=null;function p(){if(f!==null)return f;let o=A.join(u.get("CLAUDE_MEM_DATA_DIR"),"settings.json"),t=u.loadFromFile(o);return f=parseInt(t.CLAUDE_MEM_WORKER_PORT,10),f}async function q(){let o=p();return(await fetch(`http://127.0.0.1:${o}/api/readiness`)).ok}function Q(){let o=A.join(z,"package.json");return JSON.parse(J(o,"utf-8")).version}async function Z(){let o=p(),t=await fetch(`http://127.0.0.1:${o}/api/version`);if(!t.ok)throw new Error(`Failed to get worker version: ${t.status}`);return(await t.json()).version}async function tt(){let o=Q(),t=await Z();o!==t&&a.debug("SYSTEM","Version check",{pluginVersion:o,workerVersion:t,note:"Mismatch will be auto-restarted by worker-service start command"})}async function P(){for(let r=0;r<75;r++){try{if(await q()){await tt();return}}catch(e){a.debug("SYSTEM","Worker health check failed, will retry",{attempt:r+1,maxRetries:75,error:e instanceof Error?e.message:String(e)})}await new Promise(e=>setTimeout(e,200))}throw new Error($({port:p(),customPrefix:"Worker did not become ready within 15 seconds."}))}import et from"path";function v(o){if(!o||o.trim()==="")return a.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:o}),"unknown-project";let t=et.basename(o);if(t===""){if(process.platform==="win32"){let e=o.match(/^([A-Z]):\\/i);if(e){let i=`drive-${e[1].toUpperCase()}`;return a.info("PROJECT_NAME","Drive root detected",{cwd:o,projectName:i}),i}}return a.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:o}),"unknown-project"}return t}async function rt(o){if(await P(),!o)throw new Error("newHook requires input");let{session_id:t,cwd:r,prompt:e}=o,n=v(r);a.info("HOOK","new-hook: Received hook input",{session_id:t,has_prompt:!!e,cwd:r});let i=p();a.info("HOOK","new-hook: Calling /api/sessions/init",{contentSessionId:t,project:n,prompt_length:e?.length});let E=await fetch(`http://127.0.0.1:${i}/api/sessions/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:t,project:n,prompt:e})});if(!E.ok)throw new Error(`Session initialization failed: ${E.status}`);let s=await E.json(),l=s.sessionDbId,_=s.promptNumber;if(a.info("HOOK","new-hook: Received from /api/sessions/init",{sessionDbId:l,promptNumber:_,skipped:s.skipped}),a.info("HOOK",`[ALIGNMENT] Hook Entry | contentSessionId=${t} | prompt#=${_} | sessionDbId=${l}`),s.skipped&&s.reason==="private"){a.info("HOOK",`new-hook: Session ${l}, prompt #${_} (fully private - skipped)`),console.log(S);return}a.info("HOOK",`new-hook: Session ${l}, prompt #${_}`);let c=e.startsWith("/")?e.substring(1):e;a.info("HOOK","new-hook: Calling /sessions/{sessionDbId}/init",{sessionDbId:l,promptNumber:_,userPrompt_length:c?.length});let g=await fetch(`http://127.0.0.1:${i}/sessions/${l}/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userPrompt:c,promptNumber:_})});if(!g.ok)throw new Error(`SDK agent start failed: ${g.status}`);console.log(S)}var L="";w.on("data",o=>L+=o);w.on("end",async()=>{try{let o;try{o=L?JSON.parse(L):void 0}catch(t){throw new Error(`Failed to parse hook input: ${t instanceof Error?t.message:String(t)}`)}await rt(o)}catch(o){a.error("HOOK","new-hook failed",{},o)}finally{process.exit(0)}});
${i}`),i}var X=A.join(K(),".claude","plugins","marketplaces","thedotmack"),Lt=N(m.HEALTH_CHECK),O=null;function p(){if(O!==null)return O;let o=A.join(c.get("CLAUDE_MEM_DATA_DIR"),"settings.json"),t=c.loadFromFile(o);return O=parseInt(t.CLAUDE_MEM_WORKER_PORT,10),O}async function V(){let o=p();return(await fetch(`http://127.0.0.1:${o}/api/readiness`)).ok}function B(){let o=A.join(X,"package.json");return JSON.parse(G(o,"utf-8")).version}async function Y(){let o=p(),t=await fetch(`http://127.0.0.1:${o}/api/version`);if(!t.ok)throw new Error(`Failed to get worker version: ${t.status}`);return(await t.json()).version}async function J(){let o=B(),t=await Y();o!==t&&E.debug("SYSTEM","Version check",{pluginVersion:o,workerVersion:t,note:"Mismatch will be auto-restarted by worker-service start command"})}async function U(){for(let r=0;r<75;r++){try{if(await V()){await J();return}}catch(e){E.debug("SYSTEM","Worker health check failed, will retry",{attempt:r+1,maxRetries:75,error:e instanceof Error?e.message:String(e)})}await new Promise(e=>setTimeout(e,200))}throw new Error(I({port:p(),customPrefix:"Worker did not become ready within 15 seconds."}))}import z from"path";function P(o){if(!o||o.trim()==="")return E.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:o}),"unknown-project";let t=z.basename(o);if(t===""){if(process.platform==="win32"){let e=o.match(/^([A-Z]):\\/i);if(e){let s=`drive-${e[1].toUpperCase()}`;return E.info("PROJECT_NAME","Drive root detected",{cwd:o,projectName:s}),s}}return E.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:o}),"unknown-project"}return t}async function q(o){if(await U(),!o)throw new Error("newHook requires input");let{session_id:t,cwd:r,prompt:e}=o,n=P(r),s=p();E.debug("HOOK","new-hook: Calling /api/sessions/init",{contentSessionId:t,project:n});let a=await fetch(`http://127.0.0.1:${s}/api/sessions/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:t,project:n,prompt:e})});if(!a.ok)throw new Error(`Session initialization failed: ${a.status}`);let i=await a.json(),l=i.sessionDbId,_=i.promptNumber;if(E.debug("HOOK","new-hook: Received from /api/sessions/init",{sessionDbId:l,promptNumber:_,skipped:i.skipped}),E.debug("HOOK",`[ALIGNMENT] Hook Entry | contentSessionId=${t} | prompt#=${_} | sessionDbId=${l}`),i.skipped&&i.reason==="private"){E.info("HOOK",`INIT_COMPLETE | sessionDbId=${l} | promptNumber=${_} | skipped=true | reason=private`,{sessionId:l}),console.log(f);return}let g=e.startsWith("/")?e.substring(1):e;E.debug("HOOK","new-hook: Calling /sessions/{sessionDbId}/init",{sessionDbId:l,promptNumber:_});let u=await fetch(`http://127.0.0.1:${s}/sessions/${l}/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userPrompt:g,promptNumber:_})});if(!u.ok)throw new Error(`SDK agent start failed: ${u.status}`);E.info("HOOK",`INIT_COMPLETE | sessionDbId=${l} | promptNumber=${_} | project=${n}`,{sessionId:l}),console.log(f)}var L="";k.on("data",o=>L+=o);k.on("end",async()=>{try{let o;try{o=L?JSON.parse(L):void 0}catch(t){throw new Error(`Failed to parse hook input: ${t instanceof Error?t.message:String(t)}`)}await q(o)}catch(o){E.error("HOOK","new-hook failed",{},o)}finally{process.exit(0)}});
+8 -8
View File
@@ -1,13 +1,13 @@
#!/usr/bin/env bun
import{stdin as v}from"process";var T=JSON.stringify({continue:!0,suppressOutput:!0});import{appendFileSync as H,existsSync as R,mkdirSync as W,readFileSync as b}from"fs";import{join as S}from"path";import{homedir as G}from"os";var p=(o=>(o[o.DEBUG=0]="DEBUG",o[o.INFO=1]="INFO",o[o.WARN=2]="WARN",o[o.ERROR=3]="ERROR",o[o.SILENT=4]="SILENT",o))(p||{}),U=S(G(),".claude-mem"),M=class{level=null;useColor;logFilePath=null;logFileInitialized=!1;constructor(){this.useColor=process.stdout.isTTY??!1}ensureLogFileInitialized(){if(!this.logFileInitialized){this.logFileInitialized=!0;try{let t=S(U,"logs");R(t)||W(t,{recursive:!0});let r=new Date().toISOString().split("T")[0];this.logFilePath=S(t,`claude-mem-${r}.log`)}catch(t){console.error("[LOGGER] Failed to initialize log file:",t),this.logFilePath=null}}}getLevel(){if(this.level===null)try{let t=S(U,"settings.json");if(R(t)){let r=b(t,"utf-8"),n=(JSON.parse(r).CLAUDE_MEM_LOG_LEVEL||"INFO").toUpperCase();this.level=p[n]??1}else this.level=1}catch{this.level=1}return this.level}correlationId(t,r){return`obs-${t}-${r}`}sessionId(t){return`session-${t}`}formatData(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return t.toString();if(typeof t=="object"){if(t instanceof Error)return this.getLevel()===0?`${t.message}
${t.stack}`:t.message;if(Array.isArray(t))return`[${t.length} items]`;let r=Object.keys(t);return r.length===0?"{}":r.length<=3?JSON.stringify(t):`{${r.length} keys: ${r.slice(0,3).join(", ")}...}`}return String(t)}formatTool(t,r){if(!r)return t;let e=r;if(typeof r=="string")try{e=JSON.parse(r)}catch{e=r}if(t==="Bash"&&e.command)return`${t}(${e.command})`;if(e.file_path)return`${t}(${e.file_path})`;if(e.notebook_path)return`${t}(${e.notebook_path})`;if(t==="Glob"&&e.pattern)return`${t}(${e.pattern})`;if(t==="Grep"&&e.pattern)return`${t}(${e.pattern})`;if(e.url)return`${t}(${e.url})`;if(e.query)return`${t}(${e.query})`;if(t==="Task"){if(e.subagent_type)return`${t}(${e.subagent_type})`;if(e.description)return`${t}(${e.description})`}return t==="Skill"&&e.skill?`${t}(${e.skill})`:t==="LSP"&&e.operation?`${t}(${e.operation})`:t}formatTimestamp(t){let r=t.getFullYear(),e=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0"),o=String(t.getHours()).padStart(2,"0"),E=String(t.getMinutes()).padStart(2,"0"),i=String(t.getSeconds()).padStart(2,"0"),_=String(t.getMilliseconds()).padStart(3,"0");return`${r}-${e}-${n} ${o}:${E}:${i}.${_}`}log(t,r,e,n,o){if(t<this.getLevel())return;this.ensureLogFileInitialized();let E=this.formatTimestamp(new Date),i=p[t].padEnd(5),_=r.padEnd(6),a="";n?.correlationId?a=`[${n.correlationId}] `:n?.sessionId&&(a=`[session-${n.sessionId}] `);let l="";o!=null&&(o instanceof Error?l=this.getLevel()===0?`
import{stdin as $}from"process";var S=JSON.stringify({continue:!0,suppressOutput:!0});import{readFileSync as w,writeFileSync as v,existsSync as F}from"fs";import{join as x}from"path";import{homedir as H}from"os";var U="bugfix,feature,refactor,discovery,decision,change",d="how-it-works,why-it-exists,what-changed,problem-solution,gotcha,pattern,trade-off";var g=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:x(H(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",CLAUDE_MEM_MODE:"code",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:U,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:d,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return this.DEFAULTS[t]}static getInt(t){let r=this.get(t);return parseInt(r,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){try{if(!F(t))return this.getAllDefaults();let r=w(t,"utf-8"),e=JSON.parse(r),n=e;if(e.env&&typeof e.env=="object"){n=e.env;try{v(t,JSON.stringify(n,null,2),"utf-8"),l.info("SETTINGS","Migrated settings file from nested to flat schema",{settingsPath:t})}catch(E){l.warn("SETTINGS","Failed to auto-migrate settings file",{settingsPath:t},E)}}let o={...this.DEFAULTS};for(let E of Object.keys(this.DEFAULTS))n[E]!==void 0&&(o[E]=n[E]);return o}catch(r){return l.warn("SETTINGS","Failed to load settings, using defaults",{settingsPath:t},r),this.getAllDefaults()}}};import{appendFileSync as W,existsSync as b,mkdirSync as G}from"fs";import{join as T}from"path";var p=(o=>(o[o.DEBUG=0]="DEBUG",o[o.INFO=1]="INFO",o[o.WARN=2]="WARN",o[o.ERROR=3]="ERROR",o[o.SILENT=4]="SILENT",o))(p||{}),M=class{level=null;useColor;logFilePath=null;constructor(){this.useColor=process.stdout.isTTY??!1,this.initializeLogFile()}initializeLogFile(){try{let t=g.get("CLAUDE_MEM_DATA_DIR"),r=T(t,"logs");b(r)||G(r,{recursive:!0});let e=new Date().toISOString().split("T")[0];this.logFilePath=T(r,`claude-mem-${e}.log`)}catch(t){console.error("[LOGGER] Failed to initialize log file:",t),this.logFilePath=null}}getLevel(){if(this.level===null)try{let t=g.get("CLAUDE_MEM_DATA_DIR"),r=T(t,"settings.json"),n=g.loadFromFile(r).CLAUDE_MEM_LOG_LEVEL.toUpperCase();this.level=p[n]??1}catch(t){console.error("[LOGGER] Failed to load settings, using INFO level:",t),this.level=1}return this.level}correlationId(t,r){return`obs-${t}-${r}`}sessionId(t){return`session-${t}`}formatData(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return t.toString();if(typeof t=="object"){if(t instanceof Error)return this.getLevel()===0?`${t.message}
${t.stack}`:t.message;if(Array.isArray(t))return`[${t.length} items]`;let r=Object.keys(t);return r.length===0?"{}":r.length<=3?JSON.stringify(t):`{${r.length} keys: ${r.slice(0,3).join(", ")}...}`}return String(t)}formatTool(t,r){if(!r)return t;let e=typeof r=="string"?JSON.parse(r):r;if(t==="Bash"&&e.command)return`${t}(${e.command})`;if(e.file_path)return`${t}(${e.file_path})`;if(e.notebook_path)return`${t}(${e.notebook_path})`;if(t==="Glob"&&e.pattern)return`${t}(${e.pattern})`;if(t==="Grep"&&e.pattern)return`${t}(${e.pattern})`;if(e.url)return`${t}(${e.url})`;if(e.query)return`${t}(${e.query})`;if(t==="Task"){if(e.subagent_type)return`${t}(${e.subagent_type})`;if(e.description)return`${t}(${e.description})`}return t==="Skill"&&e.skill?`${t}(${e.skill})`:t==="LSP"&&e.operation?`${t}(${e.operation})`:t}formatTimestamp(t){let r=t.getFullYear(),e=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0"),o=String(t.getHours()).padStart(2,"0"),E=String(t.getMinutes()).padStart(2,"0"),i=String(t.getSeconds()).padStart(2,"0"),_=String(t.getMilliseconds()).padStart(3,"0");return`${r}-${e}-${n} ${o}:${E}:${i}.${_}`}log(t,r,e,n,o){if(t<this.getLevel())return;let E=this.formatTimestamp(new Date),i=p[t].padEnd(5),_=r.padEnd(6),a="";n?.correlationId?a=`[${n.correlationId}] `:n?.sessionId&&(a=`[session-${n.sessionId}] `);let c="";o!=null&&(o instanceof Error?c=this.getLevel()===0?`
${o.message}
${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?l=`
`+JSON.stringify(o,null,2):l=" "+this.formatData(o));let f="";if(n){let{sessionId:D,memorySessionId:st,correlationId:ot,...d}=n;Object.keys(d).length>0&&(f=` {${Object.entries(d).map(([F,x])=>`${F}=${x}`).join(", ")}}`)}let C=`[${E}] [${i}] [${_}] ${a}${e}${f}${l}`;if(this.logFilePath)try{H(this.logFilePath,C+`
${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?c=`
`+JSON.stringify(o,null,2):c=" "+this.formatData(o));let O="";if(n){let{sessionId:D,memorySessionId:Z,correlationId:tt,...R}=n;Object.keys(R).length>0&&(O=` {${Object.entries(R).map(([k,P])=>`${k}=${P}`).join(", ")}}`)}let C=`[${E}] [${i}] [${_}] ${a}${e}${O}${c}`;if(this.logFilePath)try{W(this.logFilePath,C+`
`,"utf8")}catch(D){process.stderr.write(`[LOGGER] Failed to write to log file: ${D}
`)}else process.stderr.write(C+`
`)}debug(t,r,e,n){this.log(0,t,r,e,n)}info(t,r,e,n){this.log(1,t,r,e,n)}warn(t,r,e,n){this.log(2,t,r,e,n)}error(t,r,e,n){this.log(3,t,r,e,n)}dataIn(t,r,e,n){this.info(t,`\u2192 ${r}`,e,n)}dataOut(t,r,e,n){this.info(t,`\u2190 ${r}`,e,n)}success(t,r,e,n){this.info(t,`\u2713 ${r}`,e,n)}failure(t,r,e,n){this.error(t,`\u2717 ${r}`,e,n)}timing(t,r,e,n){this.info(t,`\u23F1 ${r}`,n,{duration:`${e}ms`})}happyPathError(t,r,e,n,o=""){let a=((new Error().stack||"").split(`
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),l=a?`${a[1].split("/").pop()}:${a[2]}`:"unknown",f={...e,location:l};return this.warn(t,`[HAPPY-PATH] ${r}`,f,n),o}},c=new M;import A from"path";import{homedir as Y}from"os";import{readFileSync as J}from"fs";var m={DEFAULT:3e5,HEALTH_CHECK:3e4,WORKER_STARTUP_WAIT:1e3,WORKER_STARTUP_RETRIES:300,PRE_RESTART_SETTLE_DELAY:2e3,WINDOWS_MULTIPLIER:1.5};function h(s){return process.platform==="win32"?Math.round(s*m.WINDOWS_MULTIPLIER):s}import{readFileSync as K,writeFileSync as N,existsSync as $,mkdirSync as X}from"fs";import{join as V,dirname as j}from"path";import{homedir as B}from"os";var I="bugfix,feature,refactor,discovery,decision,change",y="how-it-works,why-it-exists,what-changed,problem-solution,gotcha,pattern,trade-off";var g=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:V(B(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",CLAUDE_MEM_MODE:"code",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:I,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:y,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return this.DEFAULTS[t]}static getInt(t){let r=this.get(t);return parseInt(r,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){try{if(!$(t)){let E=this.getAllDefaults();try{let i=j(t);$(i)||X(i,{recursive:!0}),N(t,JSON.stringify(E,null,2),"utf-8"),console.log("[SETTINGS] Created settings file with defaults:",t)}catch(i){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",t,i)}return E}let r=K(t,"utf-8"),e=JSON.parse(r),n=e;if(e.env&&typeof e.env=="object"){n=e.env;try{N(t,JSON.stringify(n,null,2),"utf-8"),console.log("[SETTINGS] Migrated settings file from nested to flat schema:",t)}catch(E){console.warn("[SETTINGS] Failed to auto-migrate settings file:",t,E)}}let o={...this.DEFAULTS};for(let E of Object.keys(this.DEFAULTS))n[E]!==void 0&&(o[E]=n[E]);return o}catch(r){return console.warn("[SETTINGS] Failed to load settings, using defaults:",t,r),this.getAllDefaults()}}};function k(s={}){let{port:t,includeSkillFallback:r=!1,customPrefix:e,actualError:n}=s,o=e||"Worker service connection failed.",E=t?` (port ${t})`:"",i=`${o}${E}
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),c=a?`${a[1].split("/").pop()}:${a[2]}`:"unknown",O={...e,location:c};return this.warn(t,`[HAPPY-PATH] ${r}`,O,n),o}},l=new M;import L from"path";import{homedir as K}from"os";import{readFileSync as X}from"fs";var A={DEFAULT:3e5,HEALTH_CHECK:3e4,WORKER_STARTUP_WAIT:1e3,WORKER_STARTUP_RETRIES:300,PRE_RESTART_SETTLE_DELAY:2e3,WINDOWS_MULTIPLIER:1.5};function h(s){return process.platform==="win32"?Math.round(s*A.WINDOWS_MULTIPLIER):s}function I(s={}){let{port:t,includeSkillFallback:r=!1,customPrefix:e,actualError:n}=s,o=e||"Worker service connection failed.",E=t?` (port ${t})`:"",i=`${o}${E}
`;return i+=`To restart the worker:
`,i+=`1. Exit Claude Code completely
@@ -16,8 +16,8 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?l=`
If that doesn't work, try: /troubleshoot`),n&&(i=`Worker Error: ${n}
${i}`),i}var z=A.join(Y(),".claude","plugins","marketplaces","thedotmack"),Ut=h(m.HEALTH_CHECK),O=null;function u(){if(O!==null)return O;let s=A.join(g.get("CLAUDE_MEM_DATA_DIR"),"settings.json"),t=g.loadFromFile(s);return O=parseInt(t.CLAUDE_MEM_WORKER_PORT,10),O}async function q(){let s=u();return(await fetch(`http://127.0.0.1:${s}/api/readiness`)).ok}function Q(){let s=A.join(z,"package.json");return JSON.parse(J(s,"utf-8")).version}async function Z(){let s=u(),t=await fetch(`http://127.0.0.1:${s}/api/version`);if(!t.ok)throw new Error(`Failed to get worker version: ${t.status}`);return(await t.json()).version}async function tt(){let s=Q(),t=await Z();s!==t&&c.debug("SYSTEM","Version check",{pluginVersion:s,workerVersion:t,note:"Mismatch will be auto-restarted by worker-service start command"})}async function P(){for(let r=0;r<75;r++){try{if(await q()){await tt();return}}catch(e){c.debug("SYSTEM","Worker health check failed, will retry",{attempt:r+1,maxRetries:75,error:e instanceof Error?e.message:String(e)})}await new Promise(e=>setTimeout(e,200))}throw new Error(k({port:u(),customPrefix:"Worker did not become ready within 15 seconds."}))}import{readFileSync as et,existsSync as rt}from"fs";function w(s,t,r=!1){if(!s||!rt(s))throw new Error(`Transcript path missing or file does not exist: ${s}`);let e=et(s,"utf-8").trim();if(!e)throw new Error(`Transcript file exists but is empty: ${s}`);let n=e.split(`
`),o=!1;for(let E=n.length-1;E>=0;E--){let i=JSON.parse(n[E]);if(i.type===t&&(o=!0,i.message?.content)){let _="",a=i.message.content;if(typeof a=="string")_=a;else if(Array.isArray(a))_=a.filter(l=>l.type==="text").map(l=>l.text).join(`
${i}`),i}var V=L.join(K(),".claude","plugins","marketplaces","thedotmack"),Ct=h(A.HEALTH_CHECK),f=null;function u(){if(f!==null)return f;let s=L.join(g.get("CLAUDE_MEM_DATA_DIR"),"settings.json"),t=g.loadFromFile(s);return f=parseInt(t.CLAUDE_MEM_WORKER_PORT,10),f}async function j(){let s=u();return(await fetch(`http://127.0.0.1:${s}/api/readiness`)).ok}function B(){let s=L.join(V,"package.json");return JSON.parse(X(s,"utf-8")).version}async function Y(){let s=u(),t=await fetch(`http://127.0.0.1:${s}/api/version`);if(!t.ok)throw new Error(`Failed to get worker version: ${t.status}`);return(await t.json()).version}async function J(){let s=B(),t=await Y();s!==t&&l.debug("SYSTEM","Version check",{pluginVersion:s,workerVersion:t,note:"Mismatch will be auto-restarted by worker-service start command"})}async function N(){for(let r=0;r<75;r++){try{if(await j()){await J();return}}catch(e){l.debug("SYSTEM","Worker health check failed, will retry",{attempt:r+1,maxRetries:75,error:e instanceof Error?e.message:String(e)})}await new Promise(e=>setTimeout(e,200))}throw new Error(I({port:u(),customPrefix:"Worker did not become ready within 15 seconds."}))}import{readFileSync as q,existsSync as z}from"fs";function y(s,t,r=!1){if(!s||!z(s))throw new Error(`Transcript path missing or file does not exist: ${s}`);let e=q(s,"utf-8").trim();if(!e)throw new Error(`Transcript file exists but is empty: ${s}`);let n=e.split(`
`),o=!1;for(let E=n.length-1;E>=0;E--){let i=JSON.parse(n[E]);if(i.type===t&&(o=!0,i.message?.content)){let _="",a=i.message.content;if(typeof a=="string")_=a;else if(Array.isArray(a))_=a.filter(c=>c.type==="text").map(c=>c.text).join(`
`);else throw new Error(`Unknown message content format in transcript. Type: ${typeof a}`);return r&&(_=_.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g,""),_=_.replace(/\n{3,}/g,`
`).trim()),_}}if(!o)throw new Error(`No message found for role '${t}' in transcript: ${s}`);return""}async function nt(s){if(await P(),!s)throw new Error("summaryHook requires input");let{session_id:t}=s,r=u();if(!s.transcript_path)throw new Error(`Missing transcript_path in Stop hook input for session ${t}`);let e=w(s.transcript_path,"assistant",!0);c.dataIn("HOOK","Stop: Requesting summary",{workerPort:r,hasLastAssistantMessage:!!e});let n=await fetch(`http://127.0.0.1:${r}/api/sessions/summarize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:t,last_assistant_message:e})});if(!n.ok)throw console.log(T),new Error(`Summary generation failed: ${n.status}`);c.debug("HOOK","Summary request sent successfully"),console.log(T)}var L="";v.on("data",s=>L+=s);v.on("end",async()=>{try{let s;try{s=L?JSON.parse(L):void 0}catch(t){throw new Error(`Failed to parse hook input: ${t instanceof Error?t.message:String(t)}`)}await nt(s)}catch(s){c.error("HOOK","summary-hook failed",{},s)}finally{process.exit(0)}});
`).trim()),_}}if(!o)throw new Error(`No message found for role '${t}' in transcript: ${s}`);return""}async function Q(s){if(await N(),!s)throw new Error("summaryHook requires input");let{session_id:t}=s,r=u();if(!s.transcript_path)throw new Error(`Missing transcript_path in Stop hook input for session ${t}`);let e=y(s.transcript_path,"assistant",!0);l.dataIn("HOOK","Stop: Requesting summary",{workerPort:r,hasLastAssistantMessage:!!e});let n=await fetch(`http://127.0.0.1:${r}/api/sessions/summarize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:t,last_assistant_message:e})});if(!n.ok)throw console.log(S),new Error(`Summary generation failed: ${n.status}`);l.debug("HOOK","Summary request sent successfully"),console.log(S)}var m="";$.on("data",s=>m+=s);$.on("end",async()=>{try{let s;try{s=m?JSON.parse(m):void 0}catch(t){throw new Error(`Failed to parse hook input: ${t instanceof Error?t.message:String(t)}`)}await Q(s)}catch(s){l.error("HOOK","summary-hook failed",{},s)}finally{process.exit(0)}});
File diff suppressed because one or more lines are too long
+62
View File
@@ -0,0 +1,62 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Nov 5, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #3910 | 8:28 PM | ✅ | Refined stats counter visual design | ~343 |
| #3909 | " | 🟣 | Added clarifying descriptions to settings UI | ~335 |
| #3812 | 6:08 PM | 🟣 | Enhanced card typography and centered content layout | ~358 |
### Nov 8, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #5133 | 7:29 PM | ✅ | Version 5.2.3 Released with Build Process | ~487 |
| #4916 | 1:49 PM | ⚖️ | Claude Mem Pro Premium Offering Implementation Plan Finalized | ~946 |
| #4902 | 1:35 PM | 🟣 | Claude Mem Pro Premium Project Initialization | ~679 |
| #4901 | 1:31 PM | ⚖️ | Premium claude-mem Project Architecture and Planning | ~797 |
### Dec 1, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #18480 | 3:39 PM | ✅ | Successfully Rebuilt Plugin After Merge Conflict Resolution | ~294 |
### Dec 4, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #20052 | 3:23 PM | ✅ | Built and deployed version 6.5.2 to marketplace | ~321 |
### Dec 9, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #22557 | 1:08 AM | ✅ | Build completed for version 7.0.3 | ~342 |
### Dec 10, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23444 | 2:25 PM | 🟣 | Build Pipeline Execution Successful | ~293 |
### Dec 16, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #27554 | 4:48 PM | ✅ | Project built successfully with version 7.3.1 | ~306 |
### Dec 26, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32983 | 11:04 PM | 🟣 | Complete build and deployment pipeline executed | ~260 |
| #32965 | 10:53 PM | 🔵 | Found plugin/ui/viewer.html - potential styling source | ~201 |
| #32966 | " | 🔵 | viewer.html contains modal CSS including modal-header and modal-body | ~218 |
| #32967 | " | 🔵 | ContextSettingsModal.tsx uses CSS classes defined in viewer.html | ~218 |
| #32968 | " | 🔵 | Need to add CSS for footer to viewer.html | ~223 |
</claude-mem-context>
+99
View File
@@ -0,0 +1,99 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Nov 7, 2025
**monaspace-radon-var.woff**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #4722 | 8:25 PM | ✅ | Rebuilt and deployed claude-mem plugin version 5.2.0 | ~324 |
| #4675 | 7:37 PM | ✅ | Claude-mem plugin v5.2.0 build and deployment | ~346 |
### Nov 9, 2025
**monaspace-radon-var.woff**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #6126 | 10:55 PM | ✅ | Deployed claude-mem plugin to marketplace and restarted worker | ~332 |
### Nov 11, 2025
**monaspace-radon-var.woff**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #7207 | 8:02 PM | ✅ | Built and Deployed claude-mem v5.5.1 to Marketplace | ~318 |
### Nov 19, 2025
**monaspace-radon-var.woff**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #11816 | 3:41 PM | ✅ | Build and deployment of claude-mem version 6.0.9 completed successfully | ~421 |
| #11786 | 3:13 PM | ✅ | Build, sync, and restart worker after UI changes | ~329 |
### Nov 21, 2025
**monaspace-radon-var.woff**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #13523 | 5:13 PM | ✅ | Claude-mem v6.0.9 built and deployed to marketplace | ~332 |
| #13143 | 1:13 AM | ✅ | Build and Sync of claude-mem Plugin Version 6.0.9 | ~365 |
| #13093 | 12:54 AM | ✅ | Build, Sync, and Restart Worker Service Deployment | ~371 |
### Dec 2, 2025
**monaspace-radon-var.woff**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #19569 | 11:01 PM | ✅ | Version 6.4.9 Build and Deployment | ~340 |
| #19566 | 10:59 PM | ✅ | Build and Deploy Complete for claude-mem 6.4.9 | ~328 |
| #19497 | 10:37 PM | ✅ | Synced UX improvements to marketplace and restarted worker | ~295 |
| #19464 | 10:04 PM | ✅ | Built and deployed claude-mem version 6.4.9 | ~284 |
### Dec 5, 2025
**monaspace-radon-var.woff**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #20972 | 11:41 PM | ✅ | Built and synced claude-mem v6.5.3 to marketplace | ~436 |
| #20923 | 11:14 PM | 🟣 | Built and deployed claude-mem v6.5.3 to marketplace | ~359 |
### Dec 7, 2025
**monaspace-radon-var.woff**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #21627 | 9:20 PM | ✅ | Claude-Mem v6.5.3 Built and Deployed to Marketplace | ~378 |
| #21424 | 7:27 PM | ✅ | Full build and deployment of claude-mem 6.5.3 completed | ~361 |
| #21174 | 4:58 PM | ✅ | Build and deployment of claude-mem v6.5.3 | ~359 |
### Dec 8, 2025
**monaspace-radon-var.woff**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #22365 | 11:52 PM | ✅ | Build and sync version 7.0.0 to marketplace | ~392 |
### Dec 10, 2025
**monaspace-radon-var.woff**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23405 | 2:14 PM | ✅ | Claude-mem v7.0.7 Build, Sync, and Worker Restart Completed | ~380 |
### Dec 25, 2025
*****
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32643 | 8:46 PM | ✅ | Plugin Build and Marketplace Synchronization | ~336 |
### Dec 26, 2025
**monaspace-radon-var.woff**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32975 | 11:04 PM | ✅ | Build and sync pipeline completed successfully | ~208 |
</claude-mem-context>
-109
View File
@@ -1,109 +0,0 @@
# Postmortem: Worker Debug Failure - 2025-11-17
## Incident Summary
Attempted to fix broken worker service. Worker was in crash loop with 225 restarts, failing with "MCP error -32000: Connection closed". Debug attempt failed and changes were reverted.
## What Went Wrong
### 1. **Jumped to Symptoms, Not Root Cause**
- Saw "MCP connection failed" errors in logs
- Immediately focused on MCP/Chroma connection code
- Never asked: "Why is this suddenly broken when it worked before?"
- Classic symptom chasing instead of root cause analysis
### 2. **Ignored the Build Pipeline**
- Worker file wasn't in the expected location (`plugin/worker-service.cjs` vs `plugin/scripts/worker-service.cjs`)
- Build output existed but search server was producing corrupted/error output
- Never investigated: "Is the build system broken?"
- Should have compared built artifacts between main and current branch
### 3. **Tried to Fix by Disabling Instead of Understanding**
- Final approach: comment out Chroma, comment out search server
- This is the opposite of debugging - it's just making things "work" by removing functionality
- User called this out as "duct tape around 5 things unrelated to the problem"
- Violated YAGNI/KISS by adding defensive complexity instead of fixing the actual issue
### 4. **Didn't Compare Working vs Broken State**
- User specifically said "we fixed this before"
- Should have immediately: `git diff main src/services/worker-service.ts`
- Did this eventually but didn't follow through on the findings
- The diff showed only search-everything additions - the core worker code was UNCHANGED
- This should have been a huge red flag: "If the code is the same, why is it broken?"
### 5. **Overcomplicated the Investigation**
- Started reading through ChromaSync implementation
- Traced through MCP connection code
- Analyzed startup sequences
- All of this was unnecessary if the root cause was a build issue
## What Should Have Happened
### Correct Debug Sequence:
1. ✅ Check worker status (`pm2 list`) - DONE
2. ✅ Check error logs - DONE
3. ❌ **Compare current code to main branch** - SKIPPED INITIALLY
4. ❌ **Check if built files are correct** - SKIPPED
5. ❌ **Test the build pipeline** - NEVER DONE
6. ❌ **Verify dependencies are installed** - NEVER CHECKED
### The Real Questions:
- Is this a code change or a build issue?
- What changed between working state and broken state?
- Are the built artifacts corrupted?
- Is the search server build actually valid?
- Are there missing dependencies in plugin/scripts/node_modules?
## Likely Root Causes (Untested)
Based on evidence:
1. **Build artifacts are corrupted** - search-server.mjs threw syntax errors when run
2. **Node modules missing/outdated** - plugin/scripts/node_modules may be stale
3. **ESM/CJS bundling issue** - esbuild may have produced invalid output
4. **search-everything branch has broken build config** - scripts/build-hooks.js may have issues
## Key Lessons
### KISS/DRY/YAGNI Violations
- Added complexity (disabling features) instead of removing it
- Tried to work around symptoms instead of fixing root cause
- Ignored the principle: "If it worked before and code is same, it's environment/build"
### Debugging Anti-Patterns
1. **Symptom Chasing**: Following error messages down rabbit holes
2. **Defensive Coding**: Commenting out "broken" features instead of fixing them
3. **Ignoring History**: Not comparing working vs broken states
4. **Build Blindness**: Assuming built artifacts are correct without verification
### What Good Debugging Looks Like
1. Compare working state (main) vs broken state (current branch)
2. Identify what actually changed (code? deps? build?)
3. Test the simplest hypothesis first (build issue vs code issue)
4. Never disable features to "fix" things - that's not fixing
## Action Items for Next Attempt
### Before Writing Any Code:
- [ ] `git diff main` for all modified files
- [ ] Check if `plugin/scripts/` artifacts are valid JavaScript
- [ ] Compare build process: `npm run build` output on main vs current branch
- [ ] Verify `plugin/scripts/node_modules` exists and is current
- [ ] Test search-server.mjs in isolation: `node plugin/scripts/search-server.mjs`
### If Build is Broken:
- [ ] Check scripts/build-hooks.js for recent changes
- [ ] Verify esbuild configuration
- [ ] Test build on main branch, then on current branch
- [ ] Don't modify source code until build is proven working
### If Code is Broken:
- [ ] Create minimal repro (which specific change broke it?)
- [ ] Fix the actual bug, don't add workarounds
- [ ] Test the fix in isolation
## Conclusion
This failure exemplifies "debugging by making changes" instead of "debugging by understanding". The instinct to fix symptoms (MCP errors) instead of investigating root cause (why is it broken now?) led to wasted effort and ultimately no solution.
The user's frustration was justified - I was adding defensive duct tape instead of finding and fixing the real problem. This is exactly what KISS/DRY/YAGNI principles are meant to prevent.
**Next time: Compare, verify, understand, THEN fix. Never disable features to make errors go away.**
-119
View File
@@ -1,119 +0,0 @@
Unified Search API Consolidation Plan
Overview
Consolidate 10 search endpoints into 6 powerful, semantic endpoints with intelligent aliasing for backward compatibility.
New Endpoint Structure
1. /search - Unified Cross-Type Search
- Searches all record types (observations + sessions + prompts) via Chroma multi-collection search
- Optional type filter to narrow down
- Replaces: search_observations, search_sessions, search_user_prompts
- Params: query, response=[index|full], type, project, dateRange, limit, offset, orderBy
2. /timeline - Unified Timeline Tool
- Supports both anchor-based and query-based modes via params
- If anchor → direct timeline lookup (like get_context_timeline)
- If query → search-first then timeline (like get_timeline_by_query)
- Params: anchor OR query, depth_before, depth_after, response, mode, project
3. /decisions - Decision Observations
- Metadata-first search for type=decision observations
- Uses specialized search logic for precision
- Params: response, project, dateRange, limit, offset, orderBy
4. /changes - Change Observations
- Metadata-first search for type=change observations
- Same pattern as /decisions
5. /how-it-works - How-It-Works Concept
- Metadata-first search for concept=how-it-works observations
- Same pattern as concept endpoints
6. /contextualize - Intelligent Context Builder
- Complex hybrid endpoint:
a. Get 7 latest decisions + 7 latest changes + 3 latest how-it-works
b. Find newest date across all results
c. Get timeline (7 before + 7 after) around that date
d. Merge & re-sort into single timeline (newest → oldest)
e. Return timeline + narratives of each concept's latest result
- Params: query (for contextualization), project
Implementation Phases
Phase 1: Core Unified Search (search-server.ts)
- Create search tool with Chroma multi-collection query
- Add type filtering support
- Alias old tools: search_observations → search(type=['observations'])
Phase 2: Unified Timeline (search-server.ts)
- Merge get_context_timeline + get_timeline_by_query logic
- Support both anchor and query params (mutually exclusive)
- Alias old timeline tools to new unified implementation
Phase 3: Specialized Concept Endpoints (search-server.ts)
- Create decisions, changes, how_it_works tools
- Use metadata-first search strategy
- Update find_by_type and find_by_concept to call these internally
Phase 4: Contextualize Endpoint (search-server.ts)
- Implement parallel fetching (7 decisions, 7 changes, 3 how-it-works)
- Find newest date, get timeline around it
- Merge, re-sort, extract narratives
- Return structured response with timeline + narratives
Phase 5: HTTP API Routes (worker-service.ts)
- Add 6 new routes: /api/search, /api/timeline, /api/decisions, /api/changes, /api/how-it-works, /api/contextualize
- Update old routes to alias new implementations
- Maintain backward compatibility
Phase 6: Chroma Multi-Collection Search (ChromaSync.ts)
- Add searchAll() method to query all collections in parallel
- Include source collection metadata in results
- Merge and rank by similarity score
Phase 7: SQLite Fallback (SessionSearch.ts)
- Add searchAll() for FTS5 fallback when Chroma unavailable
- Merge results from all three FTS5 tables
Phase 8: Documentation & Skill Updates
- Update mem-search skill with new endpoints
- Update CLAUDE.md and README.md
- Add examples and migration guide
Phase 9: Testing & Deployment
- Unit tests for all new tools
- Integration tests for aliasing
- Manual testing via mem-search skill
- Build → sync → worker restart
Key Design Decisions
✅ Aliasing Strategy: Old endpoints call new implementations internally (zero breaking changes)
✅ Unified Search: Chroma multi-collection search for true cross-type queries
✅ Flexible Timeline: Single tool supports both direct and query-based modes
✅ Specialized Shortcuts: /decisions, /changes, /how-it-works for common queries
✅ Intelligent Context: /contextualize auto-builds rich context with narratives
Migration Impact
- Users: Zero breaking changes, old endpoints work via aliasing
- Codebase: Simplified from 10 conceptual endpoints to 6
- Performance: Improved via Chroma multi-collection search
- Developer UX: Cleaner, more semantic API
+115
View File
@@ -0,0 +1,115 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 18, 2025
**README.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29649 | 6:08 PM | 🟣 | Created ragtime README with dual-license documentation | ~304 |
**LICENSE**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29648 | 6:08 PM | ✅ | Added PolyForm Non-commercial LICENSE to ragtime | ~172 |
### Dec 19, 2025
**context-builder.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30238 | 8:44 PM | 🔵 | Context builder creates investigation-style prompts from observations and summaries | ~441 |
| #30215 | 8:38 PM | 🟣 | RAGTIME Agent SDK Plugin Loading Implementation | ~388 |
| #30194 | 8:34 PM | 🟣 | Progressive Context Builder for Email Analysis | ~400 |
| #30139 | 8:18 PM | 🟣 | RAGTIME Plugin Loading Implementation Committed | ~382 |
| #30138 | " | ✅ | RAGTIME Scripts Reorganized into Dedicated Directory | ~254 |
**email-loader.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30235 | 8:43 PM | 🔵 | Email loader supports JSONL, index.json, and legacy JSON formats | ~393 |
| #30230 | 8:41 PM | 🔵 | Email Loader Multi-Format Parser Architecture | ~362 |
| #30193 | 8:33 PM | 🟣 | Multi-Format Email Corpus Loader | ~347 |
**ragtime.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30234 | 8:43 PM | 🔵 | RAGTIME uses Agent SDK query API with plugin loading | ~359 |
| #30228 | 8:41 PM | 🔵 | Per-Session Mode System Integration Architecture Mapped | ~735 |
| #30227 | " | 🟣 | RAGTIME Email Processing with Temp File Strategy | ~463 |
| #30221 | 8:39 PM | 🟣 | Email Investigation Mode for RAGTIME | ~502 |
| #30214 | 8:38 PM | 🔵 | RAGTIME Plugin Configuration Pattern | ~303 |
| #30189 | 8:33 PM | 🔵 | RAGTIME Email Processor Core Implementation | ~420 |
| #30143 | 8:20 PM | ✅ | Modified RAGTIME to write emails to temp files for Read tool access | ~319 |
| #30141 | 8:19 PM | ⚖️ | Simplified RAGTIME Prompt to Minimal Recursive Form | ~443 |
| #30136 | 8:17 PM | 🔄 | Switched Email Processor from Session API to Query API | ~334 |
| #30134 | 8:16 PM | ✅ | Switched RAGTIME from V2 unstable_v2_createSession to V1 query API | ~377 |
| #30126 | 8:15 PM | 🔄 | RAGTIME Migrated from Agent SDK v1 query() to v2 createSession() API | ~413 |
| #30125 | " | 🔄 | Ragtime Scripts Moved to Dedicated Ragtime Directory | ~230 |
**README.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30195 | 8:34 PM | 🔵 | RAGTIME Module Licensed Under PolyForm Noncommercial | ~232 |
| #30122 | 8:14 PM | 🔵 | RAGTIME README Content Defines Noncommercial License Boundaries | ~380 |
**LICENSE**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30120 | 8:14 PM | 🔵 | Complete RAGTIME Dual-License Implementation Timeline | ~513 |
| #30119 | 8:13 PM | 🔵 | RAGTIME Dual-License Architecture with PolyForm Non-Commercial | ~345 |
### Dec 20, 2025
**ragtime.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31289 | 9:40 PM | 🔵 | Memory System Contains 50 Architectural Decisions Across Multiple Initiatives | ~419 |
| #30377 | 4:04 PM | ✅ | Added debugging output to RAGTIME email processor | ~327 |
| #30376 | 4:03 PM | 🔵 | RAGTIME email investigation script architecture | ~437 |
| #30349 | 3:50 PM | 🔄 | ProcessEmail Function Simplified to Use File Path Prompt | ~304 |
| #30348 | " | 🔄 | Ragtime Script Refactored to Use Directory-Based Markdown Emails | ~298 |
| #30343 | 3:43 PM | ✅ | Removed Progress Logging from Email Processing Loop | ~233 |
| #32278 | 3:37 PM | ✅ | Project name configured for email investigation | ~197 |
| #30253 | 3:17 PM | 🔵 | Agent SDK Integration Throughout Codebase | ~402 |
| #32277 | 8:04 PM | 🔵 | Email Processing Pipeline in Ragtime | ~308 |
**export-to-markdown.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30345 | 3:46 PM | 🟣 | Email to Markdown Export Script | ~182 |
**email-loader.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30344 | 3:44 PM | 🔵 | Email Loader Supports Three Format Types | ~388 |
| #30246 | 3:12 PM | 🔵 | Email Corpus Loader With Multiple Format Support | ~502 |
### Dec 22, 2025
**README.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31865 | 6:56 PM | ✅ | 開発ドキュメントのクリーンアップをコミット | ~150 |
| #31864 | " | ✅ | 計画ドキュメントと分析ファイルの削除 | ~142 |
| #31863 | " | ✅ | Ragtime READMEに未実装状態と前提条件を文書化 | ~181 |
| #31861 | 6:55 PM | 🔵 | ragtimeディレクトリのライセンス構造の確認 | ~126 |
| #31858 | " | ✅ | 計画ドキュメントの削除とragtimeスタブの整理 | ~110 |
### Dec 24, 2025
**ragtime.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32211 | 8:17 PM | 🔵 | RAGTIME batch processing script for sequential file analysis | ~421 |
| #32310 | 3:54 PM | 🔴 | Fixed email processing order in ragtime script | ~274 |
### Dec 25, 2025
**ragtime.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32456 | 5:41 PM | ✅ | Completed merge of main branch into feature/titans-phase1-3 | ~354 |
</claude-mem-context>
+120
View File
@@ -0,0 +1,120 @@
<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 |
|----|------|---|-------|------|
| #23818 | 10:52 PM | ✅ | Build Script Updated to Bundle Worker CLI with Bun Shebang | ~225 |
| #23817 | " | 🔵 | Build Script Handles Hook Bundling; Worker Shebang Currently Uses Node | ~323 |
| #23793 | 10:14 PM | 🔄 | Smart Install Script Simplified for Clarity | ~479 |
| #23667 | 8:35 PM | 🔵 | Export-Memories Script Structure and Database Query Pattern | ~287 |
| #23649 | 8:13 PM | 🔴 | Fixed Sessions Array Type in Export Script | ~189 |
| #23648 | " | 🔴 | Applied Type Annotations to Export Script Variables | ~305 |
| #23647 | 8:12 PM | 🔴 | Improved Type Safety in Export Script | ~352 |
| #23646 | " | 🔴 | Fixed Variable Shadowing in Export Script | ~234 |
| #23645 | " | 🔵 | Export Script Has Variable Shadowing Issue | ~234 |
| #23644 | 8:11 PM | 🔴 | Added Database Existence Check to Export Script | ~245 |
| #23643 | " | 🔵 | Export Script Opens Database Without Existence Check | ~238 |
| #23642 | " | 🔴 | Fixed Export Script Hardcoded Port - Now Reads from User Settings | ~244 |
| #23641 | " | ✅ | Added Settings Import to Export Script | ~189 |
| #23640 | " | 🔵 | Export Script Has Hardcoded Port Parameter | ~213 |
| #23639 | " | 🔴 | Fixed Import Script insertSession.run() Call Parameters | ~218 |
### Dec 11, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24051 | 2:54 PM | 🟣 | Auto-Restart Worker After Marketplace Sync | ~384 |
| #24050 | " | ✅ | Build Worker Binary Script Made Executable | ~225 |
| #24049 | 2:53 PM | 🟣 | Windows Binary Build Script Created | ~362 |
| #24048 | " | ✅ | MCP Server Shebang Updated to Bun Runtime | ~342 |
| #24047 | " | ✅ | Hook Scripts Shebang Updated to Bun Runtime | ~305 |
| #24046 | " | ✅ | Worker Service Shebang Updated to Bun Runtime | ~306 |
| #24045 | 2:52 PM | 🔵 | Sync Marketplace Script Analysis for Auto-Restart Integration | ~366 |
| #24043 | " | 🔵 | Build Script Analysis for Phase 4 Updates | ~380 |
| #23922 | 1:34 PM | 🔵 | Three Node Shebangs Found in Build Configuration | ~349 |
| #23917 | 1:33 PM | 🔵 | Worker Service Build Configuration Current State | ~365 |
### Dec 12, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24639 | 10:46 PM | 🔴 | Enhanced UV Detection to Support Fresh Installs Before PATH Reload | ~326 |
| #24638 | " | 🔴 | Enhanced Bun Detection to Support Fresh Installs Before PATH Reload | ~338 |
| #24637 | " | 🔵 | Bun Installation Detection Using spawnSync | ~288 |
| #24636 | " | 🔵 | Duplicate Smart Install Scripts in Project Structure | ~288 |
### Dec 14, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #26768 | 11:31 PM | 🔵 | Build Script Generates Empty plugin/package.json Without Postinstall Hook | ~492 |
| #26767 | " | 🔵 | Build Script Generates Empty Plugin Package.json Without Postinstall Hook | ~523 |
| #26766 | 11:30 PM | ⚖️ | Root Cause Identified: Missing Post-Install Worker Restart Trigger in Plugin Update Flow | ~604 |
| #26765 | " | 🔵 | Explore Agent Confirms Root Cause: No Proactive Worker Restart After Plugin Updates | ~613 |
| #25815 | 5:31 PM | 🔵 | Comprehensive MCP Server and SKILL.md Structure Analysis | ~575 |
| #25809 | 5:30 PM | 🔵 | Build System Architecture Using esbuild for Component Bundling | ~484 |
### Dec 16, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #27725 | 5:45 PM | 🔵 | Export script uses hybrid search API to export observations, sessions, summaries, and prompts | ~335 |
| #27705 | 5:38 PM | ✅ | Switched import-memories.ts from better-sqlite3 to bun:sqlite | ~212 |
### Dec 17, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29052 | 10:02 PM | 🔵 | Sync Script Manages Multiple Plugin Installation Locations | ~394 |
### Dec 18, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29565 | 5:28 PM | ✅ | Output File Changed from code.yaml to code.json | ~234 |
| #29564 | " | 🔄 | Script Refactored to Generate JSON Instead of YAML | ~332 |
### Dec 19, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30109 | 8:11 PM | 🔵 | RAGTIME Script Uses Agent SDK Without Plugin Loading | ~490 |
| #30076 | 8:05 PM | 🔵 | RAGTIME Script Uses Agent SDK Query Function for Email Processing | ~389 |
### Dec 20, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30340 | 3:42 PM | 🔄 | Relocated simple ragtime.ts to ragtime folder | ~219 |
| #30337 | 3:40 PM | 🔵 | Simplified Ragtime Runner in Scripts Directory | ~456 |
| #30256 | 3:18 PM | 🔵 | Plugin Path Resolution Strategy | ~386 |
| #30250 | 3:17 PM | 🟣 | RAGTIME Email Investigation Runner Implemented | ~503 |
### Dec 26, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32983 | 11:04 PM | 🟣 | Complete build and deployment pipeline executed | ~260 |
### Dec 28, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33261 | 2:58 PM | 🔄 | Build script cleanup removes obsolete worker-wrapper and worker-cli build steps | ~335 |
### Dec 30, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34460 | 2:23 PM | 🔵 | Build System Architecture Using ESBuild | ~492 |
### Jan 4, 2026
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36765 | 12:41 AM | 🔵 | Smart Install Script Path Detection Logic | ~405 |
</claude-mem-context>
+30
View File
@@ -135,3 +135,33 @@ These files are **NEVER** allowed to have catch-and-continue:
- `worker-service.ts` - Core service errors must be visible
On critical paths, prefer **NO TRY-CATCH** and let errors propagate naturally.
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 2, 2026
**detect-error-handling-antipatterns.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36018 | 9:12 PM | 🔵 | Anti-pattern detection scan shows progress | ~301 |
| #36012 | 9:09 PM | 🔵 | Error Handling Anti-Pattern Detection Baseline | ~222 |
| #36011 | 8:55 PM | 🔄 | Simplified anti-pattern severity levels | ~238 |
| #35810 | 2:15 PM | 🔄 | Relocated Error Handling Detector Script | ~254 |
**CLAUDE.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35901 | 2:49 PM | 🔵 | PR #525 File Changes Summary | ~376 |
| #35812 | 2:15 PM | ✅ | Updated test script path in CLAUDE.md after file relocation | ~298 |
| #35811 | " | ✅ | Created Error Handling Rules Documentation in Test Directory | ~315 |
| #35808 | " | ✅ | Moved CLAUDE.md into anti-pattern-test subfolder | ~140 |
**claude.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35807 | 2:15 PM | ✅ | Reorganized anti-pattern test files into dedicated subfolder | ~265 |
</claude-mem-context>
+15
View File
@@ -0,0 +1,15 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 30, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34517 | 2:34 PM | 🔵 | Bug Report Script Successfully Migrated to V2 Pattern | ~388 |
| #34513 | 2:33 PM | ✅ | Phase 4 Utility Scripts Migration Committed and Pushed | ~437 |
| #34512 | " | ✅ | Bug Report Script Migrated to V2 Prompt API | ~524 |
| #34509 | 2:32 PM | 🔵 | Bug Report Script Still Uses V1 SDK Pattern | ~499 |
| #34457 | 2:21 PM | 🔵 | Bug Report Script Using V2 Prompt API | ~325 |
</claude-mem-context>
+562
View File
@@ -0,0 +1,562 @@
#!/usr/bin/env bun
/**
* Regenerate CLAUDE.md files for folders in the current project
*
* Usage:
* bun scripts/regenerate-claude-md.ts [--dry-run] [--clean]
*
* Options:
* --dry-run Show what would be done without writing files
* --clean Remove auto-generated CLAUDE.md files instead of regenerating
*
* Behavior:
* - Scopes to current working directory (not entire database history)
* - Uses git ls-files to respect .gitignore (skips node_modules, .git, etc.)
* - Only processes folders that exist within the current project
* - Filters database to current project observations only
*/
import { Database } from 'bun:sqlite';
import path from 'path';
import os from 'os';
import { existsSync, mkdirSync, writeFileSync, readFileSync, renameSync, unlinkSync, readdirSync } from 'fs';
import { execSync } from 'child_process';
import { SettingsDefaultsManager } from '../src/shared/SettingsDefaultsManager.js';
const DB_PATH = path.join(os.homedir(), '.claude-mem', 'claude-mem.db');
const SETTINGS_PATH = path.join(os.homedir(), '.claude-mem', 'settings.json');
const settings = SettingsDefaultsManager.loadFromFile(SETTINGS_PATH);
const OBSERVATION_LIMIT = parseInt(settings.CLAUDE_MEM_CONTEXT_OBSERVATIONS, 10) || 50;
interface ObservationRow {
id: number;
title: string | null;
subtitle: string | null;
narrative: string | null;
facts: string | null;
type: string;
created_at: string;
created_at_epoch: number;
files_modified: string | null;
files_read: string | null;
project: string;
discovery_tokens: number | null;
}
// Import shared formatting utilities
import { formatTime, groupByDate } from '../src/shared/timeline-formatting.js';
// Type icon map (matches ModeManager)
const TYPE_ICONS: Record<string, string> = {
'bugfix': '🔴',
'feature': '🟣',
'refactor': '🔄',
'change': '✅',
'discovery': '🔵',
'decision': '⚖️',
'session': '🎯',
'prompt': '💬'
};
function getTypeIcon(type: string): string {
return TYPE_ICONS[type] || '📝';
}
function estimateTokens(obs: ObservationRow): number {
const size = (obs.title?.length || 0) +
(obs.subtitle?.length || 0) +
(obs.narrative?.length || 0) +
(obs.facts?.length || 0);
return Math.ceil(size / 4);
}
/**
* Get tracked folders using git ls-files
* This respects .gitignore and only returns folders within the project
*/
function getTrackedFolders(workingDir: string): Set<string> {
const folders = new Set<string>();
try {
// Get all tracked files using git ls-files
const output = execSync('git ls-files', {
cwd: workingDir,
encoding: 'utf-8',
maxBuffer: 50 * 1024 * 1024 // 50MB buffer for large repos
});
const files = output.trim().split('\n').filter(f => f);
for (const file of files) {
// Get the absolute path, then extract directory
const absPath = path.join(workingDir, file);
let dir = path.dirname(absPath);
// Add all parent directories up to (but not including) the working dir
while (dir.length > workingDir.length && dir.startsWith(workingDir)) {
folders.add(dir);
dir = path.dirname(dir);
}
}
} catch (error) {
console.error('Warning: git ls-files failed, falling back to directory walk');
// Fallback: walk directories but skip common ignored patterns
walkDirectoriesWithIgnore(workingDir, folders);
}
return folders;
}
/**
* Fallback directory walker that skips common ignored patterns
*/
function walkDirectoriesWithIgnore(dir: string, folders: Set<string>, depth: number = 0): void {
if (depth > 10) return; // Prevent infinite recursion
const ignorePatterns = [
'node_modules', '.git', '.next', 'dist', 'build', '.cache',
'__pycache__', '.venv', 'venv', '.idea', '.vscode', 'coverage',
'.claude-mem', '.open-next', '.turbo'
];
try {
const entries = readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isDirectory()) continue;
if (ignorePatterns.includes(entry.name)) continue;
if (entry.name.startsWith('.') && entry.name !== '.claude') continue;
const fullPath = path.join(dir, entry.name);
folders.add(fullPath);
walkDirectoriesWithIgnore(fullPath, folders, depth + 1);
}
} catch {
// Ignore permission errors
}
}
/**
* Check if a file is a direct child of a folder (not in a subfolder)
* @param filePath - File path like "src/services/foo.ts"
* @param folderPath - Folder path like "src/services"
* @returns true if file is directly in folder, false if in a subfolder
*/
function isDirectChild(filePath: string, folderPath: string): boolean {
if (!filePath.startsWith(folderPath + '/')) return false;
const remainder = filePath.slice(folderPath.length + 1);
// If remainder contains a slash, it's in a subfolder
return !remainder.includes('/');
}
/**
* Check if an observation has any files that are direct children of the folder
*/
function hasDirectChildFile(obs: ObservationRow, folderPath: string): boolean {
const checkFiles = (filesJson: string | null): boolean => {
if (!filesJson) return false;
try {
const files = JSON.parse(filesJson);
if (Array.isArray(files)) {
return files.some(f => isDirectChild(f, folderPath));
}
} catch {}
return false;
};
return checkFiles(obs.files_modified) || checkFiles(obs.files_read);
}
/**
* Query observations for a specific folder
* folderPath is a relative path from the project root (e.g., "src/services")
* Only returns observations with files directly in the folder (not in subfolders)
*/
function findObservationsByFolder(db: Database, relativeFolderPath: string, project: string, limit: number): ObservationRow[] {
// Query more results than needed since we'll filter some out
const queryLimit = limit * 3;
const sql = `
SELECT o.*, o.discovery_tokens
FROM observations o
WHERE o.project = ?
AND (o.files_modified LIKE ? OR o.files_read LIKE ?)
ORDER BY o.created_at_epoch DESC
LIMIT ?
`;
// Files in DB are stored as relative paths like "src/services/foo.ts"
// Match any file that starts with this folder path (we'll filter to direct children below)
const likePattern = `%"${relativeFolderPath}/%`;
const allMatches = db.prepare(sql).all(project, likePattern, likePattern, queryLimit) as ObservationRow[];
// Filter to only observations with direct child files (not in subfolders)
return allMatches.filter(obs => hasDirectChildFile(obs, relativeFolderPath)).slice(0, limit);
}
/**
* Extract relevant file from an observation for display
* Only returns files that are direct children of the folder (not in subfolders)
* @param obs - The observation row
* @param relativeFolder - Relative folder path (e.g., "src/services")
*/
function extractRelevantFile(obs: ObservationRow, relativeFolder: string): string {
// Try files_modified first - only direct children
if (obs.files_modified) {
try {
const modified = JSON.parse(obs.files_modified);
if (Array.isArray(modified) && modified.length > 0) {
for (const file of modified) {
if (isDirectChild(file, relativeFolder)) {
// Get just the filename (no path since it's a direct child)
return path.basename(file);
}
}
}
} catch {}
}
// Fall back to files_read - only direct children
if (obs.files_read) {
try {
const read = JSON.parse(obs.files_read);
if (Array.isArray(read) && read.length > 0) {
for (const file of read) {
if (isDirectChild(file, relativeFolder)) {
return path.basename(file);
}
}
}
} catch {}
}
return 'General';
}
/**
* Format observations for CLAUDE.md content
*/
function formatObservationsForClaudeMd(observations: ObservationRow[], folderPath: string): string {
const lines: string[] = [];
lines.push('# Recent Activity');
lines.push('');
lines.push('<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->');
lines.push('');
if (observations.length === 0) {
lines.push('*No recent activity*');
return lines.join('\n');
}
const byDate = groupByDate(observations, obs => obs.created_at);
for (const [day, dayObs] of byDate) {
lines.push(`### ${day}`);
lines.push('');
const byFile = new Map<string, ObservationRow[]>();
for (const obs of dayObs) {
const file = extractRelevantFile(obs, folderPath);
if (!byFile.has(file)) byFile.set(file, []);
byFile.get(file)!.push(obs);
}
for (const [file, fileObs] of byFile) {
lines.push(`**${file}**`);
lines.push('| ID | Time | T | Title | Read |');
lines.push('|----|------|---|-------|------|');
let lastTime = '';
for (const obs of fileObs) {
const time = formatTime(obs.created_at_epoch);
const timeDisplay = time === lastTime ? '"' : time;
lastTime = time;
const icon = getTypeIcon(obs.type);
const title = obs.title || 'Untitled';
const tokens = estimateTokens(obs);
lines.push(`| #${obs.id} | ${timeDisplay} | ${icon} | ${title} | ~${tokens} |`);
}
lines.push('');
}
}
return lines.join('\n').trim();
}
/**
* Write CLAUDE.md file with tagged content preservation
*/
function writeClaudeMdToFolder(folderPath: string, newContent: string): void {
const claudeMdPath = path.join(folderPath, 'CLAUDE.md');
const tempFile = `${claudeMdPath}.tmp`;
mkdirSync(folderPath, { recursive: true });
let existingContent = '';
if (existsSync(claudeMdPath)) {
existingContent = readFileSync(claudeMdPath, 'utf-8');
}
const startTag = '<claude-mem-context>';
const endTag = '</claude-mem-context>';
let finalContent: string;
if (!existingContent) {
finalContent = `${startTag}\n${newContent}\n${endTag}`;
} else {
const startIdx = existingContent.indexOf(startTag);
const endIdx = existingContent.indexOf(endTag);
if (startIdx !== -1 && endIdx !== -1) {
finalContent = existingContent.substring(0, startIdx) +
`${startTag}\n${newContent}\n${endTag}` +
existingContent.substring(endIdx + endTag.length);
} else {
finalContent = existingContent + `\n\n${startTag}\n${newContent}\n${endTag}`;
}
}
writeFileSync(tempFile, finalContent);
renameSync(tempFile, claudeMdPath);
}
/**
* Clean up auto-generated CLAUDE.md files
*
* For each file with <claude-mem-context> tags:
* - Strip the tagged section
* - If empty after stripping delete the file
* - If has remaining content save the stripped version
*/
function cleanupAutoGeneratedFiles(workingDir: string, dryRun: boolean): void {
console.log('=== CLAUDE.md Cleanup Mode ===\n');
console.log(`Scanning ${workingDir} for CLAUDE.md files with auto-generated content...\n`);
const filesToProcess: string[] = [];
// Walk directories to find CLAUDE.md files
function walkForClaudeMd(dir: string): void {
const ignorePatterns = ['node_modules', '.git', '.next', 'dist', 'build'];
try {
const entries = readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
if (!ignorePatterns.includes(entry.name)) {
walkForClaudeMd(fullPath);
}
} else if (entry.name === 'CLAUDE.md') {
// Check if file contains auto-generated content
try {
const content = readFileSync(fullPath, 'utf-8');
if (content.includes('<claude-mem-context>')) {
filesToProcess.push(fullPath);
}
} catch {
// Skip files we can't read
}
}
}
} catch {
// Ignore permission errors
}
}
walkForClaudeMd(workingDir);
if (filesToProcess.length === 0) {
console.log('No CLAUDE.md files with auto-generated content found.');
return;
}
console.log(`Found ${filesToProcess.length} CLAUDE.md files with auto-generated content:\n`);
let deletedCount = 0;
let cleanedCount = 0;
let errorCount = 0;
for (const file of filesToProcess) {
const relativePath = path.relative(workingDir, file);
try {
const content = readFileSync(file, 'utf-8');
// Strip the claude-mem-context tagged section
const stripped = content.replace(/<claude-mem-context>[\s\S]*?<\/claude-mem-context>/g, '').trim();
if (stripped === '') {
// Empty after stripping → delete
if (dryRun) {
console.log(` [DRY-RUN] Would delete (empty): ${relativePath}`);
} else {
unlinkSync(file);
console.log(` Deleted (empty): ${relativePath}`);
}
deletedCount++;
} else {
// Has content → write stripped version
if (dryRun) {
console.log(` [DRY-RUN] Would clean: ${relativePath}`);
} else {
writeFileSync(file, stripped);
console.log(` Cleaned: ${relativePath}`);
}
cleanedCount++;
}
} catch (error) {
console.error(` Error processing ${relativePath}: ${error}`);
errorCount++;
}
}
console.log('\n=== Summary ===');
console.log(`Deleted (empty): ${deletedCount}`);
console.log(`Cleaned: ${cleanedCount}`);
console.log(`Errors: ${errorCount}`);
if (dryRun) {
console.log('\nRun without --dry-run to actually process files.');
}
}
/**
* Regenerate CLAUDE.md for a single folder
* @param absoluteFolder - Absolute path for writing files
* @param relativeFolder - Relative path for DB queries (matches storage format)
*/
function regenerateFolder(
db: Database,
absoluteFolder: string,
relativeFolder: string,
project: string,
dryRun: boolean
): { success: boolean; observationCount: number; error?: string } {
try {
// Query using relative path (matches DB storage format)
const observations = findObservationsByFolder(db, relativeFolder, project, OBSERVATION_LIMIT);
if (observations.length === 0) {
return { success: false, observationCount: 0, error: 'No observations for folder' };
}
if (dryRun) {
return { success: true, observationCount: observations.length };
}
// Format using relative path for display, write to absolute path
const formatted = formatObservationsForClaudeMd(observations, relativeFolder);
writeClaudeMdToFolder(absoluteFolder, formatted);
return { success: true, observationCount: observations.length };
} catch (error) {
return { success: false, observationCount: 0, error: String(error) };
}
}
/**
* Main function
*/
async function main() {
const args = process.argv.slice(2);
const dryRun = args.includes('--dry-run');
const cleanMode = args.includes('--clean');
const workingDir = process.cwd();
// Handle cleanup mode
if (cleanMode) {
cleanupAutoGeneratedFiles(workingDir, dryRun);
return;
}
console.log('=== CLAUDE.md Regeneration Script ===\n');
console.log(`Working directory: ${workingDir}`);
// Determine project identifier (matches how hooks determine project - uses folder name)
const project = path.basename(workingDir);
console.log(`Project: ${project}\n`);
// Get tracked folders using git ls-files
console.log('Discovering folders (using git ls-files to respect .gitignore)...');
const trackedFolders = getTrackedFolders(workingDir);
if (trackedFolders.size === 0) {
console.log('No folders found in project.');
process.exit(0);
}
console.log(`Found ${trackedFolders.size} folders in project.\n`);
// Open database
if (!existsSync(DB_PATH)) {
console.log('Database not found. No observations to process.');
process.exit(0);
}
console.log('Opening database...');
const db = new Database(DB_PATH, { readonly: true, create: false });
if (dryRun) {
console.log('[DRY RUN] Would regenerate the following folders:\n');
}
// Process each folder
let successCount = 0;
let skipCount = 0;
let errorCount = 0;
const foldersArray = Array.from(trackedFolders).sort();
for (let i = 0; i < foldersArray.length; i++) {
const absoluteFolder = foldersArray[i];
const progress = `[${i + 1}/${foldersArray.length}]`;
const relativeFolder = path.relative(workingDir, absoluteFolder);
if (dryRun) {
// Query using relative path (matches DB storage format)
const observations = findObservationsByFolder(db, relativeFolder, project, OBSERVATION_LIMIT);
if (observations.length > 0) {
console.log(`${progress} ${relativeFolder} (${observations.length} obs)`);
successCount++;
} else {
skipCount++;
}
continue;
}
const result = regenerateFolder(db, absoluteFolder, relativeFolder, project, dryRun);
if (result.success) {
console.log(`${progress} ${relativeFolder} - ${result.observationCount} obs`);
successCount++;
} else if (result.error?.includes('No observations')) {
skipCount++;
} else {
console.log(`${progress} ${relativeFolder} - ERROR: ${result.error}`);
errorCount++;
}
}
db.close();
// Summary
console.log('\n=== Summary ===');
console.log(`Total folders scanned: ${foldersArray.length}`);
console.log(`With observations: ${successCount}`);
console.log(`No observations: ${skipCount}`);
console.log(`Errors: ${errorCount}`);
if (dryRun) {
console.log('\nRun without --dry-run to actually regenerate files.');
}
}
main().catch(error => {
console.error('Fatal error:', error);
process.exit(1);
});
+145
View File
@@ -0,0 +1,145 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 12, 2025
**cli.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24246 | 2:43 AM | 🟣 | Comprehensive Translation System Added with 22 Language READMEs | ~386 |
| #24235 | 2:32 AM | 🔵 | Translation CLI Script Structure | ~267 |
| #24215 | 1:49 AM | 🟣 | Wired parallel argument to translateReadme function call | ~290 |
| #24214 | " | 🟣 | Implemented --parallel argument parsing with validation | ~271 |
| #24213 | " | 🟣 | Initialized parallel default value in parseArgs | ~212 |
**index.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24236 | 2:33 AM | 🔵 | Translation Core Logic and Output Directory Handling | ~288 |
| #24219 | 1:50 AM | 🟣 | Implemented concurrent translation processing with parallelism control | ~461 |
| #24218 | " | 🟣 | Extracted parallel parameter in translateReadme function | ~259 |
| #24217 | " | 🔵 | Current translateReadme uses sequential for-loop processing | ~312 |
| #24216 | " | 🟣 | Added parallel option to TranslationOptions interface | ~262 |
### Dec 13, 2025
**examples.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #25321 | 9:12 PM | 🔵 | Console.error Usage Found in 29 Files | ~366 |
### Dec 14, 2025
**cli.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #25670 | 3:42 PM | 🔵 | Translation System Supports 38 Languages | ~259 |
| #25668 | 3:40 PM | 🟣 | Translation system enhancement with 226 net line addition | ~298 |
| #25667 | " | 🔵 | Translation script CLI interface and authentication | ~330 |
| #25664 | 3:39 PM | 🔵 | Modified files from PR-250 cherry-pick | ~238 |
| #25663 | " | 🔵 | Translation script structure with CLI and examples | ~277 |
**translate-readme**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #25660 | 3:38 PM | ✅ | Cherry-picked translation script from PR-250 branch | ~192 |
### Dec 15, 2025
**index.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #27161 | 8:08 PM | 🔵 | README Translation Script Architecture | ~420 |
| #27158 | " | 🔵 | Complete API Key Authentication Flow Traced Through System | ~460 |
**examples.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #27149 | 8:07 PM | 🔵 | API Key Management Implementation Details | ~302 |
| #27146 | " | 🔵 | ANTHROPIC_API_KEY Referenced Across Documentation and Scripts | ~254 |
### Dec 18, 2025
**README.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29244 | 12:15 AM | 🔵 | Identified YAML configuration files in claude-mem project | ~164 |
### Dec 20, 2025
**index.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30253 | 3:17 PM | 🔵 | Agent SDK Integration Throughout Codebase | ~402 |
### Dec 21, 2025
**cli.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31753 | 11:01 PM | 🔵 | README Translation CLI Tool Verified Operational | ~349 |
| #31749 | 10:57 PM | 🔵 | CLI del traductor de README incluye opción de paralelización | ~317 |
| #31713 | 9:41 PM | 🔵 | Complete Multilingual Infrastructure Documented | ~545 |
**index.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31752 | 10:59 PM | 🔴 | Fixed concurrency control bug in translation script | ~309 |
| #31751 | 10:58 PM | 🔵 | Concurrencia implementada con función runWithConcurrency personalizada | ~483 |
| #31748 | 10:57 PM | 🔵 | Ubicación del script traductor de README identificada | ~241 |
| #31601 | 8:19 PM | 🔵 | 215 console logging statements in TypeScript utility scripts | ~501 |
**README.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31750 | 10:58 PM | 🔵 | Documentación del traductor de README no menciona concurrencia | ~292 |
### Dec 22, 2025
**index.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31921 | 7:36 PM | ✅ | Updated Verbose Output to Always Show Parallel Count | ~233 |
| #31920 | " | 🟣 | Implemented Always-On Concurrent Translation with 10-Worker Limit | ~280 |
| #31919 | " | ✅ | Removed Parallel Parameter from TranslationOptions Interface | ~198 |
| #31918 | " | 🔵 | Translation Engine Uses Configurable Concurrency Control | ~322 |
**cli.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31917 | 7:35 PM | 🔵 | Current CLI Implementation Uses Optional Parallel Flag | ~237 |
### Dec 23, 2025
**cli.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32292 | 7:19 PM | ✅ | Removed parallel parameter from CLI arguments interface | ~189 |
| #32308 | " | ✅ | Removed parallel default value from argument parser initialization | ~181 |
| #32321 | " | ✅ | Removed --parallel flag parsing from CLI argument parser | ~225 |
| #32328 | " | ✅ | Removed parallel parameter from translateReadme function call | ~205 |
| #32335 | " | ✅ | Updated CLI help documentation to reflect automatic parallel execution | ~261 |
### Dec 30, 2025
**index.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34507 | 2:32 PM | 🟣 | Completed V2 Migration of Translation Script | ~394 |
| #34501 | 2:30 PM | ✅ | Started V2 Migration of Translation Script Import | ~270 |
| #34498 | " | 🔵 | Translation Script Uses V1 SDK Query API | ~409 |
| #34445 | 2:19 PM | 🔵 | Translation Script Already Using V2 API | ~264 |
| #34405 | 1:54 PM | 🔵 | Translation Script Using V1 SDK API | ~367 |
### Dec 31, 2025
**index.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34572 | 2:36 PM | ⚖️ | Comprehensive Post-Mortem Document Created | ~692 |
| #34571 | 2:35 PM | ⚖️ | Post-Mortem Analysis Identifies Scope Confusion as Root Failure Cause | ~599 |
| #34570 | " | 🔵 | Root Cause Identified: Utility Scripts Never Fixed Despite Phase 4 Review | ~513 |
| #34568 | " | 🔵 | Utility Script V2 Migration Used Incorrect systemPrompt Option | ~425 |
</claude-mem-context>
+16
View File
@@ -0,0 +1,16 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 4, 2026
**export.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36924 | 2:25 AM | ✅ | Merged fix/pr-538-followups branch into main with comprehensive updates | ~481 |
| #36914 | 2:24 AM | 🔵 | Recent commit 4d0a10c fixed multiple GitHub issues | ~365 |
| #36844 | 1:44 AM | 🔵 | Shared Type Definitions for Export/Import Operations | ~502 |
| #36829 | 1:40 AM | 🔵 | PR #542 Review Analysis - Multi-Issue Fix Validation | ~562 |
| #36827 | 1:03 AM | ✅ | Branch diff shows 1,293 insertions and 98 deletions across 15 files | ~464 |
</claude-mem-context>
+13
View File
@@ -0,0 +1,13 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 5, 2026
**CLAUDE.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37391 | 12:48 AM | ✅ | Staged 23 CLAUDE.md files with mix of new and modified content | ~400 |
| #37390 | 12:47 AM | ✅ | Regenerated 23 CLAUDE.md files in budapest workspace | ~365 |
</claude-mem-context>
+187
View File
@@ -0,0 +1,187 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Nov 21, 2025
**cleanup-duplicates.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #13458 | 4:05 PM | 🔵 | Comments already document multiple observations per tool_use_id design | ~394 |
**restore-endless-mode.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #13229 | 1:36 PM | 🔵 | Dead Code Analysis: Deferred Transformation Experiment | ~613 |
| #13228 | 1:33 PM | 🔵 | Endless Mode Restoration CLI Tool | ~601 |
### Nov 22, 2025
**restore-endless-mode.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #14203 | 1:05 AM | 🔵 | Endless Mode Feature Branch Contains Major Additions | ~566 |
### Dec 5, 2025
**run.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #20355 | 6:49 PM | 🔵 | Runtime launcher added for dynamic Bun/Node selection | ~260 |
| #20290 | 6:06 PM | 🔵 | Runtime Launcher Script for Dynamic Execution | ~269 |
| #20140 | 4:08 PM | 🔄 | Eliminated code duplication in run.ts by importing from runtime.ts | ~376 |
| #20135 | 4:03 PM | ⚖️ | Proposed Refactoring: 77% Code Reduction While Maintaining Functionality | ~411 |
| #20133 | 4:02 PM | ⚖️ | Runtime Implementation Analysis: Four Categories of Issues Identified | ~406 |
| #20130 | " | ⚖️ | Code Duplication Deemed Unnecessary Due to Bundling | ~359 |
| #20127 | 4:01 PM | 🔵 | Dual Purpose Runtime System Revealed | ~335 |
| #20126 | " | 🔵 | Invalid Justification for Duplication Analysis | ~295 |
| #20125 | " | 🔵 | Code Duplication Issue in Runtime Implementation | ~317 |
| #20123 | " | 🔵 | Source TypeScript Runtime Launcher Implementation | ~313 |
| #20120 | 3:58 PM | 🔵 | PR 169 Changes Overview | ~314 |
| #20110 | 3:55 PM | 🔵 | PR 169 adds Bun runtime support with automatic detection | ~461 |
### Dec 8, 2025
**restore-endless-mode.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #21893 | 3:30 PM | 🔵 | Endless Mode Transcript Restoration CLI Tool | ~345 |
### Dec 9, 2025
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #22929 | 3:04 PM | ⚖️ | Silent Failure Pattern Conversion Strategy | ~471 |
| #22928 | 3:03 PM | 🔵 | Silent Failure Pattern Audit Results | ~372 |
| #22927 | 3:01 PM | 🔵 | Silent Failure Pattern Detection Across Codebase | ~352 |
### Dec 10, 2025
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23755 | 9:05 PM | 🔵 | Import XML Observations Utility Uses SessionStore Directly | ~280 |
**cleanup-duplicates.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23754 | 9:05 PM | 🔵 | Cleanup Duplicates Utility Uses SessionStore Directly | ~234 |
### Dec 11, 2025
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23959 | 1:58 PM | 🔵 | TypeScript Codebase Architecture Mapped | ~337 |
### Dec 13, 2025
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #25321 | 9:12 PM | 🔵 | Console.error Usage Found in 29 Files | ~366 |
### Dec 16, 2025
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #27502 | 4:19 PM | 🔵 | Observation Storage Architecture Located | ~403 |
### Dec 18, 2025
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29773 | 7:01 PM | 🔵 | Observation Type Definitions Across Codebase | ~362 |
### Dec 19, 2025
**cleanup-duplicates.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29926 | 6:25 PM | 🔵 | cleanup-duplicates.ts Only Deletes From SQLite, Not Chroma | ~340 |
### Dec 21, 2025
**cleanup-duplicates.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31603 | 8:21 PM | 🔵 | Complete Console.* Statement Audit Across Codebase | ~813 |
| #31599 | 8:19 PM | 🔵 | 136 console logging statements found in TypeScript source files | ~538 |
### Dec 24, 2025
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32184 | 7:20 PM | 🔄 | Direct SQL replaced method call for SDK session ID update | ~259 |
| #32183 | " | 🔄 | Simplified database update in XML import script | ~254 |
| #32100 | 5:08 PM | 🔵 | storeObservation method usage spans three TypeScript files | ~237 |
### Dec 25, 2025
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32558 | 8:18 PM | 🔵 | Identified files containing 'summary' or 'Summary' | ~167 |
| #32456 | 5:41 PM | ✅ | Completed merge of main branch into feature/titans-phase1-3 | ~354 |
### Dec 27, 2025
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33082 | 6:45 PM | 🔵 | User directory path patterns in codebase | ~362 |
### Dec 28, 2025
**cleanup-duplicates.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33636 | 11:35 PM | ✅ | Major Documentation and Code Cleanup Removed 4,929 Lines | ~381 |
| #33590 | 11:11 PM | 🔵 | Database Migration Renamed sdk_session_id to memory_session_id | ~387 |
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33439 | 10:15 PM | 🔄 | Extended Session ID Renaming to Additional Codebase Components | ~352 |
### Dec 29, 2025
**cleanup-duplicates.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33675 | 12:02 AM | 🔄 | Major Documentation and Code Cleanup in MCP Clarity Branch | ~491 |
### Jan 1, 2026
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35553 | 9:50 PM | 🔵 | storeObservation method usage across codebase | ~315 |
| #35515 | 9:14 PM | ✅ | Wave 1 Extended Fixes Committed: 5 Critical Error Handling Issues Resolved | ~409 |
| #35501 | 9:10 PM | 🔵 | Wave 1 Verification Issue: Anti-Pattern Detector Not Recognizing Fixes | ~497 |
| #35500 | 9:09 PM | 🟣 | Wave 1 Complete: All 4 Empty Catch Blocks Fixed | ~511 |
| #35493 | 9:08 PM | 🔴 | Wave 1 Fix 1/4: XML Importer Empty Catch Block Fixed | ~392 |
| #35492 | " | ✅ | Wave 1 Fix 1/4: Added Logger Import to XML Importer | ~248 |
| #35488 | 9:07 PM | 🔵 | Wave 1 Target File: XML Observation Importer Structure | ~424 |
| #35485 | 9:06 PM | ⚖️ | Comprehensive error handling remediation plan completed and submitted for approval | ~555 |
| #35465 | 9:01 PM | 🔵 | Empty catch block in XML observations import script | ~281 |
### Jan 2, 2026
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35985 | 5:16 PM | 🔵 | Alignment logging implemented across session lifecycle touchpoints | ~377 |
### Jan 3, 2026
**import-xml-observations.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36296 | 8:04 PM | 🔵 | TypeScript Compilation Check: Pre-Existing Errors Unrelated to Refactoring | ~621 |
</claude-mem-context>
+36
View File
@@ -0,0 +1,36 @@
<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 |
|----|------|---|-------|------|
| #23825 | 11:12 PM | ✅ | Worker Port Set to 38888 for Migration Phase | ~283 |
| #23824 | " | 🔵 | Worker Port Sourced from getWorkerPort() Utility | ~247 |
| #23816 | 10:52 PM | 🟣 | Worker CLI Command Interface Created | ~325 |
### Dec 11, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24060 | 2:58 PM | 🔴 | Worker CLI Start Command Exit Behavior Fixed | ~232 |
### Dec 12, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #24359 | 7:00 PM | 🟣 | Phase 1 Critical Code Fixes Completed via Agent Task | ~441 |
| #24358 | 6:59 PM | ✅ | Completed Phase 1 Code Fixes for better-sqlite3 Migration | ~385 |
| #24348 | 6:57 PM | 🔴 | Added Defensive Break Statement to worker-cli.ts Restart Case | ~269 |
| #24345 | " | 🔵 | worker-cli.ts Missing Break Statement in Switch Case | ~318 |
### Dec 14, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #26766 | 11:30 PM | ⚖️ | Root Cause Identified: Missing Post-Install Worker Restart Trigger in Plugin Update Flow | ~604 |
| #26722 | 11:23 PM | 🔵 | Worker CLI TypeScript Source Shows Simple ProcessManager Delegation | ~394 |
| #26721 | " | 🔵 | Worker CLI Source Code Shows Simple Restart Logic Without Delays | ~425 |
</claude-mem-context>
+71
View File
@@ -0,0 +1,71 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Nov 25, 2025
**api.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #15545 | 8:37 PM | 🔵 | API Constants File Contains Single Comment Reference | ~227 |
### Dec 7, 2025
**observation-metadata.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #21685 | 9:48 PM | 🔵 | Configuration Defaults and Environment Variables | ~558 |
### Dec 9, 2025
**observation-metadata.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #22672 | 12:10 PM | 🔵 | Observation Type System with Six Types and Seven Concepts | ~505 |
### Dec 11, 2025
**observation-metadata.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23959 | 1:58 PM | 🔵 | TypeScript Codebase Architecture Mapped | ~337 |
### Dec 18, 2025
**observation-metadata.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29773 | 7:01 PM | 🔵 | Observation Type Definitions Across Codebase | ~362 |
| #29248 | 12:15 AM | ⚖️ | RAGTIME domain-agnostic architecture design for claude-mem | ~590 |
| #29229 | 12:08 AM | 🔵 | Claude-Mem Observation Type System Architecture Mapped | ~552 |
| #29220 | 12:04 AM | 🔵 | Observation Type and Concept Taxonomy | ~355 |
### Dec 21, 2025
**observation-metadata.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31747 | 10:43 PM | 🔵 | PR #412 Code Review Identifies Two Critical Bugs in Mode System | ~545 |
| #31433 | 6:58 PM | 🔄 | Simplified observation-metadata.ts to use hardcoded defaults | ~330 |
| #31429 | 6:57 PM | 🔄 | Removed unused emoji mapping constants from observation metadata | ~245 |
| #31423 | 6:50 PM | 🔵 | Observation Metadata Constants File Structure | ~327 |
| #31329 | 5:45 PM | 🔵 | Observation Metadata Integration Across Services and UI | ~403 |
| #31328 | " | 🔵 | Settings Defaults Manager Uses Observation Metadata Constants | ~286 |
| #31327 | " | 🔵 | Observation Metadata Constants - Core Type and Concept Definitions | ~369 |
### Dec 25, 2025
**observation-metadata.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32701 | 9:00 PM | 🔵 | Test Coverage Report Generated | ~471 |
### Jan 2, 2026
**observation-metadata.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35875 | 2:39 PM | 🔵 | Logging UI Architecture Mapped | ~599 |
| #35836 | 2:30 PM | 🔵 | Observation metadata constants for types and concepts | ~280 |
</claude-mem-context>
+95
View File
@@ -0,0 +1,95 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 9, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23126 | 6:40 PM | ✅ | Removed SKIP_TOOLS Check from saveHook Function | ~288 |
| #23125 | " | 🔵 | SKIP_TOOLS Reference Still Present in saveHook Function | ~224 |
| #23124 | " | ✅ | Removed SKIP_TOOLS Constant from save-hook.ts | ~297 |
| #23123 | 6:39 PM | 🔵 | Current SKIP_TOOLS Implementation in save-hook.ts | ~397 |
| #23122 | " | 🔴 | Hardened Spinner Stop Mechanism with Timeout and Logging | ~361 |
| #23121 | " | 🔵 | Current Spinner Stop Implementation in summary-hook.ts | ~348 |
| #23118 | 6:38 PM | ✅ | Phase 6: StopInput Interface Type Safety Restored | ~248 |
| #23117 | 6:37 PM | ✅ | Phase 6: PostToolUseInput Interface Type Safety Restored | ~222 |
| #23116 | " | ✅ | Phase 6: UserPromptSubmitInput Interface Type Safety Restored | ~216 |
| #23115 | " | ✅ | Phase 6: SessionStartInput Interface Type Safety Restored | ~341 |
| #23114 | " | 🔵 | Current State of context-hook.ts Interface | ~409 |
| #23113 | " | 🔵 | Current State of summary-hook.ts Interface and Spinner Stop | ~397 |
| #23112 | " | 🔵 | Current State of save-hook.ts Interface and SKIP_TOOLS | ~395 |
| #23111 | " | 🔵 | Current State of new-hook.ts Interface | ~381 |
| #23076 | 6:27 PM | ✅ | Added Comment Explaining Exit Code 3 in user-message-hook.ts | ~245 |
| #23075 | 6:26 PM | ✅ | Deleted Expired Announcement Code from user-message-hook.ts | ~354 |
| #23074 | " | ✅ | Replaced Verbose Manual Mode Help with Error in cleanup-hook.ts | ~222 |
| #23073 | " | ✅ | Removed cwd from cleanup-hook Debug Logging | ~177 |
| #23072 | " | ✅ | Simplified SessionEndInput Interface in cleanup-hook.ts | ~236 |
| #23071 | 6:25 PM | 🔵 | cleanup-hook.ts Has Over-Engineered Manual Mode Help (lines 36-47) | ~399 |
| #23070 | " | 🔵 | user-message-hook.ts Contains Expired Announcement Code (lines 31-70) | ~370 |
| #23045 | 4:41 PM | 🔵 | "What's the Point?" Audit: Hook Code Contains 50% Dead/Duplicated Logic | ~1458 |
| #23044 | 4:37 PM | 🔵 | Hook Architecture Audit: Purpose and Design Patterns | ~1032 |
| #22856 | 2:27 PM | ✅ | Replaced node_modules Check with Marker File in user-message-hook | ~324 |
| #22855 | " | 🔵 | Identified node_modules First-Run Check in user-message-hook | ~319 |
| #22825 | 2:06 PM | 🔄 | Removed Duplicate Session Initialization Call from New Hook | ~346 |
### Dec 10, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23407 | 2:14 PM | 🔵 | New Hook Implementation Structure | ~264 |
### Dec 13, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #25389 | 9:30 PM | 🔴 | Save Hook Error Logging Enhanced With Tool Context | ~361 |
| #25388 | " | 🔴 | New Hook Now Logs SDK Agent Start Errors | ~344 |
| #25387 | 9:29 PM | 🔴 | New Hook Now Logs Session Initialization Errors | ~350 |
| #25386 | " | 🔴 | Context Hook Now Logs Error Text Before Throwing | ~338 |
| #25385 | " | ✅ | Added Logger Import to New Hook | ~249 |
| #25384 | " | ✅ | Added Logger Import to Context Hook | ~223 |
| #25383 | " | 🔵 | New Hook Has Two Silent Failure Points | ~392 |
| #25382 | 9:28 PM | 🔵 | Save Hook Has Partial Error Logging | ~351 |
| #25381 | " | 🔵 | Summary Hook Has Partial Error Logging | ~345 |
| #25380 | " | 🔵 | Context Hook Silent Failure Pattern Confirmed | ~354 |
### Dec 14, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #26730 | 11:24 PM | 🔵 | Context Hook TypeScript Source Shows EnsureWorkerRunning as First Action | ~441 |
| #26729 | " | 🔵 | Context Hook TypeScript Source Calls ensureWorkerRunning Before API Requests | ~411 |
| #26260 | 8:32 PM | 🔵 | User Message Hook Calls Context Inject with colors=true Parameter | ~300 |
| #26244 | 8:29 PM | 🔵 | Context Hook Delegates to Worker API Context Endpoint | ~260 |
| #25692 | 4:24 PM | 🔵 | Summary hook extracts last user and assistant messages from transcript file before sending to worker | ~465 |
### Dec 17, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #28449 | 4:23 PM | 🔵 | New Hook Session Initialization Flow | ~385 |
### Dec 19, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30105 | 8:11 PM | 🔵 | Hook Response Utility Standardizes Hook Output Format | ~387 |
| #30103 | 8:10 PM | 🔵 | Context Hook Injects Mode-Based Memory Context During SessionStart | ~460 |
### Dec 20, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31085 | 7:59 PM | 🔵 | Summary Hook Uses session_id from Hook Input | ~315 |
### Dec 27, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33216 | 9:07 PM | 🔵 | UserPromptSubmit Hook (new-hook.ts) Initializes Session and Starts SDK Agent via Two HTTP Endpoints | ~735 |
| #33211 | 9:04 PM | 🔵 | User Message Hook Displays Context Info via stderr in Parallel with Context Injection | ~476 |
| #33210 | 9:03 PM | 🔵 | Summary Hook (summary-hook.ts) Extracts Messages and Triggers Summarization | ~479 |
| #33209 | " | 🔵 | SessionStart Hook (context-hook.ts) Fetches Context Injection via HTTP | ~520 |
</claude-mem-context>
+5 -3
View File
@@ -9,7 +9,7 @@
import { stdin } from "process";
import { ensureWorkerRunning, getWorkerPort } from "../shared/worker-utils.js";
import { HOOK_TIMEOUTS } from "../shared/hook-constants.js";
import { getProjectName } from "../utils/project-name.js";
import { getProjectContext } from "../utils/project-name.js";
import { logger } from "../utils/logger.js";
export interface SessionStartInput {
@@ -24,10 +24,12 @@ async function contextHook(input?: SessionStartInput): Promise<string> {
await ensureWorkerRunning();
const cwd = input?.cwd ?? process.cwd();
const project = getProjectName(cwd);
const context = getProjectContext(cwd);
const port = getWorkerPort();
const url = `http://127.0.0.1:${port}/api/context/inject?project=${encodeURIComponent(project)}`;
// Pass all projects (parent + worktree if applicable) for unified timeline
const projectsParam = context.allProjects.join(',');
const url = `http://127.0.0.1:${port}/api/context/inject?projects=${encodeURIComponent(projectsParam)}`;
// Note: Removed AbortSignal.timeout due to Windows Bun cleanup issue (libuv assertion)
// Worker service has its own timeouts, so client-side timeout is redundant
+12 -11
View File
@@ -24,12 +24,9 @@ async function newHook(input?: UserPromptSubmitInput): Promise<void> {
const { session_id, cwd, prompt } = input;
const project = getProjectName(cwd);
logger.info('HOOK', 'new-hook: Received hook input', { session_id, has_prompt: !!prompt, cwd });
const port = getWorkerPort();
logger.info('HOOK', 'new-hook: Calling /api/sessions/init', { contentSessionId: session_id, project, prompt_length: prompt?.length });
logger.debug('HOOK', 'new-hook: Calling /api/sessions/init', { contentSessionId: session_id, project });
// Initialize session via HTTP - handles DB operations and privacy checks
const initResponse = await fetch(`http://127.0.0.1:${port}/api/sessions/init`, {
@@ -51,25 +48,25 @@ async function newHook(input?: UserPromptSubmitInput): Promise<void> {
const sessionDbId = initResult.sessionDbId;
const promptNumber = initResult.promptNumber;
logger.info('HOOK', 'new-hook: Received from /api/sessions/init', { sessionDbId, promptNumber, skipped: initResult.skipped });
logger.debug('HOOK', 'new-hook: Received from /api/sessions/init', { sessionDbId, promptNumber, skipped: initResult.skipped });
// SESSION ALIGNMENT LOG: Entry point showing content session ID and prompt number
logger.info('HOOK', `[ALIGNMENT] Hook Entry | contentSessionId=${session_id} | prompt#=${promptNumber} | sessionDbId=${sessionDbId}`);
// Debug-level alignment log for detailed tracing
logger.debug('HOOK', `[ALIGNMENT] Hook Entry | contentSessionId=${session_id} | prompt#=${promptNumber} | sessionDbId=${sessionDbId}`);
// Check if prompt was entirely private (worker performs privacy check)
if (initResult.skipped && initResult.reason === 'private') {
logger.info('HOOK', `new-hook: Session ${sessionDbId}, prompt #${promptNumber} (fully private - skipped)`);
logger.info('HOOK', `INIT_COMPLETE | sessionDbId=${sessionDbId} | promptNumber=${promptNumber} | skipped=true | reason=private`, {
sessionId: sessionDbId
});
console.log(STANDARD_HOOK_RESPONSE);
return;
}
logger.info('HOOK', `new-hook: Session ${sessionDbId}, prompt #${promptNumber}`);
// Strip leading slash from commands for memory agent
// /review 101 → review 101 (more semantic for observations)
const cleanedPrompt = prompt.startsWith('/') ? prompt.substring(1) : prompt;
logger.info('HOOK', 'new-hook: Calling /sessions/{sessionDbId}/init', { sessionDbId, promptNumber, userPrompt_length: cleanedPrompt?.length });
logger.debug('HOOK', 'new-hook: Calling /sessions/{sessionDbId}/init', { sessionDbId, promptNumber });
// Initialize SDK agent session via HTTP (starts the agent!)
const response = await fetch(`http://127.0.0.1:${port}/sessions/${sessionDbId}/init`, {
@@ -83,6 +80,10 @@ async function newHook(input?: UserPromptSubmitInput): Promise<void> {
throw new Error(`SDK agent start failed: ${response.status}`);
}
logger.info('HOOK', `INIT_COMPLETE | sessionDbId=${sessionDbId} | promptNumber=${promptNumber} | project=${project}`, {
sessionId: sessionDbId
});
console.log(STANDARD_HOOK_RESPONSE);
}
+141
View File
@@ -0,0 +1,141 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 22, 2025
**SDKAgent.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31951 | 8:17 PM | 🟣 | Mode System with Inheritance and Multilingual Support | ~776 |
**prompts.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31891 | 7:17 PM | 🔴 | Migration des prompts de résumé vers les fichiers de modes pour le support multilingue | ~474 |
| #31890 | " | 🔵 | Modifications en cours sur les fichiers de modes multilingues et le système de prompts | ~325 |
| #31872 | 7:04 PM | 🔄 | Externalisation des prompts de résumé codés en dur | ~378 |
| #31868 | 7:03 PM | 🔵 | サマリープロンプトのハードコーディング箇所の特定 | ~193 |
| #31829 | 6:28 PM | 🔄 | Removed languageNote usage from continuation observation XML template | ~90 |
| #31828 | " | 🔄 | Removed languageNote variable from buildContinuationPrompt | ~199 |
| #31827 | " | 🔄 | Removed languageNote usage from summary XML template | ~79 |
| #31826 | " | 🔄 | Removed unused languageNote variable from buildSummaryPrompt | ~198 |
| #31825 | 6:26 PM | 🔄 | Removed unused languageNote variable from buildInitPrompt | ~278 |
| #31820 | 6:20 PM | 🔵 | Prompts system architecture uses mode.prompts.format_examples field | ~305 |
| #31816 | 6:10 PM | 🔄 | Extracted memory continuation header to mode configuration | ~236 |
| #31815 | 6:09 PM | 🔄 | Extracted continuation instruction to mode configuration | ~252 |
| #31814 | " | 🔄 | Extracted continuation greeting to mode configuration | ~306 |
| #31813 | 6:08 PM | 🔄 | Removed hardcoded language instruction from buildSummaryPrompt | ~291 |
| #31812 | " | 🔄 | Replaced all XML placeholder text with mode configuration variables | ~459 |
| #31811 | " | 🔄 | Replaced hardcoded memory processing header with mode variable | ~252 |
**parser.test.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31855 | 6:53 PM | ✅ | テストスイートの大規模削除とテスト分析レポートの追加 | ~197 |
### Dec 23, 2025
**prompts.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32030 | 7:44 PM | 🔵 | SDK prompt building system uses mode configuration | ~330 |
**parser.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32029 | 7:40 PM | 🔵 | Parser Layer Has No Skip Logic - Always Saves Observations | ~342 |
### Dec 24, 2025
**prompts.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32213 | 8:17 PM | 🔵 | Prompt Generation System Architecture | ~402 |
| #32337 | 4:03 PM | ✅ | Enhanced observation prompt with granularity reminder | ~278 |
### Dec 25, 2025
**parser.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32701 | 9:00 PM | 🔵 | Test Coverage Report Generated | ~471 |
| #32565 | 8:19 PM | 🔵 | Read parser.ts (first 150 lines) | ~146 |
**prompts.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32558 | 8:18 PM | 🔵 | Identified files containing 'summary' or 'Summary' | ~167 |
### Dec 27, 2025
**prompts.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33131 | 7:52 PM | 🔵 | Session ID Propagation Flow Analysis with Architectural Vulnerabilities Identified | ~577 |
| #33129 | " | 🔵 | Prompt Building Functions with Session ID Threading Documentation | ~483 |
### Dec 28, 2025
**prompts.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33438 | 10:15 PM | 🔄 | Bulk Rename Session ID Fields Across Entire Codebase | ~384 |
| #33420 | 10:06 PM | 🔵 | Complete session ID flow analysis reveals missing SDK session capture mechanism | ~545 |
| #33415 | 10:05 PM | 🔵 | Prompt building functions receive sessionId but only use it for context display | ~372 |
| #33316 | 3:09 PM | 🔴 | Fixed Disconnected SDK Agent Sessions | ~350 |
| #33296 | 3:08 PM | 🔵 | Session ID Propagation Flow Architecture Traced Through Codebase | ~720 |
### Dec 30, 2025
**parser.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34462 | 2:23 PM | 🔵 | Code Quality Review Identifies Critical V2 Migration Issues | ~418 |
**prompts.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34398 | 1:53 PM | 🔵 | SDK Prompts Module Structure | ~361 |
### Jan 1, 2026
**prompts.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35666 | 11:37 PM | ✅ | Staged error handling improvements across 10 files | ~261 |
| #35641 | 11:27 PM | ✅ | Added APPROVED OVERRIDE comments for JSON parse error handling in SDK prompts | ~336 |
### Jan 2, 2026
**prompts.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35901 | 2:49 PM | 🔵 | PR #525 File Changes Summary | ~376 |
| #35770 | 1:23 PM | ✅ | Last User Message Field Removed Across 11 Files in Codebase | ~374 |
| #35763 | 1:22 PM | 🔄 | Removed last_user_message from SDKSession interface | ~241 |
| #35762 | 1:21 PM | 🔵 | SDKSession interface includes last_user_message field | ~221 |
| #35742 | 1:15 PM | 🔵 | SDKSession interface defines both user_prompt and last_user_message fields | ~289 |
| #35738 | 1:12 PM | 🔵 | Summary prompt uses last_assistant_message but not last_user_message | ~334 |
| #35737 | " | 🔵 | Summary Prompt Interface Defines Optional last_user_message | ~253 |
| #35736 | " | 🔵 | SDKSession Interface Defines Optional last_user_message Field | ~277 |
| #35733 | 1:11 PM | 🔵 | Located last_user_message usage across codebase | ~333 |
### Jan 3, 2026
**parser.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36200 | 7:22 PM | 🔵 | Parser Module Analysis for Phase 2 Refactoring | ~562 |
### Jan 5, 2026
**prompts.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37613 | 5:31 PM | 🔵 | PR #558 Review Feedback Analysis | ~544 |
| #37571 | 4:51 PM | ✅ | Phase 1 Anti-Pattern Check Complete - Clean Implementation | ~400 |
| #37557 | 4:49 PM | 🔵 | Issue #545 Bug Location and Fix Pattern Documented | ~462 |
| #37539 | 4:45 PM | 🔵 | SDK Defensive JSON Parsing Pattern Implementation | ~408 |
</claude-mem-context>
+100
View File
@@ -0,0 +1,100 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Nov 6, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #4185 | 10:25 PM | 🔴 | Prefixed unused id parameters with underscore in filter callbacks | ~299 |
### Nov 8, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #5539 | 10:20 PM | 🔵 | Harsh critical audit of context-hook reveals systematic anti-patterns | ~3154 |
| #5497 | 9:29 PM | 🔵 | Harsh critical audit of context-hook reveals systematic anti-patterns | ~2815 |
### Nov 9, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #5757 | 5:16 PM | 🔵 | MCP search server exposes 9 tools consuming ~2,000-3,000 tokens per session | ~421 |
| #5754 | 5:14 PM | 🔵 | MCP search server provides 9 search tools with hybrid semantic/FTS5 | ~402 |
### Nov 10, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #6250 | 12:54 PM | 🔵 | MCP Search Server Connection Failure Reported | ~329 |
### Nov 17, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #10744 | 11:47 PM | ✅ | Search Query Parameter Made Optional for Filter-Only Queries | ~373 |
| #10572 | 7:47 PM | 🟣 | Unified cross-type search with search_everything tool | ~501 |
| #10571 | 7:46 PM | 🔵 | Search server architecture and hybrid search implementation | ~553 |
### Nov 18, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #11462 | 7:55 PM | 🔵 | Ready to Apply Fix to Contextualize Handler | ~261 |
| #11460 | " | 🔴 | Identified Root Cause of Contextualize Endpoint Bug | ~413 |
| #11454 | 7:54 PM | 🔵 | Unified Search Handler Shows Correct Pattern for Filter-Only Queries | ~334 |
| #11447 | " | 🔵 | Contextualize Handler Calls Search Methods with Query='*' | ~279 |
| #11432 | 7:52 PM | 🔵 | Contextualize Handler Formats Results with Sections | ~286 |
| #11431 | 7:51 PM | 🔵 | Confirmed Empty Results Trigger in Contextualize Handler | ~289 |
| #11430 | " | 🔵 | Contextualize Handler Implementation Uses Search Methods | ~424 |
| #11429 | " | 🔵 | Search Server Defines Six Main Search Tools | ~358 |
| #11428 | " | 🔵 | Contextualize Tool Definition Found in Search Server | ~357 |
| #11332 | 3:55 PM | 🔵 | Comprehensive FTS5 Removal Audit Completed for Architecture Migration | ~792 |
| #11206 | 3:01 PM | 🔵 | mem-search skill architecture and migration details retrieved in full format | ~538 |
| #11181 | 4:09 AM | 🔵 | Store methods for ID-based lookups exist but not exposed as MCP tools | ~495 |
| #11013 | 2:12 AM | 🔵 | Search Server Implements Three-Path Query Strategy with ChromaDB Primary and FTS5 Fallback | ~462 |
### Nov 28, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #16711 | 4:34 PM | 🟣 | include_inactive Parameter Extracted in Search Handler | ~369 |
| #16710 | " | 🔵 | Search Tool Schema Definition with Type and Filter Parameters | ~527 |
| #16708 | " | 🔵 | Search Server MCP Tool Architecture and ChromaDB Integration | ~491 |
| #16682 | 4:10 PM | 🔵 | Comprehensive Exploration Task Completed on Observation System | ~601 |
### Dec 14, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #26238 | 8:28 PM | 🔵 | MCP Server Architecture Maps Tools to Worker API Endpoints | ~355 |
| #26138 | 7:55 PM | ✅ | Updated Comment to Reference progressive_description Tool | ~238 |
| #26137 | " | ✅ | Completed Tool Description Minimization - All 9 Tools Updated | ~335 |
| #26136 | " | ✅ | Minimized Get Session Tool Description | ~218 |
| #26135 | " | ✅ | Minimized Get Batch Observations Tool Description | ~258 |
| #26134 | " | ✅ | Minimized Get Observation Tool Description | ~228 |
| #26133 | " | ✅ | Minimized Get Context Timeline Tool Description | ~245 |
| #26132 | 7:54 PM | ✅ | Minimized Get Recent Context Tool Description | ~214 |
| #26131 | " | ✅ | Minimized Timeline Tool Description | ~232 |
| #26130 | " | ✅ | Minimized Search Tool Description | ~235 |
| #26129 | " | ✅ | Renamed progressive_ix Tool to progressive_description with Minimized Description | ~296 |
| #26128 | " | ✅ | Renamed Tool Endpoint Mapping from progressive_ix to progressive_description | ~229 |
| #26127 | " | ✅ | Completed Format Parameter Removal from All Four MCP Tools | ~318 |
| #26126 | 7:53 PM | ✅ | Removed Format Parameter from Get Recent Context Tool Schema | ~244 |
| #26125 | " | ✅ | Removed Format Parameter from Timeline Tool Schema | ~248 |
| #26124 | " | ✅ | Removed Format Parameter from Search Tool Schema | ~283 |
| #26123 | " | 🔵 | Current MCP Server Tool Schema Analysis | ~337 |
| #25815 | 5:31 PM | 🔵 | Comprehensive MCP Server and SKILL.md Structure Analysis | ~575 |
| #25807 | 5:30 PM | 🔵 | MCP Server Architecture with 14 HTTP-Delegating Tools | ~545 |
| #25788 | 5:15 PM | 🔵 | MCP Server Capabilities and Request Handlers | ~256 |
### Dec 17, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29078 | 10:16 PM | ✅ | Updated get_recent_context tool schema to accept dynamic parameters | ~318 |
| #29077 | 10:15 PM | ✅ | Updated timeline tool schema to accept dynamic parameters | ~292 |
| #29076 | " | ✅ | Updated search tool schema to accept dynamic parameters | ~315 |
| #28923 | 7:28 PM | 🔵 | MCP Server Architecture: Thin HTTP Wrapper Pattern | ~402 |
</claude-mem-context>
+63
View File
@@ -0,0 +1,63 @@
<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 |
|----|------|---|-------|------|
| #23832 | 11:15 PM | 🔵 | Current worker-service.ts Lacks Admin Endpoints | ~393 |
### Dec 14, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #26740 | 11:26 PM | 🔵 | Worker Service Refactored to Orchestrator with Background Initialization | ~421 |
| #26739 | 11:25 PM | 🔵 | Worker Service Architecture Uses Domain Services and Background Initialization | ~438 |
| #26255 | 8:31 PM | 🔵 | Context Generator Timeline Rendering Logic Details File Grouping Implementation | ~397 |
| #26251 | 8:30 PM | 🔵 | Worker Service Orchestrates Domain Services and Route Handlers | ~292 |
| #26246 | 8:29 PM | 🔵 | Context Generator Implements Rich Date-Grouped Timeline Format | ~468 |
### Dec 17, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #28548 | 4:49 PM | 🔵 | Worker service cleanup method uses Unix-specific process management | ~323 |
| #28446 | 4:23 PM | 🔵 | Worker Service Refactored to Orchestrator Pattern | ~529 |
### Dec 18, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29340 | 3:11 PM | ✅ | Constructor Initialization Comment Updated | ~267 |
| #29339 | " | ✅ | Class Member Comment Updated in WorkerService | ~267 |
| #29338 | " | ✅ | Service Import Comment Updated | ~222 |
| #29337 | 3:10 PM | ✅ | Terminology Update in Worker Service Documentation | ~268 |
| #29239 | 12:11 AM | 🔵 | Worker Service Refactored as Domain-Driven Orchestrator | ~477 |
### Dec 20, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #30808 | 6:05 PM | 🔴 | Fixed worker readiness check to fail on initialization errors | ~315 |
| #30800 | 6:03 PM | 🔵 | Dual Error Logging in Background Initialization | ~367 |
| #30799 | " | 🔵 | Background Initialization Invocation Pattern | ~365 |
| #30797 | " | 🔵 | Background Initialization Sequence and Error Handler Confirmed | ~450 |
| #30795 | 6:02 PM | 🔵 | Readiness Endpoint Returns 503 During Initialization | ~397 |
| #30793 | " | 🔵 | Dual Initialization State Tracking Pattern | ~388 |
| #30791 | " | 🔵 | Worker Service Constructor Defers SearchRoutes Initialization | ~387 |
| #30790 | " | 🔵 | Initialization Promise Resolver Pattern Located | ~321 |
| #30788 | " | 🔵 | Worker Service Initialization Resolves Promise Despite Errors | ~388 |
### Jan 1, 2026
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35654 | 11:29 PM | ✅ | Added APPROVED OVERRIDE annotation for instruction loading HTTP route error handler | ~339 |
| #35651 | 11:28 PM | ✅ | Added APPROVED OVERRIDE annotation for shutdown error handler with process.exit | ~354 |
| #35649 | " | ✅ | Added APPROVED OVERRIDE annotation for readiness check retry loop error handling | ~374 |
| #35647 | " | ✅ | Added APPROVED OVERRIDE annotation for port availability probe error handling | ~327 |
| #35646 | " | ✅ | Added APPROVED OVERRIDE annotation for Cursor context file update error handling | ~342 |
| #35643 | 11:27 PM | ✅ | Added APPROVED OVERRIDE annotation for PID file cleanup error handling | ~320 |
</claude-mem-context>
+7
View File
@@ -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>
+12 -3
View File
@@ -17,7 +17,9 @@ import { loadContextConfig } from './ContextConfigLoader.js';
import { calculateTokenEconomics } from './TokenCalculator.js';
import {
queryObservations,
queryObservationsMulti,
querySummaries,
querySummariesMulti,
getPriorSessionMessages,
prepareSummariesForTimeline,
buildTimeline,
@@ -129,6 +131,9 @@ export async function generateContext(
const cwd = input?.cwd ?? process.cwd();
const project = getProjectName(cwd);
// Use provided projects array (for worktree support) or fall back to single project
const projects = input?.projects || [project];
// Initialize database
const db = initializeDatabase();
if (!db) {
@@ -136,9 +141,13 @@ export async function generateContext(
}
try {
// Query data
const observations = queryObservations(db, project, config);
const summaries = querySummaries(db, project, config);
// Query data for all projects (supports worktree: parent + worktree combined)
const observations = projects.length > 1
? queryObservationsMulti(db, projects, config)
: queryObservations(db, project, config);
const summaries = projects.length > 1
? querySummariesMulti(db, projects, config)
: querySummaries(db, project, config);
// Handle empty state
if (observations.length === 0 && summaries.length === 0) {
@@ -66,6 +66,65 @@ export function querySummaries(
`).all(project, config.sessionCount + SUMMARY_LOOKAHEAD) as SessionSummary[];
}
/**
* Query observations from multiple projects (for worktree support)
*
* Returns observations from all specified projects, interleaved chronologically.
* Used when running in a worktree to show both parent repo and worktree observations.
*/
export function queryObservationsMulti(
db: SessionStore,
projects: string[],
config: ContextConfig
): Observation[] {
const typeArray = Array.from(config.observationTypes);
const typePlaceholders = typeArray.map(() => '?').join(',');
const conceptArray = Array.from(config.observationConcepts);
const conceptPlaceholders = conceptArray.map(() => '?').join(',');
// Build IN clause for projects
const projectPlaceholders = projects.map(() => '?').join(',');
return db.db.prepare(`
SELECT
id, memory_session_id, type, title, subtitle, narrative,
facts, concepts, files_read, files_modified, discovery_tokens,
created_at, created_at_epoch, project
FROM observations
WHERE project IN (${projectPlaceholders})
AND type IN (${typePlaceholders})
AND EXISTS (
SELECT 1 FROM json_each(concepts)
WHERE value IN (${conceptPlaceholders})
)
ORDER BY created_at_epoch DESC
LIMIT ?
`).all(...projects, ...typeArray, ...conceptArray, config.totalObservationCount) as Observation[];
}
/**
* Query session summaries from multiple projects (for worktree support)
*
* Returns summaries from all specified projects, interleaved chronologically.
* Used when running in a worktree to show both parent repo and worktree summaries.
*/
export function querySummariesMulti(
db: SessionStore,
projects: string[],
config: ContextConfig
): SessionSummary[] {
// Build IN clause for projects
const projectPlaceholders = projects.map(() => '?').join(',');
return db.db.prepare(`
SELECT id, memory_session_id, request, investigated, learned, completed, next_steps, created_at, created_at_epoch, project
FROM session_summaries
WHERE project IN (${projectPlaceholders})
ORDER BY created_at_epoch DESC
LIMIT ?
`).all(...projects, config.sessionCount + SUMMARY_LOOKAHEAD) as SessionSummary[];
}
/**
* Convert cwd path to dashed format for transcript lookup
*/
@@ -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>
+26
View File
@@ -0,0 +1,26 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 3, 2026
**FooterRenderer.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
| #36283 | 8:02 PM | 🔄 | Phase 4: FooterRenderer Extracted with Conditional Display Logic | ~464 |
**TimelineRenderer.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36292 | 8:04 PM | 🔄 | Phase 4 Module Inventory: 12 Files Created in Context Architecture | ~571 |
| #36281 | 8:01 PM | 🔄 | Phase 4: TimelineRenderer Extracted with Dual Format Support | ~531 |
### Jan 5, 2026
**FooterRenderer.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37545 | 4:47 PM | ✅ | Issue #544 Analysis Report Created for mem-search Skill Messaging Problem | ~480 |
</claude-mem-context>
@@ -93,7 +93,7 @@ export function renderDayTimeline(
}
} else {
const obs = item.data as Observation;
const file = extractFirstFile(obs.files_modified, cwd);
const file = extractFirstFile(obs.files_modified, cwd, obs.files_read);
const time = formatTime(obs.created_at);
const showTime = time !== lastTime;
const timeDisplay = showTime ? time : '';
+6
View File
@@ -11,6 +11,8 @@ export interface ContextInput {
cwd?: string;
hook_event_name?: string;
source?: "startup" | "resume" | "clear" | "compact";
/** Array of projects to query (for worktree support: [parent, worktree]) */
projects?: string[];
[key: string]: any;
}
@@ -56,6 +58,8 @@ export interface Observation {
discovery_tokens: number | null;
created_at: string;
created_at_epoch: number;
/** Project this observation belongs to (for multi-project queries) */
project?: string;
}
/**
@@ -71,6 +75,8 @@ export interface SessionSummary {
next_steps: string | null;
created_at: string;
created_at_epoch: number;
/** Project this summary belongs to (for multi-project queries) */
project?: string;
}
/**
+127
View File
@@ -0,0 +1,127 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 21, 2025
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31766 | 11:11 PM | 🟣 | Expansión de ModePrompts con campos de configuración granular | ~327 |
| #31765 | 11:10 PM | 🔵 | Sistema de configuración de modos con interfaces TypeScript | ~321 |
| #31764 | 11:09 PM | ⚖️ | Consulta arquitectónica con Gemini sobre reconstrucción completa de prompts por modos | ~469 |
| #31704 | 9:37 PM | 🔵 | Mode system architecture discovered in claude-mem | ~457 |
| #31428 | 6:56 PM | 🔵 | Domain Types Define Observation System Interfaces | ~292 |
**ModeManager.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31747 | 10:43 PM | 🔵 | PR #412 Code Review Identifies Two Critical Bugs in Mode System | ~545 |
| #31746 | 10:42 PM | 🔵 | PR #412 Documentation Audit Identifies Comment Quality Issues | ~535 |
| #31743 | 10:36 PM | 🔵 | PR #412 proposes mode system with inheritance and multilingual support | ~523 |
| #31739 | 10:28 PM | 🟣 | Mode Inheritance System with Parent-Override Pattern | ~373 |
| #31732 | 10:05 PM | 🟣 | Implemented mode inheritance system with parent-override pattern | ~430 |
| #31731 | " | 🟣 | Added deep merge infrastructure for mode inheritance | ~313 |
| #31729 | 9:55 PM | 🟣 | Mode Inheritance Parser Implementation | ~299 |
| #31728 | 9:54 PM | 🔵 | ModeManager System Architecture | ~314 |
| #31727 | " | ⚖️ | Mode Inheritance System for Multilingual Support | ~509 |
| #31725 | 9:51 PM | ⚖️ | Mode Inheritance System Architecture | ~509 |
| #31709 | 9:39 PM | 🔵 | Mode system architecture comprehensively documented | ~588 |
| #31697 | 9:24 PM | 🔵 | Root Cause Found: getPackageRoot() Returns Wrong Directory for ModeManager | ~399 |
| #31662 | 8:56 PM | 🔵 | ModeManager Path Resolution Dependency on getPackageRoot | ~361 |
| #31649 | 8:46 PM | 🟣 | ModeManager singleton implements dynamic mode profile loading | ~363 |
| #31446 | 7:22 PM | 🔵 | ModeManager Loading System Investigation | ~297 |
| #31445 | 7:21 PM | 🔵 | ModeManager Icon Resolution Methods | ~358 |
| #31427 | 6:56 PM | 🔵 | ModeManager Imports ObservationType and ObservationConcept Types | ~192 |
| #31422 | 6:50 PM | 🔵 | Observation Metadata Constants Usage Across Codebase | ~366 |
| #31407 | 6:26 PM | 🔵 | ModeManager provides observation type metadata access methods | ~283 |
### Dec 22, 2025
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31896 | 7:18 PM | ✅ | Commit amendé avec les nouveaux types pour support multilingue des résumés | ~290 |
| #31895 | " | 🟣 | Ajout de quatre champs de prompts de résumé à l'interface ModePrompts | ~347 |
| #31894 | " | 🔵 | Interface ModePrompts contient les placeholders XML pour résumés | ~354 |
| #31808 | 6:07 PM | 🟣 | Added customizable XML placeholder fields to ModePrompts interface | ~432 |
| #31804 | 4:53 PM | ⚖️ | Refined scope for prompt placeholder extraction to mode configuration | ~439 |
| #31803 | 4:52 PM | 🔵 | Explored prompt system architecture for placeholder customization | ~472 |
| #31800 | 4:51 PM | ⚖️ | Initiated design task to extract hardcoded placeholders into mode configuration | ~441 |
| #31797 | 4:49 PM | 🔵 | ModePrompts interface defines high-level prompt sections but not field placeholders | ~364 |
| #31793 | 4:41 PM | 🔵 | Completed comprehensive exploration of mode system architecture | ~525 |
| #31784 | 4:37 PM | 🔵 | Examined ModeConfig type definitions for prompt customization | ~317 |
**ModeManager.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31790 | 4:39 PM | 🔵 | Identified files that interact with ModeManager and prompts | ~332 |
| #31785 | 4:37 PM | 🔵 | Examined ModeManager for mode loading and inheritance system | ~286 |
### Dec 23, 2025
**ModeManager.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32033 | 7:50 PM | ⚖️ | Mode-to-Settings Auto-Sync Architecture Designed | ~583 |
| #32032 | 7:45 PM | 🔵 | Queue System Bug: Mode Loaded Once at Startup Prevents Processing | ~450 |
| #32026 | 7:39 PM | 🔵 | Email Investigation Mode Configuration Located | ~300 |
| #32025 | 7:35 PM | 🔵 | ModeManager Implementation with Inheritance System | ~474 |
### Dec 24, 2025
**ModeManager.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32214 | 8:17 PM | 🔵 | ModeManager singleton handles mode profiles with inheritance support | ~483 |
### Dec 25, 2025
**ModeManager.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32701 | 9:00 PM | 🔵 | Test Coverage Report Generated | ~471 |
| #32580 | 8:22 PM | 🔵 | Grep for resetStuckMessages and processing | ~242 |
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32558 | 8:18 PM | 🔵 | Identified files containing 'summary' or 'Summary' | ~167 |
### Dec 31, 2025
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34631 | 3:02 PM | 🟣 | Context-Preservation Workflow Design Documents Created | ~729 |
| #34610 | 2:58 PM | 🔵 | Mode Configuration System Architecture for Memory Agent Behavior | ~570 |
### Jan 1, 2026
**ModeManager.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35433 | 8:43 PM | 🔵 | Try-Catch Block Distribution Across Services | ~372 |
### Jan 2, 2026
**ModeManager.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35951 | 4:42 PM | 🔵 | Multi-Layer Service Architecture Discovery | ~395 |
### Jan 3, 2026
**ModeManager.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36539 | 9:39 PM | 🔵 | ModeManager Singleton Pattern with Inheritance | ~343 |
### Jan 5, 2026
**ModeManager.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37665 | 5:52 PM | 🔵 | Codebase uses dependency injection and lazy initialization patterns to avoid circular dependencies | ~548 |
</claude-mem-context>
+37
View File
@@ -0,0 +1,37 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 4, 2026
**FolderDiscovery.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37021 | 4:59 PM | ✅ | Deleted Redundant Folder Index Service Directory | ~299 |
| #37011 | 4:50 PM | 🔵 | FolderDiscovery extracts folders from observations and applies depth, exclusion, and activity filters | ~433 |
**ClaudeMdGenerator.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37012 | 4:51 PM | 🔵 | ClaudeMdGenerator writes tag-wrapped timeline markdown while preserving manual content | ~446 |
| #36981 | 4:25 PM | 🔵 | ClaudeMdGenerator creates and updates CLAUDE.md files with timeline content | ~336 |
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37010 | 4:50 PM | 🔵 | Type definitions specify folder-index configuration schema and timeline data structures | ~349 |
**FolderTimelineCompiler.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37009 | 4:50 PM | 🔵 | FolderTimelineCompiler queries database and groups activity chronologically by date | ~419 |
| #37002 | 4:45 PM | 🔴 | Fixed session file deduplication and summary selection in FolderTimelineCompiler | ~306 |
| #37001 | " | 🔴 | Fixed FolderTimelineCompiler to generate concise summaries and deduplicate files | ~284 |
**FolderIndexOrchestrator.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37008 | 4:50 PM | 🔵 | FolderIndexOrchestrator implements event-driven regeneration triggered by observation saves | ~418 |
| #36983 | 4:26 PM | 🔵 | FolderIndexOrchestrator coordinates automatic CLAUDE.md regeneration after observation saves | ~367 |
</claude-mem-context>
+12
View File
@@ -0,0 +1,12 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 4, 2026
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36864 | 1:52 AM | 🔵 | ProcessManager Module Imports Reviewed | ~245 |
| #36860 | 1:50 AM | 🔵 | ProcessManager Source Code Reviewed for WMIC Implementation | ~608 |
</claude-mem-context>
+7
View File
@@ -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>
+60
View File
@@ -0,0 +1,60 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 28, 2025
**SessionQueueProcessor.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33396 | 9:53 PM | ✅ | Queue refactoring touched 12 files with net addition of 1021 lines | ~402 |
| #33395 | " | 🟣 | Queue system refactored with atomic message processing | ~487 |
| #33374 | 7:12 PM | 🟣 | Refactored Queue System with Atomic Message Claiming and In-Memory State Elimination | ~477 |
| #33384 | " | 🔵 | Confirmed `SessionQueueProcessor` Integration in `SessionManager` | ~289 |
| #33387 | " | ⚖️ | Formulated Plan to Address PR #470 Review Issues | ~441 |
### Dec 30, 2025
**SessionQueueProcessor.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #34409 | 1:55 PM | 🔵 | SessionQueueProcessor Event-Driven Message Iteration | ~433 |
| #34391 | 1:40 PM | 🔵 | SessionQueueProcessor Respects Abort Signal But Only Stops Iterator Loop | ~382 |
### Jan 1, 2026
**SessionQueueProcessor.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35521 | 9:35 PM | 🔵 | Queue Processor Uses Database-Backed Message Store | ~316 |
| #35433 | 8:43 PM | 🔵 | Try-Catch Block Distribution Across Services | ~372 |
| #35432 | " | 🔵 | Services Directory Structure Mapped | ~268 |
### Jan 2, 2026
**SessionQueueProcessor.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35951 | 4:42 PM | 🔵 | Multi-Layer Service Architecture Discovery | ~395 |
| #35887 | 2:47 PM | 🔵 | SessionQueueProcessor Has Error Recovery But Doesn't Mark Failed | ~353 |
| #35851 | 2:32 PM | 🔵 | Queue Processor Uses Atomic Claiming with Event-Driven Wake-Up | ~464 |
### Jan 3, 2026
**SessionQueueProcessor.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36343 | 8:29 PM | 🔄 | SessionQueueProcessor Updated to Use claimAndDelete | ~299 |
| #36340 | 8:28 PM | 🔵 | Complete Duplicate Bug Analysis via Explore Agent | ~435 |
| #36323 | 8:25 PM | 🔵 | Message Queue Architecture Scope Expanded | ~302 |
| #36314 | " | 🔵 | Message Queue Processing Duplicate Bug Investigation | ~316 |
### Jan 4, 2026
**SessionQueueProcessor.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36713 | 12:11 AM | 🔵 | Issue #520 Stuck Messages Already Resolved | ~569 |
| #36711 | " | 🔵 | Issue #520 Stuck Messages Analysis - Already Resolved | ~526 |
</claude-mem-context>
+34
View File
@@ -0,0 +1,34 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 3, 2026
**Server.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36689 | 11:56 PM | 🔵 | PR #538 Review Findings - Modular Architecture Refactor | ~590 |
| #36583 | 9:57 PM | 🟣 | Server Test Suite Created | ~485 |
| #36427 | 8:59 PM | 🔵 | Server Class Architecture and Route Registration | ~447 |
**ErrorHandler.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36581 | 9:57 PM | 🟣 | ErrorHandler Test Suite Created for Phase 6 | ~444 |
| #36454 | 9:03 PM | 🔵 | Centralized Express Error Handling | ~446 |
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
**index.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36575 | 9:55 PM | 🔵 | Server Layer API Documentation for Phase 6 | ~521 |
### Jan 5, 2026
**Server.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37758 | 6:25 PM | ⚖️ | Integration Test Design for Four Critical Testing Gaps | ~729 |
| #37533 | 4:44 PM | 🔵 | Windows IPC Detection Logic and Managed Mode Handling | ~427 |
</claude-mem-context>
+95
View File
@@ -0,0 +1,95 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 8, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #22310 | 9:46 PM | 🟣 | Complete Hook Lifecycle Documentation Generated | ~603 |
| #22305 | 9:45 PM | 🔵 | Session Summary Storage and Status Lifecycle | ~472 |
| #22304 | " | 🔵 | Session Creation Idempotency and Observation Storage | ~481 |
| #22303 | " | 🔵 | SessionStore CRUD Operations for Hook Integration | ~392 |
| #22300 | 9:44 PM | 🔵 | SessionStore Database Management and Schema Migrations | ~455 |
| #22299 | " | 🔵 | Database Schema and Entity Types | ~460 |
| #21976 | 5:24 PM | 🟣 | storeObservation Saves tool_use_id to Database | ~298 |
### Dec 10, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #23808 | 10:42 PM | 🔵 | migrations.ts Already Migrated to bun:sqlite | ~312 |
| #23807 | " | 🔵 | SessionSearch.ts Already Migrated to bun:sqlite | ~321 |
| #23805 | " | 🔵 | Database.ts Already Migrated to bun:sqlite | ~290 |
| #23784 | 9:59 PM | ✅ | SessionStore.ts db.pragma() Converted to db.query().all() Pattern | ~198 |
| #23783 | 9:58 PM | ✅ | SessionStore.ts Migration004 Multi-Statement db.exec() Converted to db.run() | ~220 |
| #23782 | " | ✅ | SessionStore.ts initializeSchema() db.exec() Converted to db.run() | ~197 |
| #23781 | " | ✅ | SessionStore.ts Constructor PRAGMA Calls Converted to db.run() | ~215 |
| #23780 | " | ✅ | SessionStore.ts Type Annotation Updated | ~183 |
| #23779 | " | ✅ | SessionStore.ts Import Updated to bun:sqlite | ~237 |
| #23778 | 9:57 PM | ✅ | Database.ts Import Updated to bun:sqlite | ~177 |
| #23777 | " | 🔵 | SessionStore.ts Current Implementation - better-sqlite3 Import and API Usage | ~415 |
| #23776 | " | 🔵 | migrations.ts Current Implementation - better-sqlite3 Import | ~285 |
| #23775 | " | 🔵 | Database.ts Current Implementation - better-sqlite3 Import | ~286 |
| #23774 | " | 🔵 | SessionSearch.ts Current Implementation - better-sqlite3 Import | ~309 |
| #23671 | 8:36 PM | 🔵 | getUserPromptsByIds Method Implementation with Filtering and Ordering | ~326 |
| #23670 | " | 🔵 | getUserPromptsByIds Method Location in SessionStore | ~145 |
| #23635 | 8:10 PM | 🔴 | Fixed SessionStore.ts Concepts Filter SQL Parameter Bug | ~297 |
| #23634 | " | 🔵 | SessionStore.ts Concepts Filter Bug Confirmed at Line 849 | ~356 |
| #23522 | 5:27 PM | 🔵 | Complete TypeScript Type Definitions for Database Entities | ~433 |
| #23521 | " | 🔵 | Database Schema Structure with 7 Migration Versions | ~461 |
### Dec 18, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29868 | 8:19 PM | 🔵 | SessionStore Architecture Review for Mode Metadata Addition | ~350 |
| #29243 | 12:13 AM | 🔵 | Observations Table Schema Migration: Text Field Made Nullable | ~496 |
| #29241 | 12:12 AM | 🔵 | Migration001: Core Schema for Sessions, Memories, Overviews, Diagnostics, Transcripts | ~555 |
| #29238 | 12:11 AM | 🔵 | Observation Type Schema Evolution: Five to Six Types | ~331 |
| #29237 | " | 🔵 | SQLite SessionStore with Schema Migrations and WAL Mode | ~520 |
### Dec 21, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31622 | 8:26 PM | 🔄 | Completed SessionStore logging standardization | ~270 |
| #31621 | " | 🔄 | Standardized error logging for boundary timestamps query | ~253 |
| #31620 | " | 🔄 | Standardized error logging in getTimelineAroundObservation | ~252 |
| #31619 | " | 🔄 | Replaced console.log with logger.debug in SessionStore | ~263 |
### Dec 27, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33213 | 9:04 PM | 🔵 | SessionStore Implements KISS Session ID Threading via INSERT OR IGNORE Pattern | ~673 |
### Dec 28, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33548 | 10:59 PM | ✅ | Reverted memory_session_id NULL Initialization to contentSessionId Placeholder | ~421 |
| #33546 | 10:57 PM | 🔴 | Fixed createSDKSession to Initialize memory_session_id as NULL | ~406 |
| #33545 | " | 🔵 | createSDKSession Sets memory_session_id Equal to content_session_id Initially | ~378 |
| #33544 | " | 🔵 | SessionStore Migration 17 Already Renamed Session ID Columns | ~451 |
### Jan 2, 2026
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36028 | 9:20 PM | 🔄 | Try-Catch Block Removed from Database Migration | ~291 |
### Jan 3, 2026
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36653 | 11:03 PM | 🔵 | storeObservation Method Signature Shows Parameter Named memorySessionId | ~474 |
| #36652 | " | 🔵 | createSDKSession Implementation Confirms NULL Initialization With Security Rationale | ~488 |
| #36650 | 11:02 PM | 🔵 | Phase 1 Analysis Reveals Implementation-Test Mismatch on NULL vs Placeholder Initialization | ~687 |
| #36649 | " | 🔵 | SessionStore Implementation Reveals NULL-Based Memory Session ID Initialization Pattern | ~770 |
| #36175 | 6:52 PM | ✅ | MigrationRunner Re-exported from Migrations.ts | ~405 |
| #36172 | " | 🔵 | Migrations.ts Contains Legacy Migration System | ~650 |
| #36163 | 6:48 PM | 🔵 | SessionStore Method Inventory and Extraction Boundaries | ~692 |
| #36162 | 6:47 PM | 🔵 | SessionStore Architecture and Migration History | ~593 |
</claude-mem-context>
@@ -96,6 +96,11 @@ export class PendingMessageStore {
// Delete immediately - no "processing" state needed
const deleteStmt = this.db.prepare('DELETE FROM pending_messages WHERE id = ?');
deleteStmt.run(msg.id);
// Log claim with minimal info (avoid logging full payload)
logger.info('QUEUE', `CLAIMED | sessionDbId=${sessionId} | messageId=${msg.id} | type=${msg.message_type}`, {
sessionId: sessionId
});
}
return msg;
});
+64 -5
View File
@@ -336,15 +336,64 @@ export class SessionSearch {
return this.db.prepare(sql).all(...params) as ObservationSearchResult[];
}
/**
* Check if a file is a direct child of a folder (not in a subfolder)
*/
private isDirectChild(filePath: string, folderPath: string): boolean {
if (!filePath.startsWith(folderPath + '/')) return false;
const remainder = filePath.slice(folderPath.length + 1);
return !remainder.includes('/');
}
/**
* Check if an observation has any files that are direct children of the folder
*/
private hasDirectChildFile(obs: ObservationSearchResult, folderPath: string): boolean {
const checkFiles = (filesJson: string | null): boolean => {
if (!filesJson) return false;
try {
const files = JSON.parse(filesJson);
if (Array.isArray(files)) {
return files.some(f => this.isDirectChild(f, folderPath));
}
} catch {}
return false;
};
return checkFiles(obs.files_modified) || checkFiles(obs.files_read);
}
/**
* Check if a session has any files that are direct children of the folder
*/
private hasDirectChildFileSession(session: SessionSummarySearchResult, folderPath: string): boolean {
const checkFiles = (filesJson: string | null): boolean => {
if (!filesJson) return false;
try {
const files = JSON.parse(filesJson);
if (Array.isArray(files)) {
return files.some(f => this.isDirectChild(f, folderPath));
}
} catch {}
return false;
};
return checkFiles(session.files_read) || checkFiles(session.files_edited);
}
/**
* Find observations and summaries by file path
* When isFolder=true, only returns results with files directly in the folder (not subfolders)
*/
findByFile(filePath: string, options: SearchOptions = {}): {
observations: ObservationSearchResult[];
sessions: SessionSummarySearchResult[];
} {
const params: any[] = [];
const { limit = 50, offset = 0, orderBy = 'date_desc', ...filters } = options;
const { limit = 50, offset = 0, orderBy = 'date_desc', isFolder = false, ...filters } = options;
// Query more results if we're filtering to direct children
const queryLimit = isFolder ? limit * 3 : limit;
// Add file to filters
const fileFilters = { ...filters, files: filePath };
@@ -359,9 +408,14 @@ export class SessionSearch {
LIMIT ? OFFSET ?
`;
params.push(limit, offset);
params.push(queryLimit, offset);
const observations = this.db.prepare(observationsSql).all(...params) as ObservationSearchResult[];
let observations = this.db.prepare(observationsSql).all(...params) as ObservationSearchResult[];
// Post-filter to direct children if isFolder mode
if (isFolder) {
observations = observations.filter(obs => this.hasDirectChildFile(obs, filePath)).slice(0, limit);
}
// For session summaries, search files_read and files_edited
const sessionParams: any[] = [];
@@ -403,9 +457,14 @@ export class SessionSearch {
LIMIT ? OFFSET ?
`;
sessionParams.push(limit, offset);
sessionParams.push(queryLimit, offset);
const sessions = this.db.prepare(sessionsSql).all(...sessionParams) as SessionSummarySearchResult[];
let sessions = this.db.prepare(sessionsSql).all(...sessionParams) as SessionSummarySearchResult[];
// Post-filter to direct children if isFolder mode
if (isFolder) {
sessions = sessions.filter(s => this.hasDirectChildFileSession(s, filePath)).slice(0, limit);
}
return { observations, sessions };
}
+21 -21
View File
@@ -152,7 +152,7 @@ export class SessionStore {
if (!hasWorkerPort) {
this.db.run('ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER');
logger.info('DB', 'Added worker_port column to sdk_sessions table');
logger.debug('DB', 'Added worker_port column to sdk_sessions table');
}
// Record migration
@@ -173,7 +173,7 @@ export class SessionStore {
if (!hasPromptCounter) {
this.db.run('ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0');
logger.info('DB', 'Added prompt_counter column to sdk_sessions table');
logger.debug('DB', 'Added prompt_counter column to sdk_sessions table');
}
// Check observations for prompt_number
@@ -182,7 +182,7 @@ export class SessionStore {
if (!obsHasPromptNumber) {
this.db.run('ALTER TABLE observations ADD COLUMN prompt_number INTEGER');
logger.info('DB', 'Added prompt_number column to observations table');
logger.debug('DB', 'Added prompt_number column to observations table');
}
// Check session_summaries for prompt_number
@@ -191,7 +191,7 @@ export class SessionStore {
if (!sumHasPromptNumber) {
this.db.run('ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER');
logger.info('DB', 'Added prompt_number column to session_summaries table');
logger.debug('DB', 'Added prompt_number column to session_summaries table');
}
// Record migration
@@ -216,7 +216,7 @@ export class SessionStore {
return;
}
logger.info('DB', 'Removing UNIQUE constraint from session_summaries.memory_session_id');
logger.debug('DB', 'Removing UNIQUE constraint from session_summaries.memory_session_id');
// Begin transaction
this.db.run('BEGIN TRANSACTION');
@@ -270,7 +270,7 @@ export class SessionStore {
// Record migration
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(7, new Date().toISOString());
logger.info('DB', 'Successfully removed UNIQUE constraint from session_summaries.memory_session_id');
logger.debug('DB', 'Successfully removed UNIQUE constraint from session_summaries.memory_session_id');
}
/**
@@ -291,7 +291,7 @@ export class SessionStore {
return;
}
logger.info('DB', 'Adding hierarchical fields to observations table');
logger.debug('DB', 'Adding hierarchical fields to observations table');
// Add new columns
this.db.run(`
@@ -307,7 +307,7 @@ export class SessionStore {
// Record migration
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(8, new Date().toISOString());
logger.info('DB', 'Successfully added hierarchical fields to observations table');
logger.debug('DB', 'Successfully added hierarchical fields to observations table');
}
/**
@@ -329,7 +329,7 @@ export class SessionStore {
return;
}
logger.info('DB', 'Making observations.text nullable');
logger.debug('DB', 'Making observations.text nullable');
// Begin transaction
this.db.run('BEGIN TRANSACTION');
@@ -385,7 +385,7 @@ export class SessionStore {
// Record migration
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(9, new Date().toISOString());
logger.info('DB', 'Successfully made observations.text nullable');
logger.debug('DB', 'Successfully made observations.text nullable');
}
/**
@@ -404,7 +404,7 @@ export class SessionStore {
return;
}
logger.info('DB', 'Creating user_prompts table with FTS5 support');
logger.debug('DB', 'Creating user_prompts table with FTS5 support');
// Begin transaction
this.db.run('BEGIN TRANSACTION');
@@ -462,7 +462,7 @@ export class SessionStore {
// Record migration
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(10, new Date().toISOString());
logger.info('DB', 'Successfully created user_prompts table with FTS5 support');
logger.debug('DB', 'Successfully created user_prompts table with FTS5 support');
}
/**
@@ -481,7 +481,7 @@ export class SessionStore {
if (!obsHasDiscoveryTokens) {
this.db.run('ALTER TABLE observations ADD COLUMN discovery_tokens INTEGER DEFAULT 0');
logger.info('DB', 'Added discovery_tokens column to observations table');
logger.debug('DB', 'Added discovery_tokens column to observations table');
}
// Check if discovery_tokens column exists in session_summaries table
@@ -490,7 +490,7 @@ export class SessionStore {
if (!sumHasDiscoveryTokens) {
this.db.run('ALTER TABLE session_summaries ADD COLUMN discovery_tokens INTEGER DEFAULT 0');
logger.info('DB', 'Added discovery_tokens column to session_summaries table');
logger.debug('DB', 'Added discovery_tokens column to session_summaries table');
}
// Record migration only after successful column verification/addition
@@ -514,7 +514,7 @@ export class SessionStore {
return;
}
logger.info('DB', 'Creating pending_messages table');
logger.debug('DB', 'Creating pending_messages table');
this.db.run(`
CREATE TABLE pending_messages (
@@ -544,7 +544,7 @@ export class SessionStore {
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(16, new Date().toISOString());
logger.info('DB', 'pending_messages table created successfully');
logger.debug('DB', 'pending_messages table created successfully');
}
/**
@@ -559,7 +559,7 @@ export class SessionStore {
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(17) as SchemaVersion | undefined;
if (applied) return;
logger.info('DB', 'Checking session ID columns for semantic clarity rename');
logger.debug('DB', 'Checking session ID columns for semantic clarity rename');
let renamesPerformed = 0;
@@ -577,7 +577,7 @@ export class SessionStore {
if (hasOldCol) {
// SQLite 3.25+ supports ALTER TABLE RENAME COLUMN
this.db.run(`ALTER TABLE ${table} RENAME COLUMN ${oldCol} TO ${newCol}`);
logger.info('DB', `Renamed ${table}.${oldCol} to ${newCol}`);
logger.debug('DB', `Renamed ${table}.${oldCol} to ${newCol}`);
return true;
}
@@ -606,9 +606,9 @@ export class SessionStore {
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(17, new Date().toISOString());
if (renamesPerformed > 0) {
logger.info('DB', `Successfully renamed ${renamesPerformed} session ID columns`);
logger.debug('DB', `Successfully renamed ${renamesPerformed} session ID columns`);
} else {
logger.info('DB', 'No session ID column renames needed (already up to date)');
logger.debug('DB', 'No session ID column renames needed (already up to date)');
}
}
@@ -639,7 +639,7 @@ export class SessionStore {
if (!hasColumn) {
this.db.run('ALTER TABLE pending_messages ADD COLUMN failed_at_epoch INTEGER');
logger.info('DB', 'Added failed_at_epoch column to pending_messages table');
logger.debug('DB', 'Added failed_at_epoch column to pending_messages table');
}
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(20, new Date().toISOString());
+14
View File
@@ -0,0 +1,14 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 3, 2026
**bulk.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36670 | 11:37 PM | ✅ | Resolved merge conflicts by accepting branch changes for 39 files | ~435 |
| #36469 | 9:04 PM | 🔵 | Bulk Import with Duplicate Detection | ~451 |
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
</claude-mem-context>
+15
View File
@@ -0,0 +1,15 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 3, 2026
**runner.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36487 | 9:13 PM | 🔴 | Fixed Foreign Key Constraint Issues in Observations Test Suite | ~677 |
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
| #36353 | 8:42 PM | 🔵 | Multiple observation table definitions found across codebase | ~280 |
| #36323 | 8:25 PM | 🔵 | Message Queue Architecture Scope Expanded | ~302 |
</claude-mem-context>
+21 -21
View File
@@ -136,7 +136,7 @@ export class MigrationRunner {
if (!hasWorkerPort) {
this.db.run('ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER');
logger.info('DB', 'Added worker_port column to sdk_sessions table');
logger.debug('DB', 'Added worker_port column to sdk_sessions table');
}
// Record migration
@@ -157,7 +157,7 @@ export class MigrationRunner {
if (!hasPromptCounter) {
this.db.run('ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0');
logger.info('DB', 'Added prompt_counter column to sdk_sessions table');
logger.debug('DB', 'Added prompt_counter column to sdk_sessions table');
}
// Check observations for prompt_number
@@ -166,7 +166,7 @@ export class MigrationRunner {
if (!obsHasPromptNumber) {
this.db.run('ALTER TABLE observations ADD COLUMN prompt_number INTEGER');
logger.info('DB', 'Added prompt_number column to observations table');
logger.debug('DB', 'Added prompt_number column to observations table');
}
// Check session_summaries for prompt_number
@@ -175,7 +175,7 @@ export class MigrationRunner {
if (!sumHasPromptNumber) {
this.db.run('ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER');
logger.info('DB', 'Added prompt_number column to session_summaries table');
logger.debug('DB', 'Added prompt_number column to session_summaries table');
}
// Record migration
@@ -200,7 +200,7 @@ export class MigrationRunner {
return;
}
logger.info('DB', 'Removing UNIQUE constraint from session_summaries.memory_session_id');
logger.debug('DB', 'Removing UNIQUE constraint from session_summaries.memory_session_id');
// Begin transaction
this.db.run('BEGIN TRANSACTION');
@@ -254,7 +254,7 @@ export class MigrationRunner {
// Record migration
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(7, new Date().toISOString());
logger.info('DB', 'Successfully removed UNIQUE constraint from session_summaries.memory_session_id');
logger.debug('DB', 'Successfully removed UNIQUE constraint from session_summaries.memory_session_id');
}
/**
@@ -275,7 +275,7 @@ export class MigrationRunner {
return;
}
logger.info('DB', 'Adding hierarchical fields to observations table');
logger.debug('DB', 'Adding hierarchical fields to observations table');
// Add new columns
this.db.run(`
@@ -291,7 +291,7 @@ export class MigrationRunner {
// Record migration
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(8, new Date().toISOString());
logger.info('DB', 'Successfully added hierarchical fields to observations table');
logger.debug('DB', 'Successfully added hierarchical fields to observations table');
}
/**
@@ -313,7 +313,7 @@ export class MigrationRunner {
return;
}
logger.info('DB', 'Making observations.text nullable');
logger.debug('DB', 'Making observations.text nullable');
// Begin transaction
this.db.run('BEGIN TRANSACTION');
@@ -369,7 +369,7 @@ export class MigrationRunner {
// Record migration
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(9, new Date().toISOString());
logger.info('DB', 'Successfully made observations.text nullable');
logger.debug('DB', 'Successfully made observations.text nullable');
}
/**
@@ -388,7 +388,7 @@ export class MigrationRunner {
return;
}
logger.info('DB', 'Creating user_prompts table with FTS5 support');
logger.debug('DB', 'Creating user_prompts table with FTS5 support');
// Begin transaction
this.db.run('BEGIN TRANSACTION');
@@ -446,7 +446,7 @@ export class MigrationRunner {
// Record migration
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(10, new Date().toISOString());
logger.info('DB', 'Successfully created user_prompts table with FTS5 support');
logger.debug('DB', 'Successfully created user_prompts table with FTS5 support');
}
/**
@@ -465,7 +465,7 @@ export class MigrationRunner {
if (!obsHasDiscoveryTokens) {
this.db.run('ALTER TABLE observations ADD COLUMN discovery_tokens INTEGER DEFAULT 0');
logger.info('DB', 'Added discovery_tokens column to observations table');
logger.debug('DB', 'Added discovery_tokens column to observations table');
}
// Check if discovery_tokens column exists in session_summaries table
@@ -474,7 +474,7 @@ export class MigrationRunner {
if (!sumHasDiscoveryTokens) {
this.db.run('ALTER TABLE session_summaries ADD COLUMN discovery_tokens INTEGER DEFAULT 0');
logger.info('DB', 'Added discovery_tokens column to session_summaries table');
logger.debug('DB', 'Added discovery_tokens column to session_summaries table');
}
// Record migration only after successful column verification/addition
@@ -498,7 +498,7 @@ export class MigrationRunner {
return;
}
logger.info('DB', 'Creating pending_messages table');
logger.debug('DB', 'Creating pending_messages table');
this.db.run(`
CREATE TABLE pending_messages (
@@ -528,7 +528,7 @@ export class MigrationRunner {
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(16, new Date().toISOString());
logger.info('DB', 'pending_messages table created successfully');
logger.debug('DB', 'pending_messages table created successfully');
}
/**
@@ -543,7 +543,7 @@ export class MigrationRunner {
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(17) as SchemaVersion | undefined;
if (applied) return;
logger.info('DB', 'Checking session ID columns for semantic clarity rename');
logger.debug('DB', 'Checking session ID columns for semantic clarity rename');
let renamesPerformed = 0;
@@ -561,7 +561,7 @@ export class MigrationRunner {
if (hasOldCol) {
// SQLite 3.25+ supports ALTER TABLE RENAME COLUMN
this.db.run(`ALTER TABLE ${table} RENAME COLUMN ${oldCol} TO ${newCol}`);
logger.info('DB', `Renamed ${table}.${oldCol} to ${newCol}`);
logger.debug('DB', `Renamed ${table}.${oldCol} to ${newCol}`);
return true;
}
@@ -590,9 +590,9 @@ export class MigrationRunner {
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(17, new Date().toISOString());
if (renamesPerformed > 0) {
logger.info('DB', `Successfully renamed ${renamesPerformed} session ID columns`);
logger.debug('DB', `Successfully renamed ${renamesPerformed} session ID columns`);
} else {
logger.info('DB', 'No session ID column renames needed (already up to date)');
logger.debug('DB', 'No session ID column renames needed (already up to date)');
}
}
@@ -623,7 +623,7 @@ export class MigrationRunner {
if (!hasColumn) {
this.db.run('ALTER TABLE pending_messages ADD COLUMN failed_at_epoch INTEGER');
logger.info('DB', 'Added failed_at_epoch column to pending_messages table');
logger.debug('DB', 'Added failed_at_epoch column to pending_messages table');
}
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(20, new Date().toISOString());
@@ -0,0 +1,33 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 3, 2026
**files.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36670 | 11:37 PM | ✅ | Resolved merge conflicts by accepting branch changes for 39 files | ~435 |
| #36453 | 9:02 PM | 🔵 | Session File Aggregation | ~384 |
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
**store.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36483 | 9:11 PM | 🟣 | Observations Module Test Suite Implemented | ~716 |
| #36445 | 9:01 PM | 🔵 | Observation Storage with Timestamp Override | ~444 |
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36470 | 9:06 PM | 🔵 | SQLite Module API Documentation Verified for Test Implementation | ~765 |
| #36447 | 9:02 PM | 🔵 | Observation Type Definitions | ~459 |
### Jan 4, 2026
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36770 | 12:42 AM | 🔵 | Export Script Type Duplication Analysis Complete | ~555 |
</claude-mem-context>
+32
View File
@@ -0,0 +1,32 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 3, 2026
**get.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36670 | 11:37 PM | ✅ | Resolved merge conflicts by accepting branch changes for 39 files | ~435 |
| #36464 | 9:04 PM | 🔵 | User Prompt Retrieval Functions | ~471 |
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
**store.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36485 | 9:12 PM | 🟣 | Prompts Module Test Suite Implemented | ~680 |
| #36466 | 9:04 PM | 🔵 | User Prompt Storage | ~363 |
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36470 | 9:06 PM | 🔵 | SQLite Module API Documentation Verified for Test Implementation | ~765 |
### Jan 4, 2026
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36770 | 12:42 AM | 🔵 | Export Script Type Duplication Analysis Complete | ~555 |
</claude-mem-context>
+32
View File
@@ -0,0 +1,32 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 3, 2026
**create.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36670 | 11:37 PM | ✅ | Resolved merge conflicts by accepting branch changes for 39 files | ~435 |
| #36482 | 9:10 PM | 🟣 | Sessions Module Test Suite Implemented | ~627 |
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36470 | 9:06 PM | 🔵 | SQLite Module API Documentation Verified for Test Implementation | ~765 |
| #36439 | 9:01 PM | 🔵 | Session Type Hierarchy | ~420 |
**get.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36438 | 9:01 PM | 🔵 | Session Retrieval Functions with Database-First Pattern | ~479 |
### Jan 4, 2026
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36770 | 12:42 AM | 🔵 | Export Script Type Duplication Analysis Complete | ~555 |
</claude-mem-context>
+32
View File
@@ -0,0 +1,32 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Jan 3, 2026
**get.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36670 | 11:37 PM | ✅ | Resolved merge conflicts by accepting branch changes for 39 files | ~435 |
| #36390 | 8:50 PM | 🔄 | Comprehensive Monolith Refactor with Modular Architecture | ~724 |
**store.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36484 | 9:11 PM | 🟣 | Summaries Module Test Suite Implemented | ~708 |
| #36461 | 9:03 PM | 🔵 | Summary Storage with Timestamp Override | ~439 |
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36470 | 9:06 PM | 🔵 | SQLite Module API Documentation Verified for Test Implementation | ~765 |
| #36457 | 9:03 PM | 🔵 | Summary Type Hierarchy | ~426 |
### Jan 4, 2026
**types.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #36770 | 12:42 AM | 🔵 | Export Script Type Duplication Analysis Complete | ~555 |
</claude-mem-context>

Some files were not shown because too many files have changed in this diff Show More