diff --git a/src/claude-spawner.ts b/src/claude-spawner.ts index 4855983..37f1abe 100644 --- a/src/claude-spawner.ts +++ b/src/claude-spawner.ts @@ -3,6 +3,42 @@ import { spawn, ChildProcess } from 'child_process'; import { findProject, touchProject } from './project-registry.js'; +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; + +// Load .env file from a directory and return as object +function loadEnvFile(dirPath: string): Record { + const envPath = join(dirPath, '.env'); + const envVars: Record = {}; + + if (existsSync(envPath)) { + try { + const content = readFileSync(envPath, 'utf-8'); + for (const line of content.split('\n')) { + const trimmed = line.trim(); + // Skip comments and empty lines + if (!trimmed || trimmed.startsWith('#')) continue; + + const eqIndex = trimmed.indexOf('='); + if (eqIndex > 0) { + const key = trimmed.substring(0, eqIndex).trim(); + let value = trimmed.substring(eqIndex + 1).trim(); + // Remove quotes if present + if ((value.startsWith('"') && value.endsWith('"')) || + (value.startsWith("'") && value.endsWith("'"))) { + value = value.slice(1, -1); + } + envVars[key] = value; + } + } + console.log(`[SPAWN] Loaded ${Object.keys(envVars).length} env vars from ${envPath}`); + } catch (error) { + console.error(`[SPAWN] Failed to load .env from ${envPath}:`, error); + } + } + + return envVars; +} interface SpawnedProcess { projectName: string; @@ -38,6 +74,9 @@ export async function spawnClaude( } try { + // Load project's .env file to pass to Claude + const projectEnv = loadEnvFile(project.path); + // Spawn Claude Code const claudeProcess = spawn('claude', initialPrompt ? [initialPrompt] : [], { cwd: project.path, @@ -45,6 +84,7 @@ export async function spawnClaude( detached: true, env: { ...process.env, + ...projectEnv, // Include project's .env variables INNERVOICE_SPAWNED: '1' // Mark as spawned by InnerVoice } }); diff --git a/src/index.ts b/src/index.ts index a293e03..e49d18a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -419,7 +419,10 @@ bot.on('text', async (ctx) => { const activeSession = Array.from(activeSessions.values()) .find(s => s.projectName.toLowerCase() === targetProject.toLowerCase()); - if (activeSession) { + // Check if Claude is actually running (not just session registered) + const claudeActuallyRunning = isClaudeRunning(targetProject); + + if (activeSession && claudeActuallyRunning) { // Add to message queue with session ID messageQueue.push({ from, @@ -430,6 +433,11 @@ bot.on('text', async (ctx) => { }); await ctx.reply(`💬 Message sent to active session: *${activeSession.projectName}*`, { parse_mode: 'Markdown' }); } else { + // Clean up stale session if Claude exited + if (activeSession && !claudeActuallyRunning) { + console.log(`[CLEANUP] Removing stale session for ${activeSession.projectName} (Claude not running)`); + activeSessions.delete(activeSession.id); + } // No active session - check if project is registered and should auto-spawn try { const project = await findProject(targetProject);