Skip to content
Open
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 Makefile.cbm
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ PIPELINE_SRCS = \
src/pipeline/pass_semantic_edges.c \
src/pipeline/pass_complexity.c \
src/pipeline/pass_cross_repo.c \
src/pipeline/pass_cross_repo_maven.c \
src/pipeline/artifact.c \
src/pipeline/pass_pkgmap.c

Expand Down
16 changes: 10 additions & 6 deletions src/mcp/mcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,8 @@ static const tool_def_t TOOLS[] = {
{"index_repository",
"Index a repository into the knowledge graph. "
"Special mode 'cross-repo-intelligence': skip extraction, only match Routes/Channels "
"across projects to create CROSS_HTTP_CALLS/CROSS_ASYNC_CALLS/CROSS_CHANNEL edges. "
"and Maven library dependencies across projects to create CROSS_HTTP_CALLS/"
"CROSS_ASYNC_CALLS/CROSS_CHANNEL/CROSS_LIBRARY_DEPENDS_ON/CROSS_LIBRARY_USED_BY edges. "
"Requires target_projects param. Ensure target projects have fresh indexes first.",
"{\"type\":\"object\",\"properties\":{\"repo_path\":{\"type\":\"string\",\"description\":"
"\"Path to the repository\"},"
Expand All @@ -282,7 +283,8 @@ static const tool_def_t TOOLS[] = {
"\"default\":\"full\",\"description\":\"All modes run type-aware LSP call/usage "
"resolution (per-file + cross-file). full: all files + similarity/semantic edges. "
"moderate: filtered files + similarity/semantic. fast: filtered files, no "
"similarity/semantic. cross-repo-intelligence: match Routes/Channels across projects.\"},"
"similarity/semantic. cross-repo-intelligence: match Routes/Channels and Maven library "
"dependencies across projects.\"},"
"\"target_projects\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},"
"\"description\":\"Projects to search for cross-repo links (cross-repo-intelligence mode). "
"Use [\\\"*\\\"] for all indexed projects. Run list_projects to see available projects.\"},"
Expand Down Expand Up @@ -1813,9 +1815,10 @@ static void append_cross_repo_summary(yyjson_mut_doc *doc, yyjson_mut_val *root,
/* Scan edge types for any CROSS_* edges and sum them */
int cross_total = 0;
yyjson_mut_val *cr = yyjson_mut_obj(doc);
static const char *cross_types[] = {"CROSS_HTTP_CALLS", "CROSS_ASYNC_CALLS",
"CROSS_CHANNEL", "CROSS_GRPC_CALLS",
"CROSS_GRAPHQL_CALLS", "CROSS_TRPC_CALLS"};
static const char *cross_types[] = {
"CROSS_HTTP_CALLS", "CROSS_ASYNC_CALLS", "CROSS_CHANNEL",
"CROSS_GRPC_CALLS", "CROSS_GRAPHQL_CALLS", "CROSS_TRPC_CALLS",
"CROSS_LIBRARY_DEPENDS_ON", "CROSS_LIBRARY_USED_BY"};
for (int t = 0; t < (int)(sizeof(cross_types) / sizeof(cross_types[0])); t++) {
for (int i = 0; i < schema->edge_type_count; i++) {
if (strcmp(schema->edge_types[i].type, cross_types[t]) == 0) {
Expand Down Expand Up @@ -2462,7 +2465,7 @@ static char *handle_cross_repo_mode(const char *repo_path, const char *args) {
yyjson_doc_free(jdoc);

int total = result.http_edges + result.async_edges + result.channel_edges + result.grpc_edges +
result.graphql_edges + result.trpc_edges;
result.graphql_edges + result.trpc_edges + result.library_edges;
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
yyjson_mut_doc_set_root(doc, root);
Expand All @@ -2476,6 +2479,7 @@ static char *handle_cross_repo_mode(const char *repo_path, const char *args) {
yyjson_mut_obj_add_int(doc, root, "cross_grpc_calls", result.grpc_edges);
yyjson_mut_obj_add_int(doc, root, "cross_graphql_calls", result.graphql_edges);
yyjson_mut_obj_add_int(doc, root, "cross_trpc_calls", result.trpc_edges);
yyjson_mut_obj_add_int(doc, root, "cross_library_edges", result.library_edges);
yyjson_mut_obj_add_int(doc, root, "total_cross_edges", total);
yyjson_mut_obj_add_real(doc, root, "elapsed_ms", result.elapsed_ms);

Expand Down
59 changes: 55 additions & 4 deletions src/pipeline/pass_cross_repo.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* get a CROSS_* edge so the link is visible from either side.
*/
#include "pipeline/pass_cross_repo.h"
#include "pipeline/pass_cross_repo_maven.h"
#include "foundation/constants.h"
#include "foundation/log.h"
#include "foundation/platform.h"
Expand Down Expand Up @@ -46,6 +47,25 @@ static const char *cr_itoa(int v) {
return cr_ibuf;
}

bool cbm_cross_repo_project_list_alloc(char ***out, int cap, void *(*malloc_fn)(size_t)) {
if (!out) {
return false;
}
*out = NULL;
if (cap <= 0 || !malloc_fn) {
return false;
}
if ((size_t)cap > SIZE_MAX / sizeof(char *)) {
return false;
}
char **items = malloc_fn((size_t)cap * sizeof(*items));
if (!items) {
return false;
}
*out = items;
return true;
}

/* ── Helpers ─────────────────────────────────────────────────────── */

static const char *cr_cache_dir(void) {
Expand Down Expand Up @@ -112,6 +132,20 @@ static void delete_cross_edges(cbm_store_t *store, const char *project) {
cbm_store_delete_edges_by_type(store, project, "CROSS_GRPC_CALLS");
cbm_store_delete_edges_by_type(store, project, "CROSS_GRAPHQL_CALLS");
cbm_store_delete_edges_by_type(store, project, "CROSS_TRPC_CALLS");
cbm_store_delete_edges_by_type(store, project, "CROSS_LIBRARY_DEPENDS_ON");
struct sqlite3 *db = cbm_store_get_db(store);
if (!db) {
return;
}
sqlite3_stmt *st = NULL;
if (sqlite3_prepare_v2(db,
"DELETE FROM nodes WHERE project=?1 AND label='Library' "
"AND qualified_name GLOB '__library__*'",
CBM_NOT_FOUND, &st, NULL) == SQLITE_OK) {
sqlite3_bind_text(st, SKIP_ONE, project, CBM_NOT_FOUND, SQLITE_STATIC);
sqlite3_step(st);
sqlite3_finalize(st);
}
}

/* Insert a CROSS_* edge into a store. */
Expand Down Expand Up @@ -561,7 +595,12 @@ static int collect_all_projects(char ***out) {

int cap = CR_INIT_CAP;
int count = 0;
char **projects = malloc((size_t)cap * sizeof(char *));
char **projects = NULL;
if (!cbm_cross_repo_project_list_alloc(&projects, cap, malloc)) {
cbm_closedir(d);
*out = NULL;
return 0;
}

cbm_dirent_t *ent;
while ((ent = cbm_readdir(d)) != NULL) {
Expand All @@ -576,15 +615,25 @@ static int collect_all_projects(char ***out) {
continue;
}
if (count >= cap) {
cap *= PAIR_LEN;
char **tmp = realloc(projects, (size_t)cap * sizeof(char *));
if (cap > INT32_MAX / PAIR_LEN) {
break;
}
int new_cap = cap * PAIR_LEN;
if ((size_t)new_cap > SIZE_MAX / sizeof(*projects)) {
break;
}
char **tmp = realloc(projects, (size_t)new_cap * sizeof(*projects));
if (!tmp) {
break;
}
cap = new_cap;
projects = tmp;
}
/* Strip .db extension */
projects[count] = malloc(len - PAIR_LEN);
if (!projects[count]) {
break;
}
memcpy(projects[count], ent->name, len - CR_DB_EXT_LEN);
projects[count][len - CR_DB_EXT_LEN] = '\0';
count++;
Expand Down Expand Up @@ -660,6 +709,8 @@ cbm_cross_repo_result_t cbm_cross_repo_match(const char *project, const char **t
"operation", "CROSS_GRAPHQL_CALLS");
result.trpc_edges += match_typed_routes(src_store, project, tgt_store, tgt, "TRPC_CALLS",
"procedure", "procedure", "CROSS_TRPC_CALLS");
result.library_edges +=
cbm_cross_repo_match_maven_libraries(src_store, project, tgt_store, tgt);
result.projects_scanned++;

cbm_store_close(tgt_store);
Expand All @@ -677,7 +728,7 @@ cbm_cross_repo_result_t cbm_cross_repo_match(const char *project, const char **t
((double)(t1.tv_nsec - t0.tv_nsec) / CR_NS_PER_MS);

int total = result.http_edges + result.async_edges + result.channel_edges + result.grpc_edges +
result.graphql_edges + result.trpc_edges;
result.graphql_edges + result.trpc_edges + result.library_edges;
cbm_log_info("cross_repo.done", "project", project, "total", cr_itoa(total));

return result;
Expand Down
1 change: 1 addition & 0 deletions src/pipeline/pass_cross_repo.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ typedef struct {
int grpc_edges; /* CROSS_GRPC_CALLS edges created */
int graphql_edges; /* CROSS_GRAPHQL_CALLS edges created */
int trpc_edges; /* CROSS_TRPC_CALLS edges created */
int library_edges; /* CROSS_LIBRARY_DEPENDS_ON/CROSS_LIBRARY_USED_BY pairs created */
int projects_scanned;
double elapsed_ms;
} cbm_cross_repo_result_t;
Expand Down
Loading
Loading