Refactor path management: Migrate path discovery logic to shared paths module
- Removed `path-discovery.ts` service and replaced its usage with a new `paths.ts` module. - Updated all commands and services to utilize the new path constants and helper functions. - Ensured all necessary directories are created using the new utility functions. - Improved code readability and maintainability by centralizing path configurations.
This commit is contained in:
+9
-12
@@ -1,7 +1,7 @@
|
||||
import { OptionValues } from 'commander';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import * as paths from '../shared/paths.js';
|
||||
import { HooksDatabase } from '../services/sqlite/index.js';
|
||||
|
||||
type CheckStatus = 'pass' | 'fail' | 'warn';
|
||||
@@ -20,24 +20,22 @@ function printCheck(result: CheckResult): void {
|
||||
}
|
||||
|
||||
export async function doctor(options: OptionValues = {}): Promise<void> {
|
||||
const discovery = PathDiscovery.getInstance();
|
||||
const checks: CheckResult[] = [];
|
||||
|
||||
// Data directory
|
||||
try {
|
||||
const dataDir = discovery.getDataDirectory();
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
fs.mkdirSync(dataDir, { recursive: true });
|
||||
checks.push({ name: `Data directory created at ${dataDir}`, status: 'warn' });
|
||||
if (!fs.existsSync(paths.DATA_DIR)) {
|
||||
fs.mkdirSync(paths.DATA_DIR, { recursive: true });
|
||||
checks.push({ name: `Data directory created at ${paths.DATA_DIR}`, status: 'warn' });
|
||||
} else {
|
||||
const stats = fs.statSync(dataDir);
|
||||
const stats = fs.statSync(paths.DATA_DIR);
|
||||
let writable = false;
|
||||
try {
|
||||
fs.accessSync(dataDir, fs.constants.W_OK);
|
||||
fs.accessSync(paths.DATA_DIR, fs.constants.W_OK);
|
||||
writable = true;
|
||||
} catch {}
|
||||
checks.push({
|
||||
name: `Data directory ${dataDir}`,
|
||||
name: `Data directory ${paths.DATA_DIR}`,
|
||||
status: stats.isDirectory() && writable ? 'pass' : 'fail',
|
||||
details: stats.isDirectory() && writable ? 'accessible' : 'not writable'
|
||||
});
|
||||
@@ -68,12 +66,11 @@ export async function doctor(options: OptionValues = {}): Promise<void> {
|
||||
|
||||
// Chroma connectivity
|
||||
try {
|
||||
const chromaDir = discovery.getChromaDirectory();
|
||||
const chromaExists = fs.existsSync(chromaDir);
|
||||
const chromaExists = fs.existsSync(paths.CHROMA_DIR);
|
||||
checks.push({
|
||||
name: 'Chroma vector store',
|
||||
status: chromaExists ? 'pass' : 'warn',
|
||||
details: chromaExists ? `data dir ${path.resolve(chromaDir)}` : 'Not yet initialized'
|
||||
details: chromaExists ? `data dir ${path.resolve(paths.CHROMA_DIR)}` : 'Not yet initialized'
|
||||
});
|
||||
} catch (error: any) {
|
||||
checks.push({
|
||||
|
||||
+17
-29
@@ -10,8 +10,8 @@ import chalk from 'chalk';
|
||||
import boxen from 'boxen';
|
||||
import { PACKAGE_NAME } from '../shared/config.js';
|
||||
import type { Settings } from '../shared/types.js';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import { Platform } from '../utils/platform.js';
|
||||
import * as paths from '../shared/paths.js';
|
||||
|
||||
|
||||
// Enhanced animation utilities
|
||||
@@ -60,8 +60,7 @@ function installUv(): void {
|
||||
|
||||
|
||||
function hasExistingInstallation(): boolean {
|
||||
const pathDiscovery = PathDiscovery.getInstance();
|
||||
const settingsPath = pathDiscovery.getClaudeSettingsPath();
|
||||
const settingsPath = paths.CLAUDE_SETTINGS_PATH;
|
||||
|
||||
if (!existsSync(settingsPath)) return false;
|
||||
|
||||
@@ -181,16 +180,14 @@ async function runInstallationWizard(existingInstall: boolean): Promise<InstallC
|
||||
|
||||
// <Block> Directory structure creation - natural setup flow
|
||||
function ensureDirectoryStructure(): void {
|
||||
const pathDiscovery = PathDiscovery.getInstance();
|
||||
|
||||
// Create all data directories
|
||||
pathDiscovery.ensureAllDataDirectories();
|
||||
|
||||
paths.ensureAllDataDirs();
|
||||
|
||||
// Create all Claude integration directories
|
||||
pathDiscovery.ensureAllClaudeDirectories();
|
||||
|
||||
paths.ensureAllClaudeDirs();
|
||||
|
||||
// Create package.json in .claude-mem to fix ESM module issues
|
||||
const packageJsonPath = join(pathDiscovery.getDataDirectory(), 'package.json');
|
||||
const packageJsonPath = join(paths.DATA_DIR, 'package.json');
|
||||
if (!existsSync(packageJsonPath)) {
|
||||
const packageJson = {
|
||||
name: "claude-mem-data",
|
||||
@@ -204,9 +201,7 @@ function ensureDirectoryStructure(): void {
|
||||
function copyFileRecursively(src: string, dest: string): void {
|
||||
const stat = statSync(src);
|
||||
if (stat.isDirectory()) {
|
||||
if (!existsSync(dest)) {
|
||||
mkdirSync(dest, { recursive: true });
|
||||
}
|
||||
mkdirSync(dest, { recursive: true });
|
||||
const files = readdirSync(src);
|
||||
files.forEach((file: string) => {
|
||||
copyFileRecursively(join(src, file), join(dest, file));
|
||||
@@ -219,14 +214,11 @@ function copyFileRecursively(src: string, dest: string): void {
|
||||
|
||||
|
||||
function ensureClaudeMdInstructions(): void {
|
||||
const pathDiscovery = PathDiscovery.getInstance();
|
||||
const claudeMdPath = pathDiscovery.getClaudeMdPath();
|
||||
const claudeMdPath = paths.CLAUDE_MD_PATH;
|
||||
const claudeMdDir = dirname(claudeMdPath);
|
||||
|
||||
|
||||
// Ensure .claude directory exists
|
||||
if (!existsSync(claudeMdDir)) {
|
||||
mkdirSync(claudeMdDir, { recursive: true });
|
||||
}
|
||||
mkdirSync(claudeMdDir, { recursive: true });
|
||||
|
||||
const instructions = `
|
||||
<!-- CLAUDE-MEM QUICK REFERENCE -->
|
||||
@@ -308,7 +300,7 @@ function installChromaMcp(forceReinstall: boolean = false): void {
|
||||
}
|
||||
}
|
||||
|
||||
const chromaMcpCommand = `claude mcp add claude-mem -- uvx chroma-mcp --client-type persistent --data-dir ${PathDiscovery.getInstance().getChromaDirectory()}`;
|
||||
const chromaMcpCommand = `claude mcp add claude-mem -- uvx chroma-mcp --client-type persistent --data-dir ${paths.CHROMA_DIR}`;
|
||||
execSync(chromaMcpCommand, { stdio: 'inherit' });
|
||||
}
|
||||
|
||||
@@ -355,13 +347,12 @@ function getSettingsPath(config: InstallConfig): string {
|
||||
} else if (config.scope === 'project') {
|
||||
return join(process.cwd(), '.claude', 'settings.json');
|
||||
} else {
|
||||
return PathDiscovery.getInstance().getClaudeSettingsPath();
|
||||
return paths.CLAUDE_SETTINGS_PATH;
|
||||
}
|
||||
}
|
||||
|
||||
function configureUserSettings(config: InstallConfig): void {
|
||||
const pathDiscovery = PathDiscovery.getInstance();
|
||||
const userSettingsPath = pathDiscovery.getUserSettingsPath();
|
||||
const userSettingsPath = paths.USER_SETTINGS_PATH;
|
||||
|
||||
let userSettings: Settings = existsSync(userSettingsPath)
|
||||
? JSON.parse(readFileSync(userSettingsPath, 'utf8'))
|
||||
@@ -384,9 +375,7 @@ function configureSmartTrashAlias(): void {
|
||||
if (!existsSync(configPath)) {
|
||||
// Create the file if it doesn't exist (especially for PowerShell profiles)
|
||||
const dir = dirname(configPath);
|
||||
if (!existsSync(dir)) {
|
||||
mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
mkdirSync(dir, { recursive: true });
|
||||
writeFileSync(configPath, '');
|
||||
}
|
||||
|
||||
@@ -401,9 +390,8 @@ function configureSmartTrashAlias(): void {
|
||||
|
||||
|
||||
function installClaudeCommands(): void {
|
||||
const pathDiscovery = PathDiscovery.getInstance();
|
||||
const claudeCommandsDir = pathDiscovery.getClaudeCommandsDirectory();
|
||||
const packageCommandsDir = pathDiscovery.findPackageCommandsDirectory();
|
||||
const claudeCommandsDir = paths.CLAUDE_COMMANDS_DIR;
|
||||
const packageCommandsDir = paths.getPackageCommandsDir();
|
||||
|
||||
mkdirSync(claudeCommandsDir, { recursive: true });
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { OptionValues } from 'commander';
|
||||
import { readFileSync, readdirSync, statSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import * as paths from '../shared/paths.js';
|
||||
|
||||
// <Block> 1.1 ====================================
|
||||
async function showLog(logPath: string, logType: string, tail: number): Promise<void> {
|
||||
@@ -39,7 +39,7 @@ async function showLog(logPath: string, logType: string, tail: number): Promise<
|
||||
// <Block> 2.1 ====================================
|
||||
export async function logs(options: OptionValues = {}): Promise<void> {
|
||||
// <Block> 2.2 ====================================
|
||||
const logsDir = PathDiscovery.getLogsDirectory();
|
||||
const logsDir = paths.LOGS_DIR;
|
||||
const tail = parseInt(options.tail) || 20;
|
||||
// </Block> =======================================
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { readdirSync, renameSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import * as p from '@clack/prompts';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import * as paths from '../shared/paths.js';
|
||||
|
||||
export async function restore(): Promise<void> {
|
||||
const trashDir = PathDiscovery.getInstance().getTrashDirectory();
|
||||
const trashDir = paths.TRASH_DIR;
|
||||
const files = readdirSync(trashDir);
|
||||
|
||||
if (files.length === 0) {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { readFileSync, existsSync, readdirSync, statSync } from 'fs';
|
||||
import { join, resolve, dirname } from 'path';
|
||||
import { execSync } from 'child_process';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import * as paths from '../shared/paths.js';
|
||||
import { HooksDatabase } from '../services/sqlite/index.js';
|
||||
import chalk from 'chalk';
|
||||
|
||||
@@ -12,7 +12,7 @@ export async function status(): Promise<void> {
|
||||
console.log('🔍 Claude Memory System Status Check');
|
||||
console.log('=====================================\n');
|
||||
|
||||
const pathDiscovery = PathDiscovery.getInstance();
|
||||
// paths imported
|
||||
|
||||
console.log('⚙️ Settings Configuration:');
|
||||
|
||||
@@ -53,13 +53,13 @@ export async function status(): Promise<void> {
|
||||
}
|
||||
};
|
||||
|
||||
checkSettings('Global', pathDiscovery.getClaudeSettingsPath());
|
||||
checkSettings('Global', paths.ClaudeSettingsPath());
|
||||
checkSettings('Project', join(process.cwd(), '.claude', 'settings.json'));
|
||||
|
||||
console.log('');
|
||||
|
||||
console.log('📦 Compressed Transcripts:');
|
||||
const claudeProjectsDir = join(pathDiscovery.getClaudeConfigDirectory(), 'projects');
|
||||
const claudeProjectsDir = join(paths.ClaudeConfigDirectory(), 'projects');
|
||||
|
||||
if (existsSync(claudeProjectsDir)) {
|
||||
try {
|
||||
@@ -116,13 +116,13 @@ export async function status(): Promise<void> {
|
||||
|
||||
console.log('🧠 Chroma Storage Status:');
|
||||
console.log(' ✅ Storage backend: Chroma MCP');
|
||||
console.log(` 📍 Data location: ${pathDiscovery.getChromaDirectory()}`);
|
||||
console.log(` 📍 Data location: ${paths.ChromaDirectory()}`);
|
||||
console.log(' 🔍 Features: Vector search, semantic similarity, document storage');
|
||||
|
||||
console.log('');
|
||||
|
||||
console.log('📊 Summary:');
|
||||
const globalPath = pathDiscovery.getClaudeSettingsPath();
|
||||
const globalPath = paths.ClaudeSettingsPath();
|
||||
const projectPath = join(process.cwd(), '.claude', 'settings.json');
|
||||
|
||||
let isInstalled = false;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { rmSync, readdirSync, existsSync, statSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import * as p from '@clack/prompts';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import * as paths from '../shared/paths.js';
|
||||
|
||||
export async function emptyTrash(options: { force?: boolean } = {}): Promise<void> {
|
||||
const trashDir = PathDiscovery.getInstance().getTrashDirectory();
|
||||
const trashDir = paths.TRASH_DIR;
|
||||
|
||||
// Check if trash directory exists
|
||||
if (!existsSync(trashDir)) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { readdirSync, statSync } from 'fs';
|
||||
import { join, basename } from 'path';
|
||||
import * as p from '@clack/prompts';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import * as paths from '../shared/paths.js';
|
||||
|
||||
interface TrashItem {
|
||||
originalName: string;
|
||||
@@ -51,7 +51,7 @@ function getDirectorySize(dirPath: string): number {
|
||||
}
|
||||
|
||||
export async function viewTrash(): Promise<void> {
|
||||
const trashDir = PathDiscovery.getInstance().getTrashDirectory();
|
||||
const trashDir = paths.TRASH_DIR;
|
||||
|
||||
try {
|
||||
const files = readdirSync(trashDir);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { renameSync, existsSync, mkdirSync, statSync } from 'fs';
|
||||
import { join, basename } from 'path';
|
||||
import { glob } from 'glob';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import * as paths from '../shared/paths.js';
|
||||
|
||||
interface TrashOptions {
|
||||
force?: boolean;
|
||||
@@ -9,7 +9,7 @@ interface TrashOptions {
|
||||
}
|
||||
|
||||
export async function trash(filePaths: string | string[], options: TrashOptions = {}): Promise<void> {
|
||||
const trashDir = PathDiscovery.getInstance().getTrashDirectory();
|
||||
const trashDir = paths.TRASH_DIR;
|
||||
if (!existsSync(trashDir)) mkdirSync(trashDir, { recursive: true });
|
||||
|
||||
// Handle single string or array of paths
|
||||
|
||||
@@ -2,7 +2,7 @@ import { OptionValues } from 'commander';
|
||||
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { homedir } from 'os';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import * as paths from '../shared/paths.js';
|
||||
|
||||
async function removeSmartTrashAlias(): Promise<boolean> {
|
||||
const homeDir = homedir();
|
||||
@@ -71,7 +71,7 @@ export async function uninstall(options: OptionValues = {}): Promise<void> {
|
||||
if (options.all) {
|
||||
locations.push({
|
||||
name: 'User',
|
||||
path: PathDiscovery.getInstance().getClaudeSettingsPath()
|
||||
path: paths.CLAUDE_SETTINGS_PATH
|
||||
});
|
||||
locations.push({
|
||||
name: 'Project',
|
||||
@@ -79,10 +79,9 @@ export async function uninstall(options: OptionValues = {}): Promise<void> {
|
||||
});
|
||||
} else {
|
||||
const isProject = options.project;
|
||||
const pathDiscovery = PathDiscovery.getInstance();
|
||||
locations.push({
|
||||
name: isProject ? 'Project' : 'User',
|
||||
path: isProject ? join(process.cwd(), '.claude', 'settings.json') : pathDiscovery.getClaudeSettingsPath()
|
||||
path: isProject ? join(process.cwd(), '.claude', 'settings.json') : paths.CLAUDE_SETTINGS_PATH
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { HooksDatabase } from '../services/sqlite/HooksDatabase.js';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import path from 'path';
|
||||
|
||||
export interface SessionStartInput {
|
||||
@@ -69,7 +68,7 @@ export function contextHook(input: SessionStartInput): void {
|
||||
output.push(`**Files Edited:** ${files.join(', ')}`);
|
||||
}
|
||||
} catch {
|
||||
// If not valid JSON, show as text
|
||||
// Backwards compatibility: if not valid JSON, show as text
|
||||
if (summary.files_edited.trim()) {
|
||||
output.push(`**Files Edited:** ${summary.files_edited}`);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,7 +1,6 @@
|
||||
import net from 'net';
|
||||
import { join } from 'path';
|
||||
import { HooksDatabase } from '../services/sqlite/HooksDatabase.js';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import { getWorkerSocketPath } from '../shared/paths.js';
|
||||
|
||||
export interface PostToolUseInput {
|
||||
session_id: string;
|
||||
@@ -45,8 +44,7 @@ export function saveHook(input: PostToolUseInput): void {
|
||||
}
|
||||
|
||||
// Get socket path
|
||||
const dataDir = PathDiscovery.getInstance().getDataDirectory();
|
||||
const socketPath = join(dataDir, `worker-${session.id}.sock`);
|
||||
const socketPath = getWorkerSocketPath(session.id);
|
||||
|
||||
// Send observation via Unix socket
|
||||
const message = {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import net from 'net';
|
||||
import { join } from 'path';
|
||||
import { HooksDatabase } from '../services/sqlite/HooksDatabase.js';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import { getWorkerSocketPath } from '../shared/paths.js';
|
||||
|
||||
export interface StopInput {
|
||||
session_id: string;
|
||||
@@ -29,8 +28,7 @@ export function summaryHook(input: StopInput): void {
|
||||
}
|
||||
|
||||
// Get socket path
|
||||
const dataDir = PathDiscovery.getInstance().getDataDirectory();
|
||||
const socketPath = join(dataDir, `worker-${session.id}.sock`);
|
||||
const socketPath = getWorkerSocketPath(session.id);
|
||||
|
||||
// Send FINALIZE message via Unix socket
|
||||
const message = {
|
||||
|
||||
+2
-6
@@ -6,10 +6,9 @@
|
||||
|
||||
import net from 'net';
|
||||
import { unlinkSync, existsSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { query } from '@anthropic-ai/claude-agent-sdk';
|
||||
import { HooksDatabase } from '../services/sqlite/HooksDatabase.js';
|
||||
import { PathDiscovery } from '../services/path-discovery.js';
|
||||
import { getWorkerSocketPath } from '../shared/paths.js';
|
||||
import { buildInitPrompt, buildObservationPrompt, buildFinalizePrompt } from './prompts.js';
|
||||
import { parseObservations, parseSummary } from './parser.js';
|
||||
import type { SDKSession } from './prompts.js';
|
||||
@@ -64,10 +63,7 @@ class SDKWorker {
|
||||
this.sessionDbId = sessionDbId;
|
||||
this.db = new HooksDatabase();
|
||||
this.abortController = new AbortController();
|
||||
|
||||
// Socket path: ~/.claude-mem/worker-{sessionId}.sock
|
||||
const dataDir = PathDiscovery.getInstance().getDataDirectory();
|
||||
this.socketPath = join(dataDir, `worker-${sessionDbId}.sock`);
|
||||
this.socketPath = getWorkerSocketPath(sessionDbId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { Database as BunDatabase } from 'bun:sqlite';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { PathDiscovery } from '../path-discovery.js';
|
||||
import { DATA_DIR, DB_PATH, ensureDir } from '../../shared/paths.js';
|
||||
|
||||
// Type alias for better-sqlite3 compatibility
|
||||
type Database = BunDatabase;
|
||||
@@ -47,11 +45,9 @@ export class DatabaseManager {
|
||||
}
|
||||
|
||||
// Ensure the data directory exists
|
||||
const dataDir = PathDiscovery.getInstance().getDataDirectory();
|
||||
fs.mkdirSync(dataDir, { recursive: true });
|
||||
ensureDir(DATA_DIR);
|
||||
|
||||
const dbPath = path.join(dataDir, 'claude-mem.db');
|
||||
this.db = new BunDatabase(dbPath, { create: true, readwrite: true });
|
||||
this.db = new BunDatabase(DB_PATH, { create: true, readwrite: true });
|
||||
|
||||
// Apply optimized SQLite settings
|
||||
this.db.run('PRAGMA journal_mode = WAL');
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { Database } from 'bun:sqlite';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { PathDiscovery } from '../path-discovery.js';
|
||||
import { DATA_DIR, DB_PATH, ensureDir } from '../../shared/paths.js';
|
||||
|
||||
/**
|
||||
* Lightweight database interface for hooks
|
||||
@@ -12,11 +10,8 @@ export class HooksDatabase {
|
||||
private db: Database;
|
||||
|
||||
constructor() {
|
||||
const dataDir = PathDiscovery.getInstance().getDataDirectory();
|
||||
fs.mkdirSync(dataDir, { recursive: true });
|
||||
|
||||
const dbPath = path.join(dataDir, 'claude-mem.db');
|
||||
this.db = new Database(dbPath, { create: true, readwrite: true });
|
||||
ensureDir(DATA_DIR);
|
||||
this.db = new Database(DB_PATH, { create: true, readwrite: true });
|
||||
|
||||
// Ensure optimized settings
|
||||
this.db.run('PRAGMA journal_mode = WAL');
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import { join, dirname, basename, sep } from 'path';
|
||||
import { homedir } from 'os';
|
||||
import { existsSync, mkdirSync } from 'fs';
|
||||
import { execSync } from 'child_process';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
/**
|
||||
* Simple path configuration for claude-mem
|
||||
* Standard paths based on Claude Code conventions
|
||||
*/
|
||||
|
||||
// Base directories
|
||||
export const DATA_DIR = process.env.CLAUDE_MEM_DATA_DIR || join(homedir(), '.claude-mem');
|
||||
export const CLAUDE_CONFIG_DIR = process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude');
|
||||
|
||||
// Data subdirectories
|
||||
export const ARCHIVES_DIR = join(DATA_DIR, 'archives');
|
||||
export const LOGS_DIR = join(DATA_DIR, 'logs');
|
||||
export const TRASH_DIR = join(DATA_DIR, 'trash');
|
||||
export const BACKUPS_DIR = join(DATA_DIR, 'backups');
|
||||
export const CHROMA_DIR = join(DATA_DIR, 'chroma');
|
||||
export const USER_SETTINGS_PATH = join(DATA_DIR, 'settings.json');
|
||||
export const DB_PATH = join(DATA_DIR, 'claude-mem.db');
|
||||
|
||||
// Claude integration paths
|
||||
export const CLAUDE_SETTINGS_PATH = join(CLAUDE_CONFIG_DIR, 'settings.json');
|
||||
export const CLAUDE_COMMANDS_DIR = join(CLAUDE_CONFIG_DIR, 'commands');
|
||||
export const CLAUDE_MD_PATH = join(CLAUDE_CONFIG_DIR, 'CLAUDE.md');
|
||||
|
||||
/**
|
||||
* Get project-specific archive directory
|
||||
*/
|
||||
export function getProjectArchiveDir(projectName: string): string {
|
||||
return join(ARCHIVES_DIR, projectName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get worker socket path for a session
|
||||
*/
|
||||
export function getWorkerSocketPath(sessionId: number): string {
|
||||
return join(DATA_DIR, `worker-${sessionId}.sock`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure a directory exists
|
||||
*/
|
||||
export function ensureDir(dirPath: string): void {
|
||||
mkdirSync(dirPath, { recursive: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure all data directories exist
|
||||
*/
|
||||
export function ensureAllDataDirs(): void {
|
||||
ensureDir(DATA_DIR);
|
||||
ensureDir(ARCHIVES_DIR);
|
||||
ensureDir(LOGS_DIR);
|
||||
ensureDir(TRASH_DIR);
|
||||
ensureDir(BACKUPS_DIR);
|
||||
ensureDir(CHROMA_DIR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure all Claude integration directories exist
|
||||
*/
|
||||
export function ensureAllClaudeDirs(): void {
|
||||
ensureDir(CLAUDE_CONFIG_DIR);
|
||||
ensureDir(CLAUDE_COMMANDS_DIR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current project name from git root or cwd
|
||||
*/
|
||||
export function getCurrentProjectName(): string {
|
||||
try {
|
||||
const gitRoot = execSync('git rev-parse --show-toplevel', {
|
||||
cwd: process.cwd(),
|
||||
encoding: 'utf8',
|
||||
stdio: ['pipe', 'pipe', 'ignore']
|
||||
}).trim();
|
||||
return basename(gitRoot);
|
||||
} catch {
|
||||
return basename(process.cwd());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find package root directory (for install command)
|
||||
*/
|
||||
export function getPackageRoot(): string {
|
||||
// Method 1: Try require.resolve for package.json
|
||||
try {
|
||||
const packageJsonPath = require.resolve('claude-mem/package.json');
|
||||
return dirname(packageJsonPath);
|
||||
} catch {
|
||||
// Continue to next method
|
||||
}
|
||||
|
||||
// Method 2: Walk up from current module location
|
||||
const currentFile = fileURLToPath(import.meta.url);
|
||||
let currentDir = dirname(currentFile);
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const packageJsonPath = join(currentDir, 'package.json');
|
||||
if (existsSync(packageJsonPath)) {
|
||||
const packageJson = require(packageJsonPath);
|
||||
if (packageJson.name === 'claude-mem') {
|
||||
return currentDir;
|
||||
}
|
||||
}
|
||||
|
||||
const parentDir = dirname(currentDir);
|
||||
if (parentDir === currentDir) break;
|
||||
currentDir = parentDir;
|
||||
}
|
||||
|
||||
throw new Error('Cannot locate claude-mem package root. Ensure claude-mem is properly installed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Find commands directory in the installed package
|
||||
*/
|
||||
export function getPackageCommandsDir(): string {
|
||||
const packageRoot = getPackageRoot();
|
||||
const commandsDir = join(packageRoot, 'commands');
|
||||
|
||||
if (!existsSync(join(commandsDir, 'save.md'))) {
|
||||
throw new Error('Package commands directory missing required files');
|
||||
}
|
||||
|
||||
return commandsDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a timestamped backup filename
|
||||
*/
|
||||
export function createBackupFilename(originalPath: string): string {
|
||||
const timestamp = new Date()
|
||||
.toISOString()
|
||||
.replace(/[:.]/g, '-')
|
||||
.replace('T', '_')
|
||||
.slice(0, 19);
|
||||
|
||||
return `${originalPath}.backup.${timestamp}`;
|
||||
}
|
||||
Reference in New Issue
Block a user