Compare commits

...

4 Commits

Author SHA1 Message Date
Alex Newman 4ebf0cad6b Release v3.6.8
Published from npm package build
Source: https://github.com/thedotmack/claude-mem-source
2025-09-14 19:38:27 -04:00
Alex Newman 98d959112c Release v3.6.6
Published from npm package build
Source: https://github.com/thedotmack/claude-mem-source
2025-09-14 18:48:58 -04:00
Alex Newman d01c2afaa6 Release v3.6.5
Published from npm package build
Source: https://github.com/thedotmack/claude-mem-source
2025-09-14 14:36:54 -04:00
Alex Newman 8ebcb55b0d Release v3.6.4
Published from npm package build
Source: https://github.com/thedotmack/claude-mem-source
2025-09-13 22:54:41 -04:00
9 changed files with 179 additions and 230 deletions
+30
View File
@@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [3.6.8] - 2025-09-14
### Fixed
- Fixed publish command failing when no version-related memories exist for changelog generation
## [3.6.6] - 2025-09-14
### Fixed
- Resolved compaction errors when processing large conversation histories by reducing chunk size limits to stay within Claude's context window
## [3.6.5] - 2025-09-14
### Changed
- Session groups now display in chronological order (most recent first)
### Fixed
- Improved CLI path detection for cross-platform compatibility
## [3.6.4] - 2025-09-13
### Changed
- Update save documentation to include allowed-tools and description metadata fields
### Removed
- Remove deprecated markdown to JSONL migration script
## [3.6.3] - 2025-09-11
### Changed
+7 -3
View File
@@ -1,3 +1,7 @@
Write an overview of the current conversation context and:
1. Add it to claude-mem using the chroma MCP tools
2. Save the overview using the claude-mem CLI tool: `claude-mem save "your overview message"`
---
allowed-tools: Bash
description: Write an overview and save with claude-mem
---
**Write an overview** of the current conversation context and:
1. **Add it to claude-mem** using the chroma MCP tools. Always use primitive types (strings, numbers, booleans) when calling MCP Chroma tools directly. Arrays should be comma-separated strings, and nested objects should be flattened.
2. **Save the overview to index** using the claude-mem CLI tool: `claude-mem save "your overview message"`
+98 -97
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "claude-mem",
"version": "3.6.3",
"version": "3.6.8",
"description": "Memory compression system for Claude Code - persist context across sessions",
"keywords": [
"claude",
+28 -2
View File
@@ -393,8 +393,34 @@ Start searching now.` :
}
if (memories.length === 0) {
console.log('\n⚠️ No version-related memories found. Try compressing more sessions first.');
process.exit(1);
console.log('\n⚠️ No version-related memories found for this version.');
console.log(' This is normal for the first release or when no changes were tracked.');
console.log(' Creating a placeholder changelog entry...');
// Create a minimal placeholder entry
const placeholderEntry: ChangelogEntry = {
version: versionsToSearch[0], // Use the first (current) version
date: todayStr,
type: 'Changed',
description: 'Initial release or minor updates',
timestamp: new Date().toISOString(),
generatedAt: new Date().toISOString()
};
// Save the placeholder entry
if (!fs.existsSync(projectChangelogDir)) {
fs.mkdirSync(projectChangelogDir, { recursive: true });
}
const jsonlContent = JSON.stringify(placeholderEntry) + '\n';
fs.appendFileSync(changelogJsonlPath, jsonlContent);
console.log(`✅ Created placeholder changelog entry for v${versionsToSearch[0]}`);
// Generate the CHANGELOG.md with the placeholder
await updateChangelogFromJsonl(options);
return; // Exit successfully
}
console.log(`✅ Found ${memories.length} version-related memories\n`);
+5 -3
View File
@@ -1,7 +1,7 @@
import { OptionValues } from 'commander';
import { readFileSync, writeFileSync, existsSync, chmodSync, mkdirSync, copyFileSync, statSync, readdirSync } from 'fs';
import { join, resolve, dirname } from 'path';
import { homedir } from 'os';
import { homedir, platform } from 'os';
import { execSync } from 'child_process';
import { fileURLToPath } from 'url';
import * as p from '@clack/prompts';
@@ -95,7 +95,8 @@ async function validatePrerequisites(): Promise<boolean> {
name: 'Claude Code CLI',
check: async () => {
try {
execSync('which claude', { stdio: 'ignore' });
const command = platform() === 'win32' ? 'where claude' : 'which claude';
execSync(command, { stdio: 'ignore' });
return { success: true, message: '' };
} catch {
return { success: false, message: 'Claude Code CLI not found. Please install: https://docs.anthropic.com/claude/docs/claude-code' };
@@ -184,7 +185,8 @@ async function validatePrerequisites(): Promise<boolean> {
// <Block> Claude binary path detection
function detectClaudePath(): string | null {
try {
const path = execSync('which claude', {
const command = platform() === 'win32' ? 'where claude' : 'which claude';
const path = execSync(command, {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore']
}).trim();
-122
View File
@@ -1,122 +0,0 @@
#!/usr/bin/env node
/**
* One-time migration script to convert claude-mem-index.md to claude-mem-index.jsonl
*/
import fs from 'fs';
import path from 'path';
import { PathDiscovery } from '../services/path-discovery.js';
export function migrateToJSONL(): void {
const pathDiscovery = PathDiscovery.getInstance();
const oldIndexPath = path.join(pathDiscovery.getDataDirectory(), 'claude-mem-index.md');
const newIndexPath = pathDiscovery.getIndexPath();
// Check if old index exists
if (!fs.existsSync(oldIndexPath)) {
console.log('No markdown index found to migrate');
return;
}
// Check if new index already exists
if (fs.existsSync(newIndexPath)) {
console.log('JSONL index already exists, skipping migration');
return;
}
console.log('Starting migration from MD to JSONL...');
const content = fs.readFileSync(oldIndexPath, 'utf-8');
const lines = content.split('\n').filter(line => line.trim());
const jsonlLines: string[] = [];
let currentSessionId = '';
let currentSessionTimestamp = '';
for (const line of lines) {
// Parse session headers: # Session: <id> [<timestamp>]
const sessionMatch = line.match(/^# Session:\s*([^\[]+)(?:\s*\[([^\]]+)\])?/);
if (sessionMatch) {
currentSessionId = sessionMatch[1].trim();
currentSessionTimestamp = sessionMatch[2]?.trim() || new Date().toISOString();
// Extract project from session ID (assuming format like <project>_<uuid>)
const projectMatch = currentSessionId.match(/^([^_]+)_/);
const project = projectMatch ? projectMatch[1] : 'unknown';
jsonlLines.push(JSON.stringify({
type: 'session',
session_id: currentSessionId,
timestamp: currentSessionTimestamp,
project
}));
continue;
}
// Parse overviews: **Overview:** <text>
const overviewMatch = line.match(/^\*\*Overview:\*\*\s*(.+)/);
if (overviewMatch) {
const overviewText = overviewMatch[1].trim();
// Extract project from current session ID
const projectMatch = currentSessionId.match(/^([^_]+)_/);
const project = projectMatch ? projectMatch[1] : 'unknown';
jsonlLines.push(JSON.stringify({
type: 'overview',
content: overviewText,
session_id: currentSessionId,
project,
timestamp: currentSessionTimestamp
}));
continue;
}
// Skip certain lines
if (line.startsWith('# NO SUMMARIES EXTRACTED')) {
continue;
}
// Parse memory entries (pipe-separated)
if (line.includes(' | ')) {
const parts = line.split(' | ').map(p => p.trim());
if (parts.length >= 3) {
const [text, document_id, keywords, timestamp, archive] = parts;
// Extract project from document_id (format: <project>_<session>_<number>)
const projectMatch = document_id?.match(/^([^_]+)_/);
const project = projectMatch ? projectMatch[1] : 'unknown';
jsonlLines.push(JSON.stringify({
type: 'memory',
text,
document_id: document_id || `${currentSessionId}_${Date.now()}`,
keywords: keywords || '',
session_id: currentSessionId,
project,
timestamp: timestamp || currentSessionTimestamp,
archive: archive || `${currentSessionId}.jsonl.archive`
}));
}
}
}
// Write JSONL file
fs.writeFileSync(newIndexPath, jsonlLines.join('\n') + '\n');
// Backup old index
const backupPath = oldIndexPath + '.backup';
fs.renameSync(oldIndexPath, backupPath);
console.log(`✅ Migration complete!`);
console.log(` - Converted ${jsonlLines.length} entries`);
console.log(` - New index: ${newIndexPath}`);
console.log(` - Backup: ${backupPath}`);
}
// Run if called directly
if (import.meta.url === `file://${process.argv[1]}`) {
migrateToJSONL();
}
+2 -2
View File
@@ -34,8 +34,8 @@ export interface ChunkedMessage {
}
export class ChunkManager {
private static readonly DEFAULT_MAX_TOKENS = 28000;
private static readonly DEFAULT_MAX_BYTES = 98000;
private static readonly DEFAULT_MAX_TOKENS = 22400; // Reduced by 20% from 28000
private static readonly DEFAULT_MAX_BYTES = 78400; // Reduced by 20% from 98000
private static readonly DEFAULT_CONTEXT_OVERLAP = 2;
private static readonly CHARS_PER_TOKEN_ESTIMATE = 3.5;
@@ -613,6 +613,14 @@ export function outputSessionStartContent(params: {
// Overview section at bottom with session grouping
if (overviews.length > 0) {
const sessionGroups = groupOverviewsBySession(overviews);
// Sort groups by timestamp, newest first
sessionGroups.sort((a, b) => {
const timeA = a.earliestTimestamp?.getTime() || 0;
const timeB = b.earliestTimestamp?.getTime() || 0;
return timeB - timeA; // Descending order (newest first)
});
console.log('');
console.log(wrapText('🧠 Overviews', width));