From 9099d4849516a180dc8dea8715f98f498cf75638 Mon Sep 17 00:00:00 2001 From: Lex Christopherson Date: Tue, 20 Jan 2026 01:01:16 -0600 Subject: [PATCH] perf(intel): simplify SessionStart hook + gitignore intel/ - SessionStart now reads pre-generated summary.md directly - No more JSON parsing of potentially large index.json - Added guidance: .planning/intel/ should always be gitignored (changes constantly, can be regenerated with /gsd:analyze-codebase) Co-Authored-By: Claude Opus 4.5 --- commands/gsd/new-project.md | 3 ++ hooks/gsd-intel-session.js | 81 +++---------------------------------- 2 files changed, 8 insertions(+), 76 deletions(-) diff --git a/commands/gsd/new-project.md b/commands/gsd/new-project.md index a7cf62149..88ec27d9f 100644 --- a/commands/gsd/new-project.md +++ b/commands/gsd/new-project.md @@ -353,6 +353,9 @@ Create `.planning/config.json` with all settings: - Set `commit_docs: false` in config.json - Add `.planning/` to `.gitignore` (create if needed) +**If commit_docs = Yes:** +- Add `.planning/intel/` to `.gitignore` (intel is always local — changes constantly, can be regenerated) + **Commit config.json:** ```bash diff --git a/hooks/gsd-intel-session.js b/hooks/gsd-intel-session.js index 4820bf440..2a65287f6 100644 --- a/hooks/gsd-intel-session.js +++ b/hooks/gsd-intel-session.js @@ -1,71 +1,10 @@ #!/usr/bin/env node // Codebase Intelligence - SessionStart Context Injection Hook -// Injects codebase summary into Claude's context at session start +// Reads pre-generated summary.md and injects into Claude's context const fs = require('fs'); const path = require('path'); -/** - * Generate concise codebase summary for context injection - * Target: < 500 tokens to minimize context usage - */ -function generateSummary(index, conventions) { - const lines = []; - - // File count - const fileCount = Object.keys(index.files || {}).length; - if (fileCount === 0) return null; - - lines.push(`Indexed files: ${fileCount}`); - - // Naming conventions (if detected with confidence) - if (conventions.naming?.exports?.dominant) { - const n = conventions.naming.exports; - lines.push(`Export naming: ${n.dominant} (${n.percentage}%)`); - } - - // Key directories (top 5) - const dirs = Object.entries(conventions.directories || {}); - if (dirs.length > 0) { - lines.push(''); - lines.push('Key directories:'); - for (const [dir, info] of dirs.slice(0, 5)) { - lines.push(` ${dir}: ${info.purpose} (${info.files} files)`); - } - } - - // Suffix patterns (top 3) - const suffixes = Object.entries(conventions.suffixes || {}); - if (suffixes.length > 0) { - lines.push(''); - lines.push('File patterns:'); - for (const [suffix, info] of suffixes.slice(0, 3)) { - lines.push(` ${suffix}: ${info.purpose} (${info.count} files)`); - } - } - - // Key exports overview (categorize if enough data) - const allExports = []; - for (const [filePath, fileData] of Object.entries(index.files || {})) { - for (const exp of fileData.exports || []) { - if (exp !== 'default') { - allExports.push(exp); - } - } - } - - if (allExports.length > 0) { - lines.push(''); - lines.push(`Total exports: ${allExports.length}`); - // List a few example exports if available - if (allExports.length <= 10) { - lines.push(`Exports: ${allExports.join(', ')}`); - } - } - - return lines.join('\n'); -} - // Read JSON from stdin (standard hook pattern) let input = ''; process.stdin.setEncoding('utf8'); @@ -79,25 +18,15 @@ process.stdin.on('end', () => { process.exit(0); } - // Check for intel files - const intelDir = path.join(process.cwd(), '.planning', 'intel'); - const indexPath = path.join(intelDir, 'index.json'); + // Read pre-generated summary (created by gsd-intel-index.js) + const summaryPath = path.join(process.cwd(), '.planning', 'intel', 'summary.md'); - if (!fs.existsSync(indexPath)) { + if (!fs.existsSync(summaryPath)) { process.exit(0); // No intel, skip silently } - // Read intel files - const index = JSON.parse(fs.readFileSync(indexPath, 'utf8')); + const summary = fs.readFileSync(summaryPath, 'utf8').trim(); - let conventions = { naming: {}, directories: {}, suffixes: {} }; - const conventionsPath = path.join(intelDir, 'conventions.json'); - if (fs.existsSync(conventionsPath)) { - conventions = JSON.parse(fs.readFileSync(conventionsPath, 'utf8')); - } - - // Generate and output summary - const summary = generateSummary(index, conventions); if (summary) { process.stdout.write(`\n${summary}\n`); }