From a65346f0a9667ed0d9b546fb54fe95db896d25e8 Mon Sep 17 00:00:00 2001 From: Tony Casey Date: Sat, 14 Feb 2026 19:19:05 +0000 Subject: [PATCH 1/3] feat: update init-hooks.ts to write YAML config (GIT-91) - Create .git-mem/ directory if it doesn't exist - Write config as YAML to .git-mem/.git-mem.yaml - Update path references and console messages - Remove entire .git-mem/ directory in remove mode - Parse existing config as YAML when merging Co-Authored-By: Claude Opus 4.5 AI-Agent: Claude-Code/2.1.42 AI-Model: claude-opus-4-5-20251101 AI-Decision: update init-hooks.ts to write YAML config (GIT-91). - Create .git-mem/ directory if it doesn't exist AI-Confidence: medium AI-Tags: commands, typescript AI-Lifecycle: project AI-Memory-Id: eeee468d AI-Source: heuristic --- src/commands/init-hooks.ts | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/commands/init-hooks.ts b/src/commands/init-hooks.ts index 6a61f993..ab01f71f 100644 --- a/src/commands/init-hooks.ts +++ b/src/commands/init-hooks.ts @@ -3,16 +3,18 @@ * * Generates Claude Code hook configuration files: * - .claude/settings.json (or ~/.claude/settings.json for user scope) - * - .git-mem.json (hook-specific config) + * - .git-mem/.git-mem.yaml (hook-specific config) * * Preserves existing non-git-mem hooks in settings.json and - * user customizations in .git-mem.json on re-runs. + * user customizations in .git-mem/.git-mem.yaml on re-runs. */ -import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'fs'; +import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, rmSync } from 'fs'; import { join } from 'path'; import { homedir } from 'os'; +import { parse as parseYaml, stringify as stringifyYaml } from 'yaml'; import type { ILogger } from '../domain/interfaces/ILogger'; +import { getConfigPath, getConfigDir } from '../hooks/utils/config'; interface IInitHooksOptions { yes?: boolean; @@ -95,7 +97,7 @@ export function removeGitMemHooks(hooks: Record): Record { try { return JSON.parse(readFileSync(gitMemConfigPath, 'utf8')) as Record; } catch { return {}; } })() + // Deep-merge into existing .git-mem/.git-mem.yaml (preserves user customizations) + if (!existsSync(configDir)) { + mkdirSync(configDir, { recursive: true }); + } + const existingGitMemConfig = existsSync(configPath) + ? (() => { try { return parseYaml(readFileSync(configPath, 'utf8')) as Record; } catch { return {}; } })() : {}; const newGitMemConfig = buildGitMemConfig(); const mergedGitMemConfig = deepMergeGitMemConfig(existingGitMemConfig, newGitMemConfig); - writeFileSync(gitMemConfigPath, JSON.stringify(mergedGitMemConfig, null, 2) + '\n'); - console.log('Written .git-mem.json'); + writeFileSync(configPath, stringifyYaml(mergedGitMemConfig)); + console.log('Written .git-mem/.git-mem.yaml'); console.log('\nHooks configured:'); console.log(' SessionStart — Load memories into Claude context on startup'); @@ -283,5 +290,5 @@ export async function initHooksCommand(options: IInitHooksOptions, logger?: ILog console.log('\nNext steps:'); console.log(' 1. Start Claude Code in this repo: claude'); console.log(' 2. Memories will load automatically on session start'); - console.log(' 3. Adjust settings in .git-mem.json'); + console.log(' 3. Adjust settings in .git-mem/.git-mem.yaml'); } From 69358caae532a54039708e2e728dc1c00417e3f8 Mon Sep 17 00:00:00 2001 From: Tony Casey Date: Sat, 14 Feb 2026 20:34:24 +0000 Subject: [PATCH 2/3] fix: guard YAML parsing against null values + update docs - Add type guard to coerce null/non-object parseYaml results - Update HookConfigLoader.ts documentation to reference YAML Addresses CodeRabbit review feedback. Co-Authored-By: Claude Opus 4.5 AI-Agent: Claude-Code/2.1.42 AI-Model: claude-opus-4-5-20251101 AI-Gotcha: guard YAML parsing against null values + update docs. - Add type guard to coerce null/non-object parseYaml results AI-Confidence: medium AI-Tags: commands, infrastructure, services AI-Lifecycle: project AI-Memory-Id: 842957db AI-Source: heuristic --- src/commands/init-hooks.ts | 14 +++++++++++--- src/infrastructure/services/HookConfigLoader.ts | 5 +++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/commands/init-hooks.ts b/src/commands/init-hooks.ts index ab01f71f..8897e412 100644 --- a/src/commands/init-hooks.ts +++ b/src/commands/init-hooks.ts @@ -274,9 +274,17 @@ export async function initHooksCommand(options: IInitHooksOptions, logger?: ILog if (!existsSync(configDir)) { mkdirSync(configDir, { recursive: true }); } - const existingGitMemConfig = existsSync(configPath) - ? (() => { try { return parseYaml(readFileSync(configPath, 'utf8')) as Record; } catch { return {}; } })() - : {}; + const existingGitMemConfig = (() => { + if (!existsSync(configPath)) return {}; + try { + const parsed = parseYaml(readFileSync(configPath, 'utf8')); + return parsed && typeof parsed === 'object' && !Array.isArray(parsed) + ? (parsed as Record) + : {}; + } catch { + return {}; + } + })(); const newGitMemConfig = buildGitMemConfig(); const mergedGitMemConfig = deepMergeGitMemConfig(existingGitMemConfig, newGitMemConfig); writeFileSync(configPath, stringifyYaml(mergedGitMemConfig)); diff --git a/src/infrastructure/services/HookConfigLoader.ts b/src/infrastructure/services/HookConfigLoader.ts index 1e900eae..1b59d53e 100644 --- a/src/infrastructure/services/HookConfigLoader.ts +++ b/src/infrastructure/services/HookConfigLoader.ts @@ -2,7 +2,7 @@ * HookConfigLoader * * Infrastructure implementation of IHookConfigLoader. - * Loads and merges hook configuration from .git-mem.json. + * Loads and merges hook configuration from .git-mem/.git-mem.yaml. */ import type { IHookConfigLoader } from '../../domain/interfaces/IHookConfigLoader'; @@ -10,7 +10,8 @@ import type { IHookConfig } from '../../domain/interfaces/IHookConfig'; import { loadHookConfig } from '../../hooks/utils/config'; /** - * Implementation of IHookConfigLoader that reads from .git-mem.json. + * Implementation of IHookConfigLoader that reads from .git-mem/.git-mem.yaml. + * Returns defaults on missing file or parse errors (never throws). */ export class HookConfigLoader implements IHookConfigLoader { loadConfig(cwd: string): IHookConfig { From 494540b4402c929a1d75bab5375bc90785ae240d Mon Sep 17 00:00:00 2001 From: Tony Casey Date: Sat, 14 Feb 2026 20:44:27 +0000 Subject: [PATCH 3/3] docs: update IHookConfig comment to reference YAML Co-Authored-By: Claude Opus 4.5 AI-Agent: Claude-Code/2.1.42 AI-Model: claude-opus-4-5-20251101 AI-Convention: Hook configuration files are now located in a .git-mem directory rather than being a single file at the root level. AI-Confidence: verified AI-Tags: configuration, file-format, hooks, yaml, json, file-structure, directory-organization AI-Lifecycle: project AI-Memory-Id: 11b7de7b AI-Source: llm-enrichment --- src/domain/interfaces/IHookConfig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domain/interfaces/IHookConfig.ts b/src/domain/interfaces/IHookConfig.ts index a8f31ce2..c382b272 100644 --- a/src/domain/interfaces/IHookConfig.ts +++ b/src/domain/interfaces/IHookConfig.ts @@ -1,7 +1,7 @@ /** * IHookConfig * - * Type definitions for .git-mem.json hook configuration. + * Type definitions for .git-mem/.git-mem.yaml hook configuration. * Read by hook entry points to control per-hook behaviour. */