Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
### New Features

- `zcodegraph status` and `zcodegraph doctor` now share graph health language, so users and scripts can distinguish healthy, degraded, stale, failed, unavailable, and corrupted indexes with exact next-step commands.
- `rust-hybrid` indexing now handles Java baseline symbols through the Rust-owned path, so Java classes, interfaces, annotations, enums, imports, and method calls no longer depend on TypeScript fallback extraction.
- `rust-hybrid` indexing now preserves Python decorator relationships through the Rust-owned path, so decorated Python functions and methods can appear in graph impact and traversal results.
- `rust-hybrid` indexing now understands Python calls, imported names, and module-level values, so Python search, callers/callees, and file dependents work through the Rust indexer.
- `zcodegraph status` now shows decision-ready `rust-hybrid` fallback diagnostics, including top reason groups, graph usability, the exact doctor command, and the privacy-preserving bundle artifact to share with maintainers. (#668, #669, #670)
Expand Down
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions __tests__/frameworks-integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ describe('Java end-to-end — field-injected bean trace (issue #389)', () => {
);

const cg = CodeGraph.initSync(tmpDir);
await cg.indexAll({ engine: 'typescript' });
await cg.indexAll({ engine: 'rust-hybrid' });

const methods = cg.getNodesByKind('method');
const find = (cls: string, name: string) =>
Expand Down Expand Up @@ -503,7 +503,7 @@ describe('Java end-to-end — field-injected bean trace (issue #389)', () => {
);

const cg = CodeGraph.initSync(tmpDir);
await cg.indexAll({ engine: 'typescript' });
await cg.indexAll({ engine: 'rust-hybrid' });

const methods = cg.getNodesByKind('method');
const getByIdJava = methods.find((m) => m.name === 'getById' && m.language === 'java');
Expand Down Expand Up @@ -665,7 +665,7 @@ describe('Java end-to-end — field-injected bean trace (issue #389)', () => {
);

const cg = CodeGraph.initSync(tmpDir);
await cg.indexAll({ engine: 'typescript' });
await cg.indexAll({ engine: 'rust-hybrid' });

const methods = cg.getNodesByKind('method');
const go = methods.find((m) => m.name === 'go');
Expand Down Expand Up @@ -752,7 +752,7 @@ describe('JVM FQN imports — end-to-end', () => {
);

const cg = CodeGraph.initSync(tmpDir);
await cg.indexAll({ engine: 'typescript' });
await cg.indexAll({ engine: 'rust-hybrid' });

const javaBar = cg.getNodesByKind('class').find((n) => n.qualifiedName === 'com.example::JavaBar');
expect(javaBar, 'JavaBar should be extracted under com.example regardless of language').toBeDefined();
Expand Down Expand Up @@ -840,7 +840,7 @@ describe('Java anonymous-class override synthesis — end-to-end', () => {
);

const cg = CodeGraph.initSync(tmpDir);
await cg.indexAll({ engine: 'typescript' });
await cg.indexAll({ engine: 'rust-hybrid' });

// The anon class is extracted and contains the override.
const anonClass = cg
Expand Down
2 changes: 1 addition & 1 deletion __tests__/resolution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1385,7 +1385,7 @@ public class Handler {
`
);

cg = await CodeGraph.init(tempDir, { index: true, engine: 'typescript' });
cg = await CodeGraph.init(tempDir, { index: true, engine: 'rust-hybrid' });

const use = cg
.getNodesByKind('method')
Expand Down
92 changes: 92 additions & 0 deletions __tests__/rust-index-engine-cli-language-smoke.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,98 @@ describe('zcodegraph rust index language framework and MCP smoke behavior', () =
}
}, 30_000);

it('indexes Java as Rust-owned under rust-hybrid', () => {
const javaDir = path.join(tempDir, 'src/main/java/com/example');
fs.mkdirSync(javaDir, { recursive: true });
fs.writeFileSync(
path.join(javaDir, 'Worker.java'),
[
'package com.example;',
'',
'public interface Worker {',
' void run();',
'}',
].join('\n') + '\n',
);
fs.writeFileSync(
path.join(javaDir, 'Service.java'),
[
'package com.example;',
'',
'import java.util.List;',
'',
'public class Service {',
' private Worker worker;',
'',
' public Service(Worker worker) {',
' this.worker = worker;',
' }',
'',
' public void handle() {',
' int result = assist();',
' worker.run();',
' }',
'',
' private int assist() {',
' return List.of(1).size();',
' }',
'',
' enum Mode { FAST }',
'}',
'',
'@interface CustomMapping {',
' String value();',
'}',
].join('\n') + '\n',
);

const result = runZcodegraphCli(tempDir, ['index', '--quiet'], {
ZCODEGRAPH_RUST_CORE_BINARY: RUST_CORE_BIN,
});

expect(result.status, `stdout:\n${result.stdout}\nstderr:\n${result.stderr}`).toBe(0);
const cg = CodeGraph.openSync(tempDir);
try {
expect(cg.getStats().filesByLanguage.java).toBe(2);
const expectations = [
['com.example', 'module'],
['java.util.List', 'import'],
['Worker', 'interface'],
['Service', 'class'],
['worker', 'field'],
['Service', 'method'],
['handle', 'method'],
['result', 'variable'],
['assist', 'method'],
['Mode', 'enum'],
['FAST', 'enum_member'],
['CustomMapping', 'interface'],
['value', 'method'],
] as const;
for (const [name, kind] of expectations) {
expect(
cg.searchNodes(name).some((match) => match.node.name === name && match.node.kind === kind && match.node.language === 'java'),
`${name} (${kind}) should be indexed as Java`,
).toBe(true);
}

const assist = cg.searchNodes('assist').find((match) => match.node.kind === 'method')?.node;
expect(assist?.qualifiedName).toContain('Service::assist');

const buildInfo = cg.getIndexBuildInfo();
expect(buildInfo.engine).toBe('rust-hybrid');
expect(buildInfo.hybrid).toMatchObject({
rustOwnedLanguages: expect.arrayContaining(['java']),
engineByLanguage: { java: 'rust' },
fallbackByLanguage: {},
fallbackFileCount: 0,
fallbackReasonTaxonomy: {},
});
} finally {
cg.close();
}
}, 30_000);

it('reports Rust index-engine metadata through MCP status', async () => {
const indexResult = runZcodegraphCli(tempDir, ['index', '--engine', 'rust', '--quiet'], {
ZCODEGRAPH_RUST_CORE_BINARY: RUST_CORE_BIN,
Expand Down
1 change: 1 addition & 0 deletions crates/zcodegraph-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ serde_json = "1"
sha2 = "0.10"
tree-sitter = "0.24"
tree-sitter-go = "0.23"
tree-sitter-java = "0.23"
tree-sitter-javascript = "0.23"
tree-sitter-python = "0.23"
tree-sitter-rust = "0.23"
Expand Down
Loading