e975555896
* feat: Switch to persistent Chroma HTTP server Replace MCP subprocess approach with persistent Chroma HTTP server for improved performance and reliability. This re-enables Chroma on Windows by eliminating the subprocess spawning that caused console popups. Changes: - NEW: ChromaServerManager.ts - Manages local Chroma server lifecycle via `npx chroma run` - REFACTOR: ChromaSync.ts - Uses chromadb npm package's ChromaClient instead of MCP subprocess (removes Windows disabling) - UPDATE: worker-service.ts - Starts Chroma server on initialization - UPDATE: GracefulShutdown.ts - Stops Chroma server on shutdown - UPDATE: SettingsDefaultsManager.ts - New Chroma configuration options - UPDATE: build-hooks.js - Mark optional chromadb deps as external Benefits: - Eliminates subprocess spawn latency on first query - Single server process instead of per-operation subprocesses - No Python/uvx dependency for local mode - Re-enables Chroma vector search on Windows - Future-ready for cloud-hosted Chroma (claude-mem pro) - Cross-platform: Linux, macOS, Windows Configuration: CLAUDE_MEM_CHROMA_MODE=local|remote CLAUDE_MEM_CHROMA_HOST=127.0.0.1 CLAUDE_MEM_CHROMA_PORT=8000 CLAUDE_MEM_CHROMA_SSL=false Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Use chromadb v3.2.2 with v2 API heartbeat endpoint - Updated chromadb from ^1.9.2 to ^3.2.2 (includes CLI binary) - Changed heartbeat endpoint from /api/v1 to /api/v2 The 1.9.x version did not include the CLI, causing `npx chroma run` to fail. Version 3.2.2 includes the chroma CLI and uses the v2 API. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Add DefaultEmbeddingFunction for local vector embeddings - Added @chroma-core/default-embed dependency for local embeddings - Updated ChromaSync to use DefaultEmbeddingFunction with collections - Added isServerReachable() async method for reliable server detection - Fixed start() to detect and reuse existing Chroma servers - Updated build script to externalize native ONNX binaries - Added runtime dependency to plugin/package.json The embedding function uses all-MiniLM-L6-v2 model locally via ONNX, eliminating need for external embedding API calls. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Update src/services/sync/ChromaServerManager.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: Remove duplicate else block from merge Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Add multi-tenancy support for claude-mem pro Wire tenant, database, and API key settings into ChromaSync for remote/pro mode. In remote mode: - Passes tenant and database to ChromaClient for data isolation - Adds Authorization header when API key is configured - Logs tenant isolation connection details Local mode unchanged - uses default_tenant without explicit params. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: add plugin.json to root .claude-plugin directory Claude Code's plugin discovery looks for plugin.json at the marketplace root level in .claude-plugin/, not nested inside plugin/.claude-plugin/. Without this file at the root level, skills and commands are not discovered. This matches the structure of working plugins like claude-research-team. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: resolve SDK spawn failures and sharp native binary crashes - Strip CLAUDECODE env var from SDK subprocesses to prevent "cannot be launched inside another Claude Code session" error (Claude Code 2.1.42+) - Lazy-load @chroma-core/default-embed to avoid eagerly pulling in sharp native binaries at bundle startup (fixes ERR_DLOPEN_FAILED) - Add stderr capture to SDK spawn for diagnosing future process failures - Exclude lockfiles from marketplace rsync and delete stale lockfiles before npm install to prevent native dep version mismatches Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: scaffold installer package with @clack/prompts and esbuild Sets up the claude-mem-installer project structure with build tooling, placeholder step and utility modules, and verified esbuild bundling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: implement entry point, welcome screen, and dependency checks Adds TTY guard, styled welcome banner with install mode selection, OS detection utilities, and automated dependency checking/installation for Node.js, git, Bun, and uv. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: implement IDE selection and AI provider configuration Adds multiselect IDE picker (Claude Code, Cursor) and provider configuration with Claude CLI/API, Gemini, and OpenRouter support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: implement settings configuration wizard and settings file writer Adds interactive settings wizard with default/custom modes, Chroma configuration, and a settings writer that merges with existing settings for upgrade support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: implement installation execution and worker startup Adds git clone, build, plugin registration (marketplace, cache, settings), and worker startup with health check polling. Fixes TypeScript errors in settings.ts validate callbacks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add completion screen and curl|bash bootstrap script Completion screen shows configuration summary and next steps. Bootstrap shell script enables curl -fsSL install.cmem.ai | bash with TTY reconnection for interactive prompts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: wire up full installer flow in index.ts Connects all steps: welcome → dependency checks → IDE selection → provider config → settings → installation → worker startup → completion. Configure-only mode skips clone/build/worker steps. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add animated installer implementation plan Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: bigphoot <bigphoot@local> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Alexander Knigge <166455923+bigph00t@users.noreply.github.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: bigphoot <bigphoot@gmail.com>
169 lines
5.0 KiB
TypeScript
169 lines
5.0 KiB
TypeScript
import * as p from '@clack/prompts';
|
|
import pc from 'picocolors';
|
|
import { findBinary, compareVersions, installBun, installUv } from '../utils/dependencies.js';
|
|
import { detectOS } from '../utils/system.js';
|
|
|
|
const BUN_EXTRA_PATHS = ['~/.bun/bin/bun', '/usr/local/bin/bun', '/opt/homebrew/bin/bun'];
|
|
const UV_EXTRA_PATHS = ['~/.local/bin/uv', '~/.cargo/bin/uv'];
|
|
|
|
interface DependencyStatus {
|
|
nodeOk: boolean;
|
|
gitOk: boolean;
|
|
bunOk: boolean;
|
|
uvOk: boolean;
|
|
bunPath: string | null;
|
|
uvPath: string | null;
|
|
}
|
|
|
|
export async function runDependencyChecks(): Promise<DependencyStatus> {
|
|
const status: DependencyStatus = {
|
|
nodeOk: false,
|
|
gitOk: false,
|
|
bunOk: false,
|
|
uvOk: false,
|
|
bunPath: null,
|
|
uvPath: null,
|
|
};
|
|
|
|
await p.tasks([
|
|
{
|
|
title: 'Checking Node.js',
|
|
task: async () => {
|
|
const version = process.version.slice(1); // remove 'v'
|
|
if (compareVersions(version, '18.0.0')) {
|
|
status.nodeOk = true;
|
|
return `Node.js ${process.version} ${pc.green('✓')}`;
|
|
}
|
|
return `Node.js ${process.version} — requires >= 18.0.0 ${pc.red('✗')}`;
|
|
},
|
|
},
|
|
{
|
|
title: 'Checking git',
|
|
task: async () => {
|
|
const info = findBinary('git');
|
|
if (info.found) {
|
|
status.gitOk = true;
|
|
return `git ${info.version ?? ''} ${pc.green('✓')}`;
|
|
}
|
|
return `git not found ${pc.red('✗')}`;
|
|
},
|
|
},
|
|
{
|
|
title: 'Checking Bun',
|
|
task: async () => {
|
|
const info = findBinary('bun', BUN_EXTRA_PATHS);
|
|
if (info.found && info.version && compareVersions(info.version, '1.1.14')) {
|
|
status.bunOk = true;
|
|
status.bunPath = info.path;
|
|
return `Bun ${info.version} ${pc.green('✓')}`;
|
|
}
|
|
if (info.found && info.version) {
|
|
return `Bun ${info.version} — requires >= 1.1.14 ${pc.yellow('⚠')}`;
|
|
}
|
|
return `Bun not found ${pc.yellow('⚠')}`;
|
|
},
|
|
},
|
|
{
|
|
title: 'Checking uv',
|
|
task: async () => {
|
|
const info = findBinary('uv', UV_EXTRA_PATHS);
|
|
if (info.found) {
|
|
status.uvOk = true;
|
|
status.uvPath = info.path;
|
|
return `uv ${info.version ?? ''} ${pc.green('✓')}`;
|
|
}
|
|
return `uv not found ${pc.yellow('⚠')}`;
|
|
},
|
|
},
|
|
]);
|
|
|
|
// Handle missing dependencies
|
|
if (!status.gitOk) {
|
|
const os = detectOS();
|
|
p.log.error('git is required but not found.');
|
|
if (os === 'macos') {
|
|
p.log.info('Install with: xcode-select --install');
|
|
} else if (os === 'linux') {
|
|
p.log.info('Install with: sudo apt install git (or your distro equivalent)');
|
|
} else {
|
|
p.log.info('Download from: https://git-scm.com/downloads');
|
|
}
|
|
p.cancel('Please install git and try again.');
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!status.nodeOk) {
|
|
p.log.error(`Node.js >= 18.0.0 is required. Current: ${process.version}`);
|
|
p.cancel('Please upgrade Node.js and try again.');
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!status.bunOk) {
|
|
const shouldInstall = await p.confirm({
|
|
message: 'Bun is required but not found. Install it now?',
|
|
initialValue: true,
|
|
});
|
|
|
|
if (p.isCancel(shouldInstall)) {
|
|
p.cancel('Installation cancelled.');
|
|
process.exit(0);
|
|
}
|
|
|
|
if (shouldInstall) {
|
|
const s = p.spinner();
|
|
s.start('Installing Bun...');
|
|
try {
|
|
installBun();
|
|
const recheck = findBinary('bun', BUN_EXTRA_PATHS);
|
|
if (recheck.found) {
|
|
status.bunOk = true;
|
|
status.bunPath = recheck.path;
|
|
s.stop(`Bun installed ${pc.green('✓')}`);
|
|
} else {
|
|
s.stop(`Bun installed but not found in PATH. You may need to restart your shell.`);
|
|
}
|
|
} catch {
|
|
s.stop(`Bun installation failed. Install manually: curl -fsSL https://bun.sh/install | bash`);
|
|
}
|
|
} else {
|
|
p.log.warn('Bun is required for claude-mem. Install manually: curl -fsSL https://bun.sh/install | bash');
|
|
p.cancel('Cannot continue without Bun.');
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (!status.uvOk) {
|
|
const shouldInstall = await p.confirm({
|
|
message: 'uv (Python package manager) is recommended for Chroma. Install it now?',
|
|
initialValue: true,
|
|
});
|
|
|
|
if (p.isCancel(shouldInstall)) {
|
|
p.cancel('Installation cancelled.');
|
|
process.exit(0);
|
|
}
|
|
|
|
if (shouldInstall) {
|
|
const s = p.spinner();
|
|
s.start('Installing uv...');
|
|
try {
|
|
installUv();
|
|
const recheck = findBinary('uv', UV_EXTRA_PATHS);
|
|
if (recheck.found) {
|
|
status.uvOk = true;
|
|
status.uvPath = recheck.path;
|
|
s.stop(`uv installed ${pc.green('✓')}`);
|
|
} else {
|
|
s.stop('uv installed but not found in PATH. You may need to restart your shell.');
|
|
}
|
|
} catch {
|
|
s.stop('uv installation failed. Install manually: curl -fsSL https://astral.sh/uv/install.sh | sh');
|
|
}
|
|
} else {
|
|
p.log.warn('Skipping uv — Chroma vector search will not be available.');
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|