Compare commits

...

10 Commits

Author SHA1 Message Date
Alex Newman bc7e0ba3e0 chore: bump version to 6.4.9
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 22:06:50 -05:00
Alex Newman cbfc94bc26 Merge pull request #160 from thedotmack/feature/context-settings
feat: Add comprehensive context configuration and display settings
2025-12-01 22:03:30 -05:00
Alex Newman c768a80bf0 Refactor context configuration and settings handling
- Updated context configuration loading path from ~/.claude/settings.json to ~/.claude-mem/settings.json.
- Modified the extractPriorMessages function to focus on retrieving the last assistant message only, removing user message extraction.
- Enhanced output formatting for displaying prior assistant messages in the context hook.
- Added new settings related to token economics and observation filtering in the useSettings hook.
2025-12-01 19:26:33 -05:00
Alex Newman 6dc648f07c feat: add functionality to extract and display prior session messages
- Implemented `cwdToDashed` helper function to format current working directory for transcript file paths.
- Added `extractPriorMessages` function to read and parse the last user and assistant messages from a transcript file.
- Enhanced `contextHook` to retrieve and display prior session messages if enabled in the configuration.
- Updated output formatting to include a "Previously" section showing last messages from the prior session.
2025-12-01 18:10:55 -05:00
Alex Newman b116681529 refactor: improve context economics display logic and logging
- Updated logging category from 'CONTEXT' to 'HOOK' for context settings loading failure.
- Simplified the display logic for the Context Economics section to show only when relevant settings are enabled.
- Enhanced readability by consolidating repeated code for displaying token savings.
- Adjusted footer logic to conditionally display token savings message based on visibility of context economics.
2025-12-01 17:43:04 -05:00
Alex Newman d1876cb6e0 Refactor observation handling: centralize constants and improve context settings
- Introduced `observation-metadata.ts` to define valid observation types and concepts, along with their corresponding emoji mappings.
- Updated `context-hook.ts` to utilize new constants for observation types and concepts, enhancing maintainability.
- Refactored `worker-service.ts` to validate observation types and concepts against the new centralized constants.
- Consolidated settings management in `Sidebar.tsx` to streamline state handling for context settings.
- Improved error handling and logging for context loading failures.
2025-12-01 17:29:48 -05:00
Alex Newman e1017b483b feat: Enhance context settings with validation and UI options
- Added ContextConfig interface and loadContextConfig function to manage context settings.
- Implemented validation for context settings in WorkerService.
- Updated Sidebar component to include new context settings for token economics, observation filtering, display configuration, and feature toggles.
- Introduced default settings for new context features.
- Adjusted types to accommodate new settings in the application state.
2025-12-01 16:53:35 -05:00
Alex Newman 8d5b886f63 docs: Update CHANGELOG.md for v6.4.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 23:30:15 -05:00
Alex Newman 6e8d823139 Release v6.4.1: Live AMA Announcement
Added dynamic announcement system to welcome users to our first-ever Live AMA event! 🎉

What's New:
• Time-aware announcement for Live AMA (Dec 1-5, 5-7pm EST)
• Live indicator (🔴) appears during active sessions
• Announcement automatically expires after event ends

