claude-mem 3.3.7 → 3.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +183 -46
  2. package/dist/bin/cli.d.ts +2 -0
  3. package/dist/bin/cli.js +179 -0
  4. package/dist/commands/compress.d.ts +2 -0
  5. package/dist/commands/compress.js +27 -0
  6. package/dist/commands/hooks.d.ts +19 -0
  7. package/dist/commands/hooks.js +131 -0
  8. package/dist/commands/install.d.ts +2 -0
  9. package/dist/commands/install.js +836 -0
  10. package/dist/commands/load-context.d.ts +2 -0
  11. package/dist/commands/load-context.js +151 -0
  12. package/dist/commands/logs.d.ts +2 -0
  13. package/dist/commands/logs.js +76 -0
  14. package/dist/commands/migrate-to-jsonl.d.ts +5 -0
  15. package/dist/commands/migrate-to-jsonl.js +99 -0
  16. package/dist/commands/restore.d.ts +1 -0
  17. package/dist/commands/restore.js +20 -0
  18. package/dist/commands/status.d.ts +1 -0
  19. package/dist/commands/status.js +136 -0
  20. package/dist/commands/trash-empty.d.ts +3 -0
  21. package/dist/commands/trash-empty.js +56 -0
  22. package/dist/commands/trash-view.d.ts +1 -0
  23. package/dist/commands/trash-view.js +101 -0
  24. package/dist/commands/trash.d.ts +6 -0
  25. package/dist/commands/trash.js +49 -0
  26. package/dist/commands/uninstall.d.ts +2 -0
  27. package/dist/commands/uninstall.js +107 -0
  28. package/dist/constants.d.ts +271 -0
  29. package/dist/constants.js +199 -0
  30. package/dist/core/compression/TranscriptCompressor.d.ts +79 -0
  31. package/dist/core/compression/TranscriptCompressor.js +585 -0
  32. package/dist/core/orchestration/PromptOrchestrator.d.ts +165 -0
  33. package/dist/core/orchestration/PromptOrchestrator.js +182 -0
  34. package/dist/lib/time-utils.d.ts +5 -0
  35. package/dist/lib/time-utils.js +70 -0
  36. package/dist/prompts/constants.d.ts +126 -0
  37. package/dist/prompts/constants.js +161 -0
  38. package/dist/prompts/index.d.ts +10 -0
  39. package/dist/prompts/index.js +11 -0
  40. package/dist/prompts/templates/analysis/AnalysisTemplates.d.ts +13 -0
  41. package/dist/prompts/templates/analysis/AnalysisTemplates.js +94 -0
  42. package/dist/prompts/templates/context/ContextTemplates.d.ts +119 -0
  43. package/dist/prompts/templates/context/ContextTemplates.js +399 -0
  44. package/dist/prompts/templates/hooks/HookTemplates.d.ts +175 -0
  45. package/dist/prompts/templates/hooks/HookTemplates.js +394 -0
  46. package/dist/prompts/templates/hooks/HookTemplates.test.d.ts +7 -0
  47. package/dist/prompts/templates/hooks/HookTemplates.test.js +127 -0
  48. package/dist/shared/config.d.ts +4 -0
  49. package/dist/shared/config.js +41 -0
  50. package/dist/shared/error-handler.d.ts +22 -0
  51. package/dist/shared/error-handler.js +142 -0
  52. package/dist/shared/logger.d.ts +19 -0
  53. package/dist/shared/logger.js +51 -0
  54. package/dist/shared/paths.d.ts +28 -0
  55. package/dist/shared/paths.js +100 -0
  56. package/dist/shared/settings.d.ts +41 -0
  57. package/dist/shared/settings.js +81 -0
  58. package/dist/shared/types.d.ts +145 -0
  59. package/dist/shared/types.js +78 -0
  60. package/docs/STATUS.md +155 -0
  61. package/docs/chroma-backend-migration.md +161 -0
  62. package/docs/landing-page-outline.md +287 -0
  63. package/docs/multi-platform-builds.md +96 -0
  64. package/docs/plans/cloud-service-plan.md +274 -0
  65. package/docs/plans/fix-response-format-issue.md +61 -0
  66. package/docs/plans/restructure-session-hook-output.md +102 -0
  67. package/docs/plans/session-start-hook-investigation.md +45 -0
  68. package/docs/plans/src-reorganization-plan.md +181 -0
  69. package/docs/plans/terminal-effects-decision.md +22 -0
  70. package/docs/plans/terminal-effects-integration.md +82 -0
  71. package/docs/plans/trash-bin-feature-plan.md +240 -0
  72. package/docs/plans/trash-bin-minimal-plan.md +102 -0
  73. package/docs/reference/bun-single-executable.md +584 -0
  74. package/docs/reference/cc-output-styles.md +99 -0
  75. package/docs/reference/chroma-mcp-project-memory-example.md +80 -0
  76. package/docs/reference/chroma-mcp-team-example.md +92 -0
  77. package/docs/reference/claude-code/cc-hooks.md +787 -0
  78. package/docs/reference/claude-code/cc-status-line.md +202 -0
  79. package/docs/reference/claude-code/hook-configuration.md +173 -0
  80. package/docs/reference/claude-code/hook-responses.md +127 -0
  81. package/docs/reference/claude-code/hooks.md +175 -0
  82. package/docs/reference/claude-code/mcp-configuration.md +133 -0
  83. package/docs/reference/claude-code/session-start-hook.md +82 -0
  84. package/docs/reference/load-context-format-example.md +33 -0
  85. package/docs/reference/mcp-sdk/mcp-typescript-sdk-readme.md +1323 -0
  86. package/docs/reference/mcp-sdk/server-implementation.md +286 -0
  87. package/docs/reference/mcp-sdk/stdio-transport.md +345 -0
  88. package/docs/todos/fix-response-format-tasks.md +43 -0
  89. package/docs/todos/implementation-todos.md +280 -0
  90. package/docs/todos/restructure-hook-output-tasks.md +103 -0
  91. package/docs/todos/session-start-hook-fix.md +26 -0
  92. package/docs/todos/terminal-effects-tasks.md +42 -0
  93. package/docs/todos/trash-bin-implementation-todos.md +348 -0
  94. package/docs/todos/trash-bin-minimal-todos.md +27 -0
  95. package/package.json +56 -6
  96. package/claude-mem +0 -0
