Release v3.5.4
- Updated to match npm package structure - Includes minified dist/claude-mem.min.js - Added commands directory - Updated hooks with latest fixes - Synced with npm package claude-mem@3.5.4
This commit is contained in:
+17
-12
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
import { loadCliCommand } from './shared/config-loader.js';
|
||||
import { getLogsDir } from './shared/path-resolver.js';
|
||||
import {
|
||||
createHookResponse,
|
||||
executeCliCommand,
|
||||
@@ -16,7 +17,9 @@ import {
|
||||
debugLog
|
||||
} from './shared/hook-helpers.js';
|
||||
|
||||
const cliCommand = loadCliCommand();
|
||||
// Set up stdin immediately before any async operations
|
||||
process.stdin.setEncoding('utf8');
|
||||
process.stdin.resume(); // Explicitly enter flowing mode to prevent data loss
|
||||
|
||||
// Read input from stdin
|
||||
let input = '';
|
||||
@@ -26,6 +29,9 @@ process.stdin.on('data', chunk => {
|
||||
|
||||
process.stdin.on('end', async () => {
|
||||
try {
|
||||
// Load CLI command inside try-catch to handle config errors properly
|
||||
const cliCommand = loadCliCommand();
|
||||
|
||||
const payload = JSON.parse(input);
|
||||
debugLog('Pre-compact hook started', { payload });
|
||||
|
||||
@@ -33,17 +39,18 @@ process.stdin.on('end', async () => {
|
||||
const validation = validateHookPayload(payload, 'PreCompact');
|
||||
if (!validation.valid) {
|
||||
const response = createHookResponse('PreCompact', false, { reason: validation.error });
|
||||
console.log(JSON.stringify(response));
|
||||
debugLog('Validation failed', { response });
|
||||
// Exit silently - validation failure is expected flow control
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Check for environment-based blocking conditions
|
||||
if (payload.trigger === 'auto' && process.env.DISABLE_AUTO_COMPRESSION === 'true') {
|
||||
debugLog('Auto-compression disabled by configuration');
|
||||
const response = createHookResponse('PreCompact', false, {
|
||||
reason: 'Auto-compression disabled by configuration'
|
||||
});
|
||||
console.log(JSON.stringify(response));
|
||||
debugLog('Auto-compression disabled', { response });
|
||||
// Exit silently - disabled compression is expected flow control
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
@@ -56,26 +63,24 @@ process.stdin.on('end', async () => {
|
||||
const result = await executeCliCommand(cliCommand, ['compress', payload.transcript_path]);
|
||||
|
||||
if (!result.success) {
|
||||
debugLog('Compression command failed', { stderr: result.stderr });
|
||||
const response = createHookResponse('PreCompact', false, {
|
||||
reason: `Compression failed: ${result.stderr || 'Unknown error'}`
|
||||
});
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
debugLog('Compression command failed', { stderr: result.stderr, response });
|
||||
console.log(`claude-mem error: compression failed, see logs at ${getLogsDir()}`);
|
||||
process.exit(1); // Exit with error code for actual compression failure
|
||||
}
|
||||
|
||||
// Success - create standardized approval response using HookTemplates
|
||||
// Success - exit silently (suppressOutput is true)
|
||||
debugLog('Compression completed successfully');
|
||||
const response = createHookResponse('PreCompact', true);
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
|
||||
} catch (error) {
|
||||
debugLog('Pre-compact hook error', { error: error.message });
|
||||
const response = createHookResponse('PreCompact', false, {
|
||||
reason: `Hook execution error: ${error.message}`
|
||||
});
|
||||
console.log(JSON.stringify(response));
|
||||
debugLog('Pre-compact hook error', { error: error.message, response });
|
||||
console.log(`claude-mem error: hook failed, see logs at ${getLogsDir()}`);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
@@ -5,16 +5,15 @@
|
||||
*/
|
||||
|
||||
import { loadCliCommand } from './shared/config-loader.js';
|
||||
import { getSettingsPath, getArchivesDir } from './shared/path-resolver.js';
|
||||
import { execSync } from 'child_process';
|
||||
import { join } from 'path';
|
||||
import { homedir } from 'os';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
|
||||
const cliCommand = loadCliCommand();
|
||||
|
||||
// Check if save-on-clear is enabled
|
||||
function isSaveOnClearEnabled() {
|
||||
const settingsPath = join(homedir(), '.claude-mem', 'settings.json');
|
||||
const settingsPath = getSettingsPath();
|
||||
if (existsSync(settingsPath)) {
|
||||
try {
|
||||
const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
||||
@@ -26,6 +25,10 @@ function isSaveOnClearEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up stdin immediately before any async operations
|
||||
process.stdin.setEncoding('utf8');
|
||||
process.stdin.resume(); // Explicitly enter flowing mode to prevent data loss
|
||||
|
||||
// Read input
|
||||
let input = '';
|
||||
process.stdin.on('data', chunk => {
|
||||
@@ -41,7 +44,7 @@ process.stdin.on('end', async () => {
|
||||
|
||||
try {
|
||||
// Use the CLI to compress current transcript
|
||||
execSync(`${cliCommand} compress --output ${homedir()}/.claude-mem/archives`, {
|
||||
execSync(`${cliCommand} compress --output ${getArchivesDir()}`, {
|
||||
stdio: 'inherit',
|
||||
env: { ...process.env, CLAUDE_MEM_SILENT: 'true' }
|
||||
});
|
||||
|
||||
+10
-6
@@ -21,6 +21,10 @@ import {
|
||||
|
||||
const cliCommand = loadCliCommand();
|
||||
|
||||
// Set up stdin immediately before any async operations
|
||||
process.stdin.setEncoding('utf8');
|
||||
process.stdin.resume(); // Explicitly enter flowing mode to prevent data loss
|
||||
|
||||
// Read input from stdin
|
||||
let input = '';
|
||||
process.stdin.on('data', chunk => {
|
||||
@@ -47,14 +51,14 @@ process.stdin.on('end', async () => {
|
||||
// Skip load-context when source is "resume" to avoid duplicate context
|
||||
if (payload.source === 'resume') {
|
||||
debugLog('Skipping load-context for resume source');
|
||||
// Output nothing at all for resume - no message, no context
|
||||
// Output valid JSON response with suppressOutput for resume
|
||||
const response = createHookResponse('SessionStart', true);
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Extract project name from current working directory and sanitize
|
||||
const rawProjectName = path.basename(process.cwd());
|
||||
const projectName = rawProjectName.replace(/-/g, '_');
|
||||
debugLog('Extracted project name', { rawProjectName, projectName });
|
||||
// Extract project name from current working directory
|
||||
const projectName = path.basename(process.cwd());
|
||||
|
||||
// Load context using standardized CLI execution helper
|
||||
const contextResult = await executeCliCommand(cliCommand, [
|
||||
@@ -152,7 +156,7 @@ function extractProjectName(transcriptPath) {
|
||||
|
||||
// Look for project pattern: /path/to/PROJECT_NAME/.claude/
|
||||
// Need to get PROJECT_NAME, not the parent directory
|
||||
const parts = transcriptPath.split('/');
|
||||
const parts = transcriptPath.split(path.sep);
|
||||
const claudeIndex = parts.indexOf('.claude');
|
||||
|
||||
if (claudeIndex > 0) {
|
||||
|
||||
@@ -47,13 +47,10 @@ export function createHookResponse(hookType, success, options = {}) {
|
||||
}
|
||||
};
|
||||
} else if (success) {
|
||||
// No context - just suppress output without any message
|
||||
return {
|
||||
continue: true,
|
||||
suppressOutput: true,
|
||||
hookSpecificOutput: {
|
||||
hookEventName: 'SessionStart',
|
||||
additionalContext: 'Starting fresh session - no previous context available'
|
||||
}
|
||||
suppressOutput: true
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Path resolver utility for Claude Memory hooks
|
||||
* Provides proper path handling using environment variables
|
||||
*/
|
||||
|
||||
import { join } from 'path';
|
||||
import { homedir } from 'os';
|
||||
|
||||
/**
|
||||
* Gets the base data directory for claude-mem
|
||||
* @returns {string} Data directory path
|
||||
*/
|
||||
export function getDataDir() {
|
||||
return process.env.CLAUDE_MEM_DATA_DIR || join(homedir(), '.claude-mem');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the settings file path
|
||||
* @returns {string} Settings file path
|
||||
*/
|
||||
export function getSettingsPath() {
|
||||
return join(getDataDir(), 'settings.json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the archives directory path
|
||||
* @returns {string} Archives directory path
|
||||
*/
|
||||
export function getArchivesDir() {
|
||||
return process.env.CLAUDE_MEM_ARCHIVES_DIR || join(getDataDir(), 'archives');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the logs directory path
|
||||
* @returns {string} Logs directory path
|
||||
*/
|
||||
export function getLogsDir() {
|
||||
return process.env.CLAUDE_MEM_LOGS_DIR || join(getDataDir(), 'logs');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all common paths used by hooks
|
||||
* @returns {Object} Object containing all common paths
|
||||
*/
|
||||
export function getPaths() {
|
||||
return {
|
||||
dataDir: getDataDir(),
|
||||
settingsPath: getSettingsPath(),
|
||||
archivesDir: getArchivesDir(),
|
||||
logsDir: getLogsDir()
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user