Files
claude-mem/installer/src/steps/complete.ts
T
Alex Newman e975555896 feat: add interactive CLI installer with @clack/prompts (#1093)
* 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>
2026-02-16 00:44:21 -05:00

57 lines
2.0 KiB
TypeScript

import * as p from '@clack/prompts';
import pc from 'picocolors';
import type { ProviderConfig } from './provider.js';
import type { SettingsConfig } from './settings.js';
import type { IDE } from './ide-selection.js';
function getProviderLabel(config: ProviderConfig): string {
switch (config.provider) {
case 'claude':
return config.claudeAuthMethod === 'api' ? 'Claude (API Key)' : 'Claude (CLI subscription)';
case 'gemini':
return `Gemini (${config.model ?? 'gemini-2.5-flash-lite'})`;
case 'openrouter':
return `OpenRouter (${config.model ?? 'xiaomi/mimo-v2-flash:free'})`;
}
}
function getIDELabels(ides: IDE[]): string {
return ides.map((ide) => {
switch (ide) {
case 'claude-code': return 'Claude Code';
case 'cursor': return 'Cursor';
}
}).join(', ');
}
export function runCompletion(
providerConfig: ProviderConfig,
settingsConfig: SettingsConfig,
selectedIDEs: IDE[],
): void {
const summaryLines = [
`Provider: ${pc.cyan(getProviderLabel(providerConfig))}`,
`IDEs: ${pc.cyan(getIDELabels(selectedIDEs))}`,
`Data dir: ${pc.cyan(settingsConfig.dataDir)}`,
`Port: ${pc.cyan(settingsConfig.workerPort)}`,
`Chroma: ${settingsConfig.chromaEnabled ? pc.green('enabled') : pc.dim('disabled')}`,
];
p.note(summaryLines.join('\n'), 'Configuration Summary');
const nextStepsLines: string[] = [];
if (selectedIDEs.includes('claude-code')) {
nextStepsLines.push('Open Claude Code and start a conversation — memory is automatic!');
}
if (selectedIDEs.includes('cursor')) {
nextStepsLines.push('Open Cursor — hooks are active in your projects.');
}
nextStepsLines.push(`View your memories: ${pc.underline(`http://localhost:${settingsConfig.workerPort}`)}`);
nextStepsLines.push(`Search past work: use ${pc.bold('/mem-search')} in Claude Code`);
p.note(nextStepsLines.join('\n'), 'Next Steps');
p.outro(pc.green('claude-mem installed successfully!'));
}