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
6 changes: 6 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,11 @@
set -euo pipefail
repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"
# Git hands hooks the repository-locating environment (GIT_DIR, GIT_INDEX_FILE,
# ...). Tests create throwaway repositories; inheriting these variables would
# point their commits at THIS repository, so clear them before the gate.
for name in $(git rev-parse --local-env-vars); do
unset "$name"
done
echo "==> [pre-push] make pre-ci"
exec make pre-ci
6 changes: 4 additions & 2 deletions Cargo.lock

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

14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,20 @@ codegraph install --yes --init
codegraph install --target=codex,claude,kiro --yes
```

Global profile overrides are honored: Claude Code follows
`CLAUDE_CONFIG_DIR`, Codex follows `CODEX_HOME`, and OpenCode 2 receives its
native `mcp.servers.codegraph` entry with `codemode: false`. Claude entries set
`alwaysLoad: true`; Copilot CLI entries set `deferTools: "never"` so Explore is
available from the first prompt.

A server launched without `--path` can serve an existing index selected by an
explicit per-call `projectPath`, client roots, or deterministic workspace
adoption. Pin `--path` when a project should be the default rather than
supplied per call.
adoption. First explicit access to an existing index waits for catch-up and
retains that project's shared daemon/watcher; multiple child projects remain
separate and multiple MCP sessions share one writer per project. Pin `--path`
when a project should be the default rather than supplied per call. Explicit
direct mode (`CODEGRAPH_NO_DAEMON=1`) opts out of lazy cross-project daemon
services, permits one direct writer, and rejects a second.

The default visible MCP surface emphasizes exploration, file/symbol reads,
search, and callers. Additional known tools can be enabled with
Expand Down
55 changes: 55 additions & 0 deletions crates/codegraph-bench/fixtures/cpp/constructor_resolution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
struct AggregateOnly {
int value;
};

class WithConstructor {
public:
WithConstructor() {}
explicit WithConstructor(int value) {}
};

class Defaults {
public:
Defaults() {}
explicit Defaults(int value = 0) {}
};

namespace left {
struct Widget {
Widget() {}
};
}

namespace right {
struct Widget {
Widget() {}
};
}

void aggregate_only() {
AggregateOnly value{};
}

void constructor_default() {
WithConstructor value;
}

void constructor_braced() {
WithConstructor value{};
}

void constructor_value() {
WithConstructor value(1);
}

void constructor_ambiguous_overload() {
Defaults value;
}

void constructor_ambiguous_owner() {
Widget value;
}

void constructor_explicit_owner() {
left::Widget value;
}
16 changes: 16 additions & 0 deletions crates/codegraph-bench/fixtures/cpp/designated_macro.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
void reset_profile(void)
{
RESET_CONFIG(profile_t, profile,
.pid = { [0] = 10, [1] = { 50, 75 } },
.limit = 500,
);
}

void after_reset(void)
{
}

int final_value(void)
{
return 1;
}
21 changes: 21 additions & 0 deletions crates/codegraph-bench/fixtures/cpp/pure_virtual.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class AbstractStore {
public:
virtual int read(int key) = 0;
virtual AbstractStore *clone() = 0;
virtual AbstractStore &operator=(const AbstractStore &) = 0;
int inherited_pure() = 0;
int declaration_only(int key = 0);
int (*callback)(int) = 0;
int data = 0;
};

class DiskStore : public AbstractStore {
public:
int read(int key) override { return key; }
AbstractStore *clone() override { return this; }
};

int fetch_store(AbstractStore *store, int key)
{
return store->read(key);
}
21 changes: 21 additions & 0 deletions crates/codegraph-bench/fixtures/cpp/raw_string.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace fixture {
const char *source_template = u8R"MARKUP(
DECLARE_THING(
struct Ghost { int value; };
UE_DEPRECATED(
class GHOST_API IgnoredApi {};
float4 position [[position]];
__global__ void ignored_kernel() {}
ignored_kernel<<<1, 1>>>();
)MARKUP";
}

int after_raw_string(int value)
{
return value;
}

int final_after_raw_string(void)
{
return 1;
}
11 changes: 11 additions & 0 deletions crates/codegraph-bench/fixtures/dart/extension_type.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
extension type MetersT(double value) {
double get km => value / 1000;

void report() {
print(km);
}
}

class Widget {
double get half => 1.0;
}
43 changes: 43 additions & 0 deletions crates/codegraph-bench/fixtures/rust/self_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,46 @@ impl Countdown {
}
}
}

pub struct SplitTarget;

impl SplitTarget {
pub fn reset(&mut self) {}
}

pub struct SplitDecoy;

impl SplitDecoy {
pub fn reset(&mut self) {}

pub fn missing(&mut self) {}
}

impl SplitTarget {
pub fn drive(&mut self) {
self.reset();
self.missing();
}
}

pub trait Drive {
fn go(&mut self);
}

pub struct StepDecoy;

impl StepDecoy {
pub fn step(&mut self) {}
}

pub struct Doer;

impl Doer {
pub fn step(&mut self) {}
}

impl Drive for Doer {
fn go(&mut self) {
self.step();
}
}
9 changes: 9 additions & 0 deletions crates/codegraph-bench/fixtures/scala/agreements.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
object ExtAgreement {}

trait ExtAgreement {
def extId: String = "x"
}

trait OtherAgreement

class MAgreement(agreement: String)(implicit queryService: Int)
4 changes: 4 additions & 0 deletions crates/codegraph-bench/fixtures/scala/m_ext_agreement.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class MExtAgreement(agreement: String, ext: String)(implicit queryService: Int)
extends MAgreement(agreement)(queryService) with ExtAgreement with OtherAgreement {
def render(): String = extId
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export interface PlatformApi {
fetchPage(id: string): Promise<string>;
version: string;
}

export type Handle = { stop(): void; label: string };

function callableSemanticsUniqueHelper(): number {
return 1;
}

export function* generatorTask() {
yield callableSemanticsUniqueHelper();
}

export function Screen() {
const plainHandler = () => callableSemanticsUniqueHelper();
const callbackHandler = useCallback(() => callableSemanticsUniqueHelper(), []);
const eventHandler = useEffectEvent(function () {
return callableSemanticsUniqueHelper();
});
const wrappedHandler = Effect.fn("Screen.wrapped")(function* () {
yield callableSemanticsUniqueHelper();
});
const memoValue = useMemo(() => callableSemanticsUniqueHelper(), []);
const mappedValue = [1].map(() => callableSemanticsUniqueHelper());
return plainHandler() + callbackHandler() + eventHandler() + memoValue + mappedValue.length;
}
16 changes: 16 additions & 0 deletions crates/codegraph-bench/fixtures/typescript/commonjs_handlers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
function findItems() {}
function removeItem() {}

exports.getItems = async () => {
findItems();
};

module.exports.deleteItem = function () {
removeItem();
};

exports.plain = 42;
module.exports = { legacy: 1 };

const handlers = {};
handlers.onSave = () => findItems();
53 changes: 53 additions & 0 deletions crates/codegraph-bench/tests/equivalence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,43 @@ fn kotlin_db_is_self_equivalent_to_kotlin_golden() {
assert_equivalent(&kotlin_db(), &kotlin_golden_dir()).unwrap();
}

#[test]
fn generated_golden_matches_committed_scala_fixture() {
// Guards Scala grammar 0.26.2's multi-parameter-list inheritance shape,
// every `extends`/`with` parent, companion object -> Module classification,
// inheritance preference for the real type, and eta-expansion method values.
let tempdir = TestDir::new("generated-golden-scala");
write_golden(&scala_db(), tempdir.path()).unwrap();

let expected = load_golden(&scala_golden_dir()).unwrap();
let actual = load_golden(tempdir.path()).unwrap();

diff_canonical(&expected, &actual, None).unwrap();
}

#[test]
fn scala_db_is_self_equivalent_to_scala_golden() {
assert_equivalent(&scala_db(), &scala_golden_dir()).unwrap();
}

#[test]
fn generated_golden_matches_committed_dart_fixture() {
// Guards Dart 3 `extension type`: the type is class-like and owns getter /
// method nodes rather than leaving top-level functions or dropping members.
let tempdir = TestDir::new("generated-golden-dart");
write_golden(&dart_db(), tempdir.path()).unwrap();

let expected = load_golden(&dart_golden_dir()).unwrap();
let actual = load_golden(tempdir.path()).unwrap();

diff_canonical(&expected, &actual, None).unwrap();
}

#[test]
fn dart_db_is_self_equivalent_to_dart_golden() {
assert_equivalent(&dart_db(), &dart_golden_dir()).unwrap();
}

#[test]
fn generated_golden_matches_committed_typescript_fixture() {
let tempdir = TestDir::new("generated-golden-typescript");
Expand Down Expand Up @@ -511,6 +548,22 @@ fn kotlin_golden_dir() -> PathBuf {
workspace_root().join("reference/golden/kotlin")
}

fn scala_db() -> PathBuf {
workspace_root().join("reference/golden/scala/colby.db")
}

fn scala_golden_dir() -> PathBuf {
workspace_root().join("reference/golden/scala")
}

fn dart_db() -> PathBuf {
workspace_root().join("reference/golden/dart/colby.db")
}

fn dart_golden_dir() -> PathBuf {
workspace_root().join("reference/golden/dart")
}

fn typescript_db() -> PathBuf {
workspace_root().join("reference/golden/typescript/colby.db")
}
Expand Down
9 changes: 9 additions & 0 deletions crates/codegraph-cli/src/installer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,19 @@ fn context_from_env() -> Result<InstallContext> {
.map(PathBuf::from)
.ok_or_else(|| anyhow::anyhow!("could not resolve home directory (HOME/USERPROFILE)"))?;
let cwd = std::env::current_dir()?;
let non_blank_path = |name: &str| {
std::env::var_os(name)
.filter(|value| !value.to_string_lossy().trim().is_empty())
.map(PathBuf::from)
};
Ok(InstallContext {
home,
cwd,
app_data: std::env::var_os("APPDATA").map(PathBuf::from),
xdg_config_home: std::env::var_os("XDG_CONFIG_HOME").map(PathBuf::from),
hermes_home: std::env::var_os("HERMES_HOME").map(PathBuf::from),
claude_config_dir: non_blank_path("CLAUDE_CONFIG_DIR"),
codex_home: non_blank_path("CODEX_HOME"),
})
}

Expand Down Expand Up @@ -747,6 +754,8 @@ mod tests {
app_data: None,
xdg_config_home: Some(base.join("xdg")),
hermes_home: Some(base.join("hermes")),
claude_config_dir: None,
codex_home: None,
};
(ctx, base)
}
Expand Down
Loading
Loading