Refactor settings management to use ~/.claude-mem/settings.json

- Updated paths in troubleshooting documentation to reflect new settings file location.
- Modified diagnostics and reference files to read from ~/.claude-mem/settings.json.
- Introduced getWorkerPort utility for cleaner worker port retrieval.
- Enhanced ChromaSync and SDKAgent to load Python version and Claude path from settings.
- Updated SettingsRoutes to validate new settings: CLAUDE_MEM_LOG_LEVEL and CLAUDE_MEM_PYTHON_VERSION.
- Added early-settings module to load settings for logger and other early-stage modules.
- Adjusted logger to use early-loaded log level setting.
- Refactored paths to utilize early-loaded data directory setting.
This commit is contained in:
Alex Newman
2025-12-09 12:23:33 -05:00
parent b22adcca05
commit fc5c2d5e07
23 changed files with 342 additions and 166 deletions
+3 -1
View File
@@ -18,6 +18,7 @@ import { silentDebug } from '../../utils/silent-debug.js';
import { parseObservations, parseSummary } from '../../sdk/parser.js';
import { buildInitPrompt, buildObservationPrompt, buildSummaryPrompt, buildContinuationPrompt } from '../../sdk/prompts.js';
import { SettingsDefaultsManager } from './settings/SettingsDefaultsManager.js';
import { USER_SETTINGS_PATH } from '../../shared/paths.js';
import type { ActiveSession, SDKUserMessage, PendingMessage } from '../worker-types.js';
// Import Agent SDK (assumes it's installed)
@@ -410,7 +411,8 @@ export class SDKAgent {
* Find Claude executable (inline, called once per session)
*/
private findClaudeExecutable(): string {
const claudePath = process.env.CLAUDE_CODE_PATH ||
const settings = SettingsDefaultsManager.loadFromFile(USER_SETTINGS_PATH);
const claudePath = settings.CLAUDE_CODE_PATH ||
execSync(process.platform === 'win32' ? 'where claude' : 'which claude', { encoding: 'utf8', windowsHide: true })
.trim().split('\n')[0].trim();
@@ -45,7 +45,7 @@ export class SettingsRoutes extends BaseRouteHandler {
}
/**
* Get environment settings (from ~/.claude/settings.json)
* Get environment settings (from ~/.claude-mem/settings.json)
*/
private handleGetSettings = this.wrapHandler((req: Request, res: Response): void => {
const settingsPath = path.join(homedir(), '.claude-mem', 'settings.json');
@@ -54,7 +54,7 @@ export class SettingsRoutes extends BaseRouteHandler {
});
/**
* Update environment settings (in ~/.claude/settings.json) with validation
* Update environment settings (in ~/.claude-mem/settings.json) with validation
*/
private handleUpdateSettings = this.wrapHandler((req: Request, res: Response): void => {
// Validate CLAUDE_MEM_CONTEXT_OBSERVATIONS
@@ -81,6 +81,30 @@ export class SettingsRoutes extends BaseRouteHandler {
}
}
// Validate CLAUDE_MEM_LOG_LEVEL
if (req.body.CLAUDE_MEM_LOG_LEVEL) {
const validLevels = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'SILENT'];
if (!validLevels.includes(req.body.CLAUDE_MEM_LOG_LEVEL.toUpperCase())) {
res.status(400).json({
success: false,
error: 'CLAUDE_MEM_LOG_LEVEL must be one of: DEBUG, INFO, WARN, ERROR, SILENT'
});
return;
}
}
// Validate CLAUDE_MEM_PYTHON_VERSION (must be valid Python version format)
if (req.body.CLAUDE_MEM_PYTHON_VERSION) {
const pythonVersionRegex = /^3\.\d+$/;
if (!pythonVersionRegex.test(req.body.CLAUDE_MEM_PYTHON_VERSION)) {
res.status(400).json({
success: false,
error: 'CLAUDE_MEM_PYTHON_VERSION must be in format "3.X" (e.g., "3.13")'
});
return;
}
}
// Validate context settings
const validation = this.validateContextSettings(req.body);
if (!validation.valid) {
@@ -108,15 +132,24 @@ export class SettingsRoutes extends BaseRouteHandler {
'CLAUDE_MEM_MODEL',
'CLAUDE_MEM_CONTEXT_OBSERVATIONS',
'CLAUDE_MEM_WORKER_PORT',
// System Configuration
'CLAUDE_MEM_DATA_DIR',
'CLAUDE_MEM_LOG_LEVEL',
'CLAUDE_MEM_PYTHON_VERSION',
'CLAUDE_CODE_PATH',
// Token Economics
'CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS',
'CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS',
'CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT',
'CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT',
// Observation Filtering
'CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES',
'CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS',
// Display Configuration
'CLAUDE_MEM_CONTEXT_FULL_COUNT',
'CLAUDE_MEM_CONTEXT_FULL_FIELD',
'CLAUDE_MEM_CONTEXT_SESSION_COUNT',
// Feature Toggles
'CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY',
'CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE',
];
@@ -6,12 +6,19 @@
*/
import { readFileSync, existsSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
import { DEFAULT_OBSERVATION_TYPES_STRING, DEFAULT_OBSERVATION_CONCEPTS_STRING } from '../../../constants/observation-metadata.js';
export interface SettingsDefaults {
CLAUDE_MEM_MODEL: string;
CLAUDE_MEM_CONTEXT_OBSERVATIONS: string;
CLAUDE_MEM_WORKER_PORT: string;
// System Configuration
CLAUDE_MEM_DATA_DIR: string;
CLAUDE_MEM_LOG_LEVEL: string;
CLAUDE_MEM_PYTHON_VERSION: string;
CLAUDE_CODE_PATH: string;
// Token Economics
CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS: string;
CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS: string;
@@ -37,6 +44,11 @@ export class SettingsDefaultsManager {
CLAUDE_MEM_MODEL: 'claude-haiku-4-5',
CLAUDE_MEM_CONTEXT_OBSERVATIONS: '50',
CLAUDE_MEM_WORKER_PORT: '37777',
// System Configuration
CLAUDE_MEM_DATA_DIR: join(homedir(), '.claude-mem'),
CLAUDE_MEM_LOG_LEVEL: 'INFO',
CLAUDE_MEM_PYTHON_VERSION: '3.13',
CLAUDE_CODE_PATH: '', // Empty means auto-detect via 'which claude'
// Token Economics
CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS: 'true',
CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS: 'true',