Cleanup worker-service.ts: remove dead code and fallback concept (#706)

* refactor(worker): remove dead code from worker-service.ts

Remove ~216 lines of unreachable code:
- Delete `runInteractiveSetup` function (defined but never called)
- Remove unused imports: fs namespace, spawn, homedir, readline,
  existsSync/writeFileSync/readFileSync/mkdirSync
- Clean up CursorHooksInstaller imports (keep only used exports)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(worker): only enable SDK fallback when Claude is configured

Add isConfigured() method to SDKAgent that checks for ANTHROPIC_API_KEY
or claude CLI availability. Worker now only sets SDK agent as fallback
for third-party providers when credentials exist, preventing cascading
failures for users who intentionally use Gemini/OpenRouter without Claude.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(worker): remove misleading re-export indirection

Remove unnecessary re-export of updateCursorContextForProject from
worker-service.ts. ResponseProcessor now imports directly from
CursorHooksInstaller.ts where the function is defined. This eliminates
misleading indirection that suggested a circular dependency existed.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(mcp): use build-time injected version instead of hardcoded strings

Replace hardcoded '1.0.0' version strings with __DEFAULT_PACKAGE_VERSION__
constant that esbuild replaces at build time. This ensures MCP server and
client versions stay synchronized with package.json.

- worker-service.ts: MCP client version now uses packageVersion
- ChromaSync.ts: MCP client version now uses packageVersion
- mcp-server.ts: MCP server version now uses packageVersion
- Added clarifying comments for empty MCP capabilities objects

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: Implement cleanup and validation plans for worker-service.ts

- Added a comprehensive cleanup plan addressing 23 identified issues in worker-service.ts, focusing on safe deletions, low-risk simplifications, and medium-risk improvements.
- Created an execution plan for validating intentional patterns in worker-service.ts, detailing necessary actions and priorities.
- Generated a report on unjustified logic in worker-service.ts, categorizing issues by severity and providing recommendations for immediate and short-term actions.
- Introduced documentation for recent activity in the mem-search plugin, enhancing traceability and context for changes.

* fix(sdk): remove dangerous ANTHROPIC_API_KEY check from isConfigured

Claude Code uses CLI authentication, not direct API calls. Checking for
ANTHROPIC_API_KEY could accidentally use a user's API key (from other
projects) which costs 20x more than Claude Code's pricing.

Now only checks for claude CLI availability.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(worker): remove fallback agent concept entirely

