Skip to content

Commit 36c6fdb

Browse files
authored
feat: add CODEOWNERS integration with codegraph owners command (#195)
Map graph nodes to CODEOWNERS entries, show ownership coverage, per-owner breakdown, and cross-owner boundary edges. Integrates ownership into diff-impact output with affected owners and suggested reviewers. Exposes code_owners MCP tool. Impact: 10 functions changed, 12 affected
1 parent 70f26c0 commit 36c6fdb

File tree

8 files changed

+814
-0
lines changed

8 files changed

+814
-0
lines changed

src/cli.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,29 @@ program
834834
});
835835
});
836836

837+
program
838+
.command('owners [target]')
839+
.description('Show CODEOWNERS mapping for files and functions')
840+
.option('-d, --db <path>', 'Path to graph.db')
841+
.option('--owner <owner>', 'Filter to a specific owner')
842+
.option('--boundary', 'Show cross-owner boundary edges')
843+
.option('-f, --file <path>', 'Scope to a specific file')
844+
.option('-k, --kind <kind>', 'Filter by symbol kind')
845+
.option('-T, --no-tests', 'Exclude test/spec files')
846+
.option('--include-tests', 'Include test/spec files (overrides excludeTests config)')
847+
.option('-j, --json', 'Output as JSON')
848+
.action(async (target, opts) => {
849+
const { owners } = await import('./owners.js');
850+
owners(opts.db, {
851+
owner: opts.owner,
852+
boundary: opts.boundary,
853+
file: opts.file || target,
854+
kind: opts.kind,
855+
noTests: resolveNoTests(opts),
856+
json: opts.json,
857+
});
858+
});
859+
837860
program
838861
.command('branch-compare <base> <target>')
839862
.description('Compare code structure between two branches/refs')

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ export { setVerbose } from './logger.js';
7070
export { manifesto, manifestoData, RULE_DEFS } from './manifesto.js';
7171
// Native engine
7272
export { isNativeAvailable } from './native.js';
73+
// Ownership (CODEOWNERS)
74+
export { matchOwners, owners, ownersData, ownersForFiles, parseCodeowners } from './owners.js';
7375
// Pagination utilities
7476
export { MCP_DEFAULTS, MCP_MAX_LIMIT, paginate, paginateResult } from './paginate.js';
7577

src/mcp.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,28 @@ const BASE_TOOLS = [
491491
},
492492
},
493493
},
494+
{
495+
name: 'code_owners',
496+
description:
497+
'Show CODEOWNERS mapping for files and functions. Shows ownership coverage, per-owner breakdown, and cross-owner boundary edges.',
498+
inputSchema: {
499+
type: 'object',
500+
properties: {
501+
file: { type: 'string', description: 'Scope to a specific file (partial match)' },
502+
owner: { type: 'string', description: 'Filter to a specific owner (e.g. @team-name)' },
503+
boundary: {
504+
type: 'boolean',
505+
description: 'Show cross-owner boundary edges',
506+
default: false,
507+
},
508+
kind: {
509+
type: 'string',
510+
description: 'Filter by symbol kind (function, method, class, etc.)',
511+
},
512+
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
513+
},
514+
},
515+
},
494516
];
495517

496518
const LIST_REPOS_TOOL = {
@@ -859,6 +881,17 @@ export async function startMCPServer(customDbPath, options = {}) {
859881
});
860882
break;
861883
}
884+
case 'code_owners': {
885+
const { ownersData } = await import('./owners.js');
886+
result = ownersData(dbPath, {
887+
file: args.file,
888+
owner: args.owner,
889+
boundary: args.boundary,
890+
kind: args.kind,
891+
noTests: args.no_tests,
892+
});
893+
break;
894+
}
862895
case 'list_repos': {
863896
const { listRepos, pruneRegistry } = await import('./registry.js');
864897
pruneRegistry();

0 commit comments

Comments
 (0)