fix: respect CLAUDE_CONFIG_DIR for plugin paths (#626)
Add MARKETPLACE_ROOT constant to paths.ts and update 5 source files to use centralized path constants instead of hardcoded ~/.claude paths. Preserves backwards compatibility when CLAUDE_CONFIG_DIR is not set. Based on PR #634 by @Kuroakira, cherry-picked onto main due to build artifact merge conflicts (source changes applied cleanly). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,10 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { homedir } from 'os';
|
|
||||||
import { existsSync, readFileSync } from 'fs';
|
import { existsSync, readFileSync } from 'fs';
|
||||||
import { SessionStore } from '../sqlite/SessionStore.js';
|
import { SessionStore } from '../sqlite/SessionStore.js';
|
||||||
import { logger } from '../../utils/logger.js';
|
import { logger } from '../../utils/logger.js';
|
||||||
|
import { CLAUDE_CONFIG_DIR } from '../../shared/paths.js';
|
||||||
import type {
|
import type {
|
||||||
ContextConfig,
|
ContextConfig,
|
||||||
Observation,
|
Observation,
|
||||||
@@ -203,7 +203,8 @@ export function getPriorSessionMessages(
|
|||||||
|
|
||||||
const priorSessionId = priorSessionObs.memory_session_id;
|
const priorSessionId = priorSessionObs.memory_session_id;
|
||||||
const dashedCwd = cwdToDashed(cwd);
|
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);
|
return extractPriorMessages(transcriptPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { homedir } from 'os';
|
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { logger } from '../../utils/logger.js';
|
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
|
* Check if a port is in use by querying the health endpoint
|
||||||
@@ -100,8 +100,7 @@ export async function httpShutdown(port: number): Promise<boolean> {
|
|||||||
* This is the "expected" version that should be running
|
* This is the "expected" version that should be running
|
||||||
*/
|
*/
|
||||||
export function getInstalledPluginVersion(): string {
|
export function getInstalledPluginVersion(): string {
|
||||||
const marketplaceRoot = path.join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack');
|
const packageJsonPath = path.join(MARKETPLACE_ROOT, 'package.json');
|
||||||
const packageJsonPath = path.join(marketplaceRoot, 'package.json');
|
|
||||||
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
||||||
return packageJson.version;
|
return packageJson.version;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { exec } from 'child_process';
|
|||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
import { logger } from '../../utils/logger.js';
|
import { logger } from '../../utils/logger.js';
|
||||||
import { getWorkerPort } from '../../shared/worker-utils.js';
|
import { getWorkerPort } from '../../shared/worker-utils.js';
|
||||||
|
import { DATA_DIR, MARKETPLACE_ROOT, CLAUDE_CONFIG_DIR } from '../../shared/paths.js';
|
||||||
import {
|
import {
|
||||||
readCursorRegistry as readCursorRegistryFromFile,
|
readCursorRegistry as readCursorRegistryFromFile,
|
||||||
writeCursorRegistry as writeCursorRegistryToFile,
|
writeCursorRegistry as writeCursorRegistryToFile,
|
||||||
@@ -27,7 +28,6 @@ import type { CursorInstallTarget, CursorHooksJson, CursorMcpConfig, Platform }
|
|||||||
const execAsync = promisify(exec);
|
const execAsync = promisify(exec);
|
||||||
|
|
||||||
// Standard paths
|
// Standard paths
|
||||||
const DATA_DIR = path.join(homedir(), '.claude-mem');
|
|
||||||
const CURSOR_REGISTRY_FILE = path.join(DATA_DIR, 'cursor-projects.json');
|
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 {
|
export function findCursorHooksDir(): string | null {
|
||||||
const possiblePaths = [
|
const possiblePaths = [
|
||||||
// Marketplace install location
|
// 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/)
|
// Development/source location (relative to built worker-service.cjs in plugin/scripts/)
|
||||||
path.join(path.dirname(__filename), '..', '..', 'cursor-hooks'),
|
path.join(path.dirname(__filename), '..', '..', 'cursor-hooks'),
|
||||||
// Alternative dev location
|
// Alternative dev location
|
||||||
@@ -156,7 +156,7 @@ export function findCursorHooksDir(): string | null {
|
|||||||
export function findMcpServerPath(): string | null {
|
export function findMcpServerPath(): string | null {
|
||||||
const possiblePaths = [
|
const possiblePaths = [
|
||||||
// Marketplace install location
|
// 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/)
|
// Development/source location (relative to built worker-service.cjs in plugin/scripts/)
|
||||||
path.join(path.dirname(__filename), 'mcp-server.cjs'),
|
path.join(path.dirname(__filename), 'mcp-server.cjs'),
|
||||||
// Alternative dev location
|
// Alternative dev location
|
||||||
@@ -178,7 +178,7 @@ export function findMcpServerPath(): string | null {
|
|||||||
export function findWorkerServicePath(): string | null {
|
export function findWorkerServicePath(): string | null {
|
||||||
const possiblePaths = [
|
const possiblePaths = [
|
||||||
// Marketplace install location
|
// 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/)
|
// Development/source location (relative to built worker-service.cjs in plugin/scripts/)
|
||||||
path.join(path.dirname(__filename), 'worker-service.cjs'),
|
path.join(path.dirname(__filename), 'worker-service.cjs'),
|
||||||
// Alternative dev location
|
// Alternative dev location
|
||||||
@@ -596,8 +596,8 @@ export async function detectClaudeCode(): Promise<boolean> {
|
|||||||
logger.debug('SYSTEM', 'Claude CLI not in PATH', {}, error as Error);
|
logger.debug('SYSTEM', 'Claude CLI not in PATH', {}, error as Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for Claude Code plugin directory
|
// Check for Claude Code plugin directory (respects CLAUDE_CONFIG_DIR)
|
||||||
const pluginDir = path.join(homedir(), '.claude', 'plugins');
|
const pluginDir = path.join(CLAUDE_CONFIG_DIR, 'plugins');
|
||||||
if (existsSync(pluginDir)) {
|
if (existsSync(pluginDir)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,12 @@
|
|||||||
|
|
||||||
import { execSync, spawnSync } from 'child_process';
|
import { execSync, spawnSync } from 'child_process';
|
||||||
import { existsSync, unlinkSync } from 'fs';
|
import { existsSync, unlinkSync } from 'fs';
|
||||||
import { homedir } from 'os';
|
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { logger } from '../../utils/logger.js';
|
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
|
* Validate branch name to prevent command injection
|
||||||
|
|||||||
@@ -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
|
// 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');
|
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
|
// Data subdirectories
|
||||||
export const ARCHIVES_DIR = join(DATA_DIR, 'archives');
|
export const ARCHIVES_DIR = join(DATA_DIR, 'archives');
|
||||||
export const LOGS_DIR = join(DATA_DIR, 'logs');
|
export const LOGS_DIR = join(DATA_DIR, 'logs');
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import { homedir } from "os";
|
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
import { logger } from "../utils/logger.js";
|
import { logger } from "../utils/logger.js";
|
||||||
import { HOOK_TIMEOUTS, getTimeout } from "./hook-constants.js";
|
import { HOOK_TIMEOUTS, getTimeout } from "./hook-constants.js";
|
||||||
import { SettingsDefaultsManager } from "./SettingsDefaultsManager.js";
|
import { SettingsDefaultsManager } from "./SettingsDefaultsManager.js";
|
||||||
|
import { MARKETPLACE_ROOT } from "./paths.js";
|
||||||
const MARKETPLACE_ROOT = path.join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack');
|
|
||||||
|
|
||||||
// Named constants for health checks
|
// Named constants for health checks
|
||||||
const HEALTH_CHECK_TIMEOUT_MS = getTimeout(HOOK_TIMEOUTS.HEALTH_CHECK);
|
const HEALTH_CHECK_TIMEOUT_MS = getTimeout(HOOK_TIMEOUTS.HEALTH_CHECK);
|
||||||
|
|||||||
Reference in New Issue
Block a user