fix: address 10 unresolved PR review threads

- README: add language specifier to fenced code block
- paths.ts: guard npmPackageRootDirectory() against bundle structure drift
- OpenCodeInstaller: resolve bundle from import.meta.url, not process.cwd()
- OpenCodeInstaller: log warnings on AGENTS.md injection failures
- WindsurfHooksInstaller: key registry by full workspace path, not basename
- uninstall.ts: poll health endpoint to wait for worker exit before file deletion
- uninstall.ts: call IDE-specific uninstallers (Gemini, Windsurf, OpenCode, OpenClaw, Codex)
- opencode-plugin: cap session tracking Map at 1000 entries with LRU eviction
- GeminiCliHooksInstaller: document intentional JSON double-escaping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alex Newman
2026-04-04 14:45:53 -07:00
parent 21b10b4696
commit c7c68e81f4
7 changed files with 126 additions and 37 deletions
+49 -2
View File
@@ -105,13 +105,25 @@ export async function runUninstallCommand(): Promise<void> {
}
}
// Stop the worker first (best-effort)
// Stop the worker and wait for it to exit before deleting files
const workerPort = process.env.CLAUDE_MEM_WORKER_PORT || '37777';
try {
const workerPort = process.env.CLAUDE_MEM_WORKER_PORT || '37777';
await fetch(`http://127.0.0.1:${workerPort}/api/admin/shutdown`, {
method: 'POST',
signal: AbortSignal.timeout(5000),
});
// Poll health endpoint until worker is gone (max 10s)
for (let attempt = 0; attempt < 20; attempt++) {
await new Promise((resolve) => setTimeout(resolve, 500));
try {
await fetch(`http://127.0.0.1:${workerPort}/api/health`, {
signal: AbortSignal.timeout(1000),
});
// Still alive — keep waiting
} catch {
break; // Connection refused = worker is gone
}
}
p.log.info('Worker service stopped.');
} catch {
// Worker may not be running — that is fine
@@ -159,6 +171,41 @@ export async function runUninstallCommand(): Promise<void> {
},
]);
// Remove IDE-specific hooks and config (best-effort, each is independent)
const ideCleanups: Array<{ label: string; fn: () => Promise<number> | number }> = [
{ label: 'Gemini CLI hooks', fn: async () => {
const { uninstallGeminiCliHooks } = await import('../../services/integrations/GeminiCliHooksInstaller.js');
return uninstallGeminiCliHooks();
}},
{ label: 'Windsurf hooks', fn: async () => {
const { uninstallWindsurfHooks } = await import('../../services/integrations/WindsurfHooksInstaller.js');
return uninstallWindsurfHooks();
}},
{ label: 'OpenCode plugin', fn: async () => {
const { uninstallOpenCodePlugin } = await import('../../services/integrations/OpenCodeInstaller.js');
return uninstallOpenCodePlugin();
}},
{ label: 'OpenClaw plugin', fn: async () => {
const { uninstallOpenClawPlugin } = await import('../../services/integrations/OpenClawInstaller.js');
return uninstallOpenClawPlugin();
}},
{ label: 'Codex CLI', fn: async () => {
const { uninstallCodexCli } = await import('../../services/integrations/CodexCliInstaller.js');
return uninstallCodexCli();
}},
];
for (const { label, fn } of ideCleanups) {
try {
const result = await fn();
if (result === 0) {
p.log.info(`${label}: removed.`);
}
} catch {
// IDE not configured or uninstaller errored — skip silently
}
}
p.note(
[
`Your data directory at ${pc.cyan('~/.claude-mem')} was preserved.`,