Join us for our inaugural AMA! Ask questions, share ideas, and connect with the community. Whether you're a longtime user or just getting started with claude-mem, we'd love to hear from you!

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 23:29:11 -05:00
Alex Newman e1212d2dd9 docs: Update CHANGELOG.md for v6.4.0 2025-11-30 23:15:55 -05:00
17 changed files with 1043 additions and 390 deletions
+1 -1
View File
@@ -10,7 +10,7 @@
"plugins": [
{
"name": "claude-mem",
"version": "6.4.0",
"version": "6.4.9",
"source": "./plugin",
"description": "Persistent memory system for Claude Code - context compression across sessions"
}
+174 -163
View File
@@ -2,9 +2,105 @@
All notable changes to this project will be documented in this file.
This file is auto-generated from GitHub releases.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [v6.3.7](https://github.com/thedotmack/claude-mem/releases/tag/v6.3.7) - 2025-12-01
## [6.4.1] - 2025-12-01
## Hey there, claude-mem community! 👋
We're doing something new and exciting: **our first-ever Live AMA**!
### 🔴 When You'll See Us Live
**December 1st-5th, 2025**
**Daily from 5-7pm EST**
During these times, you'll see a live indicator (🔴) when you start a new session, letting you know we're available right now to answer questions, discuss ideas, or just chat about what you're building with claude-mem.
### What Changed in This Release
We've added a smart announcement system that:
- Shows upcoming AMA schedule before/after live hours
- Displays a live indicator (🔴) when we're actively available
- Automatically cleans up after the event ends
### Why We're Doing This
We want to hear from **you**! Whether you're:
- Just getting started with claude-mem
- A power user with feature ideas
- Curious about how memory compression works
- Running into any issues
- Or just want to say hi 👋
This is your chance to connect directly with the developer (@thedotmack) and fellow community members.
### Join the Community
Can't make the live times? No worries! Join our Discord to stay connected:
**https://discord.gg/J4wttp9vDu**
We're excited to meet you and hear what you're building!
---
## Technical Details
**Changed Files:**
- `src/hooks/user-message-hook.ts` - Added time-aware announcement logic
- Version bumped across all manifests (6.4.0 → 6.4.1)
**Built Artifacts:**
- `plugin/scripts/user-message-hook.js` - Updated compiled hook
---
Looking forward to seeing you at the AMA! 🎉
## [6.4.0] - 2025-12-01
## 🎯 Highlights
This release introduces a powerful **dual-tag privacy system** that gives you fine-grained control over what gets stored in your observation history, along with significant search API improvements.
## ✨ New Features
### Dual-Tag Privacy System
- **`<private>` tags**: User-level privacy control - wrap any sensitive content to prevent storage in observation history
- **`<claude-mem-context>` tags**: System-level tags for auto-injected observations to prevent recursive storage
- Tag stripping happens at the hook layer (edge processing) before data reaches worker/database
- Comprehensive documentation in `docs/public/usage/private-tags.mdx`
### User Experience
- New inline help message in context hook highlighting the `<private>` tag feature
- Improved Community link formatting in startup messages
## 🔧 Improvements
### Search API
- Simplified search endpoint parameters to eliminate bracket encoding issues (#154)
- Cleaner API interface for mem-search skill
### Performance
- Added composite index for user prompts lookup optimization
- Shared tag-stripping utilities in `src/utils/tag-stripping.ts`
## 📚 Documentation
- Updated CLAUDE.md with Privacy Tags section
- Enhanced private-tags.mdx with implementation details
- Added comprehensive test coverage for tag stripping
## 🔗 Related PRs
- #153: Dual-tag system for meta-observation control
- #154: Eliminate bracket encoding in search API parameters
---
💡 **Try it now**: Wrap sensitive data with `<private>your-secret-data</private>` in any message to Claude Code!
## [6.3.7] - 2025-12-01
## Bug Fixes
@@ -16,7 +112,7 @@ Fixed a syntax error in `scripts/smart-install.js` where an extra closing brace
This bug was introduced in a recent release and prevented the plugin from loading correctly for users.
## [v6.3.6](https://github.com/thedotmack/claude-mem/releases/tag/v6.3.6) - 2025-11-30
## [6.3.6] - 2025-11-30
## Auto-detect and rebuild native modules on Node.js version changes
@@ -39,7 +135,7 @@ This release fixes a critical issue where upgrading Node.js (e.g., v22 → v25)
### Merged PRs
- #149 - feat: Auto-detect and rebuild native modules on Node.js version changes
## [v6.3.5](https://github.com/thedotmack/claude-mem/releases/tag/v6.3.5) - 2025-11-30
## [6.3.5] - 2025-11-30
## Changes
@@ -57,7 +153,7 @@ This release fixes a critical issue where upgrading Node.js (e.g., v22 → v25)
Full changelog: https://github.com/thedotmack/claude-mem/compare/v6.3.4...v6.3.5
## [v6.3.4](https://github.com/thedotmack/claude-mem/releases/tag/v6.3.4) - 2025-11-30
## [6.3.4] - 2025-11-30
## Bug Fixes
@@ -75,11 +171,7 @@ These changes significantly improve the first-time installation experience, elim
**Special thanks to @dreamiurg for identifying and fixing this critical UX issue!** 🙏
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## [v6.3.3](https://github.com/thedotmack/claude-mem/releases/tag/v6.3.3) - 2025-11-30
## [6.3.3] - 2025-11-30
Bug fixes and improvements to timeline context feature:
@@ -90,7 +182,7 @@ Bug fixes and improvements to timeline context feature:
Full changes: https://github.com/thedotmack/claude-mem/compare/v6.3.2...v6.3.3
## [v6.3.2](https://github.com/thedotmack/claude-mem/releases/tag/v6.3.2) - 2025-11-25
## [6.3.2] - 2025-11-25
## What's Changed
@@ -106,13 +198,13 @@ curl "http://localhost:37777/api/decisions?query=architecture&format=full&limit=
curl "http://localhost:37777/api/decisions?format=index&limit=10"
```
## [v6.3.1](https://github.com/thedotmack/claude-mem/releases/tag/v6.3.1) - 2025-11-25
## [6.3.1] - 2025-11-25
## What's New
- Add script to help estimate token savings from on-the-fly replacements
## [v6.3.0](https://github.com/thedotmack/claude-mem/releases/tag/v6.3.0) - 2025-11-25
## [6.3.0] - 2025-11-25
## What's New
@@ -133,7 +225,7 @@ Added Version Channel section to Settings sidebar allowing users to switch betwe
## Installation
To update, restart Claude Code or run the plugin installer.
## [v6.2.1](https://github.com/thedotmack/claude-mem/releases/tag/v6.2.1) - 2025-11-23
## [6.2.1] - 2025-11-23
## 🐛 Bug Fixes
@@ -167,7 +259,7 @@ To update, restart Claude Code or run the plugin installer.
- `54ef149` - fix: Refresh in-memory session project when updated in database
- `5d23c60` - fix: Update project name when session already exists in createSDKSession
## [v6.2.0](https://github.com/thedotmack/claude-mem/releases/tag/v6.2.0) - 2025-11-22
## [6.2.0] - 2025-11-22
## Major Features
@@ -211,9 +303,7 @@ Users with auto-update enabled will receive this update automatically. To manual
npm run sync-marketplace
\`\`\`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## [v6.1.1](https://github.com/thedotmack/claude-mem/releases/tag/v6.1.1) - 2025-11-21
## [6.1.1] - 2025-11-21
## Bug Fixes
@@ -236,7 +326,7 @@ Users with auto-update enabled will receive this patch automatically. To manuall
npm run sync-marketplace
\`\`\`
## [v6.1.0](https://github.com/thedotmack/claude-mem/releases/tag/v6.1.0) - 2025-11-19
## [6.1.0] - 2025-11-19
## Viewer UI: Responsive Layout Improvements
@@ -248,7 +338,7 @@ The viewer UI now handles narrow screens better with responsive breakpoints:
Makes the viewer usable on phones and narrow browser windows.
## [v6.0.9](https://github.com/thedotmack/claude-mem/releases/tag/v6.0.9) - 2025-11-17
## [6.0.9] - 2025-11-17
## Queue Depth Indicator Feature
@@ -278,7 +368,7 @@ Added a real-time queue depth indicator to the viewer UI that displays the count
Original implementation by @thedotmack in PR #96
Bug fix by @copilot-swe-agent in PR #97
## [v6.0.8](https://github.com/thedotmack/claude-mem/releases/tag/v6.0.8) - 2025-11-17
## [6.0.8] - 2025-11-17
## Critical Fix
@@ -301,11 +391,7 @@ Run `pm2 info claude-mem-worker` to verify:
- **exec cwd** should be: `/Users/[username]/.claude/plugins/marketplaces/thedotmack`
- **script path** should be: `/Users/[username]/.claude/plugins/marketplaces/thedotmack/plugin/scripts/worker-service.cjs`
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## [v6.0.7](https://github.com/thedotmack/claude-mem/releases/tag/v6.0.7) - 2025-11-17
## [6.0.7] - 2025-11-17
## Critical Hotfix: Database Migration Issue (#121)
@@ -355,7 +441,7 @@ See [CHANGELOG.md](https://github.com/thedotmack/claude-mem/blob/main/CHANGELOG.
Thanks to everyone who reported this issue with detailed error logs! 🙏
## [v6.0.6](https://github.com/thedotmack/claude-mem/releases/tag/v6.0.6) - 2025-11-17
## [6.0.6] - 2025-11-17
## Critical Bugfix Release
@@ -376,11 +462,7 @@ Thanks to everyone who reported this issue with detailed error logs! 🙏
**Affected Users**: All users who upgraded to v6.0.5 and experienced the migration error
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## [v6.0.5](https://github.com/thedotmack/claude-mem/releases/tag/v6.0.5) - 2025-11-17
## [6.0.5] - 2025-11-17
## Changes
@@ -402,7 +484,7 @@ Thanks to everyone who reported this issue with detailed error logs! 🙏
**Release Date**: November 16, 2025
**Plugin Version**: 6.0.5
## [v6.0.4](https://github.com/thedotmack/claude-mem/releases/tag/v6.0.4) - 2025-11-17
## [6.0.4] - 2025-11-17
**Patch Release**
@@ -414,7 +496,7 @@ Fixes memory leaks from orphaned uvx/python processes that could accumulate duri
**Full Changelog:** https://github.com/thedotmack/claude-mem/compare/v6.0.3...v6.0.4
## [v6.0.3](https://github.com/thedotmack/claude-mem/releases/tag/v6.0.3) - 2025-11-16
## [6.0.3] - 2025-11-16
## What's Changed
@@ -427,7 +509,7 @@ Documentation alignment release - merged PR #116 fixing hybrid search architectu
**Full Changelog**: https://github.com/thedotmack/claude-mem/compare/v6.0.2...v6.0.3
## [v6.0.2](https://github.com/thedotmack/claude-mem/releases/tag/v6.0.2) - 2025-11-14
## [6.0.2] - 2025-11-14
## Changes
@@ -438,7 +520,7 @@ Documentation alignment release - merged PR #116 fixing hybrid search architectu
**Full Changelog**: https://github.com/thedotmack/claude-mem/compare/v6.0.1...v6.0.2
## [v6.0.1](https://github.com/thedotmack/claude-mem/releases/tag/v6.0.1) - 2025-11-14
## [6.0.1] - 2025-11-14
## UI Enhancements
@@ -456,7 +538,7 @@ Documentation alignment release - merged PR #116 fixing hybrid search architectu
Full changelog: https://github.com/thedotmack/claude-mem/compare/v6.0.0...v6.0.1
## [v6.0.0](https://github.com/thedotmack/claude-mem/releases/tag/v6.0.0) - 2025-11-13
## [6.0.0] - 2025-11-13
## What's New
@@ -494,9 +576,7 @@ This is a major version bump due to significant architectural changes in session
📦 Install via Claude Code: `~/.claude/plugins/marketplaces/thedotmack/`
📖 Documentation: [CLAUDE.md](https://github.com/thedotmack/claude-mem/blob/main/CLAUDE.md)
## [v5.5.1](https://github.com/thedotmack/claude-mem/releases/tag/v5.5.1) - 2025-11-11
## v5.5.1 (2025-11-11)
## [5.5.1] - 2025-11-11
**Breaking Changes**: None (patch version)
@@ -521,9 +601,7 @@ This is a major version bump due to significant architectural changes in session
**What Changed**:
The summary hook now reads Claude Code transcript files to extract the last user message before generating session summaries. This provides better context for AI-powered session summarization. The activity indicator now accurately reflects both active sessions and queued work, giving users better feedback about what's happening behind the scenes.
## [v5.5.0](https://github.com/thedotmack/claude-mem/releases/tag/v5.5.0) - 2025-11-11
## v5.5.0 (2025-11-11)
## [5.5.0] - 2025-11-11
**Breaking Changes**: None (minor version)
@@ -546,21 +624,11 @@ The summary hook now reads Claude Code transcript files to extract the last user
**Credits**:
- Skill design and enhancement by @basher83
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## [v5.4.5](https://github.com/thedotmack/claude-mem/releases/tag/v5.4.5) - 2025-11-11
## v5.4.5 (2025-11-11)
## [5.4.5] - 2025-11-11
**Patch Release**: Bugfixes and minor improvements
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## [v5.4.4](https://github.com/thedotmack/claude-mem/releases/tag/v5.4.4) - 2025-11-10
## v5.4.4 (2025-11-10)
## [5.4.4] - 2025-11-10
**Breaking Changes**: None (patch version)
@@ -582,9 +650,7 @@ The summary hook now reads Claude Code transcript files to extract the last user
Merged via PR #86
## [v5.4.3](https://github.com/thedotmack/claude-mem/releases/tag/v5.4.3) - 2025-11-10
## v5.4.3 (2025-11-10)
## [5.4.3] - 2025-11-10
**Breaking Changes**: None (patch version)
@@ -607,9 +673,7 @@ Merged via PR #86
**Upgrade Notes**: No action required. PM2 watch mode will automatically restart the worker on plugin updates.
## [v5.4.2](https://github.com/thedotmack/claude-mem/releases/tag/v5.4.2) - 2025-11-10
## v5.4.2 (2025-11-10)
## [5.4.2] - 2025-11-10
**Bugfix Release**: CWD spatial awareness for SDK agent
@@ -685,9 +749,7 @@ Or restart Claude Code to auto-update.
**Full Changelog**: https://github.com/thedotmack/claude-mem/compare/v5.4.1...v5.4.2
## [v5.4.1](https://github.com/thedotmack/claude-mem/releases/tag/v5.4.1) - 2025-11-10
## v5.4.1 (2025-11-10)
## [5.4.1] - 2025-11-10
**Breaking Changes**: None (patch version)
@@ -711,9 +773,7 @@ Or restart Claude Code to auto-update.
**Upgrade Notes**: No breaking changes. Upgrade by running standard update process.
## [v5.4.0](https://github.com/thedotmack/claude-mem/releases/tag/v5.4.0) - 2025-11-10
## v5.4.0 - Skill-Based Search Migration & Progressive Disclosure (2025-11-09)
## [5.4.0] - 2025-11-10
### ⚠️ BREAKING CHANGE: MCP Search Tools Removed
@@ -830,9 +890,7 @@ Restart Claude Code to start using v5.4.0.
**Full Changelog**: https://github.com/thedotmack/claude-mem/compare/v5.3.0...v5.4.0
## [v5.3.0](https://github.com/thedotmack/claude-mem/releases/tag/v5.3.0) - 2025-11-09
## v5.3.0 (2025-11-09)
## [5.3.0] - 2025-11-09
**Breaking Changes**: None (minor version)
@@ -864,9 +922,7 @@ Restart Claude Code to start using v5.4.0.
**Upgrade Notes**: No breaking changes. Worker will automatically pick up improvements on restart.
## [v5.2.3](https://github.com/thedotmack/claude-mem/releases/tag/v5.2.3) - 2025-11-09
## v5.2.3 (2025-11-08)
## [5.2.3] - 2025-11-09
**Breaking Changes**: None (patch version)
@@ -893,11 +949,7 @@ The skill provides systematic checks for:
- Viewer UI endpoints
- Full system diagnostic report
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## [v5.2.2](https://github.com/thedotmack/claude-mem/releases/tag/v5.2.2) - 2025-11-08
## v5.2.2 (2025-11-08)
## [5.2.2] - 2025-11-08
**Breaking Changes**: None (patch version)
@@ -916,9 +968,7 @@ The skill provides systematic checks for:
**Impact**: Users will now see more comprehensive session summary information at startup, providing better context about what was investigated and learned in previous sessions.
## [v5.2.1](https://github.com/thedotmack/claude-mem/releases/tag/v5.2.1) - 2025-11-08
## v5.2.1 (2025-11-07)
## [5.2.1] - 2025-11-08
**Breaking Changes**: None (patch version)
@@ -957,11 +1007,7 @@ Verified fixes work correctly:
3. ✅ Rapid switching between projects → No race conditions or stale data
4. ✅ Switch back to "All Projects" → All data appears correctly with SSE updates
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## [v5.2.0](https://github.com/thedotmack/claude-mem/releases/tag/v5.2.0) - 2025-11-07
## v5.2.0 (2025-11-07)
## [5.2.0] - 2025-11-07
This release delivers a comprehensive architectural refactor of the worker service, extensive UI enhancements, and significant code cleanup. Merges PR #69.
@@ -1132,13 +1178,7 @@ To activate:
- **Previous Version**: 5.1.4
- **Semantic Version**: MINOR (backward compatible features & improvements)
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## [v5.1.4](https://github.com/thedotmack/claude-mem/releases/tag/v5.1.4) - 2025-11-07
## v5.1.4 (2025-11-07)
## [5.1.4] - 2025-11-07
**Bugfix Release**: PostToolUse Hook Schema Compliance
@@ -1156,11 +1196,7 @@ To activate:
**Why This Matters**: The Claude Code PostToolUse hook API provides `tool_response` not `tool_output`. This fix ensures proper schema compliance and prevents potential errors when capturing tool executions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## [v5.1.2](https://github.com/thedotmack/claude-mem/releases/tag/v5.1.2) - 2025-11-06
## v5.1.2 (2025-11-06)
## [5.1.2] - 2025-11-06
**Breaking Changes**: None (patch version)
@@ -1178,11 +1214,7 @@ To activate:
**Usage**:
Access the viewer at http://localhost:37777 and use the theme toggle to switch between light mode, dark mode, or system preference.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## [v5.1.1](https://github.com/thedotmack/claude-mem/releases/tag/v5.1.1) - 2025-11-06
## v5.1.1 (2025-11-06)
## [5.1.1] - 2025-11-06
**Breaking Changes**: None (patch version)
@@ -1200,9 +1232,7 @@ Access the viewer at http://localhost:37777 and use the theme toggle to switch b
**Installation**:
Users on Windows will now have a smoother installation experience with automatic PM2 worker startup working correctly.
## [v5.1.0](https://github.com/thedotmack/claude-mem/releases/tag/v5.1.0) - 2025-11-06
## v5.1.0 (2025-11-05)
## [5.1.0] - 2025-11-06
### 🎉 Major Feature: Web-Based Viewer UI
@@ -1317,9 +1347,7 @@ Built with:
**Full Changelog**: https://github.com/thedotmack/claude-mem/compare/v5.0.3...v5.1.0
## [v5.0.3](https://github.com/thedotmack/claude-mem/releases/tag/v5.0.3) - 2025-11-05
## v5.0.3 (2025-11-05)
## [5.0.3] - 2025-11-05
**Breaking Changes**: None (patch version)
@@ -1351,9 +1379,7 @@ This release should completely resolve installation issues. The smart installer
2. Guide you to install VS Build Tools if needed (though you probably won't need them)
3. Only run once on first launch, then be instant on subsequent launches
## [v5.0.2](https://github.com/thedotmack/claude-mem/releases/tag/v5.0.2) - 2025-11-05
## v5.0.2 (2025-11-04)
## [5.0.2] - 2025-11-05
**Breaking Changes**: None (patch version)
@@ -1381,9 +1407,7 @@ Install via Claude Code marketplace:
## Full Changelog
[View all changes](https://github.com/thedotmack/claude-mem/compare/v5.0.1...v5.0.2)
## [v5.0.1](https://github.com/thedotmack/claude-mem/releases/tag/v5.0.1) - 2025-11-04
## v5.0.1 (2025-11-04)
## [5.0.1] - 2025-11-04
**Breaking Changes**: None (patch version)
@@ -1415,9 +1439,7 @@ Install via Claude Code marketplace:
**Installation**: See [README](https://github.com/thedotmack/claude-mem#readme) for installation instructions.
## [v5.0.0](https://github.com/thedotmack/claude-mem/releases/tag/v5.0.0) - 2025-11-04
## v5.0.0 (2025-11-03)
## [5.0.0] - 2025-11-04
### BREAKING CHANGES
- **Python dependency for optimal performance**: While the plugin works without Python, installing Python 3.8+ and the Chroma MCP server unlocks semantic search capabilities. Without Python, the system falls back to SQLite FTS5 keyword search.
@@ -1478,9 +1500,7 @@ Install via Claude Code marketplace:
- Validation: 1,390 observations synced to 8,279 vector documents
- Performance: Semantic search with 90-day window returns results in <200ms
## [v4.3.4](https://github.com/thedotmack/claude-mem/releases/tag/v4.3.4) - 2025-11-02
## v4.3.4 (2025-11-01)
## [4.3.4] - 2025-11-02
**Breaking Changes**: None (patch version)
@@ -1493,9 +1513,7 @@ Install via Claude Code marketplace:
- Modified: plugin/hooks/hooks.json:4 (added `"matcher": "startup|clear|compact"`)
- Impact: Hooks now skip execution when resuming existing sessions
## [v4.3.3](https://github.com/thedotmack/claude-mem/releases/tag/v4.3.3) - 2025-10-27
## v4.3.3 (2025-10-27)
## [4.3.3] - 2025-10-27
**Breaking Changes**: None (patch version)
@@ -1514,9 +1532,7 @@ Install via Claude Code marketplace:
- Modified: plugin/scripts/context-hook.js (rebuilt)
- Modified: plugin/scripts/user-message-hook.js (rebuilt)
## [v4.3.2](https://github.com/thedotmack/claude-mem/releases/tag/v4.3.2) - 2025-10-27
## v4.3.2 (2025-10-27)
## [4.3.2] - 2025-10-27
**Breaking Changes**: None (patch version)
@@ -1540,7 +1556,7 @@ Install via Claude Code marketplace:
- scripts/build-hooks.js (build support for new hook)
- Design rationale: Error messages don't get added to context, so we intentionally duplicate context output via stderr for user visibility. This is a temporary workaround until Claude Code potentially adds ability to share messages with both user and context simultaneously.
## [v4.3.1](https://github.com/thedotmack/claude-mem/releases/tag/v4.3.1) - 2025-10-26
## [4.3.1] - 2025-10-26
## Fixes
@@ -1564,7 +1580,7 @@ None (patch version)
**Full Changelog**: https://github.com/thedotmack/claude-mem/compare/v4.3.0...v4.3.1
## [v4.3.0](https://github.com/thedotmack/claude-mem/releases/tag/v4.3.0) - 2025-10-25
## [4.3.0] - 2025-10-25
## What's Changed
* feat: Enhanced context hook with session observations and cross-platform improvements by @thedotmack in https://github.com/thedotmack/claude-mem/pull/25
@@ -1574,7 +1590,7 @@ None (patch version)
**Full Changelog**: https://github.com/thedotmack/claude-mem/compare/v4.2.11...v4.3.0
## [v4.2.10](https://github.com/thedotmack/claude-mem/releases/tag/v4.2.10) - 2025-10-25
## [4.2.10] - 2025-10-25
## Fixed
- **Windows compatibility**: Removed hardcoded macOS-specific Claude executable path that prevented worker service from running on Windows
@@ -1600,15 +1616,11 @@ None (patch version)
- `src/services/worker-service.ts`
- `plugin/scripts/worker-service.cjs` (rebuilt)
## [4.2.3](https://github.com/thedotmack/claude-mem/releases/tag/4.2.3) - 2025-10-24
## [4.2.3] - 2025-10-24
## [4.2.1] - 2025-10-23
## [v4.2.1](https://github.com/thedotmack/claude-mem/releases/tag/v4.2.1) - 2025-10-23
## [v3.9.16](https://github.com/thedotmack/claude-mem/releases/tag/v3.9.16) - 2025-10-07
## [3.9.16] - 2025-10-07
## What's New
@@ -1626,7 +1638,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.9.14](https://github.com/thedotmack/claude-mem/releases/tag/v3.9.14) - 2025-10-04
## [3.9.14] - 2025-10-04
## What's New
@@ -1644,7 +1656,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.9.13](https://github.com/thedotmack/claude-mem/releases/tag/v3.9.13) - 2025-10-04
## [3.9.13] - 2025-10-04
## What's New
@@ -1662,7 +1674,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.9.12](https://github.com/thedotmack/claude-mem/releases/tag/v3.9.12) - 2025-10-04
## [3.9.12] - 2025-10-04
## What's New
@@ -1680,7 +1692,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.9.11](https://github.com/thedotmack/claude-mem/releases/tag/v3.9.11) - 2025-10-04
## [3.9.11] - 2025-10-04
## What's New
@@ -1698,7 +1710,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.9.10](https://github.com/thedotmack/claude-mem/releases/tag/v3.9.10) - 2025-10-03
## [3.9.10] - 2025-10-03
## What's New
@@ -1716,7 +1728,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.9.9](https://github.com/thedotmack/claude-mem/releases/tag/v3.9.9) - 2025-10-03
## [3.9.9] - 2025-10-03
## What's New
@@ -1734,7 +1746,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.7.2](https://github.com/thedotmack/claude-mem/releases/tag/v3.7.2) - 2025-09-22
## [3.7.2] - 2025-09-22
## What's New
@@ -1752,7 +1764,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.7.1](https://github.com/thedotmack/claude-mem/releases/tag/v3.7.1) - 2025-09-18
## [3.7.1] - 2025-09-18
## What's New
@@ -1770,7 +1782,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.7.0](https://github.com/thedotmack/claude-mem/releases/tag/v3.7.0) - 2025-09-18
## [3.7.0] - 2025-09-18
## What's New
@@ -1788,7 +1800,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.6.10](https://github.com/thedotmack/claude-mem/releases/tag/v3.6.10) - 2025-09-17
## [3.6.10] - 2025-09-17
## What's New
@@ -1806,7 +1818,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.6.9](https://github.com/thedotmack/claude-mem/releases/tag/v3.6.9) - 2025-09-15
## [3.6.9] - 2025-09-15
## What's New
@@ -1824,7 +1836,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.6.8](https://github.com/thedotmack/claude-mem/releases/tag/v3.6.8) - 2025-09-14
## [3.6.8] - 2025-09-14
## What's New
@@ -1842,7 +1854,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.6.6](https://github.com/thedotmack/claude-mem/releases/tag/v3.6.6) - 2025-09-14
## [3.6.6] - 2025-09-14
## What's New
@@ -1860,7 +1872,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.6.5](https://github.com/thedotmack/claude-mem/releases/tag/v3.6.5) - 2025-09-14
## [3.6.5] - 2025-09-14
## What's New
@@ -1878,7 +1890,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.6.4](https://github.com/thedotmack/claude-mem/releases/tag/v3.6.4) - 2025-09-14
## [3.6.4] - 2025-09-14
## What's New
@@ -1896,7 +1908,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.6.3](https://github.com/thedotmack/claude-mem/releases/tag/v3.6.3) - 2025-09-11
## [3.6.3] - 2025-09-11
## What's New
@@ -1914,7 +1926,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.6.2](https://github.com/thedotmack/claude-mem/releases/tag/v3.6.2) - 2025-09-11
## [3.6.2] - 2025-09-11
## What's New
@@ -1932,7 +1944,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.6.1](https://github.com/thedotmack/claude-mem/releases/tag/v3.6.1) - 2025-09-10
## [3.6.1] - 2025-09-10
## What's New
@@ -1950,7 +1962,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.6.0](https://github.com/thedotmack/claude-mem/releases/tag/v3.6.0) - 2025-09-10
## [3.6.0] - 2025-09-10
## What's New
@@ -1968,7 +1980,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.5.9](https://github.com/thedotmack/claude-mem/releases/tag/v3.5.9) - 2025-09-10
## [3.5.9] - 2025-09-10
## What's New
@@ -1986,7 +1998,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.5.8](https://github.com/thedotmack/claude-mem/releases/tag/v3.5.8) - 2025-09-10
## [3.5.8] - 2025-09-10
## What's New
@@ -2004,7 +2016,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.5.7](https://github.com/thedotmack/claude-mem/releases/tag/v3.5.7) - 2025-09-10
## [3.5.7] - 2025-09-10
## What's New
@@ -2022,7 +2034,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.5.6](https://github.com/thedotmack/claude-mem/releases/tag/v3.5.6) - 2025-09-09
## [3.5.6] - 2025-09-09
## What's New
@@ -2040,7 +2052,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.5.5](https://github.com/thedotmack/claude-mem/releases/tag/v3.5.5) - 2025-09-09
## [3.5.5] - 2025-09-09
## What's New
@@ -2058,7 +2070,7 @@ claude-mem install
For full documentation, visit the [README](https://github.com/thedotmack/claude-mem#readme).
## [v3.5.4](https://github.com/thedotmack/claude-mem/releases/tag/v3.5.4) - 2025-09-09
## [3.5.4] - 2025-09-09
## 🎉 claude-mem v3.5.4
@@ -2094,4 +2106,3 @@ claude-mem install
- uv (automatically installed if missing)
For documentation and support, visit the [GitHub repository](https://github.com/thedotmack/claude-mem).
+1 -1
View File
@@ -6,7 +6,7 @@
Claude-mem is a Claude Code plugin providing persistent memory across sessions. It captures tool usage, compresses observations using the Claude Agent SDK, and injects relevant context into future sessions.
**Current Version**: 6.4.0
**Current Version**: 6.4.9
## Architecture
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "claude-mem",
"version": "6.4.0",
"version": "6.4.9",
"description": "Memory compression system for Claude Code - persist context across sessions",
"keywords": [
"claude",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "claude-mem",
"version": "6.4.0",
"version": "6.4.9",
"description": "Persistent memory system for Claude Code - seamlessly preserve context across sessions",
"author": {
"name": "Alex Newman"
File diff suppressed because one or more lines are too long
+9 -6
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env node
import{execSync as _}from"child_process";import{join as i}from"path";import{homedir as p}from"os";import{existsSync as y}from"fs";import l from"path";import{homedir as f}from"os";import{existsSync as g,readFileSync as h}from"fs";import{join as t,dirname as m,basename as T}from"path";import{homedir as a}from"os";import{fileURLToPath as u}from"url";function d(){return typeof __dirname<"u"?__dirname:m(u(import.meta.url))}var P=d(),e=process.env.CLAUDE_MEM_DATA_DIR||t(a(),".claude-mem"),s=process.env.CLAUDE_CONFIG_DIR||t(a(),".claude"),A=t(e,"archives"),C=t(e,"logs"),S=t(e,"trash"),v=t(e,"backups"),I=t(e,"settings.json"),b=t(e,"claude-mem.db"),M=t(e,"vector-db"),U=t(s,"settings.json"),j=t(s,"commands"),L=t(s,"CLAUDE.md");function c(){try{let o=l.join(f(),".claude-mem","settings.json");if(g(o)){let n=JSON.parse(h(o,"utf-8")),r=parseInt(n.env?.CLAUDE_MEM_WORKER_PORT,10);if(!isNaN(r))return r}}catch{}return parseInt(process.env.CLAUDE_MEM_WORKER_PORT||"37777",10)}var x=i(p(),".claude","plugins","marketplaces","thedotmack"),D=i(x,"node_modules");y(D)||(console.error(`
import{execSync as A}from"child_process";import{join as c}from"path";import{homedir as d}from"os";import{existsSync as C}from"fs";import x from"path";import{homedir as E}from"os";import{existsSync as k,readFileSync as R}from"fs";import{join as t,dirname as T,basename as U}from"path";import{homedir as u}from"os";import{fileURLToPath as y}from"url";function w(){return typeof __dirname<"u"?__dirname:T(y(import.meta.url))}var H=w(),e=process.env.CLAUDE_MEM_DATA_DIR||t(u(),".claude-mem"),a=process.env.CLAUDE_CONFIG_DIR||t(u(),".claude"),W=t(e,"archives"),j=t(e,"logs"),N=t(e,"trash"),$=t(e,"backups"),F=t(e,"settings.json"),K=t(e,"claude-mem.db"),B=t(e,"vector-db"),G=t(a,"settings.json"),V=t(a,"commands"),J=t(a,"CLAUDE.md");function l(){try{let o=x.join(E(),".claude-mem","settings.json");if(k(o)){let s=JSON.parse(R(o,"utf-8")),n=parseInt(s.env?.CLAUDE_MEM_WORKER_PORT,10);if(!isNaN(n))return n}}catch{}return parseInt(process.env.CLAUDE_MEM_WORKER_PORT||"37777",10)}var P=c(d(),".claude","plugins","marketplaces","thedotmack"),S=c(P,"node_modules");C(S)||(console.error(`
---
\u{1F389} Note: This appears under Plugin Hook Error, but it's not an error. That's the only option for
user messages in Claude Code UI until a better method is provided.
@@ -17,16 +17,19 @@ Dependencies have been installed in the background. This only happens once.
Thank you for installing Claude-Mem!
This message was not added to your startup context, so you can continue working as normal.
`),process.exit(3));try{let o=i(p(),".claude","plugins","marketplaces","thedotmack","plugin","scripts","context-hook.js"),n=_(`node "${o}" --colors`,{encoding:"utf8"}),r=c();console.error(`
`),process.exit(3));try{let o=c(d(),".claude","plugins","marketplaces","thedotmack","plugin","scripts","context-hook.js"),s=A(`node "${o}" --colors`,{encoding:"utf8"}),n=l(),r=new Date,f=new Date("2025-12-06T00:00:00Z"),i="";if(r<f){let g=r.getUTCHours()*60+r.getUTCMinutes(),m=Math.floor((g-300+1440)%1440/60),p=r.getUTCDate(),h=r.getUTCMonth(),D=r.getUTCFullYear()===2025&&h===11&&p>=1&&p<=5,_=m>=17&&m<19;D&&_?i=`
\u{1F534} LIVE NOW: AMA w/ Dev (@thedotmack) until 7pm EST
`:i=`
\u2013 LIVE AMA w/ Dev (@thedotmack) Dec 1st\u20135th, 5pm to 7pm EST
`}console.error(`
\u{1F4DD} Claude-Mem Context Loaded
\u2139\uFE0F Note: This appears as stderr but is informational only
`+n+`
`+s+`
\u{1F4A1} New! Wrap all or part of any message with <private> ... </private> to prevent storing sensitive information in your observation history.
\u{1F4AC} Community https://discord.gg/J4wttp9vDu
\u{1F4FA} Watch live in browser http://localhost:${r}/
\u{1F4AC} Community https://discord.gg/J4wttp9vDu`+i+`
\u{1F4FA} Watch live in browser http://localhost:${n}/
`)}catch(o){console.error(`\u274C Failed to load context display: ${o}`)}process.exit(3);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+68
View File
@@ -0,0 +1,68 @@
/**
* Observation metadata constants
* Shared across hooks, worker service, and UI components
*/
/**
* Valid observation types
*/
export const OBSERVATION_TYPES = [
'bugfix',
'feature',
'refactor',
'discovery',
'decision',
'change'
] as const;
export type ObservationType = typeof OBSERVATION_TYPES[number];
/**
* Valid observation concepts
*/
export const OBSERVATION_CONCEPTS = [
'how-it-works',
'why-it-exists',
'what-changed',
'problem-solution',
'gotcha',
'pattern',
'trade-off'
] as const;
export type ObservationConcept = typeof OBSERVATION_CONCEPTS[number];
/**
* Map observation types to emoji icons
*/
export const TYPE_ICON_MAP: Record<ObservationType | 'session-request', string> = {
'bugfix': '🔴',
'feature': '🟣',
'refactor': '🔄',
'change': '✅',
'discovery': '🔵',
'decision': '⚖️',
'session-request': '🎯'
};
/**
* Map observation types to work emoji (for token display)
*/
export const TYPE_WORK_EMOJI_MAP: Record<ObservationType, string> = {
'discovery': '🔍', // research/exploration
'change': '🛠️', // building/modifying
'feature': '🛠️', // building/modifying
'bugfix': '🛠️', // building/modifying
'refactor': '🛠️', // building/modifying
'decision': '⚖️' // decision-making
};
/**
* Default observation types (comma-separated string for settings)
*/
export const DEFAULT_OBSERVATION_TYPES_STRING = OBSERVATION_TYPES.join(',');
/**
* Default observation concepts (comma-separated string for settings)
*/
export const DEFAULT_OBSERVATION_CONCEPTS_STRING = OBSERVATION_CONCEPTS.join(',');
+347 -96
View File
@@ -10,6 +10,15 @@ import { stdin } from 'process';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import { SessionStore } from '../services/sqlite/SessionStore.js';
import {
OBSERVATION_TYPES,
OBSERVATION_CONCEPTS,
TYPE_ICON_MAP,
TYPE_WORK_EMOJI_MAP,
DEFAULT_OBSERVATION_TYPES_STRING,
DEFAULT_OBSERVATION_CONCEPTS_STRING
} from '../constants/observation-metadata.js';
import { logger } from '../utils/logger.js';
// Get __dirname equivalent in ESM
const __filename = fileURLToPath(import.meta.url);
@@ -19,31 +28,82 @@ const __dirname = dirname(__filename);
// From src/hooks/ we need to go up to plugin root: ../../
const VERSION_MARKER_PATH = path.join(__dirname, '../../.install-version');
/**
* Get context depth from settings
* Priority: ~/.claude/settings.json > env var > default
*/
function getContextDepth(): number {
try {
const settingsPath = path.join(homedir(), '.claude', 'settings.json');
if (existsSync(settingsPath)) {
const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
if (settings.env?.CLAUDE_MEM_CONTEXT_OBSERVATIONS) {
const count = parseInt(settings.env.CLAUDE_MEM_CONTEXT_OBSERVATIONS, 10);
if (!isNaN(count) && count > 0) {
return count;
}
}
}
} catch {
// Fall through to env var or default
}
return parseInt(process.env.CLAUDE_MEM_CONTEXT_OBSERVATIONS || '50', 10);
interface ContextConfig {
// Display counts
totalObservationCount: number;
fullObservationCount: number;
sessionCount: number;
// Token display toggles
showReadTokens: boolean;
showWorkTokens: boolean;
showSavingsAmount: boolean;
showSavingsPercent: boolean;
// Filters
observationTypes: Set<string>;
observationConcepts: Set<string>;
// Display options
fullObservationField: 'narrative' | 'facts';
showLastSummary: boolean;
showLastMessage: boolean;
}
// Configuration: Read from settings.json or environment
const DISPLAY_OBSERVATION_COUNT = getContextDepth();
const DISPLAY_SESSION_COUNT = 10; // Recent sessions for timeline context
/**
* Load all context configuration settings
* Priority: ~/.claude-mem/settings.json > env var > defaults
*/
function loadContextConfig(): ContextConfig {
const defaults = {
totalObservationCount: parseInt(process.env.CLAUDE_MEM_CONTEXT_OBSERVATIONS || '50', 10),
fullObservationCount: 5,
sessionCount: 10,
showReadTokens: true,
showWorkTokens: true,
showSavingsAmount: true,
showSavingsPercent: true,
observationTypes: new Set(OBSERVATION_TYPES),
observationConcepts: new Set(OBSERVATION_CONCEPTS),
fullObservationField: 'narrative' as const,
showLastSummary: true,
showLastMessage: false,
};
try {
const settingsPath = path.join(homedir(), '.claude-mem', 'settings.json');
if (!existsSync(settingsPath)) return defaults;
const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
const env = settings.env || {};
return {
totalObservationCount: parseInt(env.CLAUDE_MEM_CONTEXT_OBSERVATIONS || '50', 10),
fullObservationCount: parseInt(env.CLAUDE_MEM_CONTEXT_FULL_COUNT || '5', 10),
sessionCount: parseInt(env.CLAUDE_MEM_CONTEXT_SESSION_COUNT || '10', 10),
showReadTokens: env.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS !== 'false',
showWorkTokens: env.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS !== 'false',
showSavingsAmount: env.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT !== 'false',
showSavingsPercent: env.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT !== 'false',
observationTypes: new Set(
(env.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES || DEFAULT_OBSERVATION_TYPES_STRING)
.split(',').map((t: string) => t.trim()).filter(Boolean)
),
observationConcepts: new Set(
(env.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS || DEFAULT_OBSERVATION_CONCEPTS_STRING)
.split(',').map((c: string) => c.trim()).filter(Boolean)
),
fullObservationField: (env.CLAUDE_MEM_CONTEXT_FULL_FIELD || 'narrative') as 'narrative' | 'facts',
showLastSummary: env.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY !== 'false',
showLastMessage: env.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE === 'true',
};
} catch (error) {
logger.warn('HOOK', 'Failed to load context settings, using defaults', {}, error as Error);
return defaults;
}
}
// Configuration constants
const CHARS_PER_TOKEN_ESTIMATE = 4; // Rough estimate for token counting
const SUMMARY_LOOKAHEAD = 1; // Fetch one extra summary for offset calculation
@@ -159,10 +219,73 @@ function renderSummaryField(label: string, value: string | null, color: string,
return [`**${label}**: ${value}`, ''];
}
// Helper: Convert cwd path to dashed format for transcript directory name
function cwdToDashed(cwd: string): string {
// Convert all slashes to dashes (including leading slash)
return cwd.replace(/\//g, '-');
}
// Helper: Extract last assistant message from transcript file
function extractPriorMessages(transcriptPath: string): { userMessage: string; assistantMessage: string } {
try {
if (!existsSync(transcriptPath)) {
return { userMessage: '', assistantMessage: '' };
}
const content = readFileSync(transcriptPath, 'utf-8').trim();
if (!content) {
return { userMessage: '', assistantMessage: '' };
}
const lines = content.split('\n').filter(line => line.trim());
// Find the last assistant message by filtering for assistant type and taking the last one
let lastAssistantMessage = '';
// Iterate backwards to find the most recent assistant message with text content
for (let i = lines.length - 1; i >= 0; i--) {
try {
const line = lines[i];
// Quick check if this line is an assistant message
if (!line.includes('"type":"assistant"')) {
continue;
}
const entry = JSON.parse(line);
if (entry.type === 'assistant' && entry.message?.content && Array.isArray(entry.message.content)) {
let text = '';
for (const block of entry.message.content) {
if (block.type === 'text') {
text += block.text;
}
}
// Remove system-reminder tags
text = text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, '').trim();
if (text) {
lastAssistantMessage = text;
break; // Found it, stop searching
}
}
} catch (parseError) {
// Skip malformed lines
continue;
}
}
return { userMessage: '', assistantMessage: lastAssistantMessage };
} catch (error) {
logger.failure('HOOK', `Failed to extract prior messages from transcript`, { transcriptPath }, error as Error);
return { userMessage: '', assistantMessage: '' };
}
}
/**
* Context Hook Main Logic
*/
async function contextHook(input?: SessionStartInput, useColors: boolean = false): Promise<string> {
const config = loadContextConfig();
const cwd = input?.cwd ?? process.cwd();
const project = cwd ? path.basename(cwd) : 'unknown-project';
@@ -188,19 +311,32 @@ async function contextHook(input?: SessionStartInput, useColors: boolean = false
throw error;
}
// Get ALL recent observations for this project (not filtered by summaries)
// Build SQL WHERE clause for observation types
const typeArray = Array.from(config.observationTypes);
const typePlaceholders = typeArray.map(() => '?').join(',');
// Build SQL WHERE clause for concepts
const conceptArray = Array.from(config.observationConcepts);
const conceptPlaceholders = conceptArray.map(() => '?').join(',');
// Get recent observations filtered by type and concepts at SQL level
// This ensures we show observations even when summaries haven't been generated
// Configurable via CLAUDE_MEM_CONTEXT_OBSERVATIONS env var (default: 50)
const allObservations = db.db.prepare(`
// Configurable via settings (default: 50)
const observations = db.db.prepare(`
SELECT
id, sdk_session_id, type, title, subtitle, narrative,
facts, concepts, files_read, files_modified, discovery_tokens,
created_at, created_at_epoch
FROM observations
WHERE project = ?
AND type IN (${typePlaceholders})
AND EXISTS (
SELECT 1 FROM json_each(concepts)
WHERE value IN (${conceptPlaceholders})
)
ORDER BY created_at_epoch DESC
LIMIT ?
`).all(project, DISPLAY_OBSERVATION_COUNT) as Observation[];
`).all(project, ...typeArray, ...conceptArray, config.totalObservationCount) as Observation[];
// Get recent summaries (optional - may not exist for recent sessions)
// Fetch one extra for offset calculation
@@ -210,10 +346,53 @@ async function contextHook(input?: SessionStartInput, useColors: boolean = false
WHERE project = ?
ORDER BY created_at_epoch DESC
LIMIT ?
`).all(project, DISPLAY_SESSION_COUNT + SUMMARY_LOOKAHEAD) as SessionSummary[];
`).all(project, config.sessionCount + SUMMARY_LOOKAHEAD) as SessionSummary[];
// Retrieve prior session messages if enabled
let priorUserMessage = '';
let priorAssistantMessage = '';
// let debugInfo: string[] = [];
if (config.showLastMessage && observations.length > 0) {
try {
const currentSessionId = input?.session_id;
// Find the first observation from a different session (the prior session)
const priorSessionObs = observations.find(obs => obs.sdk_session_id !== currentSessionId);
if (priorSessionObs) {
const priorSessionId = priorSessionObs.sdk_session_id;
// Construct transcript path: ~/.claude/projects/{dashed-cwd}/{session_id}.jsonl
const dashedCwd = cwdToDashed(cwd);
const transcriptPath = path.join(homedir(), '.claude', 'projects', dashedCwd, `${priorSessionId}.jsonl`);
// debugInfo.push(`📋 Prior Message Retrieval:`);
// debugInfo.push(` Session ID: ${priorSessionId}`);
// debugInfo.push(` Transcript: ${transcriptPath}`);
// debugInfo.push(` Exists: ${existsSync(transcriptPath)}`);
// Extract messages from transcript
const messages = extractPriorMessages(transcriptPath);
priorUserMessage = messages.userMessage;
priorAssistantMessage = messages.assistantMessage;
// if (!priorUserMessage && !priorAssistantMessage) {
// debugInfo.push(` ⚠️ No messages extracted from transcript`);
// } else {
// debugInfo.push(` ✅ Found user message: ${!!priorUserMessage}`);
// debugInfo.push(` ✅ Found assistant message: ${!!priorAssistantMessage}`);
// }
} // else {
// debugInfo.push(`📋 Prior Message Retrieval: No prior session found (all observations from current session)`);
// }
} catch (error) {
// debugInfo.push(`📋 Prior Message Retrieval Error: ${(error as Error).message}`);
}
}
// If we have neither observations nor summaries, show empty state
if (allObservations.length === 0 && recentSummaries.length === 0) {
if (observations.length === 0 && recentSummaries.length === 0) {
db.close();
if (useColors) {
return `\n${colors.bright}${colors.cyan}📝 [${project}] recent context${colors.reset}\n${colors.gray}${'─'.repeat(60)}${colors.reset}\n\n${colors.dim}No previous sessions found for this project yet.${colors.reset}\n`;
@@ -221,11 +400,9 @@ async function contextHook(input?: SessionStartInput, useColors: boolean = false
return `# [${project}] recent context\n\nNo previous sessions found for this project yet.`;
}
// Use observations for display (summaries are supplementary)
const observations = allObservations;
const displaySummaries = recentSummaries.slice(0, DISPLAY_SESSION_COUNT);
const displaySummaries = recentSummaries.slice(0, config.sessionCount);
// All observations are shown in timeline (filtered by type, not concepts)
// All filtered observations are shown in timeline
const timelineObs = observations;
// Build output
@@ -298,23 +475,44 @@ async function contextHook(input?: SessionStartInput, useColors: boolean = false
? Math.round((savings / totalDiscoveryTokens) * 100)
: 0;
// Display Context Economics section
if (useColors) {
output.push(`${colors.bright}${colors.cyan}📊 Context Economics${colors.reset}`);
output.push(`${colors.dim} Loading: ${totalObservations} observations (${totalReadTokens.toLocaleString()} tokens to read)${colors.reset}`);
output.push(`${colors.dim} Work investment: ${totalDiscoveryTokens.toLocaleString()} tokens spent on research, building, and decisions${colors.reset}`);
if (totalDiscoveryTokens > 0) {
output.push(`${colors.green} Your savings: ${savings.toLocaleString()} tokens (${savingsPercent}% reduction from reuse)${colors.reset}`);
// Display Context Economics section only if at least one token setting is enabled
const showContextEconomics = config.showReadTokens || config.showWorkTokens ||
config.showSavingsAmount || config.showSavingsPercent;
if (showContextEconomics) {
if (useColors) {
output.push(`${colors.bright}${colors.cyan}📊 Context Economics${colors.reset}`);
output.push(`${colors.dim} Loading: ${totalObservations} observations (${totalReadTokens.toLocaleString()} tokens to read)${colors.reset}`);
output.push(`${colors.dim} Work investment: ${totalDiscoveryTokens.toLocaleString()} tokens spent on research, building, and decisions${colors.reset}`);
if (totalDiscoveryTokens > 0 && (config.showSavingsAmount || config.showSavingsPercent)) {
let savingsLine = ' Your savings: ';
if (config.showSavingsAmount && config.showSavingsPercent) {
savingsLine += `${savings.toLocaleString()} tokens (${savingsPercent}% reduction from reuse)`;
} else if (config.showSavingsAmount) {
savingsLine += `${savings.toLocaleString()} tokens`;
} else {
savingsLine += `${savingsPercent}% reduction from reuse`;
}
output.push(`${colors.green}${savingsLine}${colors.reset}`);
}
output.push('');
} else {
output.push(`📊 **Context Economics**:`);
output.push(`- Loading: ${totalObservations} observations (${totalReadTokens.toLocaleString()} tokens to read)`);
output.push(`- Work investment: ${totalDiscoveryTokens.toLocaleString()} tokens spent on research, building, and decisions`);
if (totalDiscoveryTokens > 0 && (config.showSavingsAmount || config.showSavingsPercent)) {
let savingsLine = '- Your savings: ';
if (config.showSavingsAmount && config.showSavingsPercent) {
savingsLine += `${savings.toLocaleString()} tokens (${savingsPercent}% reduction from reuse)`;
} else if (config.showSavingsAmount) {
savingsLine += `${savings.toLocaleString()} tokens`;
} else {
savingsLine += `${savingsPercent}% reduction from reuse`;
}
output.push(savingsLine);
}
output.push('');
}
output.push('');
} else {
output.push(`📊 **Context Economics**:`);
output.push(`- Loading: ${totalObservations} observations (${totalReadTokens.toLocaleString()} tokens to read)`);
output.push(`- Work investment: ${totalDiscoveryTokens.toLocaleString()} tokens spent on research, building, and decisions`);
if (totalDiscoveryTokens > 0) {
output.push(`- Your savings: ${savings.toLocaleString()} tokens (${savingsPercent}% reduction from reuse)`);
}
output.push('');
}
// Prepare summaries for timeline display
@@ -341,6 +539,13 @@ async function contextHook(input?: SessionStartInput, useColors: boolean = false
};
});
// Identify which observations should show full details (most recent N)
const fullObservationIds = new Set(
observations
.slice(0, config.fullObservationCount)
.map(obs => obs.id)
);
type TimelineItem =
| { type: 'observation'; data: Observation }
| { type: 'summary'; data: SummaryTimelineItem };
@@ -449,29 +654,7 @@ async function contextHook(input?: SessionStartInput, useColors: boolean = false
const title = obs.title || 'Untitled';
// Map observation type to emoji icon
let icon = '•';
switch (obs.type) {
case 'bugfix':
icon = '🔴';
break;
case 'feature':
icon = '🟣';
break;
case 'refactor':
icon = '🔄';
break;
case 'change':
icon = '✅';
break;
case 'discovery':
icon = '🔵';
break;
case 'decision':
icon = '⚖️';
break;
default:
icon = '•';
}
const icon = TYPE_ICON_MAP[obs.type as keyof typeof TYPE_ICON_MAP] || '•';
// Section 2: Calculate read tokens (estimate from observation size)
const obsSize = (obs.title?.length || 0) +
@@ -484,21 +667,7 @@ async function contextHook(input?: SessionStartInput, useColors: boolean = false
const discoveryTokens = obs.discovery_tokens || 0;
// Map observation type to work emoji
let workEmoji = '🔍'; // default to research/discovery
switch (obs.type) {
case 'discovery':
workEmoji = '🔍'; // research/exploration
break;
case 'change':
case 'feature':
case 'bugfix':
case 'refactor':
workEmoji = '🛠️'; // building/modifying
break;
case 'decision':
workEmoji = '⚖️'; // decision-making
break;
}
const workEmoji = TYPE_WORK_EMOJI_MAP[obs.type as keyof typeof TYPE_WORK_EMOJI_MAP] || '🔍';
const discoveryDisplay = discoveryTokens > 0 ? `${workEmoji} ${discoveryTokens.toLocaleString()}` : '-';
@@ -506,13 +675,68 @@ async function contextHook(input?: SessionStartInput, useColors: boolean = false
const timeDisplay = showTime ? time : '';
lastTime = time;
if (useColors) {
const timePart = showTime ? `${colors.dim}${time}${colors.reset}` : ' '.repeat(time.length);
const readPart = readTokens > 0 ? `${colors.dim}(~${readTokens}t)${colors.reset}` : '';
const discoveryPart = discoveryTokens > 0 ? `${colors.dim}(${workEmoji} ${discoveryTokens.toLocaleString()}t)${colors.reset}` : '';
output.push(` ${colors.dim}#${obs.id}${colors.reset} ${timePart} ${icon} ${title} ${readPart} ${discoveryPart}`);
// Check if this observation should show full details
const shouldShowFull = fullObservationIds.has(obs.id);
if (shouldShowFull) {
// Render with full details (narrative or facts)
const detailField = config.fullObservationField === 'narrative'
? obs.narrative
: (obs.facts ? parseJsonArray(obs.facts).join('\n') : null);
if (useColors) {
const timePart = showTime ? `${colors.dim}${time}${colors.reset}` : ' '.repeat(time.length);
const readPart = (config.showReadTokens && readTokens > 0) ? `${colors.dim}(~${readTokens}t)${colors.reset}` : '';
const discoveryPart = (config.showWorkTokens && discoveryTokens > 0) ? `${colors.dim}(${workEmoji} ${discoveryTokens.toLocaleString()}t)${colors.reset}` : '';
output.push(` ${colors.dim}#${obs.id}${colors.reset} ${timePart} ${icon} ${colors.bright}${title}${colors.reset}`);
if (detailField) {
output.push(` ${colors.dim}${detailField}${colors.reset}`);
}
if (readPart || discoveryPart) {
output.push(` ${readPart} ${discoveryPart}`);
}
output.push('');
} else {
// Close table for full observation
if (tableOpen) {
output.push('');
tableOpen = false;
}
output.push(`**#${obs.id}** ${timeDisplay || '″'} ${icon} **${title}**`);
if (detailField) {
output.push('');
output.push(detailField);
output.push('');
}
const tokenParts: string[] = [];
if (config.showReadTokens) {
tokenParts.push(`Read: ~${readTokens}`);
}
if (config.showWorkTokens) {
tokenParts.push(`Work: ${discoveryDisplay}`);
}
if (tokenParts.length > 0) {
output.push(tokenParts.join(', '));
}
output.push('');
// Reopen table for next items if in same file
currentFile = null;
}
} else {
output.push(`| #${obs.id} | ${timeDisplay || '″'} | ${icon} | ${title} | ~${readTokens} | ${discoveryDisplay} |`);
// Compact index rendering (existing code)
if (useColors) {
const timePart = showTime ? `${colors.dim}${time}${colors.reset}` : ' '.repeat(time.length);
const readPart = (config.showReadTokens && readTokens > 0) ? `${colors.dim}(~${readTokens}t)${colors.reset}` : '';
const discoveryPart = (config.showWorkTokens && discoveryTokens > 0) ? `${colors.dim}(${workEmoji} ${discoveryTokens.toLocaleString()}t)${colors.reset}` : '';
output.push(` ${colors.dim}#${obs.id}${colors.reset} ${timePart} ${icon} ${title} ${readPart} ${discoveryPart}`);
} else {
const readCol = config.showReadTokens ? `~${readTokens}` : '';
const workCol = config.showWorkTokens ? discoveryDisplay : '';
output.push(`| #${obs.id} | ${timeDisplay || '″'} | ${icon} | ${title} | ${readCol} | ${workCol} |`);
}
}
}
}
@@ -528,7 +752,8 @@ async function contextHook(input?: SessionStartInput, useColors: boolean = false
const mostRecentSummary = recentSummaries[0];
const mostRecentObservation = observations[0]; // observations are DESC by created_at_epoch
const shouldShowSummary = mostRecentSummary &&
const shouldShowSummary = config.showLastSummary &&
mostRecentSummary &&
(mostRecentSummary.investigated || mostRecentSummary.learned || mostRecentSummary.completed || mostRecentSummary.next_steps) &&
(!mostRecentObservation || mostRecentSummary.created_at_epoch > mostRecentObservation.created_at_epoch);
@@ -539,8 +764,25 @@ async function contextHook(input?: SessionStartInput, useColors: boolean = false
output.push(...renderSummaryField('Next Steps', mostRecentSummary.next_steps, colors.magenta, useColors));
}
// Footer with token savings message
if (totalDiscoveryTokens > 0 && savings > 0) {
// Previously section (last assistant message from prior session) - positioned at bottom for chronological sense
if (priorAssistantMessage) {
output.push('');
output.push('---');
output.push('');
if (useColors) {
output.push(`${colors.bright}${colors.magenta}📋 Previously${colors.reset}`);
output.push('');
output.push(`${colors.dim}A: ${priorAssistantMessage}${colors.reset}`);
} else {
output.push(`**📋 Previously**`);
output.push('');
output.push(`A: ${priorAssistantMessage}`);
}
output.push('');
}
// Footer with token savings message (only show if token economics is visible)
if (showContextEconomics && totalDiscoveryTokens > 0 && savings > 0) {
const workTokensK = Math.round(totalDiscoveryTokens / 1000);
output.push('');
if (useColors) {
@@ -552,6 +794,15 @@ async function contextHook(input?: SessionStartInput, useColors: boolean = false
}
db.close();
// Add debug info directly to output
// if (debugInfo.length > 0) {
// output.push('');
// output.push('---');
// output.push('');
// output.push(...debugInfo);
// }
return output.join('\n').trimEnd();
}
+27 -1
View File
@@ -48,12 +48,38 @@ try {
});
const port = getWorkerPort();
// If it's after Dec 5, 2025 7pm EST, patch this out
const now = new Date();
const amaEndDate = new Date('2025-12-06T00:00:00Z'); // Dec 5, 2025 7pm EST
let amaAnnouncement = "";
if (now < amaEndDate) {
// Check if we're during the live event (Dec 1-5, 5pm-7pm EST daily)
const estOffset = 5 * 60; // EST is UTC-5
const nowUtcMinutes = now.getUTCHours() * 60 + now.getUTCMinutes();
const estHour = Math.floor((nowUtcMinutes - estOffset + 1440) % 1440 / 60);
const day = now.getUTCDate();
const month = now.getUTCMonth();
const year = now.getUTCFullYear();
const isDec1to5 = year === 2025 && month === 11 && day >= 1 && day <= 5;
const isDuringLiveHours = estHour >= 17 && estHour < 19; // 5pm-7pm EST
if (isDec1to5 && isDuringLiveHours) {
amaAnnouncement = "\n 🔴 LIVE NOW: AMA w/ Dev (@thedotmack) until 7pm EST\n";
} else {
amaAnnouncement = "\n LIVE AMA w/ Dev (@thedotmack) Dec 1st5th, 5pm to 7pm EST\n";
}
}
console.error(
"\n\n📝 Claude-Mem Context Loaded\n" +
" ️ Note: This appears as stderr but is informational only\n\n" +
output +
"\n\n💡 New! Wrap all or part of any message with <private> ... </private> to prevent storing sensitive information in your observation history.\n" +
"\n💬 Community https://discord.gg/J4wttp9vDu\n" +
"\n💬 Community https://discord.gg/J4wttp9vDu" +
amaAnnouncement +
`\n📺 Watch live in browser http://localhost:${port}/\n`
);
+144 -20
View File
@@ -30,6 +30,12 @@ import { SDKAgent } from './worker/SDKAgent.js';
import { PaginationHelper } from './worker/PaginationHelper.js';
import { SettingsManager } from './worker/SettingsManager.js';
import { getBranchInfo, switchBranch, pullUpdates, type BranchInfo, type SwitchResult } from './worker/BranchManager.js';
import {
OBSERVATION_TYPES,
OBSERVATION_CONCEPTS,
DEFAULT_OBSERVATION_TYPES_STRING,
DEFAULT_OBSERVATION_CONCEPTS_STRING
} from '../constants/observation-metadata.js';
export class WorkerService {
private app: express.Application;
@@ -812,19 +818,100 @@ export class WorkerService {
}
}
/**
* Validate context settings from request body
*/
private validateContextSettings(settings: any): { valid: boolean; error?: string } {
// Validate boolean string values
const booleanSettings = [
'CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS',
'CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS',
'CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT',
'CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT',
'CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY',
'CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE',
];
for (const key of booleanSettings) {
if (settings[key] && !['true', 'false'].includes(settings[key])) {
return { valid: false, error: `${key} must be "true" or "false"` };
}
}
// Validate FULL_COUNT (0-20)
if (settings.CLAUDE_MEM_CONTEXT_FULL_COUNT) {
const count = parseInt(settings.CLAUDE_MEM_CONTEXT_FULL_COUNT, 10);
if (isNaN(count) || count < 0 || count > 20) {
return { valid: false, error: 'CLAUDE_MEM_CONTEXT_FULL_COUNT must be between 0 and 20' };
}
}
// Validate SESSION_COUNT (1-50)
if (settings.CLAUDE_MEM_CONTEXT_SESSION_COUNT) {
const count = parseInt(settings.CLAUDE_MEM_CONTEXT_SESSION_COUNT, 10);
if (isNaN(count) || count < 1 || count > 50) {
return { valid: false, error: 'CLAUDE_MEM_CONTEXT_SESSION_COUNT must be between 1 and 50' };
}
}
// Validate FULL_FIELD
if (settings.CLAUDE_MEM_CONTEXT_FULL_FIELD) {
if (!['narrative', 'facts'].includes(settings.CLAUDE_MEM_CONTEXT_FULL_FIELD)) {
return { valid: false, error: 'CLAUDE_MEM_CONTEXT_FULL_FIELD must be "narrative" or "facts"' };
}
}
// Validate observation types
if (settings.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES) {
const types = settings.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES.split(',').map((t: string) => t.trim());
for (const type of types) {
if (type && !OBSERVATION_TYPES.includes(type as any)) {
return { valid: false, error: `Invalid observation type: ${type}. Valid types: ${OBSERVATION_TYPES.join(', ')}` };
}
}
}
// Validate observation concepts
if (settings.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS) {
const concepts = settings.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS.split(',').map((c: string) => c.trim());
for (const concept of concepts) {
if (concept && !OBSERVATION_CONCEPTS.includes(concept as any)) {
return { valid: false, error: `Invalid observation concept: ${concept}. Valid concepts: ${OBSERVATION_CONCEPTS.join(', ')}` };
}
}
}
return { valid: true };
}
/**
* Get environment settings (from ~/.claude/settings.json)
*/
private handleGetSettings(req: Request, res: Response): void {
try {
const settingsPath = path.join(homedir(), '.claude', 'settings.json');
const settingsPath = path.join(homedir(), '.claude-mem', 'settings.json');
if (!existsSync(settingsPath)) {
// Return defaults if file doesn't exist
res.json({
CLAUDE_MEM_MODEL: 'claude-haiku-4-5',
CLAUDE_MEM_CONTEXT_OBSERVATIONS: '50',
CLAUDE_MEM_WORKER_PORT: '37777'
CLAUDE_MEM_WORKER_PORT: '37777',
// Token Economics
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',
// Observation Filtering
CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES: DEFAULT_OBSERVATION_TYPES_STRING,
CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS: DEFAULT_OBSERVATION_CONCEPTS_STRING,
// Display Configuration
CLAUDE_MEM_CONTEXT_FULL_COUNT: '5',
CLAUDE_MEM_CONTEXT_FULL_FIELD: 'narrative',
CLAUDE_MEM_CONTEXT_SESSION_COUNT: '10',
// Feature Toggles
CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY: 'true',
CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE: 'false',
});
return;
}
@@ -836,7 +923,22 @@ export class WorkerService {
res.json({
CLAUDE_MEM_MODEL: env.CLAUDE_MEM_MODEL || 'claude-haiku-4-5',
CLAUDE_MEM_CONTEXT_OBSERVATIONS: env.CLAUDE_MEM_CONTEXT_OBSERVATIONS || '50',
CLAUDE_MEM_WORKER_PORT: env.CLAUDE_MEM_WORKER_PORT || '37777'
CLAUDE_MEM_WORKER_PORT: env.CLAUDE_MEM_WORKER_PORT || '37777',
// Token Economics
CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS: env.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS || 'true',
CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS: env.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS || 'true',
CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT: env.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT || 'true',
CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT: env.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT || 'true',
// Observation Filtering
CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES: env.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES || DEFAULT_OBSERVATION_TYPES_STRING,
CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS: env.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS || DEFAULT_OBSERVATION_CONCEPTS_STRING,
// Display Configuration
CLAUDE_MEM_CONTEXT_FULL_COUNT: env.CLAUDE_MEM_CONTEXT_FULL_COUNT || '5',
CLAUDE_MEM_CONTEXT_FULL_FIELD: env.CLAUDE_MEM_CONTEXT_FULL_FIELD || 'narrative',
CLAUDE_MEM_CONTEXT_SESSION_COUNT: env.CLAUDE_MEM_CONTEXT_SESSION_COUNT || '10',
// Feature Toggles
CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY: env.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY || 'true',
CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE: env.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE || 'false',
});
} catch (error) {
logger.failure('WORKER', 'Get settings failed', {}, error as Error);
@@ -849,11 +951,9 @@ export class WorkerService {
*/
private handleUpdateSettings(req: Request, res: Response): void {
try {
const { CLAUDE_MEM_MODEL, CLAUDE_MEM_CONTEXT_OBSERVATIONS, CLAUDE_MEM_WORKER_PORT } = req.body;
// Validate inputs
if (CLAUDE_MEM_CONTEXT_OBSERVATIONS) {
const obsCount = parseInt(CLAUDE_MEM_CONTEXT_OBSERVATIONS, 10);
// Validate CLAUDE_MEM_CONTEXT_OBSERVATIONS
if (req.body.CLAUDE_MEM_CONTEXT_OBSERVATIONS) {
const obsCount = parseInt(req.body.CLAUDE_MEM_CONTEXT_OBSERVATIONS, 10);
if (isNaN(obsCount) || obsCount < 1 || obsCount > 200) {
res.status(400).json({
success: false,
@@ -863,8 +963,9 @@ export class WorkerService {
}
}
if (CLAUDE_MEM_WORKER_PORT) {
const port = parseInt(CLAUDE_MEM_WORKER_PORT, 10);
// Validate CLAUDE_MEM_WORKER_PORT
if (req.body.CLAUDE_MEM_WORKER_PORT) {
const port = parseInt(req.body.CLAUDE_MEM_WORKER_PORT, 10);
if (isNaN(port) || port < 1024 || port > 65535) {
res.status(400).json({
success: false,
@@ -874,8 +975,18 @@ export class WorkerService {
}
}
// Validate context settings
const validation = this.validateContextSettings(req.body);
if (!validation.valid) {
res.status(400).json({
success: false,
error: validation.error
});
return;
}
// Read existing settings
const settingsPath = path.join(homedir(), '.claude', 'settings.json');
const settingsPath = path.join(homedir(), '.claude-mem', 'settings.json');
let settings: any = { env: {} };
if (existsSync(settingsPath)) {
@@ -886,15 +997,28 @@ export class WorkerService {
}
}
// Update settings
if (CLAUDE_MEM_MODEL) {
settings.env.CLAUDE_MEM_MODEL = CLAUDE_MEM_MODEL;
}
if (CLAUDE_MEM_CONTEXT_OBSERVATIONS) {
settings.env.CLAUDE_MEM_CONTEXT_OBSERVATIONS = CLAUDE_MEM_CONTEXT_OBSERVATIONS;
}
if (CLAUDE_MEM_WORKER_PORT) {
settings.env.CLAUDE_MEM_WORKER_PORT = CLAUDE_MEM_WORKER_PORT;
// Update all settings from request body
const settingKeys = [
'CLAUDE_MEM_MODEL',
'CLAUDE_MEM_CONTEXT_OBSERVATIONS',
'CLAUDE_MEM_WORKER_PORT',
'CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS',
'CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS',
'CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT',
'CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT',
'CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES',
'CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS',
'CLAUDE_MEM_CONTEXT_FULL_COUNT',
'CLAUDE_MEM_CONTEXT_FULL_FIELD',
'CLAUDE_MEM_CONTEXT_SESSION_COUNT',
'CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY',
'CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE',
];
for (const key of settingKeys) {
if (req.body[key] !== undefined) {
settings.env[key] = req.body[key];
}
}
// Write back
+125 -19
View File
@@ -19,21 +19,52 @@ interface SidebarProps {
}
export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConnected, projects, currentFilter, onFilterChange, onSave, onClose, onRefreshStats }: SidebarProps) {
// Settings form state
const [model, setModel] = useState(settings.CLAUDE_MEM_MODEL || DEFAULT_SETTINGS.CLAUDE_MEM_MODEL);
const [contextObs, setContextObs] = useState(settings.CLAUDE_MEM_CONTEXT_OBSERVATIONS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATIONS);
const [workerPort, setWorkerPort] = useState(settings.CLAUDE_MEM_WORKER_PORT || DEFAULT_SETTINGS.CLAUDE_MEM_WORKER_PORT);
// Consolidated settings form state
const [formState, setFormState] = useState<Settings>({
CLAUDE_MEM_MODEL: settings.CLAUDE_MEM_MODEL || DEFAULT_SETTINGS.CLAUDE_MEM_MODEL,
CLAUDE_MEM_CONTEXT_OBSERVATIONS: settings.CLAUDE_MEM_CONTEXT_OBSERVATIONS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATIONS,
CLAUDE_MEM_WORKER_PORT: settings.CLAUDE_MEM_WORKER_PORT || DEFAULT_SETTINGS.CLAUDE_MEM_WORKER_PORT,
CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS: settings.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS,
CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS: settings.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS,
CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT: settings.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT,
CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT: settings.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT,
CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES: settings.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES,
CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS: settings.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS,
CLAUDE_MEM_CONTEXT_FULL_COUNT: settings.CLAUDE_MEM_CONTEXT_FULL_COUNT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_FULL_COUNT,
CLAUDE_MEM_CONTEXT_FULL_FIELD: settings.CLAUDE_MEM_CONTEXT_FULL_FIELD || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_FULL_FIELD,
CLAUDE_MEM_CONTEXT_SESSION_COUNT: settings.CLAUDE_MEM_CONTEXT_SESSION_COUNT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SESSION_COUNT,
CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY: settings.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY,
CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE: settings.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE,
});
// MCP toggle state (separate from settings)
const [mcpEnabled, setMcpEnabled] = useState(true);
const [mcpToggling, setMcpToggling] = useState(false);
const [mcpStatus, setMcpStatus] = useState('');
// Update settings form state when settings change
// Helper to update form state
const updateFormState = (field: keyof Settings, value: string) => {
setFormState(prev => ({ ...prev, [field]: value }));
};
// Update settings form state when settings prop changes
useEffect(() => {
setModel(settings.CLAUDE_MEM_MODEL || DEFAULT_SETTINGS.CLAUDE_MEM_MODEL);
setContextObs(settings.CLAUDE_MEM_CONTEXT_OBSERVATIONS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATIONS);
setWorkerPort(settings.CLAUDE_MEM_WORKER_PORT || DEFAULT_SETTINGS.CLAUDE_MEM_WORKER_PORT);
setFormState({
CLAUDE_MEM_MODEL: settings.CLAUDE_MEM_MODEL || DEFAULT_SETTINGS.CLAUDE_MEM_MODEL,
CLAUDE_MEM_CONTEXT_OBSERVATIONS: settings.CLAUDE_MEM_CONTEXT_OBSERVATIONS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATIONS,
CLAUDE_MEM_WORKER_PORT: settings.CLAUDE_MEM_WORKER_PORT || DEFAULT_SETTINGS.CLAUDE_MEM_WORKER_PORT,
CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS: settings.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS,
CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS: settings.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS,
CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT: settings.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT,
CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT: settings.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT,
CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES: settings.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES,
CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS: settings.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS,
CLAUDE_MEM_CONTEXT_FULL_COUNT: settings.CLAUDE_MEM_CONTEXT_FULL_COUNT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_FULL_COUNT,
CLAUDE_MEM_CONTEXT_FULL_FIELD: settings.CLAUDE_MEM_CONTEXT_FULL_FIELD || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_FULL_FIELD,
CLAUDE_MEM_CONTEXT_SESSION_COUNT: settings.CLAUDE_MEM_CONTEXT_SESSION_COUNT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SESSION_COUNT,
CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY: settings.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY,
CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE: settings.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE,
});
}, [settings]);
// Fetch MCP status on mount
@@ -52,11 +83,7 @@ export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConne
}, [isOpen, onRefreshStats]);
const handleSave = () => {
onSave({
CLAUDE_MEM_MODEL: model,
CLAUDE_MEM_CONTEXT_OBSERVATIONS: contextObs,
CLAUDE_MEM_WORKER_PORT: workerPort
});
onSave(formState);
};
const handleMcpToggle = async (enabled: boolean) => {
@@ -193,8 +220,8 @@ export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConne
</div>
<select
id="model"
value={model}
onChange={e => setModel(e.target.value)}
value={formState.CLAUDE_MEM_MODEL}
onChange={e => updateFormState('CLAUDE_MEM_MODEL', e.target.value)}
>
<option value="claude-haiku-4-5">claude-haiku-4-5</option>
<option value="claude-sonnet-4-5">claude-sonnet-4-5</option>
@@ -211,8 +238,8 @@ export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConne
id="contextObs"
min="1"
max="200"
value={contextObs}
onChange={e => setContextObs(e.target.value)}
value={formState.CLAUDE_MEM_CONTEXT_OBSERVATIONS}
onChange={e => updateFormState('CLAUDE_MEM_CONTEXT_OBSERVATIONS', e.target.value)}
/>
</div>
<div className="form-group">
@@ -225,10 +252,89 @@ export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConne
id="workerPort"
min="1024"
max="65535"
value={workerPort}
onChange={e => setWorkerPort(e.target.value)}
value={formState.CLAUDE_MEM_WORKER_PORT}
onChange={e => updateFormState('CLAUDE_MEM_WORKER_PORT', e.target.value)}
/>
</div>
{/* Token Economics Display */}
<div className="form-group">
<label>Token Economics Display</label>
<div className="setting-description">
Choose which token metrics to show in session start context.
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
<input type="checkbox" checked={formState.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS === 'true'} onChange={e => updateFormState('CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS', e.target.checked ? 'true' : 'false')} />
Show read tokens
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
<input type="checkbox" checked={formState.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS === 'true'} onChange={e => updateFormState('CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS', e.target.checked ? 'true' : 'false')} />
Show work tokens
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
<input type="checkbox" checked={formState.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT === 'true'} onChange={e => updateFormState('CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT', e.target.checked ? 'true' : 'false')} />
Show savings amount
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
<input type="checkbox" checked={formState.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT === 'true'} onChange={e => updateFormState('CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT', e.target.checked ? 'true' : 'false')} />
Show savings percentage
</label>
</div>
</div>
{/* Display Configuration */}
<div className="form-group">
<label>Display Configuration</label>
<div className="setting-description">
Control how observations are displayed in the timeline.
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px', marginTop: '8px' }}>
<div>
<label htmlFor="fullCount" style={{ display: 'block', marginBottom: '4px', fontSize: '13px' }}>
Full observation count (0-20)
</label>
<input type="number" id="fullCount" min="0" max="20" value={formState.CLAUDE_MEM_CONTEXT_FULL_COUNT} onChange={e => updateFormState('CLAUDE_MEM_CONTEXT_FULL_COUNT', e.target.value)} style={{ width: '100%' }} />
<div style={{ fontSize: '12px', color: '#999', marginTop: '4px' }}>
Number of most recent observations to show with full details
</div>
</div>
<div>
<label htmlFor="fullField" style={{ display: 'block', marginBottom: '4px', fontSize: '13px' }}>
Full observation field
</label>
<select id="fullField" value={formState.CLAUDE_MEM_CONTEXT_FULL_FIELD} onChange={e => updateFormState('CLAUDE_MEM_CONTEXT_FULL_FIELD', e.target.value)} style={{ width: '100%' }}>
<option value="narrative">Narrative</option>
<option value="facts">Facts</option>
</select>
</div>
<div>
<label htmlFor="sessionCount" style={{ display: 'block', marginBottom: '4px', fontSize: '13px' }}>
Session summary count (1-50)
</label>
<input type="number" id="sessionCount" min="1" max="50" value={formState.CLAUDE_MEM_CONTEXT_SESSION_COUNT} onChange={e => updateFormState('CLAUDE_MEM_CONTEXT_SESSION_COUNT', e.target.value)} style={{ width: '100%' }} />
</div>
</div>
</div>
{/* Feature Toggles */}
<div className="form-group">
<label>Context Features</label>
<div className="setting-description">
Toggle additional features in session start context.
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
<input type="checkbox" checked={formState.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY === 'true'} onChange={e => updateFormState('CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY', e.target.checked ? 'true' : 'false')} />
Show last session summary
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
<input type="checkbox" checked={formState.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE === 'true'} onChange={e => updateFormState('CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE', e.target.checked ? 'true' : 'false')} />
Include last session message
</label>
</div>
</div>
{saveStatus && (
<div className="save-status">{saveStatus}</div>
)}
+19
View File
@@ -6,4 +6,23 @@ export const DEFAULT_SETTINGS = {
CLAUDE_MEM_MODEL: 'claude-haiku-4-5',
CLAUDE_MEM_CONTEXT_OBSERVATIONS: '50',
CLAUDE_MEM_WORKER_PORT: '37777',
// Token Economics (all true for backwards compatibility)
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',
// Observation Filtering (all types and concepts)
CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES: 'bugfix,feature,refactor,discovery,decision,change',
CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS: 'how-it-works,why-it-exists,what-changed,problem-solution,gotcha,pattern,trade-off',
// Display Configuration
CLAUDE_MEM_CONTEXT_FULL_COUNT: '5',
CLAUDE_MEM_CONTEXT_FULL_FIELD: 'narrative',
CLAUDE_MEM_CONTEXT_SESSION_COUNT: '10',
// Feature Toggles
CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY: 'true',
CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE: 'false',
} as const;
+20 -1
View File
@@ -17,7 +17,26 @@ export function useSettings() {
setSettings({
CLAUDE_MEM_MODEL: data.CLAUDE_MEM_MODEL || DEFAULT_SETTINGS.CLAUDE_MEM_MODEL,
CLAUDE_MEM_CONTEXT_OBSERVATIONS: data.CLAUDE_MEM_CONTEXT_OBSERVATIONS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATIONS,
CLAUDE_MEM_WORKER_PORT: data.CLAUDE_MEM_WORKER_PORT || DEFAULT_SETTINGS.CLAUDE_MEM_WORKER_PORT
CLAUDE_MEM_WORKER_PORT: data.CLAUDE_MEM_WORKER_PORT || DEFAULT_SETTINGS.CLAUDE_MEM_WORKER_PORT,
// Token Economics Display
CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS: data.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS,
CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS: data.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS,
CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT: data.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT,
CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT: data.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT,
// Observation Filtering
CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES: data.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES,
CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS: data.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS,
// Display Configuration
CLAUDE_MEM_CONTEXT_FULL_COUNT: data.CLAUDE_MEM_CONTEXT_FULL_COUNT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_FULL_COUNT,
CLAUDE_MEM_CONTEXT_FULL_FIELD: data.CLAUDE_MEM_CONTEXT_FULL_FIELD || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_FULL_FIELD,
CLAUDE_MEM_CONTEXT_SESSION_COUNT: data.CLAUDE_MEM_CONTEXT_SESSION_COUNT || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SESSION_COUNT,
// Feature Toggles
CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY: data.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY,
CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE: data.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE,
});
})
.catch(error => {
+19
View File
@@ -58,6 +58,25 @@ export interface Settings {
CLAUDE_MEM_MODEL: string;
CLAUDE_MEM_CONTEXT_OBSERVATIONS: string;
CLAUDE_MEM_WORKER_PORT: string;
// Token Economics Display
CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS?: string;
CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS?: string;
CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT?: string;
CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT?: string;
// Observation Filtering
CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES?: string;
CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS?: string;
// Display Configuration
CLAUDE_MEM_CONTEXT_FULL_COUNT?: string;
CLAUDE_MEM_CONTEXT_FULL_FIELD?: string;
CLAUDE_MEM_CONTEXT_SESSION_COUNT?: string;
// Feature Toggles
CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY?: string;
CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE?: string;
}
export interface WorkerStats {