diff --git a/src/services/context/ObservationCompiler.ts b/src/services/context/ObservationCompiler.ts index 76fad159..a55e873c 100644 --- a/src/services/context/ObservationCompiler.ts +++ b/src/services/context/ObservationCompiler.ts @@ -5,10 +5,10 @@ */ import path from 'path'; -import { homedir } from 'os'; import { existsSync, readFileSync } from 'fs'; import { SessionStore } from '../sqlite/SessionStore.js'; import { logger } from '../../utils/logger.js'; +import { CLAUDE_CONFIG_DIR } from '../../shared/paths.js'; import type { ContextConfig, Observation, @@ -203,7 +203,8 @@ export function getPriorSessionMessages( const priorSessionId = priorSessionObs.memory_session_id; const dashedCwd = cwdToDashed(cwd); - const transcriptPath = path.join(homedir(), '.claude', 'projects', dashedCwd, `${priorSessionId}.jsonl`); + // Use CLAUDE_CONFIG_DIR to support custom Claude config directories + const transcriptPath = path.join(CLAUDE_CONFIG_DIR, 'projects', dashedCwd, `${priorSessionId}.jsonl`); return extractPriorMessages(transcriptPath); } diff --git a/src/services/infrastructure/HealthMonitor.ts b/src/services/infrastructure/HealthMonitor.ts index d0e86864..46eb9316 100644 --- a/src/services/infrastructure/HealthMonitor.ts +++ b/src/services/infrastructure/HealthMonitor.ts @@ -10,9 +10,9 @@ */ import path from 'path'; -import { homedir } from 'os'; import { readFileSync } from 'fs'; import { logger } from '../../utils/logger.js'; +import { MARKETPLACE_ROOT } from '../../shared/paths.js'; /** * Check if a port is in use by querying the health endpoint @@ -100,8 +100,7 @@ export async function httpShutdown(port: number): Promise { * This is the "expected" version that should be running */ export function getInstalledPluginVersion(): string { - const marketplaceRoot = path.join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack'); - const packageJsonPath = path.join(marketplaceRoot, 'package.json'); + const packageJsonPath = path.join(MARKETPLACE_ROOT, 'package.json'); const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')); return packageJson.version; } diff --git a/src/services/integrations/CursorHooksInstaller.ts b/src/services/integrations/CursorHooksInstaller.ts index 7e485d6e..311c55f6 100644 --- a/src/services/integrations/CursorHooksInstaller.ts +++ b/src/services/integrations/CursorHooksInstaller.ts @@ -16,6 +16,7 @@ import { exec } from 'child_process'; import { promisify } from 'util'; import { logger } from '../../utils/logger.js'; import { getWorkerPort } from '../../shared/worker-utils.js'; +import { DATA_DIR, MARKETPLACE_ROOT, CLAUDE_CONFIG_DIR } from '../../shared/paths.js'; import { readCursorRegistry as readCursorRegistryFromFile, writeCursorRegistry as writeCursorRegistryToFile, @@ -27,7 +28,6 @@ import type { CursorInstallTarget, CursorHooksJson, CursorMcpConfig, Platform } const execAsync = promisify(exec); // Standard paths -const DATA_DIR = path.join(homedir(), '.claude-mem'); const CURSOR_REGISTRY_FILE = path.join(DATA_DIR, 'cursor-projects.json'); // ============================================================================ @@ -133,7 +133,7 @@ export async function updateCursorContextForProject(projectName: string, port: n export function findCursorHooksDir(): string | null { const possiblePaths = [ // Marketplace install location - path.join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack', 'cursor-hooks'), + path.join(MARKETPLACE_ROOT, 'cursor-hooks'), // Development/source location (relative to built worker-service.cjs in plugin/scripts/) path.join(path.dirname(__filename), '..', '..', 'cursor-hooks'), // Alternative dev location @@ -156,7 +156,7 @@ export function findCursorHooksDir(): string | null { export function findMcpServerPath(): string | null { const possiblePaths = [ // Marketplace install location - path.join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack', 'plugin', 'scripts', 'mcp-server.cjs'), + path.join(MARKETPLACE_ROOT, 'plugin', 'scripts', 'mcp-server.cjs'), // Development/source location (relative to built worker-service.cjs in plugin/scripts/) path.join(path.dirname(__filename), 'mcp-server.cjs'), // Alternative dev location @@ -178,7 +178,7 @@ export function findMcpServerPath(): string | null { export function findWorkerServicePath(): string | null { const possiblePaths = [ // Marketplace install location - path.join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack', 'plugin', 'scripts', 'worker-service.cjs'), + path.join(MARKETPLACE_ROOT, 'plugin', 'scripts', 'worker-service.cjs'), // Development/source location (relative to built worker-service.cjs in plugin/scripts/) path.join(path.dirname(__filename), 'worker-service.cjs'), // Alternative dev location @@ -596,8 +596,8 @@ export async function detectClaudeCode(): Promise { logger.debug('SYSTEM', 'Claude CLI not in PATH', {}, error as Error); } - // Check for Claude Code plugin directory - const pluginDir = path.join(homedir(), '.claude', 'plugins'); + // Check for Claude Code plugin directory (respects CLAUDE_CONFIG_DIR) + const pluginDir = path.join(CLAUDE_CONFIG_DIR, 'plugins'); if (existsSync(pluginDir)) { return true; } diff --git a/src/services/worker/BranchManager.ts b/src/services/worker/BranchManager.ts index 26ed5c45..4027af45 100644 --- a/src/services/worker/BranchManager.ts +++ b/src/services/worker/BranchManager.ts @@ -7,11 +7,12 @@ import { execSync, spawnSync } from 'child_process'; import { existsSync, unlinkSync } from 'fs'; -import { homedir } from 'os'; import { join } from 'path'; import { logger } from '../../utils/logger.js'; +import { MARKETPLACE_ROOT } from '../../shared/paths.js'; -const INSTALLED_PLUGIN_PATH = join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack'); +// Alias for code clarity - this is the installed plugin path +const INSTALLED_PLUGIN_PATH = MARKETPLACE_ROOT; /** * Validate branch name to prevent command injection diff --git a/src/shared/paths.ts b/src/shared/paths.ts index ca7e7aba..09561198 100644 --- a/src/shared/paths.ts +++ b/src/shared/paths.ts @@ -28,6 +28,9 @@ export const DATA_DIR = SettingsDefaultsManager.get('CLAUDE_MEM_DATA_DIR'); // Note: CLAUDE_CONFIG_DIR is a Claude Code setting, not claude-mem, so leave as env var export const CLAUDE_CONFIG_DIR = process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude'); +// Plugin installation directory - respects CLAUDE_CONFIG_DIR for users with custom Claude locations +export const MARKETPLACE_ROOT = join(CLAUDE_CONFIG_DIR, 'plugins', 'marketplaces', 'thedotmack'); + // Data subdirectories export const ARCHIVES_DIR = join(DATA_DIR, 'archives'); export const LOGS_DIR = join(DATA_DIR, 'logs'); diff --git a/src/shared/worker-utils.ts b/src/shared/worker-utils.ts index a8b77fca..255cf3f5 100644 --- a/src/shared/worker-utils.ts +++ b/src/shared/worker-utils.ts @@ -1,11 +1,9 @@ import path from "path"; -import { homedir } from "os"; import { readFileSync } from "fs"; import { logger } from "../utils/logger.js"; import { HOOK_TIMEOUTS, getTimeout } from "./hook-constants.js"; import { SettingsDefaultsManager } from "./SettingsDefaultsManager.js"; - -const MARKETPLACE_ROOT = path.join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack'); +import { MARKETPLACE_ROOT } from "./paths.js"; // Named constants for health checks const HEALTH_CHECK_TIMEOUT_MS = getTimeout(HOOK_TIMEOUTS.HEALTH_CHECK);