Open a .db file briefly, collect node/edge counts and root_path, * then append a JSON entry to arr. */
| 1325 | /* Open a .db file briefly, collect node/edge counts and root_path, |
| 1326 | * then append a JSON entry to arr. */ |
| 1327 | static void build_project_json_entry(yyjson_mut_doc *doc, yyjson_mut_val *arr, const char *dir_path, |
| 1328 | const char *name, size_t name_len, int64_t size_bytes) { |
| 1329 | (void)name_len; |
| 1330 | |
| 1331 | char full_path[CBM_SZ_2K]; |
| 1332 | snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, name); |
| 1333 | |
| 1334 | /* #704: key on the db's INTERNAL project name, not its filename. Node/edge |
| 1335 | * rows are tagged with the internal name, so a drifted filename (copied or |
| 1336 | * renamed db, legacy '.'-vs-'-' username twin) would otherwise report 0 |
| 1337 | * nodes/edges and be unresolvable. Skip ghost/empty/corrupt dbs entirely so |
| 1338 | * they don't appear as resolvable projects. */ |
| 1339 | char project_name[CBM_SZ_1K]; |
| 1340 | cbm_store_t *pstore = NULL; |
| 1341 | if (!db_internal_project_name(full_path, project_name, sizeof(project_name), &pstore)) { |
| 1342 | return; /* ghost / unreadable — not a resolvable project */ |
| 1343 | } |
| 1344 | |
| 1345 | int nodes = cbm_store_count_nodes(pstore, project_name); |
| 1346 | int edges = cbm_store_count_edges(pstore, project_name); |
| 1347 | char root_path_buf[CBM_SZ_1K] = ""; |
| 1348 | cbm_project_t proj = {0}; |
| 1349 | if (cbm_store_get_project(pstore, project_name, &proj) == CBM_STORE_OK) { |
| 1350 | if (proj.root_path) { |
| 1351 | snprintf(root_path_buf, sizeof(root_path_buf), "%s", proj.root_path); |
| 1352 | } |
| 1353 | cbm_project_free_fields(&proj); |
| 1354 | } |
| 1355 | cbm_store_close(pstore); |
| 1356 | |
| 1357 | yyjson_mut_val *p = yyjson_mut_obj(doc); |
| 1358 | yyjson_mut_obj_add_strcpy(doc, p, "name", project_name); |
| 1359 | yyjson_mut_obj_add_strcpy(doc, p, "root_path", root_path_buf); |
| 1360 | add_git_context_json(doc, p, root_path_buf[0] ? root_path_buf : NULL); |
| 1361 | yyjson_mut_obj_add_int(doc, p, "nodes", nodes); |
| 1362 | yyjson_mut_obj_add_int(doc, p, "edges", edges); |
| 1363 | yyjson_mut_obj_add_int(doc, p, "size_bytes", size_bytes); |
| 1364 | yyjson_mut_arr_add_val(arr, p); |
| 1365 | } |
| 1366 | |
| 1367 | /* list_projects: scan cache directory for .db files. |
| 1368 | * Each project is a single .db file — no central registry needed. */ |
no test coverage detected