@@ -0,0 +1,142 @@
1
+ import { existsSync, mkdirSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { HookError, CompressionError, FileLogger } from './types.js';
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+ export class ErrorHandler {
8
+ logger;
9
+ logDir;
10
+ // <Block> 7.1 ====================================
11
+ constructor(enableDebug = false) {
12
+ this.logDir = join(__dirname, '..', 'logs');
13
+ this.ensureLogDirectory();
14
+ const logFile = join(this.logDir, `claude-mem-${new Date().toISOString().slice(0, 10)}.log`);
15
+ this.logger = new FileLogger(logFile, enableDebug);
16
+ }
17
+ // </Block> =======================================
18
+ // <Block> 7.2 ====================================
19
+ ensureLogDirectory() {
20
+ if (!existsSync(this.logDir)) {
21
+ mkdirSync(this.logDir, { recursive: true });
22
+ }
23
+ }
24
+ // </Block> =======================================
25
+ // <Block> 7.3 ====================================
26
+ handleHookError(error, hookType, payload) {
27
+ // <Block> 7.3a ====================================
28
+ const hookError = error instanceof HookError
29
+ ? error
30
+ : new HookError(error.message, hookType, payload, 'HOOK_EXECUTION_ERROR');
31
+ // </Block> =======================================
32
+ this.logger.error(`Hook execution failed in ${hookType}`, hookError, {
33
+ hookType,
34
+ payload: payload ? JSON.stringify(payload) : undefined,
35
+ });
36
+ console.log(JSON.stringify({
37
+ continue: false,
38
+ stopReason: `Hook error: ${hookError.message}`,
39
+ error: {
40
+ type: hookError.name,
41
+ message: hookError.message,
42
+ code: hookError.code,
43
+ },
44
+ }));
45
+ process.exit(1);
46
+ }
47
+ // </Block> =======================================
48
+ // <Block> 7.4 ====================================
49
+ handleCompressionError(error, transcriptPath, stage) {
50
+ // <Block> 7.4a ====================================
51
+ const compressionError = error instanceof CompressionError
52
+ ? error
53
+ : new CompressionError(error.message, transcriptPath, stage);
54
+ // </Block> =======================================
55
+ this.logger.error(`Compression failed during ${stage}`, compressionError, {
56
+ transcriptPath,
57
+ stage,
58
+ });
59
+ console.error(`Compression error: ${compressionError.message}`);
60
+ console.error(`Stage: ${stage}`);
61
+ console.error(`Transcript: ${transcriptPath}`);
62
+ process.exit(1);
63
+ }
64
+ // </Block> =======================================
65
+ // <Block> 7.5 ====================================
66
+ handleValidationError(message, context) {
67
+ this.logger.error('Validation error', undefined, { message, context });
68
+ console.error(`Validation error: ${message}`);
69
+ // <Block> 7.5a ====================================
70
+ if (context) {
71
+ console.error('Context:', JSON.stringify(context, null, 2));
72
+ }
73
+ // </Block> =======================================
74
+ process.exit(1);
75
+ }
76
+ // </Block> =======================================
77
+ // <Block> 7.6 ====================================
78
+ logSuccess(operation, details) {
79
+ this.logger.info(`Operation successful: ${operation}`, details);
80
+ }
81
+ // </Block> =======================================
82
+ // <Block> 7.7 ====================================
83
+ logWarning(message, details) {
84
+ this.logger.warn(message, details);
85
+ }
86
+ // </Block> =======================================
87
+ // <Block> 7.8 ====================================
88
+ logDebug(message, details) {
89
+ this.logger.debug(message, details);
90
+ }
91
+ }
92
+ // <Block> 7.9 ====================================
93
+ export function parseStdinJson(input) {
94
+ try {
95
+ return JSON.parse(input);
96
+ }
97
+ catch (error) {
98
+ throw new Error(`Failed to parse JSON input: ${error instanceof Error ? error.message : 'Unknown error'}`);
99
+ }
100
+ }
101
+ // </Block> =======================================
102
+ // <Block> 7.10 ===================================
103
+ export async function safeExecute(operation, errorHandler, context) {
104
+ try {
105
+ return await operation();
106
+ }
107
+ catch (error) {
108
+ const message = `Safe execution failed in ${context}: ${error instanceof Error ? error.message : String(error)}`;
109
+ errorHandler.handleValidationError(message, { context, error });
110
+ throw error;
111
+ }
112
+ }
113
+ // </Block> =======================================
114
+ // <Block> 7.11 ===================================
115
+ export function validateFileExists(filePath, errorHandler) {
116
+ if (!existsSync(filePath)) {
117
+ errorHandler.handleValidationError(`File not found: ${filePath}`, {
118
+ filePath,
119
+ });
120
+ }
121
+ }
122
+ // </Block> =======================================
123
+ // <Block> 7.12 ===================================
124
+ /**
125
+ * Creates a standardized hook response using HookTemplates
126
+ * @deprecated Use HookTemplates.createHookSuccessResponse or createHookErrorResponse instead
127
+ * This function is maintained for backward compatibility but should be replaced with HookTemplates.
128
+ */
129
+ export function createHookResponse(success, data) {
130
+ // Log deprecation warning in development mode
131
+ if (process.env.NODE_ENV === 'development') {
132
+ console.warn('createHookResponse in error-handler.ts is deprecated. Use HookTemplates.createHookSuccessResponse or createHookErrorResponse instead.');
133
+ }
134
+ const response = {
135
+ continue: success,
136
+ suppressOutput: true, // Add standard suppressOutput field for Claude Code compatibility
137
+ ...data,
138
+ };
139
+ return JSON.stringify(response);
140
+ }
141
+ // </Block> =======================================
142
+ export const globalErrorHandler = new ErrorHandler(process.env.DEBUG === 'true');
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Simple logging utility for claude-mem
3
+ */
4
+ export interface LogLevel {
5
+ DEBUG: number;
6
+ INFO: number;
7
+ WARN: number;
8
+ ERROR: number;
9
+ }
10
+ declare class Logger {
11
+ private level;
12
+ setLevel(level: keyof LogLevel): void;
13
+ debug(message: string, ...args: any[]): void;
14
+ info(message: string, ...args: any[]): void;
15
+ warn(message: string, ...args: any[]): void;
16
+ error(message: string, error?: any, context?: any): void;
17
+ }
18
+ export declare const log: Logger;
19
+ export {};
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Simple logging utility for claude-mem
3
+ */
4
+ const LOG_LEVELS = {
5
+ DEBUG: 0,
6
+ INFO: 1,
7
+ WARN: 2,
8
+ ERROR: 3,
9
+ };
10
+ class Logger {
11
+ // <Block> 2.1 ====================================
12
+ level = LOG_LEVELS.INFO;
13
+ setLevel(level) {
14
+ this.level = LOG_LEVELS[level];
15
+ }
16
+ // </Block> =======================================
17
+ // <Block> 2.2 ====================================
18
+ debug(message, ...args) {
19
+ if (this.level <= LOG_LEVELS.DEBUG) {
20
+ console.debug(`[DEBUG] ${message}`, ...args);
21
+ }
22
+ }
23
+ // </Block> =======================================
24
+ // <Block> 2.3 ====================================
25
+ info(message, ...args) {
26
+ if (this.level <= LOG_LEVELS.INFO) {
27
+ console.info(`[INFO] ${message}`, ...args);
28
+ }
29
+ }
30
+ // </Block> =======================================
31
+ // <Block> 2.4 ====================================
32
+ warn(message, ...args) {
33
+ if (this.level <= LOG_LEVELS.WARN) {
34
+ console.warn(`[WARN] ${message}`, ...args);
35
+ }
36
+ }
37
+ // </Block> =======================================
38
+ // <Block> 2.5 ====================================
39
+ error(message, error, context) {
40
+ if (this.level <= LOG_LEVELS.ERROR) {
41
+ console.error(`[ERROR] ${message}`);
42
+ if (error) {
43
+ console.error(error);
44
+ }
45
+ if (context) {
46
+ console.error('Context:', context);
47
+ }
48
+ }
49
+ }
50
+ }
51
+ export const log = new Logger();
@@ -0,0 +1,28 @@
1
+ /**
2
+ * PathResolver utility for managing claude-mem file system paths
3
+ */
4
+ export declare class PathResolver {
5
+ private baseDir;
6
+ constructor();
7
+ getConfigDir(): string;
8
+ getIndexDir(): string;
9
+ getIndexPath(): string;
10
+ getArchiveDir(): string;
11
+ getProjectArchiveDir(projectName: string): string;
12
+ getLogsDir(): string;
13
+ static ensureDirectory(dirPath: string): void;
14
+ static ensureDirectories(dirPaths: string[]): void;
15
+ static extractProjectName(transcriptPath: string): string;
16
+ /**
17
+ * DRY utility function: Canonical source for getting the current project prefix
18
+ * Replaces all instances of path.basename(process.cwd()) across the codebase
19
+ * @returns The current project directory name, sanitized for use as a prefix
20
+ */
21
+ static getCurrentProjectPrefix(): string;
22
+ /**
23
+ * DRY utility function: Gets raw project name without sanitization
24
+ * For use in contexts where original directory name is needed (e.g., display)
25
+ * @returns The current project directory name as-is
26
+ */
27
+ static getCurrentProjectName(): string;
28
+ }
@@ -0,0 +1,100 @@
1
+ import { join } from 'path';
2
+ import { homedir } from 'os';
3
+ import { existsSync, mkdirSync } from 'fs';
4
+ /**
5
+ * PathResolver utility for managing claude-mem file system paths
6
+ */
7
+ export class PathResolver {
8
+ baseDir;
9
+ // <Block> 1.1 ====================================
10
+ constructor() {
11
+ this.baseDir = join(homedir(), '.claude-mem');
12
+ }
13
+ // </Block> =======================================
14
+ // <Block> 1.2 ====================================
15
+ getConfigDir() {
16
+ return this.baseDir;
17
+ }
18
+ // </Block> =======================================
19
+ // <Block> 1.3 ====================================
20
+ getIndexDir() {
21
+ return this.baseDir;
22
+ }
23
+ // </Block> =======================================
24
+ // <Block> 1.4 ====================================
25
+ getIndexPath() {
26
+ return join(this.baseDir, 'claude-mem-index.jsonl');
27
+ }
28
+ // </Block> =======================================
29
+ // <Block> 1.5 ====================================
30
+ getArchiveDir() {
31
+ return join(this.baseDir, 'archives');
32
+ }
33
+ // </Block> =======================================
34
+ // <Block> 1.6 ====================================
35
+ getProjectArchiveDir(projectName) {
36
+ return join(this.getArchiveDir(), projectName);
37
+ }
38
+ // </Block> =======================================
39
+ // <Block> 1.7 ====================================
40
+ getLogsDir() {
41
+ return join(this.baseDir, 'logs');
42
+ }
43
+ // </Block> =======================================
44
+ // <Block> 1.8 ====================================
45
+ static ensureDirectory(dirPath) {
46
+ if (!existsSync(dirPath)) {
47
+ mkdirSync(dirPath, { recursive: true });
48
+ }
49
+ }
50
+ // </Block> =======================================
51
+ // <Block> 1.9 ====================================
52
+ static ensureDirectories(dirPaths) {
53
+ dirPaths.forEach(dirPath => PathResolver.ensureDirectory(dirPath));
54
+ }
55
+ // </Block> =======================================
56
+ // <Block> 1.10 ===================================
57
+ static extractProjectName(transcriptPath) {
58
+ // Try to extract project name from path
59
+ const pathParts = transcriptPath.split('/');
60
+ // <Block> 1.10a =================================
61
+ // Look for common project indicators
62
+ const projectIndicators = ['src', 'lib', 'app', 'project', 'workspace'];
63
+ for (let i = pathParts.length - 1; i >= 0; i--) {
64
+ if (projectIndicators.includes(pathParts[i]) && i > 0) {
65
+ return pathParts[i - 1];
66
+ }
67
+ }
68
+ // </Block> =======================================
69
+ // <Block> 1.10b =================================
70
+ // Fallback to directory name containing the transcript
71
+ if (pathParts.length > 1) {
72
+ return pathParts[pathParts.length - 2];
73
+ }
74
+ // </Block> =======================================
75
+ // Ultimate fallback
76
+ return 'unknown-project';
77
+ }
78
+ // <Block> 1.11 ===================================
79
+ /**
80
+ * DRY utility function: Canonical source for getting the current project prefix
81
+ * Replaces all instances of path.basename(process.cwd()) across the codebase
82
+ * @returns The current project directory name, sanitized for use as a prefix
83
+ */
84
+ static getCurrentProjectPrefix() {
85
+ const cwd = process.cwd();
86
+ const pathParts = cwd.split('/');
87
+ const folderName = pathParts[pathParts.length - 1];
88
+ return folderName.replace(/-/g, '_');
89
+ }
90
+ // </Block> =======================================
91
+ // <Block> 1.12 ===================================
92
+ /**
93
+ * DRY utility function: Gets raw project name without sanitization
94
+ * For use in contexts where original directory name is needed (e.g., display)
95
+ * @returns The current project directory name as-is
96
+ */
97
+ static getCurrentProjectName() {
98
+ return require('path').basename(process.cwd());
99
+ }
100
+ }
@@ -0,0 +1,41 @@
1
+ import type { Settings } from './types.js';
2
+ /**
3
+ * Settings utilities for managing ~/.claude-mem/settings.json
4
+ */
5
+ export declare class SettingsManager {
6
+ private static settingsPath;
7
+ private static cachedSettings;
8
+ /**
9
+ * Safely read settings.json with error handling
10
+ * Returns empty object if file doesn't exist or is malformed
11
+ */
12
+ static readSettings(): Settings;
13
+ /**
14
+ * Get a specific setting value with optional fallback
15
+ */
16
+ static getSetting<K extends keyof Settings>(key: K, fallback?: Settings[K]): Settings[K] | undefined;
17
+ /**
18
+ * Get the Claude binary path from settings
19
+ * Falls back to 'claude' if not found or settings don't exist
20
+ */
21
+ static getClaudePath(): string;
22
+ /**
23
+ * Clear cached settings (useful for testing or after settings changes)
24
+ */
25
+ static clearCache(): void;
26
+ }
27
+ /**
28
+ * Convenience function to get Claude binary path
29
+ * Can be imported directly for simple use cases
30
+ */
31
+ export declare function getClaudePath(): string;
32
+ /**
33
+ * Convenience function to read all settings
34
+ * Can be imported directly for simple use cases
35
+ */
36
+ export declare function readSettings(): Settings;
37
+ /**
38
+ * Convenience function to get a specific setting
39
+ * Can be imported directly for simple use cases
40
+ */
41
+ export declare function getSetting<K extends keyof Settings>(key: K, fallback?: Settings[K]): Settings[K] | undefined;
@@ -0,0 +1,81 @@
1
+ import { readFileSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { PathResolver } from './paths.js';
4
+ /**
5
+ * Settings utilities for managing ~/.claude-mem/settings.json
6
+ */
7
+ export class SettingsManager {
8
+ static settingsPath;
9
+ static cachedSettings = null;
10
+ static {
11
+ const pathResolver = new PathResolver();
12
+ this.settingsPath = join(pathResolver.getConfigDir(), 'settings.json');
13
+ }
14
+ /**
15
+ * Safely read settings.json with error handling
16
+ * Returns empty object if file doesn't exist or is malformed
17
+ */
18
+ static readSettings() {
19
+ // Return cached settings if available
20
+ if (this.cachedSettings !== null) {
21
+ return this.cachedSettings;
22
+ }
23
+ try {
24
+ if (existsSync(this.settingsPath)) {
25
+ const content = readFileSync(this.settingsPath, 'utf-8');
26
+ const settings = JSON.parse(content);
27
+ this.cachedSettings = settings;
28
+ return settings;
29
+ }
30
+ }
31
+ catch {
32
+ // File is malformed or unreadable - return empty settings
33
+ }
34
+ // File doesn't exist or failed to read
35
+ const emptySettings = {};
36
+ this.cachedSettings = emptySettings;
37
+ return emptySettings;
38
+ }
39
+ /**
40
+ * Get a specific setting value with optional fallback
41
+ */
42
+ static getSetting(key, fallback) {
43
+ const settings = this.readSettings();
44
+ return settings[key] ?? fallback;
45
+ }
46
+ /**
47
+ * Get the Claude binary path from settings
48
+ * Falls back to 'claude' if not found or settings don't exist
49
+ */
50
+ static getClaudePath() {
51
+ const claudePath = this.getSetting('claudePath', 'claude');
52
+ return claudePath;
53
+ }
54
+ /**
55
+ * Clear cached settings (useful for testing or after settings changes)
56
+ */
57
+ static clearCache() {
58
+ this.cachedSettings = null;
59
+ }
60
+ }
61
+ /**
62
+ * Convenience function to get Claude binary path
63
+ * Can be imported directly for simple use cases
64
+ */
65
+ export function getClaudePath() {
66
+ return SettingsManager.getClaudePath();
67
+ }
68
+ /**
69
+ * Convenience function to read all settings
70
+ * Can be imported directly for simple use cases
71
+ */
72
+ export function readSettings() {
73
+ return SettingsManager.readSettings();
74
+ }
75
+ /**
76
+ * Convenience function to get a specific setting
77
+ * Can be imported directly for simple use cases
78
+ */
79
+ export function getSetting(key, fallback) {
80
+ return SettingsManager.getSetting(key, fallback);
81
+ }
@@ -0,0 +1,145 @@
1
+ export interface HookPayload {
2
+ session_id: string;
3
+ transcript_path: string;
4
+ hook_event_name: string;
5
+ }
6
+ export interface PreCompactPayload extends HookPayload {
7
+ hook_event_name: 'PreCompact';
8
+ trigger: 'manual' | 'auto';
9
+ custom_instructions?: string;
10
+ }
11
+ export interface SessionStartPayload extends HookPayload {
12
+ hook_event_name: 'SessionStart';
13
+ source: 'startup' | 'compact' | 'vscode' | 'web';
14
+ }
15
+ export interface UserPromptSubmitPayload extends HookPayload {
16
+ hook_event_name: 'UserPromptSubmit';
17
+ prompt: string;
18
+ cwd: string;
19
+ }
20
+ export interface PreToolUsePayload extends HookPayload {
21
+ hook_event_name: 'PreToolUse';
22
+ tool_name: string;
23
+ tool_input: Record<string, unknown>;
24
+ }
25
+ export interface PostToolUsePayload extends HookPayload {
26
+ hook_event_name: 'PostToolUse';
27
+ tool_name: string;
28
+ tool_input: Record<string, unknown>;
29
+ tool_response: Record<string, unknown> & {
30
+ success?: boolean;
31
+ };
32
+ }
33
+ export interface NotificationPayload extends HookPayload {
34
+ hook_event_name: 'Notification';
35
+ message: string;
36
+ title?: string;
37
+ }
38
+ export interface StopPayload extends HookPayload {
39
+ hook_event_name: 'Stop';
40
+ stop_hook_active: boolean;
41
+ }
42
+ export interface BaseHookResponse {
43
+ continue?: boolean;
44
+ stopReason?: string;
45
+ suppressOutput?: boolean;
46
+ }
47
+ export interface PreCompactResponse extends BaseHookResponse {
48
+ decision?: 'approve' | 'block';
49
+ reason?: string;
50
+ }
51
+ export interface SessionStartResponse extends BaseHookResponse {
52
+ hookSpecificOutput?: {
53
+ hookEventName: 'SessionStart';
54
+ additionalContext?: string;
55
+ };
56
+ }
57
+ export interface PreToolUseResponse extends BaseHookResponse {
58
+ permissionDecision?: 'allow' | 'deny' | 'ask';
59
+ permissionDecisionReason?: string;
60
+ }
61
+ export interface CompressionResult {
62
+ compressedLines: string[];
63
+ originalTokens: number;
64
+ compressedTokens: number;
65
+ compressionRatio: number;
66
+ memoryNodes: string[];
67
+ }
68
+ export interface MemoryNode {
69
+ id: string;
70
+ type: 'document';
71
+ content: string;
72
+ timestamp: string;
73
+ metadata?: Record<string, unknown>;
74
+ }
75
+ export declare class HookError extends Error {
76
+ hookType: string;
77
+ payload?: HookPayload | undefined;
78
+ code?: string | undefined;
79
+ constructor(message: string, hookType: string, payload?: HookPayload | undefined, code?: string | undefined);
80
+ }
81
+ export declare class CompressionError extends Error {
82
+ transcriptPath: string;
83
+ stage: 'reading' | 'analyzing' | 'compressing' | 'writing';
84
+ constructor(message: string, transcriptPath: string, stage: 'reading' | 'analyzing' | 'compressing' | 'writing');
85
+ }
86
+ export interface Logger {
87
+ info(message: string, meta?: Record<string, unknown>): void;
88
+ warn(message: string, meta?: Record<string, unknown>): void;
89
+ error(message: string, error?: Error, meta?: Record<string, unknown>): void;
90
+ debug(message: string, meta?: Record<string, unknown>): void;
91
+ }
92
+ export declare class FileLogger implements Logger {
93
+ private logFile;
94
+ private enableDebug;
95
+ constructor(logFile: string, enableDebug?: boolean);
96
+ info(message: string, meta?: Record<string, unknown>): void;
97
+ warn(message: string, meta?: Record<string, unknown>): void;
98
+ error(message: string, error?: Error, meta?: Record<string, unknown>): void;
99
+ debug(message: string, meta?: Record<string, unknown>): void;
100
+ private log;
101
+ }
102
+ export declare function validateHookPayload(payload: unknown, expectedType: string): HookPayload;
103
+ export declare function createSuccessResponse(additionalData?: Record<string, unknown>): BaseHookResponse;
104
+ export declare function createErrorResponse(reason: string, additionalData?: Record<string, unknown>): BaseHookResponse;
105
+ /**
106
+ * Main settings interface for claude-mem configuration
107
+ */
108
+ export interface Settings {
109
+ autoCompress?: boolean;
110
+ projectName?: string;
111
+ installed?: boolean;
112
+ backend?: string;
113
+ embedded?: boolean;
114
+ saveMemoriesOnClear?: boolean;
115
+ claudePath?: string;
116
+ [key: string]: unknown;
117
+ }
118
+ /**
119
+ * Document structure for MCP operations
120
+ */
121
+ export interface MCPDocument {
122
+ id: string;
123
+ content: string;
124
+ metadata?: Record<string, unknown>;
125
+ }
126
+ /**
127
+ * Search result structure from MCP operations
128
+ */
129
+ export interface MCPSearchResult {
130
+ documents?: MCPDocument[];
131
+ ids?: string[];
132
+ metadatas?: Record<string, unknown>[];
133
+ distances?: number[];
134
+ [key: string]: unknown;
135
+ }
136
+ /**
137
+ * Interface for MCP client implementations (Chroma-based)
138
+ */
139
+ export interface IMCPClient {
140
+ connect(): Promise<void>;
141
+ disconnect(): Promise<void>;
142
+ addDocuments(documents: MCPDocument[]): Promise<void>;
143
+ queryDocuments(query: string, limit?: number): Promise<MCPSearchResult>;
144
+ getDocuments(ids?: string[]): Promise<MCPSearchResult>;
145
+ }
@@ -0,0 +1,78 @@
1
+ export class HookError extends Error {
2
+ hookType;
3
+ payload;
4
+ code;
5
+ constructor(message, hookType, payload, code) {
6
+ super(message);
7
+ this.hookType = hookType;
8
+ this.payload = payload;
9
+ this.code = code;
10
+ this.name = 'HookError';
11
+ }
12
+ }
13
+ export class CompressionError extends Error {
14
+ transcriptPath;
15
+ stage;
16
+ constructor(message, transcriptPath, stage) {
17
+ super(message);
18
+ this.transcriptPath = transcriptPath;
19
+ this.stage = stage;
20
+ this.name = 'CompressionError';
21
+ }
22
+ }
23
+ export class FileLogger {
24
+ logFile;
25
+ enableDebug;
26
+ constructor(logFile, enableDebug = false) {
27
+ this.logFile = logFile;
28
+ this.enableDebug = enableDebug;
29
+ }
30
+ info(message, meta) {
31
+ this.log('INFO', message, meta);
32
+ }
33
+ warn(message, meta) {
34
+ this.log('WARN', message, meta);
35
+ }
36
+ error(message, error, meta) {
37
+ const errorMeta = error ? { error: error.message, stack: error.stack } : {};
38
+ this.log('ERROR', message, { ...meta, ...errorMeta });
39
+ }
40
+ debug(message, meta) {
41
+ if (this.enableDebug) {
42
+ this.log('DEBUG', message, meta);
43
+ }
44
+ }
45
+ log(level, message, meta) {
46
+ const timestamp = new Date().toISOString();
47
+ const metaStr = meta ? ` ${JSON.stringify(meta)}` : '';
48
+ const logLine = `[${timestamp}] ${level}: ${message}${metaStr}\n`;
49
+ console.error(logLine);
50
+ }
51
+ }
52
+ export function validateHookPayload(payload, expectedType) {
53
+ if (!payload || typeof payload !== 'object') {
54
+ throw new HookError(`Invalid payload: expected object, got ${typeof payload}`, expectedType);
55
+ }
56
+ const hookPayload = payload;
57
+ if (!hookPayload.session_id || typeof hookPayload.session_id !== 'string') {
58
+ throw new HookError('Missing or invalid session_id', expectedType, hookPayload);
59
+ }
60
+ if (!hookPayload.transcript_path ||
61
+ typeof hookPayload.transcript_path !== 'string') {
62
+ throw new HookError('Missing or invalid transcript_path', expectedType, hookPayload);
63
+ }
64
+ return hookPayload;
65
+ }
66
+ export function createSuccessResponse(additionalData) {
67
+ return {
68
+ continue: true,
69
+ ...additionalData,
70
+ };
71
+ }
72
+ export function createErrorResponse(reason, additionalData) {
73
+ return {
74
+ continue: false,
75
+ stopReason: reason,
76
+ ...additionalData,
77
+ };
78
+ }