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 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>