diff --git a/package-lock.json b/package-lock.json index 828f7b2f..fda883b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "awilix": "^12.1.0", "chalk": "^5.3.0", "commander": "^11.1.0", + "dotenv": "^17.3.1", "prompts": "^2.4.2" }, "bin": { @@ -2960,6 +2961,18 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", diff --git a/package.json b/package.json index 4e662c4d..e15d736f 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "awilix": "^12.1.0", "chalk": "^5.3.0", "commander": "^11.1.0", + "dotenv": "^17.3.1", "prompts": "^2.4.2" }, "devDependencies": { diff --git a/src/commands/hook.ts b/src/commands/hook.ts index e5cf2c4e..25d3e2f4 100644 --- a/src/commands/hook.ts +++ b/src/commands/hook.ts @@ -10,6 +10,9 @@ * git-mem hook prompt-submit */ +import { join } from 'path'; +import { execFileSync } from 'child_process'; +import { config as loadEnv } from 'dotenv'; import { createContainer } from '../infrastructure/di'; import { readStdin } from '../hooks/utils/stdin'; import { setupShutdown } from '../hooks/utils/shutdown'; @@ -100,6 +103,22 @@ export function buildEvent(eventType: HookEventType, input: IHookInput): HookEve } } +/** + * Find git repository root from a working directory. + * Returns cwd if git command fails (graceful fallback). + */ +function findGitRoot(cwd: string): string { + try { + return execFileSync('git', ['rev-parse', '--show-toplevel'], { + cwd, + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'], + }).trim(); + } catch { + return cwd; + } +} + /** Stderr labels per event for user-facing messages. */ const STDERR_LABELS: Record = { 'session:start': { success: 'Memory loaded.', prefix: 'Memory loaded' }, @@ -120,7 +139,13 @@ export async function hookCommand(eventName: string, _logger?: ILogger): Promise try { const input = await readStdin(); - const config = loadHookConfig(input.cwd); + const cwd = input.cwd ?? process.cwd(); + const repoRoot = findGitRoot(cwd); + + // Load .env from repository root for API keys (e.g., ANTHROPIC_API_KEY) + loadEnv({ path: join(repoRoot, '.env'), quiet: true }); + + const config = loadHookConfig(repoRoot); if (!isEventEnabled(config.hooks, eventName)) { clearTimeout(timer);