fix: eliminate Windows console popups during daemon spawn and Chroma operations (#751)
* fix: eliminate Windows console popups during daemon spawn and Chroma operations Two changes to fix Windows Terminal popup issues: 1. Worker daemon spawn (ProcessManager.spawnDaemon): - Windows: Use WMIC to spawn truly independent process without console - WMIC creates processes that survive parent exit and have no console association - Properly handles paths with spaces via double-quoting - Unix: Unchanged behavior with standard detached spawn 2. PID file handling (worker-service.ts): - Worker now writes its own PID after listen() succeeds (all platforms) - Removes race condition where spawner wrote PID before worker was ready - On Windows, spawner PID was useless anyway 3. Chroma vector search (ChromaSync.ts): - Temporarily disabled on Windows to prevent MCP SDK subprocess popups - Will be re-enabled when we migrate to persistent HTTP server architecture - Windows users still get full observation storage, just no semantic search Tested on Windows 11 via SSH - worker spawns without console popups, survives parent process exit, and all lifecycle commands (start/stop/restart) work correctly. Fixes #748, #708, #681, #676, #675 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: add YAML frontmatter to slash commands for discoverability Commands /do and /make-plan were not appearing in Claude Code because they lacked the required YAML frontmatter metadata. Added description and argument-hint fields to both commands. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: bigphoot <bigphoot@gmail.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -83,10 +83,32 @@ export class ChromaSync {
|
||||
private readonly VECTOR_DB_DIR: string;
|
||||
private readonly BATCH_SIZE = 100;
|
||||
|
||||
// Windows: Chroma disabled due to MCP SDK spawning console popups
|
||||
// See: https://github.com/anthropics/claude-mem/issues/675
|
||||
// Will be re-enabled when we migrate to persistent HTTP server
|
||||
private readonly disabled: boolean;
|
||||
|
||||
constructor(project: string) {
|
||||
this.project = project;
|
||||
this.collectionName = `cm__${project}`;
|
||||
this.VECTOR_DB_DIR = path.join(os.homedir(), '.claude-mem', 'vector-db');
|
||||
|
||||
// Disable on Windows to prevent console popups from MCP subprocess spawning
|
||||
// The MCP SDK's StdioClientTransport spawns Python processes that create visible windows
|
||||
this.disabled = process.platform === 'win32';
|
||||
if (this.disabled) {
|
||||
logger.warn('CHROMA_SYNC', 'Vector search disabled on Windows (prevents console popups)', {
|
||||
project: this.project,
|
||||
reason: 'MCP SDK subprocess spawning causes visible console windows'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Chroma is disabled (Windows)
|
||||
*/
|
||||
isDisabled(): boolean {
|
||||
return this.disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,6 +409,7 @@ export class ChromaSync {
|
||||
/**
|
||||
* Sync a single observation to Chroma
|
||||
* Blocks until sync completes, throws on error
|
||||
* No-op on Windows (Chroma disabled to prevent console popups)
|
||||
*/
|
||||
async syncObservation(
|
||||
observationId: number,
|
||||
@@ -397,6 +420,8 @@ export class ChromaSync {
|
||||
createdAtEpoch: number,
|
||||
discoveryTokens: number = 0
|
||||
): Promise<void> {
|
||||
if (this.disabled) return;
|
||||
|
||||
// Convert ParsedObservation to StoredObservation format
|
||||
const stored: StoredObservation = {
|
||||
id: observationId,
|
||||
@@ -431,6 +456,7 @@ export class ChromaSync {
|
||||
/**
|
||||
* Sync a single summary to Chroma
|
||||
* Blocks until sync completes, throws on error
|
||||
* No-op on Windows (Chroma disabled to prevent console popups)
|
||||
*/
|
||||
async syncSummary(
|
||||
summaryId: number,
|
||||
@@ -441,6 +467,8 @@ export class ChromaSync {
|
||||
createdAtEpoch: number,
|
||||
discoveryTokens: number = 0
|
||||
): Promise<void> {
|
||||
if (this.disabled) return;
|
||||
|
||||
// Convert ParsedSummary to StoredSummary format
|
||||
const stored: StoredSummary = {
|
||||
id: summaryId,
|
||||
@@ -491,6 +519,7 @@ export class ChromaSync {
|
||||
/**
|
||||
* Sync a single user prompt to Chroma
|
||||
* Blocks until sync completes, throws on error
|
||||
* No-op on Windows (Chroma disabled to prevent console popups)
|
||||
*/
|
||||
async syncUserPrompt(
|
||||
promptId: number,
|
||||
@@ -500,6 +529,8 @@ export class ChromaSync {
|
||||
promptNumber: number,
|
||||
createdAtEpoch: number
|
||||
): Promise<void> {
|
||||
if (this.disabled) return;
|
||||
|
||||
// Create StoredUserPrompt format
|
||||
const stored: StoredUserPrompt = {
|
||||
id: promptId,
|
||||
@@ -614,8 +645,11 @@ export class ChromaSync {
|
||||
* Backfill: Sync all observations missing from Chroma
|
||||
* Reads from SQLite and syncs in batches
|
||||
* Throws error if backfill fails
|
||||
* No-op on Windows (Chroma disabled to prevent console popups)
|
||||
*/
|
||||
async ensureBackfilled(): Promise<void> {
|
||||
if (this.disabled) return;
|
||||
|
||||
logger.info('CHROMA_SYNC', 'Starting smart backfill', { project: this.project });
|
||||
|
||||
await this.ensureCollection();
|
||||
@@ -782,12 +816,17 @@ export class ChromaSync {
|
||||
/**
|
||||
* Query Chroma collection for semantic search
|
||||
* Used by SearchManager for vector-based search
|
||||
* Returns empty results on Windows (Chroma disabled to prevent console popups)
|
||||
*/
|
||||
async queryChroma(
|
||||
query: string,
|
||||
limit: number,
|
||||
whereFilter?: Record<string, any>
|
||||
): Promise<{ ids: number[]; distances: number[]; metadatas: any[] }> {
|
||||
if (this.disabled) {
|
||||
return { ids: [], distances: [], metadatas: [] };
|
||||
}
|
||||
|
||||
await this.ensureConnection();
|
||||
|
||||
if (!this.client) {
|
||||
|
||||
Reference in New Issue
Block a user