feat: added skip-agents-md cli flag (#517)

* feat: added skip-agents-md cli flag

* fix: apply prettier formatting

* feat: added skip-agents-md cli flag

* fix: apply prettier formatting

* feat: add skipAgentsMd option to skip AGENTS.md and CLAUDE.md updates

* fixed bad merge
This commit is contained in:
Gabriel J Campbell 2026-03-28 16:23:59 -05:00 committed by GitHub
parent 9f69c43100
commit b03413dcf9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 83 additions and 28 deletions

View file

@ -165,13 +165,14 @@ args = ["-y", "gitnexus@latest", "mcp"]
### CLI Commands
```bash
gitnexus setup # Configure MCP for your editors (one-time)
gitnexus analyze [path] # Index a repository (or update stale index)
gitnexus analyze --force # Force full re-index
gitnexus analyze --skills # Generate repo-specific skill files from detected communities
gitnexus setup # Configure MCP for your editors (one-time)
gitnexus analyze [path] # Index a repository (or update stale index)
gitnexus analyze --force # Force full re-index
gitnexus analyze --skills # Generate repo-specific skill files from detected communities
gitnexus analyze --skip-embeddings # Skip embedding generation (faster)
gitnexus analyze --embeddings # Enable embedding generation (slower, better search)
gitnexus analyze --verbose # Log skipped files when parsers are unavailable
gitnexus analyze --skip-agents-md # Preserve custom AGENTS.md/CLAUDE.md gitnexus section edits
gitnexus analyze --embeddings # Enable embedding generation (slower, better search)
gitnexus analyze --verbose # Log skipped files when parsers are unavailable
gitnexus mcp # Start MCP server (stdio) — serves all indexed repos
gitnexus serve # Start local HTTP server (multi-repo) for web UI connection
gitnexus list # List all indexed repositories

View file

@ -149,11 +149,12 @@ Your AI agent gets these tools automatically:
## CLI Commands
```bash
gitnexus setup # Configure MCP for your editors (one-time)
gitnexus analyze [path] # Index a repository (or update stale index)
gitnexus analyze --force # Force full re-index
gitnexus analyze --embeddings # Enable embedding generation (slower, better search)
gitnexus analyze --verbose # Log skipped files when parsers are unavailable
gitnexus setup # Configure MCP for your editors (one-time)
gitnexus analyze [path] # Index a repository (or update stale index)
gitnexus analyze --force # Force full re-index
gitnexus analyze --embeddings # Enable embedding generation (slower, better search)
gitnexus analyze --skip-agents-md # Preserve custom AGENTS.md/CLAUDE.md gitnexus section edits
gitnexus analyze --verbose # Log skipped files when parsers are unavailable
gitnexus mcp # Start MCP server (stdio) — serves all indexed repos
gitnexus serve # Start local HTTP server (multi-repo) for web UI
gitnexus index # Register an existing .gitnexus/ folder into the global registry

View file

@ -24,6 +24,10 @@ interface RepoStats {
processes?: number;
}
export interface AIContextOptions {
skipAgentsMd?: boolean;
}
const GITNEXUS_START_MARKER = '<!-- gitnexus:start -->';
const GITNEXUS_END_MARKER = '<!-- gitnexus:end -->';
@ -299,19 +303,25 @@ export async function generateAIContextFiles(
projectName: string,
stats: RepoStats,
generatedSkills?: GeneratedSkillInfo[],
options?: AIContextOptions,
): Promise<{ files: string[] }> {
const content = generateGitNexusContent(projectName, stats, generatedSkills);
const createdFiles: string[] = [];
// Create AGENTS.md (standard for Cursor, Windsurf, OpenCode, Cline, etc.)
const agentsPath = path.join(repoPath, 'AGENTS.md');
const agentsResult = await upsertGitNexusSection(agentsPath, content);
createdFiles.push(`AGENTS.md (${agentsResult})`);
if (!options?.skipAgentsMd) {
// Create AGENTS.md (standard for Cursor, Windsurf, OpenCode, Cline, etc.)
const agentsPath = path.join(repoPath, 'AGENTS.md');
const agentsResult = await upsertGitNexusSection(agentsPath, content);
createdFiles.push(`AGENTS.md (${agentsResult})`);
// Create CLAUDE.md (for Claude Code)
const claudePath = path.join(repoPath, 'CLAUDE.md');
const claudeResult = await upsertGitNexusSection(claudePath, content);
createdFiles.push(`CLAUDE.md (${claudeResult})`);
// Create CLAUDE.md (for Claude Code)
const claudePath = path.join(repoPath, 'CLAUDE.md');
const claudeResult = await upsertGitNexusSection(claudePath, content);
createdFiles.push(`CLAUDE.md (${claudeResult})`);
} else {
createdFiles.push('AGENTS.md (skipped via --skip-agents-md)');
createdFiles.push('CLAUDE.md (skipped via --skip-agents-md)');
}
// Install skills to .claude/skills/gitnexus/
const installedSkills = await installSkills(repoPath);

View file

@ -45,6 +45,8 @@ export interface AnalyzeOptions {
embeddings?: boolean;
skills?: boolean;
verbose?: boolean;
/** Skip AGENTS.md and CLAUDE.md gitnexus block updates. */
skipAgentsMd?: boolean;
/** Index the folder even when no .git directory is present. */
skipGit?: boolean;
}
@ -174,6 +176,7 @@ export const analyzeCommand = async (inputPath?: string, options?: AnalyzeOption
force: options?.force || options?.skills,
embeddings: options?.embeddings,
skipGit: options?.skipGit,
skipAgentsMd: options?.skipAgentsMd,
},
{
onProgress: (_phase, percent, message) => {
@ -237,6 +240,7 @@ export const analyzeCommand = async (inputPath?: string, options?: AnalyzeOption
processes: s.processes,
},
skillResult.skills,
{ skipAgentsMd: options?.skipAgentsMd },
);
}
} catch {

View file

@ -24,6 +24,7 @@ program
.option('-f, --force', 'Force full re-index even if up to date')
.option('--embeddings', 'Enable embedding generation for semantic search (off by default)')
.option('--skills', 'Generate repo-specific skill files from detected communities')
.option('--skip-agents-md', 'Skip updating the gitnexus section in AGENTS.md and CLAUDE.md')
.option('--skip-git', 'Index a folder without requiring a .git directory')
.option('-v, --verbose', 'Enable verbose ingestion warnings (default: false)')
.addHelpText(

View file

@ -46,6 +46,8 @@ export interface AnalyzeOptions {
force?: boolean;
embeddings?: boolean;
skipGit?: boolean;
/** Skip AGENTS.md and CLAUDE.md gitnexus block updates. */
skipAgentsMd?: boolean;
}
export interface AnalyzeResult {
@ -312,14 +314,21 @@ export async function runFullAnalysis(
}
try {
await generateAIContextFiles(repoPath, storagePath, projectName, {
files: pipelineResult.totalFileCount,
nodes: stats.nodes,
edges: stats.edges,
communities: pipelineResult.communityResult?.stats.totalCommunities,
clusters: aggregatedClusterCount,
processes: pipelineResult.processResult?.stats.totalProcesses,
});
await generateAIContextFiles(
repoPath,
storagePath,
projectName,
{
files: pipelineResult.totalFileCount,
nodes: stats.nodes,
edges: stats.edges,
communities: pipelineResult.communityResult?.stats.totalCommunities,
clusters: aggregatedClusterCount,
processes: pipelineResult.processResult?.stats.totalProcesses,
},
undefined,
{ skipAgentsMd: options.skipAgentsMd },
);
} catch {
// Best-effort — don't fail the entire analysis for context file issues
}

View file

@ -79,4 +79,32 @@ describe('generateAIContextFiles', () => {
// Skills dir may not be created if skills source doesn't exist in test context
}
});
it('preserves manual AGENTS.md and CLAUDE.md edits when skipAgentsMd is enabled', async () => {
const stats = { nodes: 42, edges: 84, processes: 3 };
const agentsPath = path.join(tmpDir, 'AGENTS.md');
const claudePath = path.join(tmpDir, 'CLAUDE.md');
const agentsContent = '# AGENTS\n\nCustom manual instructions only\n';
const claudeContent = '# CLAUDE\n\nCustom manual instructions only\n';
await fs.writeFile(agentsPath, agentsContent, 'utf-8');
await fs.writeFile(claudePath, claudeContent, 'utf-8');
const result = await generateAIContextFiles(
tmpDir,
storagePath,
'TestProject',
stats,
undefined,
{ skipAgentsMd: true },
);
expect(result.files).toContain('AGENTS.md (skipped via --skip-agents-md)');
expect(result.files).toContain('CLAUDE.md (skipped via --skip-agents-md)');
const agentsAfter = await fs.readFile(agentsPath, 'utf-8');
const claudeAfter = await fs.readFile(claudePath, 'utf-8');
expect(agentsAfter).toBe(agentsContent);
expect(claudeAfter).toBe(claudeContent);
});
});

View file

@ -6,7 +6,7 @@ import fs from 'fs';
describe('--skip-git CLI flag', () => {
it('Commander maps --skip-git to options.skipGit (not --no-git inversion)', () => {
// Verify the CLI defines --skip-git, not --no-git
// Verify the CLI defines --skip-git and --skip-agents-md in analyze help.
const helpOutput = execSync('node dist/cli/index.js analyze --help', {
cwd: path.resolve(__dirname, '../..'),
encoding: 'utf8',
@ -14,6 +14,7 @@ describe('--skip-git CLI flag', () => {
});
expect(helpOutput).toContain('--skip-git');
expect(helpOutput).toContain('--skip-agents-md');
expect(helpOutput).not.toContain('--no-git');
});