feat(xrepo): cross-repo intelligence — multi-repo query via --additional-paths (closes #15)#150
Merged
Merged
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
4684c80 to
114ed5c
Compare
…nal-paths (closes #15) Implements the Minimum Viable Version from issue #15: Just support multiple repo_path entries — resolve imports against the combined symbol table from all indexed repos. New files: - scripts/crossrepo_engine.py — load_merged_registry() merges backend registries from multiple repos, tags each node with a 'repo' field, re-runs edge_resolver.resolve_edges() on the combined node set so cross-repo calls (e.g. services/api calling lib/shared) are resolved automatically. Cross-repo edges are flagged with cross_repo=True + target_repo + source_repo. query_cross_repo() provides multi-repo symbol query with callers/callees annotated with repo + cross_repo. - tests/test_crossrepo_engine.py — 28 tests: path parsing, registry merging, cross-repo edge resolution, multi-repo query, fuzzy match across repos, graceful degradation, CLI arg integration. Modified files: - scripts/commands/query.py — added --additional-paths flag. When provided, delegates to crossrepo_engine.query_cross_repo(). When absent, behavior is unchanged (zero-risk backward compat). - scripts/mcp_server.py — added additional_paths parameter to the codelens_query MCP tool schema so agents can pass comma-separated repo paths for cross-repo search. - README.md, SKILL.md, SKILL-QUICK.md, pyproject.toml, skill.json, scripts/graph_model.py — auto-synced by sync_command_count.py --apply (command count 68->69 from other workers' merged PRs; this PR itself adds 0 new commands). Non-breaking by design: - scan/init/load_backend_registry untouched — each repo is scanned independently as before. - resolve_edges reused as-is — it already matches to_fn against the full node list, so feeding it merged nodes resolves cross-repo calls automatically. - query command without --additional-paths: identical behavior. Tests: 1398 passed (28 new), 80 skipped, 1 pre-existing failure unrelated (test_codelensignore::test_actual_target_dir_is_ignored).
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Closes #15
Summary
Implements the Minimum Viable Version from issue #15:
Agents can now query across pre-indexed repos:
Returns the symbol from
lib/shared, with the caller fromservices/apiannotatedcross_repo: true— so an agent can trace a call that crosses the repo boundary without manually chainingtrace→search→query.What was added
scripts/crossrepo_engine.pyload_merged_registry()— loads backend registries from primary + additional repos, tags each node withrepo, re-runsresolve_edges()on the combined node set so cross-repo calls resolve automatically. Cross-repo edges flagged withcross_repo=True+target_repo+source_repo.query_cross_repo()— multi-repo symbol query with callers/callees annotated.scripts/commands/query.py--additional-pathsflag. When provided, delegates tocrossrepo_engine.query_cross_repo(). When absent, behavior is unchanged (zero-risk backward compat).scripts/mcp_server.pyadditional_pathsparameter to thecodelens_queryMCP tool schema so agents can pass comma-separated repo paths.tests/test_crossrepo_engine.pyREADME.md,SKILL.md,SKILL-QUICK.md,pyproject.toml,skill.json,scripts/graph_model.pysync_command_count.py --apply(command count 68→69 from other workers' merged PRs; this PR itself adds 0 new commands).How it works
The key insight:
edge_resolver.resolve_edges()already matchesto_fn(function name) against the full node list to resolve cross-file calls. By feeding it nodes from multiple repos, cross-repo calls resolve automatically — the resolver doesn't care which repo a node came from.Non-breaking by design
scan/init/load_backend_registryuntouched — each repo is scanned independently as before. No config schema changes required.resolve_edgesreused as-is — it already does the heavy lifting; we just feed it a bigger node list.querywithout--additional-paths— identical behavior, same code path, zero risk.querycommand.Test results
1398 passed, 80 skipped, 1 failed (28 new tests included in the 1398).
The 1 failure (
test_codelensignore::TestBackwardCompat::test_actual_target_dir_is_ignored) is pre-existing and unrelated — it fails identically on cleanorigin/main.Scope alignment with multi-worker analysis
Per the aggregation comment on #15, three worker reports proposed different scopes:
--remote) — future workThis PR implements the CodeGraph #29 scope: read-only multi-repo querying across pre-indexed projects. The other two scopes can be addressed in sibling issues.
Limitations (documented, not bugs)
tracecommand not yet updated. Onlyquerygained--additional-pathsin this MVP.trace --additional-pathscan follow in a subsequent PR.CROSS_CALLS/CROSS_IMPORTSedge types. The issue body suggests distinct edge types, but the MVP uses across_repo: trueflag on existingCALLSedges instead — simpler, non-breaking, and carries the same information.