mirror of
https://github.com/thedotmack/claude-mem
synced 2026-04-25 17:15:04 +02:00
refactor: land PATHFINDER Plan 07 — dead code sweep
ts-prune-driven sweep across the tree after Plans 01-06 landed.
Deleted unused exports, orphan helpers, and one fully orphaned
file. Earlier-plan deletions verified.
Deleted:
- src/utils/bun-path.ts (entire file — getBunPath, getBunPathOrThrow,
isBunAvailable: zero importers)
- bun-resolver.getBunVersionString: zero callers
- PendingMessageStore.retryMessage / resetProcessingToPending /
abortMessage: superseded by transitionMessagesTo (Plan 06 Phase 9)
- EnvManager.MANAGED_CREDENTIAL_KEYS, EnvManager.setCredential:
zero callers
- CodexCliInstaller.checkCodexCliStatus: zero callers; no status
command exists in npx-cli
- Two "REMOVED: cleanupOrphanedSessions" stale-fence comments
Kept (with documented justification):
- Public API surface in dist/sdk/* (parseAgentXml, prompt
builders, ParsedObservation, ParsedSummary, ParseResult,
SUMMARY_MODE_MARKER) — exported via package.json sdk path.
- generateContext / loadContextConfig / token utilities — used
via dynamic await import('../../../context-generator.js') in
worker SearchRoutes.
- MCP_IDE_INSTALLERS, install/uninstall functions for codex/goose
— used via dynamic await import in npx-cli/install.ts +
uninstall.ts (ts-prune cannot trace dynamic imports).
- getExistingChromaIds — active caller in
ChromaSync.backfillMissingSyncs (Plan 04 narrowed scope).
- processPendingQueues / getSessionsWithPendingMessages — active
orphan-recovery caller in worker-service.ts plus
zombie-prevention test coverage.
- StoreAndMarkCompleteResult legacy alias — return-type annotation
in same file.
- All Database.ts barrel re-exports — used downstream.
Earlier-plan verification:
- Plan 03 Phase 9: VERIFIED — src/utils/transcript-parser.ts
is gone; TranscriptParser has 0 references in src/.
- Plan 01 Phase 8: VERIFIED — migration 19 no-op absorbed.
- SessionStore.ts:52-70 consolidation NOT executed (deferred):
the methods are not thin wrappers but ~900 LoC of bodies, and
two methods are documented as intentional mirrors so the
context-generator.cjs bundle stays schema-consistent without
pulling MigrationRunner. Deserves its own plan, not a sweep.
Verification: TranscriptParser → 0; transcript-parser.ts → gone;
no commented-out code markers remain. bun run build succeeds.
bun test → 1393 pass / 28 fail / 7 skip — EXACT match to
baseline. Zero regressions.
Plan: PATHFINDER-2026-04-22/07-dead-code.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -158,6 +158,7 @@
|
||||
"tree-sitter-scss": "^1.0.0",
|
||||
"tree-sitter-swift": "^0.7.1",
|
||||
"tree-sitter-typescript": "^0.23.2",
|
||||
"ts-prune": "^0.10.3",
|
||||
"tsx": "^4.20.6",
|
||||
"typescript": "^5.3.0"
|
||||
},
|
||||
|
||||
@@ -760,15 +760,7 @@ Please see the 3.x to 4.x migration guide for details on how to update your app.
|
||||
SELECT * FROM pending_messages
|
||||
WHERE session_db_id = ? AND status = 'pending'
|
||||
ORDER BY id ASC
|
||||
`).all(e)}retryMessage(e){return this.db.prepare(`
|
||||
UPDATE pending_messages
|
||||
SET status = 'pending', worker_pid = NULL
|
||||
WHERE id = ? AND status IN ('pending', 'processing', 'failed')
|
||||
`).run(e).changes>0}resetProcessingToPending(e){return this.db.prepare(`
|
||||
UPDATE pending_messages
|
||||
SET status = 'pending', worker_pid = NULL
|
||||
WHERE session_db_id = ? AND status = 'processing'
|
||||
`).run(e).changes}transitionMessagesTo(e,r){let n=Date.now(),s=e==="failed"?"status = 'processing'":"status IN ('pending', 'processing')";return r.sessionDbId===void 0?this.db.prepare(`
|
||||
`).all(e)}transitionMessagesTo(e,r){let n=Date.now(),s=e==="failed"?"status = 'processing'":"status IN ('pending', 'processing')";return r.sessionDbId===void 0?this.db.prepare(`
|
||||
UPDATE pending_messages
|
||||
SET status = 'failed', failed_at_epoch = ?
|
||||
WHERE ${s}
|
||||
@@ -776,7 +768,7 @@ Please see the 3.x to 4.x migration guide for details on how to update your app.
|
||||
UPDATE pending_messages
|
||||
SET status = 'failed', failed_at_epoch = ?
|
||||
WHERE session_db_id = ? AND ${s}
|
||||
`).run(n,r.sessionDbId).changes}abortMessage(e){return this.db.prepare("DELETE FROM pending_messages WHERE id = ?").run(e).changes>0}markFailed(e){let r=Date.now(),n=this.db.prepare("SELECT retry_count FROM pending_messages WHERE id = ?").get(e);n&&(n.retry_count<this.maxRetries?this.db.prepare(`
|
||||
`).run(n,r.sessionDbId).changes}markFailed(e){let r=Date.now(),n=this.db.prepare("SELECT retry_count FROM pending_messages WHERE id = ?").get(e);n&&(n.retry_count<this.maxRetries?this.db.prepare(`
|
||||
UPDATE pending_messages
|
||||
SET status = 'pending', retry_count = retry_count + 1, worker_pid = NULL
|
||||
WHERE id = ?
|
||||
|
||||
@@ -64,23 +64,3 @@ export function resolveBunBinaryPath(): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the installed Bun version string (e.g. `"1.2.3"`), or `null`
|
||||
* if Bun is not available.
|
||||
*/
|
||||
export function getBunVersionString(): string | null {
|
||||
const bunPath = resolveBunBinaryPath();
|
||||
if (!bunPath) return null;
|
||||
|
||||
try {
|
||||
const result = spawnSync(bunPath, ['--version'], {
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
shell: IS_WINDOWS,
|
||||
});
|
||||
return result.status === 0 ? result.stdout.trim() : null;
|
||||
} catch (error: unknown) {
|
||||
console.error('[bun-resolver] Failed to get Bun version:', error instanceof Error ? error.message : String(error));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,83 +281,3 @@ export function uninstallCodexCli(): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public API: Status Check
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Check Codex CLI integration status.
|
||||
*
|
||||
* @returns 0 always (informational)
|
||||
*/
|
||||
export function checkCodexCliStatus(): number {
|
||||
console.log('\nClaude-Mem Codex CLI Integration Status\n');
|
||||
|
||||
// Check transcript-watch.json
|
||||
if (!existsSync(DEFAULT_CONFIG_PATH)) {
|
||||
console.log('Status: Not installed');
|
||||
console.log(` No transcript watch config at ${DEFAULT_CONFIG_PATH}`);
|
||||
console.log('\nRun: npx claude-mem install --ide codex-cli\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
let config: TranscriptWatchConfig;
|
||||
try {
|
||||
config = loadExistingTranscriptWatchConfig();
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
logger.error('WORKER', 'Could not parse transcript-watch.json', { path: DEFAULT_CONFIG_PATH }, error);
|
||||
} else {
|
||||
logger.error('WORKER', 'Could not parse transcript-watch.json', { path: DEFAULT_CONFIG_PATH }, new Error(String(error)));
|
||||
}
|
||||
console.log('Status: Unknown');
|
||||
console.log(' Could not parse transcript-watch.json.');
|
||||
console.log('');
|
||||
return 0;
|
||||
}
|
||||
|
||||
const codexWatch = config.watches.find(
|
||||
(w: WatchTarget) => w.name === CODEX_WATCH_NAME,
|
||||
);
|
||||
const codexSchema = config.schemas?.[CODEX_WATCH_NAME];
|
||||
|
||||
if (!codexWatch) {
|
||||
console.log('Status: Not installed');
|
||||
console.log(' transcript-watch.json exists but no codex watch configured.');
|
||||
console.log('\nRun: npx claude-mem install --ide codex-cli\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
console.log('Status: Installed');
|
||||
console.log(` Config: ${DEFAULT_CONFIG_PATH}`);
|
||||
console.log(` Watch path: ${codexWatch.path}`);
|
||||
console.log(` Schema: ${codexSchema ? `codex (v${codexSchema.version ?? '?'})` : 'missing'}`);
|
||||
console.log(` Start at end: ${codexWatch.startAtEnd ?? false}`);
|
||||
|
||||
if (codexWatch.context) {
|
||||
console.log(` Context mode: ${codexWatch.context.mode}`);
|
||||
console.log(` Context path: ${codexWatch.context.path ?? '<workspace>/AGENTS.md (default)'}`);
|
||||
console.log(` Context updates on: ${codexWatch.context.updateOn?.join(', ') ?? 'none'}`);
|
||||
}
|
||||
|
||||
if (existsSync(CODEX_AGENTS_MD_PATH)) {
|
||||
const mdContent = readFileSync(CODEX_AGENTS_MD_PATH, 'utf-8');
|
||||
if (mdContent.includes('<claude-mem-context>')) {
|
||||
console.log(` Legacy global context: Present (${CODEX_AGENTS_MD_PATH})`);
|
||||
} else {
|
||||
console.log(` Legacy global context: Not active`);
|
||||
}
|
||||
} else {
|
||||
console.log(` Legacy global context: None`);
|
||||
}
|
||||
|
||||
const sessionsDir = path.join(CODEX_DIR, 'sessions');
|
||||
if (existsSync(sessionsDir)) {
|
||||
console.log(` Sessions directory: exists`);
|
||||
} else {
|
||||
console.log(` Sessions directory: not yet created (use Codex CLI to generate sessions)`);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -236,34 +236,6 @@ export class PendingMessageStore {
|
||||
return stmt.all(sessionDbId) as PersistentPendingMessage[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry a specific message (reset to pending)
|
||||
* Works for pending (re-queue), processing (reset stuck), and failed messages
|
||||
*/
|
||||
retryMessage(messageId: number): boolean {
|
||||
const stmt = this.db.prepare(`
|
||||
UPDATE pending_messages
|
||||
SET status = 'pending', worker_pid = NULL
|
||||
WHERE id = ? AND status IN ('pending', 'processing', 'failed')
|
||||
`);
|
||||
const result = stmt.run(messageId);
|
||||
return result.changes > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all processing messages for a session to pending
|
||||
* Used when force-restarting a stuck session
|
||||
*/
|
||||
resetProcessingToPending(sessionDbId: number): number {
|
||||
const stmt = this.db.prepare(`
|
||||
UPDATE pending_messages
|
||||
SET status = 'pending', worker_pid = NULL
|
||||
WHERE session_db_id = ? AND status = 'processing'
|
||||
`);
|
||||
const result = stmt.run(sessionDbId);
|
||||
return result.changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transition pending_messages rows to a terminal status — PATHFINDER-2026-04-22
|
||||
* Plan 06 Phase 9. One SQL UPDATE path, one place to add a new terminal status
|
||||
@@ -313,15 +285,6 @@ export class PendingMessageStore {
|
||||
return stmt.run(now, filter.sessionDbId).changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort a specific message (delete from queue)
|
||||
*/
|
||||
abortMessage(messageId: number): boolean {
|
||||
const stmt = this.db.prepare('DELETE FROM pending_messages WHERE id = ?');
|
||||
const result = stmt.run(messageId);
|
||||
return result.changes > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark message as failed (status: pending -> failed or back to pending for retry)
|
||||
* If retry_count < maxRetries, moves back to 'pending' for retry
|
||||
|
||||
@@ -2208,11 +2208,6 @@ export class SessionStore {
|
||||
|
||||
|
||||
|
||||
// REMOVED: cleanupOrphanedSessions - violates "EVERYTHING SHOULD SAVE ALWAYS"
|
||||
// There's no such thing as an "orphaned" session. Sessions are created by hooks
|
||||
// and managed by Claude Code's lifecycle. Worker restarts don't invalidate them.
|
||||
// Marking all active sessions as 'failed' on startup destroys the user's current work.
|
||||
|
||||
/**
|
||||
* Get session summaries by IDs (for hybrid Chroma search)
|
||||
* Returns summaries in specified temporal order
|
||||
|
||||
@@ -89,10 +89,6 @@ export class DatabaseManager {
|
||||
return this.chromaSync;
|
||||
}
|
||||
|
||||
// REMOVED: cleanupOrphanedSessions - violates "EVERYTHING SHOULD SAVE ALWAYS"
|
||||
// Worker restarts don't make sessions orphaned. Sessions are managed by hooks
|
||||
// and exist independently of worker state.
|
||||
|
||||
/**
|
||||
* Get session by ID (throws if not found)
|
||||
*/
|
||||
|
||||
@@ -30,13 +30,6 @@ const BLOCKED_ENV_VARS = [
|
||||
'CLAUDECODE', // Prevent "cannot be launched inside another Claude Code session" error
|
||||
];
|
||||
|
||||
// Credential keys that claude-mem manages
|
||||
export const MANAGED_CREDENTIAL_KEYS = [
|
||||
'ANTHROPIC_API_KEY',
|
||||
'GEMINI_API_KEY',
|
||||
'OPENROUTER_API_KEY',
|
||||
];
|
||||
|
||||
export interface ClaudeMemEnv {
|
||||
// Credentials (optional - empty means use CLI billing for Claude)
|
||||
ANTHROPIC_API_KEY?: string;
|
||||
@@ -269,16 +262,6 @@ export function getCredential(key: keyof ClaudeMemEnv): string | undefined {
|
||||
return env[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific credential in claude-mem's .env
|
||||
* Pass empty string to remove the credential
|
||||
*/
|
||||
export function setCredential(key: keyof ClaudeMemEnv, value: string): void {
|
||||
const env = loadClaudeMemEnv();
|
||||
env[key] = value || undefined;
|
||||
saveClaudeMemEnv(env);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if claude-mem has an Anthropic API key configured
|
||||
* If false, it means CLI billing should be used
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* Bun Path Utility
|
||||
*
|
||||
* Resolves the Bun executable path for environments where Bun is not in PATH
|
||||
* (e.g., fish shell users where ~/.config/fish/config.fish isn't read by /bin/sh)
|
||||
*/
|
||||
|
||||
import { spawnSync } from 'child_process';
|
||||
import { existsSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { homedir } from 'os';
|
||||
import { logger } from './logger.js';
|
||||
|
||||
/**
|
||||
* Get the Bun executable path
|
||||
* Tries PATH first, then checks common installation locations
|
||||
* Returns absolute path if found, null otherwise
|
||||
*/
|
||||
export function getBunPath(): string | null {
|
||||
const isWindows = process.platform === 'win32';
|
||||
|
||||
// Try PATH first
|
||||
try {
|
||||
const result = spawnSync('bun', ['--version'], {
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
shell: false // SECURITY: No need for shell, bun is the executable
|
||||
});
|
||||
if (result.status === 0) {
|
||||
return 'bun'; // Available in PATH
|
||||
}
|
||||
} catch (e) {
|
||||
logger.debug('SYSTEM', 'Bun not found in PATH, checking common installation locations', {
|
||||
error: e instanceof Error ? e.message : String(e)
|
||||
});
|
||||
}
|
||||
|
||||
// Check common installation paths
|
||||
const bunPaths = isWindows
|
||||
? [join(homedir(), '.bun', 'bin', 'bun.exe')]
|
||||
: [
|
||||
join(homedir(), '.bun', 'bin', 'bun'),
|
||||
'/usr/local/bin/bun',
|
||||
'/opt/homebrew/bin/bun', // Apple Silicon Homebrew
|
||||
'/home/linuxbrew/.linuxbrew/bin/bun' // Linux Homebrew
|
||||
];
|
||||
|
||||
for (const bunPath of bunPaths) {
|
||||
if (existsSync(bunPath)) {
|
||||
return bunPath;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Bun executable path or throw an error
|
||||
* Use this when Bun is required for operation
|
||||
*/
|
||||
export function getBunPathOrThrow(): string {
|
||||
const bunPath = getBunPath();
|
||||
if (!bunPath) {
|
||||
const isWindows = process.platform === 'win32';
|
||||
const installCmd = isWindows
|
||||
? 'powershell -c "irm bun.sh/install.ps1 | iex"'
|
||||
: 'curl -fsSL https://bun.sh/install | bash';
|
||||
throw new Error(
|
||||
`Bun is required but not found. Install it with:\n ${installCmd}\nThen restart your terminal.`
|
||||
);
|
||||
}
|
||||
return bunPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Bun is available (in PATH or common locations)
|
||||
*/
|
||||
export function isBunAvailable(): boolean {
|
||||
return getBunPath() !== null;
|
||||
}
|
||||
Reference in New Issue
Block a user