Users who choose Gemini/OpenRouter want those providers, not secret
fallback behavior. Removed setFallbackAgent calls and the unused
isConfigured() method.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Alex Newman
2026-01-13 23:30:13 -05:00
committed by GitHub
parent c314946204
commit 05323c9db5
18 changed files with 1836 additions and 882 deletions
+8 -222
View File
@@ -10,16 +10,15 @@
*/
import path from 'path';
import * as fs from 'fs';
import { spawn } from 'child_process';
import { homedir } from 'os';
import { existsSync, writeFileSync, readFileSync, mkdirSync } from 'fs';
import * as readline from 'readline';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { getWorkerPort, getWorkerHost } from '../shared/worker-utils.js';
import { logger } from '../utils/logger.js';
// Version injected at build time by esbuild define
declare const __DEFAULT_PACKAGE_VERSION__: string;
const packageVersion = typeof __DEFAULT_PACKAGE_VERSION__ !== 'undefined' ? __DEFAULT_PACKAGE_VERSION__ : '0.0.0-dev';
// Infrastructure imports
import {
writePidFile,
@@ -45,11 +44,7 @@ import { Server } from './server/Server.js';
// Integration imports
import {
updateCursorContextForProject,
handleCursorCommand,
detectClaudeCode,
findCursorHooksDir,
installCursorHooks,
configureCursorMcp
handleCursorCommand
} from './integrations/CursorHooksInstaller.js';
// Service layer imports
@@ -74,9 +69,6 @@ import { SearchRoutes } from './worker/http/routes/SearchRoutes.js';
import { SettingsRoutes } from './worker/http/routes/SettingsRoutes.js';
import { LogsRoutes } from './worker/http/routes/LogsRoutes.js';
// Re-export updateCursorContextForProject for SDK agents
export { updateCursorContextForProject };
/**
* Build JSON status output for hook framework communication.
* This is a pure function extracted for testability.
@@ -141,9 +133,8 @@ export class WorkerService {
this.sseBroadcaster = new SSEBroadcaster();
this.sdkAgent = new SDKAgent(this.dbManager, this.sessionManager);
this.geminiAgent = new GeminiAgent(this.dbManager, this.sessionManager);
this.geminiAgent.setFallbackAgent(this.sdkAgent);
this.openRouterAgent = new OpenRouterAgent(this.dbManager, this.sessionManager);
this.openRouterAgent.setFallbackAgent(this.sdkAgent);
this.paginationHelper = new PaginationHelper(this.dbManager);
this.settingsManager = new SettingsManager(this.dbManager);
this.sessionEventBroadcaster = new SessionEventBroadcaster(this.sseBroadcaster, this);
@@ -154,9 +145,10 @@ export class WorkerService {
});
// Initialize MCP client
// Empty capabilities object: this client only calls tools, doesn't expose any
this.mcpClient = new Client({
name: 'worker-search-proxy',
version: '1.0.0'
version: packageVersion
}, { capabilities: {} });
// Initialize HTTP server with core routes
@@ -432,212 +424,6 @@ export class WorkerService {
}
}
// ============================================================================
// Interactive Setup Wizard
// ============================================================================
async function runInteractiveSetup(): Promise<number> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const question = (prompt: string): Promise<string> => {
return new Promise(resolve => rl.question(prompt, resolve));
};
console.log(`
╔══════════════════════════════════════════════════════════════════╗
║ Claude-Mem Cursor Setup Wizard ║
║ ║
║ This wizard will guide you through setting up claude-mem ║
║ for use with Cursor IDE. ║
╚══════════════════════════════════════════════════════════════════╝
`);
try {
console.log('Step 1: Checking environment...\n');
const hasClaudeCode = await detectClaudeCode();
const settingsPath = path.join(homedir(), '.claude-mem', 'settings.json');
let settings: Record<string, unknown> = {};
if (existsSync(settingsPath)) {
try {
settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
} catch (error) {
logger.debug('SETUP', 'Corrupt settings file, starting fresh', { path: settingsPath }, error as Error);
}
}
const currentProvider = settings['CLAUDE_MEM_PROVIDER'] as string || (hasClaudeCode ? 'claude-sdk' : 'none');
if (hasClaudeCode) {
console.log('Claude Code detected\n');
} else {
console.log('Claude Code not detected\n');
}
console.log(`Current provider: ${currentProvider}\n`);
console.log('Step 2: Choose AI Provider\n');
if (hasClaudeCode) {
console.log(' [1] Claude SDK (Recommended - uses your Claude Code subscription)');
} else {
console.log(' [1] Claude SDK (requires Claude Code subscription)');
}
console.log(' [2] Gemini (1500 free requests/day)');
console.log(' [3] OpenRouter (100+ models, some free)');
console.log(' [4] Keep current settings\n');
const providerChoice = await question('Enter choice [1-4]: ');
if (providerChoice === '1') {
settings['CLAUDE_MEM_PROVIDER'] = 'claude-sdk';
mkdirSync(path.dirname(settingsPath), { recursive: true });
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
console.log('\nClaude SDK configured!\n');
} else if (providerChoice === '2') {
console.log('\nConfiguring Gemini...\n');
console.log(' Get your free API key at: https://aistudio.google.com/apikey\n');
const apiKey = await question('Enter your Gemini API key: ');
if (apiKey.trim()) {
settings['CLAUDE_MEM_PROVIDER'] = 'gemini';
settings['CLAUDE_MEM_GEMINI_API_KEY'] = apiKey.trim();
mkdirSync(path.dirname(settingsPath), { recursive: true });
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
console.log('\nGemini configured successfully!\n');
} else {
console.log('\nNo API key provided. You can add it later in ~/.claude-mem/settings.json\n');
}
} else if (providerChoice === '3') {
console.log('\nConfiguring OpenRouter...\n');
console.log(' Get your API key at: https://openrouter.ai/keys\n');
const apiKey = await question('Enter your OpenRouter API key: ');
if (apiKey.trim()) {
settings['CLAUDE_MEM_PROVIDER'] = 'openrouter';
settings['CLAUDE_MEM_OPENROUTER_API_KEY'] = apiKey.trim();
mkdirSync(path.dirname(settingsPath), { recursive: true });
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
console.log('\nOpenRouter configured successfully!\n');
} else {
console.log('\nNo API key provided. You can add it later in ~/.claude-mem/settings.json\n');
}
} else {
console.log('\nKeeping current settings.\n');
}
console.log('Step 3: Choose installation scope\n');
console.log(' [1] Project (current directory only) - Recommended');
console.log(' [2] User (all projects for current user)');
console.log(' [3] Skip hook installation\n');
const scopeChoice = await question('Enter choice [1-3]: ');
let installTarget: string | null = null;
if (scopeChoice === '1') {
installTarget = 'project';
} else if (scopeChoice === '2') {
installTarget = 'user';
} else {
console.log('\nSkipping hook installation.\n');
}
if (installTarget) {
console.log(`Step 4: Installing Cursor hooks (${installTarget})...\n`);
const cursorHooksDir = findCursorHooksDir();
if (!cursorHooksDir) {
console.error('Could not find cursor-hooks directory');
console.error(' Make sure you ran npm run build first.');
rl.close();
return 1;
}
const installResult = await installCursorHooks(cursorHooksDir, installTarget as 'project' | 'user');
if (installResult !== 0) {
rl.close();
return installResult;
}
console.log('\nStep 5: Configuring MCP server for memory search...\n');
const mcpResult = configureCursorMcp(installTarget as 'project' | 'user');
if (mcpResult !== 0) {
console.warn('MCP configuration failed, but hooks are installed.');
console.warn(' You can manually configure MCP later.\n');
} else {
console.log('');
}
}
console.log('\nStep 6: Starting claude-mem worker...\n');
const port = getWorkerPort();
const alreadyRunning = await waitForHealth(port, 1000);
if (alreadyRunning) {
console.log('Worker is already running!\n');
} else {
console.log(' Starting worker in background...');
const pid = spawnDaemon(__filename, port);
if (pid === undefined) {
console.error('Failed to start worker');
rl.close();
return 1;
}
writePidFile({ pid, port, startedAt: new Date().toISOString() });
const healthy = await waitForHealth(port, getPlatformTimeout(30000));
if (!healthy) {
removePidFile();
console.error('Worker failed to start');
rl.close();
return 1;
}
console.log('Worker started successfully!\n');
}
console.log(`
╔══════════════════════════════════════════════════════════════════╗
║ Setup Complete! ║
╚══════════════════════════════════════════════════════════════════╝
What's installed:
- Cursor hooks - Automatically capture sessions
- Context injection - Past work injected into new chats
- MCP search server - Ask "what did I work on last week?"
Next steps:
1. Restart Cursor to load the hooks and MCP server
2. Start chatting - your sessions will be remembered!
3. Use natural language to search: "find where I fixed the auth bug"
Useful commands:
npm run cursor:status Check installation status
npm run worker:status Check worker status
npm run worker:logs View worker logs
Memory viewer:
http://localhost:${port}
Documentation:
https://docs.claude-mem.ai/cursor
`);
rl.close();
return 0;
} catch (error) {
rl.close();
console.error(`\nSetup failed: ${(error as Error).message}`);
return 1;
}
}
// ============================================================================
// CLI Entry Point
// ============================================================================