diff --git a/gitnexus/src/cli/ai-context.ts b/gitnexus/src/cli/ai-context.ts index ae7f984fb9..984d1432a2 100644 --- a/gitnexus/src/cli/ai-context.ts +++ b/gitnexus/src/cli/ai-context.ts @@ -101,19 +101,6 @@ This project is indexed by GitNexus as **${projectName}**${noStats ? '' : ` (${s - When exploring unfamiliar code, use \`gitnexus_query({query: "concept"})\` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance. - When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use \`gitnexus_context({name: "symbolName"})\`. -## When Debugging - -1. \`gitnexus_query({query: ""})\` — find execution flows related to the issue -2. \`gitnexus_context({name: ""})\` — see all callers, callees, and process participation -3. \`READ gitnexus://repo/${projectName}/process/{processName}\` — trace the full execution flow step by step -4. For regressions: \`gitnexus_detect_changes({scope: "compare", base_ref: "main"})\` — see what your branch changed - -## When Refactoring - -- **Renaming**: MUST use \`gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})\` first. Review the preview — graph edits are safe, text_search edits need manual review. Then run with \`dry_run: false\`. -- **Extracting/Splitting**: MUST run \`gitnexus_context({name: "target"})\` to see all incoming/outgoing refs, then \`gitnexus_impact({target: "target", direction: "upstream"})\` to find all external callers before moving code. -- After any refactor: run \`gitnexus_detect_changes({scope: "all"})\` to verify only expected files changed. - ## Never Do - NEVER edit a function, class, or method without first running \`gitnexus_impact\` on it. @@ -121,25 +108,6 @@ This project is indexed by GitNexus as **${projectName}**${noStats ? '' : ` (${s - NEVER rename symbols with find-and-replace — use \`gitnexus_rename\` which understands the call graph. - NEVER commit changes without running \`gitnexus_detect_changes()\` to check affected scope. -## Tools Quick Reference - -| Tool | When to use | Command | -|------|-------------|---------| -| \`query\` | Find code by concept | \`gitnexus_query({query: "auth validation"})\` | -| \`context\` | 360-degree view of one symbol | \`gitnexus_context({name: "validateUser"})\` | -| \`impact\` | Blast radius before editing | \`gitnexus_impact({target: "X", direction: "upstream"})\` | -| \`detect_changes\` | Pre-commit scope check | \`gitnexus_detect_changes({scope: "staged"})\` | -| \`rename\` | Safe multi-file rename | \`gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})\` | -| \`cypher\` | Custom graph queries | \`gitnexus_cypher({query: "MATCH ..."})\` | - -## Impact Risk Levels - -| Depth | Meaning | Action | -|-------|---------|--------| -| d=1 | WILL BREAK — direct callers/importers | MUST update these | -| d=2 | LIKELY AFFECTED — indirect deps | Should test | -| d=3 | MAY NEED TESTING — transitive | Test if critical path | - ## Resources | Resource | Use for | @@ -149,32 +117,6 @@ This project is indexed by GitNexus as **${projectName}**${noStats ? '' : ` (${s | \`gitnexus://repo/${projectName}/processes\` | All execution flows | | \`gitnexus://repo/${projectName}/process/{name}\` | Step-by-step execution trace | -## Self-Check Before Finishing - -Before completing any code modification task, verify: -1. \`gitnexus_impact\` was run for all modified symbols -2. No HIGH/CRITICAL risk warnings were ignored -3. \`gitnexus_detect_changes()\` confirms changes match expected scope -4. All d=1 (WILL BREAK) dependents were updated - -## Keeping the Index Fresh - -After committing code changes, the GitNexus index becomes stale. Re-run analyze to update it: - -\`\`\`bash -npx gitnexus analyze -\`\`\` - -If the index previously included embeddings, preserve them by adding \`--embeddings\`: - -\`\`\`bash -npx gitnexus analyze --embeddings -\`\`\` - -To check whether embeddings exist, inspect \`.gitnexus/meta.json\` — the \`stats.embeddings\` field shows the count (0 means no embeddings). **Running analyze without \`--embeddings\` will delete any previously generated embeddings.** - -> Claude Code users: A PostToolUse hook handles this automatically after \`git commit\` and \`git merge\`. - ${ groupNames && groupNames.length > 0 ? `## Cross-Repo Groups diff --git a/gitnexus/test/unit/ai-context.test.ts b/gitnexus/test/unit/ai-context.test.ts index 0a9f52a687..7a8ed0e9bc 100644 --- a/gitnexus/test/unit/ai-context.test.ts +++ b/gitnexus/test/unit/ai-context.test.ts @@ -45,6 +45,63 @@ describe('generateAIContextFiles', () => { expect(content).toContain('TestProject'); }); + it('keeps the load-bearing repo-specific sections in the CLAUDE.md block (#856)', async () => { + // The trimmed block must still contain everything that is genuinely + // unique per repo or load-bearing for the agent: the freshness warning, + // the Always Do / Never Do imperative lists, the Resources URI table + // (projectName-interpolated), and the skills routing table that tells + // the agent which skill file to read for each task. + const stats = { nodes: 50, edges: 100, processes: 5 }; + await generateAIContextFiles(tmpDir, storagePath, 'TestProject', stats); + + const content = await fs.readFile(path.join(tmpDir, 'CLAUDE.md'), 'utf-8'); + + expect(content).toContain('If any GitNexus tool warns the index is stale'); + expect(content).toContain('## Always Do'); + expect(content).toContain('## Never Do'); + expect(content).toContain('## Resources'); + expect(content).toContain('gitnexus://repo/TestProject/context'); + expect(content).toContain('gitnexus-impact-analysis/SKILL.md'); + expect(content).toContain('gitnexus-refactoring/SKILL.md'); + expect(content).toContain('gitnexus-debugging/SKILL.md'); + expect(content).toContain('gitnexus-cli/SKILL.md'); + }); + + it('does not duplicate content that already lives in skill files (#856)', async () => { + // The six sections listed in issue #856 are redundant with the skill + // files shipped alongside the CLAUDE.md block (both are loaded into + // every Claude Code session). Their absence is the whole point of the + // trim — assert each header is gone so a future regression that pads + // the block back out fails here. + const stats = { nodes: 50, edges: 100, processes: 5 }; + await generateAIContextFiles(tmpDir, storagePath, 'TestProject', stats); + + const content = await fs.readFile(path.join(tmpDir, 'CLAUDE.md'), 'utf-8'); + + expect(content).not.toContain('## Tools Quick Reference'); + expect(content).not.toContain('## Impact Risk Levels'); + expect(content).not.toContain('## Self-Check Before Finishing'); + expect(content).not.toContain('## When Debugging'); + expect(content).not.toContain('## When Refactoring'); + expect(content).not.toContain('## Keeping the Index Fresh'); + }); + + it('keeps the CLAUDE.md GitNexus block under the token-cost budget (#856)', async () => { + // The pre-trim block was ~5465 chars. After #856 it's ~2580 — about a + // 52% reduction. 2700 is a soft ceiling that still leaves headroom for + // legitimate future additions but will fail loudly if the trim is + // reverted or someone pads the block back out toward the original size. + const stats = { nodes: 50, edges: 100, processes: 5 }; + await generateAIContextFiles(tmpDir, storagePath, 'TestProject', stats); + + const content = await fs.readFile(path.join(tmpDir, 'CLAUDE.md'), 'utf-8'); + const block = content.slice( + content.indexOf(''), + content.indexOf(''), + ); + expect(block.length).toBeLessThan(2700); + }); + it('handles empty stats', async () => { const stats = {}; const result = await generateAIContextFiles(tmpDir, storagePath, 'EmptyProject', stats);