Commit Graph
181 Commits
Author SHA1 Message Date
Matthew Prock f65afda0df feat(pipeline): emit USAGE edges for decorator applications (#208)
Decorators previously only created DECORATES edges. References like @login_required were invisible to find-references queries that walk CALLS/USAGE relationships. Both sequential (resolve_decorator) and parallel (resolve_def_decorators) paths now emit a USAGE edge alongside DECORATES. Empty {} properties avoid clobbering richer metadata from pass_calls when a function both has @decorator and calls decorator() directly. Using USAGE instead of CALLS keeps pass_tests' CALLS-scan from inferring false TESTS edges (decorated test function → decorator).
2026-05-08 21:36:04 +02:00
Martin Vogel c768b6154d fix(watcher): close residual gaps in #207
Follow-up to #207:
- cbm_watcher_new: NULL-check cbm_ht_create() and free w on OOM so
  later watch/unwatch/touch don't dereference a NULL hash table.
- cbm_watcher_watch_count: drop const from the signature and remove
  the const_cast around projects_lock. The function necessarily
  touches synchronization primitives so a const receiver was
  misleading; all current callers pass a non-const pointer.
2026-05-08 21:33:06 +02:00
Matthew Prock 8fbdb0fa20 fix(thread-safety): eliminate races in log mutex, watcher, and index threads (#207)
- http_server: replace lazy log mutex init with 3-state UNINIT/INITING/INITED CAS pattern; cbm_ui_log_init() called from main before thread creation, also still invoked lazily from cbm_ui_log_append() so early single-threaded logs are not dropped
- watcher: protect projects hash table with cbm_mutex_t (watch/unwatch/touch/watch_count/free); poll_once snapshots project pointers under lock then iterates without it so git I/O and indexing don't block watch/unwatch
- watcher: handle state_new() OOM in watch path
- compat_thread: add cbm_thread_detach() for POSIX and Windows; both join() and detach() clear the handle on success for consistent lifecycle tracking
- http_server: detach index job threads to prevent handle leaks
2026-05-08 21:28:00 +02:00
Martin Vogel 9653e72309 fix(cypher,store): close residual OOM gaps in #206
Follow-up to #206. Adds the allocation-check coverage that the original
PR did not reach:

- store: NULL-check malloc in cbm_store_get_schema node-labels and
  edge-types blocks; replace safe_realloc with non-destructive realloc +
  cleanup so a partial result is freed (and node-labels block freed via
  cbm_store_schema_free) instead of leaked.
- cypher: NULL-check heap_strdup return in parse_props (key/value),
  parse_rel_types (first and subsequent types), and parse_in_list (op
  and list values). Each failure path frees prior heap_strdup'd entries
  before returning.
- cypher: parse_case_expr realloc-failure cleanup now also frees
  then_val for the just-parsed branch and for each previously stored
  branch, not just the when_expr trees.
2026-05-08 20:23:37 +02:00
Matthew Prock 1bbba506b5 fix(cypher,store): prevent crashes from buffer overflow, OOM, and NULL stmts (#206)
- cypher: bounds check in lex_string_literal (4096-byte stack buffer, escapes still consumed past truncation)
- cypher: NULL checks + non-destructive realloc with cleanup in parse_props, parse_rel_types, parse_in_list, parse_case_expr
- store: sqlite3_prepare_v2 return-code checks in cbm_store_get_schema and collect_pkg_names; partial-output cleanup
- tests: regression test for >4096-byte string literal truncation
2026-05-08 20:10:51 +02:00
Martin Vogel 4fdcdd4239 fix(security): close open scanner alerts
Dependabot/CodeQL #33 — postcss XSS GHSA-qx2v-qp2m-jg93:
  npm audit fix in graph-ui (8.5.8 -> 8.5.14, above the <8.5.10 vuln range)

CodeQL #39 — TOCTOU race in artifact.c ensure_gitattributes():
  Replace stat() + fopen() with open(O_WRONLY|O_CREAT|O_EXCL).
  Atomic create-only-if-absent closes the check-vs-write window.
  Falls through to merge driver setup if file already exists.

CodeQL #55 — pip install not pinned in release.yml:
  Pin build==1.3.0 and twine==6.2.0. Comment explains why
  --require-hashes is not used (transitive-deps overhead).

Dismissed (won't-fix):
  - #56 contents: write — required for 'gh release edit --draft=false';
    no narrower permission exists.
  - #54-51 Crystal grammar warnings — vendored upstream code.
  - #50-40 Agda grammar warnings — vendored upstream code.
2026-05-05 00:51:52 +02:00
Martin Vogel 5f814e469c fix(pass_pkgmap): use cbm_strndup for Windows compatibility
strndup is a POSIX/GNU extension not available in mingw clang on
Windows. Replace 6 bare strndup() calls with cbm_strndup() and
include foundation/compat.h, matching the pattern already used in
pass_calls.c.
2026-05-04 20:48:20 +02:00
test 2c8be91757 Merge branch 'worktree-add-new-languages'
# Conflicts:
#	internal/cbm/lang_specs.c
2026-04-16 10:47:10 +02:00
test e7893a2390 Add gRPC stub detection in call resolution and chained call extraction
- pass_parallel.c: detect gRPC calls when resolved QN contains
  ServiceClient/ServiceGrpc/Servicer — emits GRPC_CALLS edges for
  calls resolved to generated protobuf client interfaces
- pass_parallel.c: emit_grpc_edge falls back to resolved QN when
  callee_name alone doesn't contain service.method pattern
- extract_calls.c: add resolve_chained_selector() for iterative
  extraction of chained method calls (NewClient(conn).GetBar →
  "NewClient.GetBar") without recursion

Known limitation: Go receiver-method chained calls like
pb.NewCartServiceClient(conn).GetCart() in rpc.go are not yet
extracted as CALLS edges — the Go grammar's AST structure for
these patterns needs dedicated investigation.
2026-04-16 00:23:06 +02:00
testandDustin Obrecht 2343f8efba feat: generic package/module resolution for IMPORTS edges across 10 languages
Bare import specifiers (@myorg/pkg, github.com/foo/bar, use my_crate::foo)
previously produced zero IMPORTS edges. This adds manifest-aware resolution
during parallel extraction for JS/TS (package.json), Go (go.mod),
Rust (Cargo.toml), Python (pyproject.toml), PHP (composer.json),
Java (pom.xml), Gradle (build.gradle), Dart (pubspec.yaml),
Elixir (mix.exs), and Ruby (*.gemspec).

Workers parse manifest files during extraction with zero extra I/O,
entries are merged into a hash table before registry build, and
cbm_pipeline_resolve_module() provides unified resolution with
prefix matching for Go/Java/PHP path-based specifiers.

Closes #180.
Based on #184 by dLo999 (JS/TS package map approach).

Co-Authored-By: Dustin Obrecht <dustin@kurtnoble.com>
2026-04-15 23:57:09 +02:00
testandDustin Obrecht 9021c22b14 feat: include property definitions per label in get_graph_schema
Adds per-label/type property key discovery via json_each() so users can
see which properties are available for Cypher queries without trial and
error. Base columns listed first, JSON keys appended (capped at 50).

Closes #179.
Based on #181 by dLo999.

Co-Authored-By: Dustin Obrecht <dustin@kurtnoble.com>
2026-04-15 23:56:03 +02:00
testandDustin Obrecht 404b5f822c feat: add Kiro CLI support (#96)
Detect ~/.kiro/ directory, auto-configure MCP at ~/.kiro/settings/mcp.json
using standard mcpServers format. Adds install, uninstall, detection, and test.

Based on #174 by dLo999, rebased onto refactored install infrastructure.

Co-Authored-By: Dustin Obrecht <dustin@kurtnoble.com>
2026-04-15 23:56:03 +02:00
test 8babe67bea feat: add persistent artifact storage for team sharing
Add .codebase-memory/graph.db.zst — a zstd-compressed knowledge graph
artifact that can be committed to the repo. Teammates bootstrap from
the artifact instead of running a full reindex from scratch.

- Vendor zstd 1.5.7 (amalgamated build) for 8-13:1 compression
- Two-tier export: zstd -9 + index stripping for explicit index,
  zstd -3 for watcher/incremental auto-updates
- Import: decompress → integrity check → auto-recreate indexes
- Bootstrap in handle_index_repository: when no local DB exists but
  artifact is present, import first then run incremental
- Auto-create .gitattributes with merge=ours to prevent conflicts
- Fix: add missing idx_edges_url_path to create_user_indexes and
  url_path_gen generated column to init_schema
- 13 new tests (5 zstd wrapper + 8 artifact round-trip/edge cases)
2026-04-15 23:56:03 +02:00
test 81385d08eb Add gRPC/GraphQL/tRPC service detection with protobuf Route extraction
Pipeline: gRPC/GraphQL/tRPC client libs in service_patterns, edge emitters
in pass_parallel, __grpc__ Route nodes from .proto service defs in
pass_route_nodes, cross-repo matchers in pass_cross_repo. Also adds MQTT,
NATS, Dapr async patterns.

Protobuf extraction: service as Class, rpc as Function with rpc_name
fallback in func_name_node. Route nodes created by line-range matching
rpc Functions to enclosing service Classes.

Tested: Online Boutique protos produce 16 gRPC Route nodes.
2026-04-15 23:53:42 +02:00
test b6eefe014c Add multi-galaxy UI layout and cross-repo architecture summary
Backend (http_server.c):
- Layout API detects CROSS_* edges and loads linked project graphs
- Each linked project computed at radial offset as satellite galaxy
- Response includes linked_projects with nodes, edges, offset

Frontend:
- LinkedProject type in types.ts
- GraphScene renders satellite galaxies at offset positions
- NodeCloud/EdgeLines accept opacity prop for dimmed rendering

Tool integration (mcp.c):
- get_architecture includes cross_repo_links summary
- Extract append_cross_repo_summary helper for linter compliance
2026-04-15 23:53:42 +02:00
Martin Vogel c5ad6e8c59 Add cross-repo intelligence mode with CROSS_* edge types
New index_repository mode="cross-repo-intelligence" that matches Routes,
Channels, and async topics across indexed projects:

- CROSS_HTTP_CALLS: matches HTTP_CALLS edges against Route nodes in
  other projects via deterministic QN (__route__METHOD__/path)
- CROSS_ASYNC_CALLS: matches ASYNC_CALLS edges by broker + topic
- CROSS_CHANNEL: matches Channel nodes (EMITS/LISTENS_ON) by name +
  transport across projects

Edges are written bidirectionally: both source and target project DBs
get a CROSS_* edge so the link is visible from either side.

Usage: index_repository(repo_path="/path", mode="cross-repo-intelligence",
       target_projects=["*"])

New files: src/pipeline/pass_cross_repo.c/.h
Modified: src/mcp/mcp.c (handler + tool schema), Makefile.cbm
2026-04-15 23:53:42 +02:00
Martin Vogel 99723b3626 Improve error handling, diagnostics, and cancellation across MCP tools and CLI
- Tool handlers: set isError:true on actual failures (delete_project, manage_adr,
  detect_changes), include errno context in system errors, add structured hints
  for empty results (search_graph, query_graph, trace_path, list_projects, index_status)
- verify_project_indexed: include available projects list in error response
- CLI: extract text from MCP envelope for human-readable output, errors to stderr,
  exit code 1 on tool errors, --json flag for raw output
- Cancellation: handle notifications/cancelled, track active pipeline in server
  struct, signal handler cancels in-progress pipeline and releases lock, watcher
  checks g_shutdown before starting new indexing
2026-04-15 23:53:42 +02:00
Martin VogelandTommy f71fded895 Cherry-pick extraction and Cypher improvements from PR #162
- Enum member extraction: C#/Java/TS/C++ enum values as Variable nodes
- JS/TS destructured variable splitting: const { A, B, C } = require()
  emits individual Variable nodes instead of one blob
- Cypher -- SQL-style single-line comments
- Cypher in_degree/out_degree virtual node properties (thread-safe
  via binding store pointer, enables dead code detection via Cypher)
- Cypher regex matching in inline property filters
- Resolution tiebreaking: test/mock QN deprioritization and C# field
  type hint resolution for obj.Method() disambiguation

Co-Authored-By: Tommy <Koolerx@users.noreply.github.com>
2026-04-15 23:53:42 +02:00
test ea98c91cf5 Add 77 extension mapping tests for new languages
Add automated extension-to-language mapping tests for all new grammars
that have file extensions. Removes conflicting extensions:
- .blade.php: compound extension, handled by userconfig system
- .env*: filenames, not extensions (no auto-discovery for dotfiles)
- .sv/.svh: already mapped to Verilog, SystemVerilog uses same grammar
2026-04-15 22:28:31 +02:00
test b2b48f8b0d Add 89 new tree-sitter grammars (66 to 155 languages)
Vendor, wire up, and compile 89 new tree-sitter grammars, expanding
language support from 66 to 155 languages. All grammars pass security
audit (no dangerous patterns in scanner.c files).

New programming languages (31):
  Solidity, Typst, GDScript, Gleam, PowerShell, Pascal, D, Nim, Scheme,
  Fennel, Fish, AWK, Zsh, Tcl, Ada, Agda, Racket, Odin, ReScript,
  PureScript, Nickel, Crystal, Teal, Hare, Pony, Luau, Janet, Sway,
  NASM, Assembly, TLA+, Pkl, Cairo, Move, Squirrel, ISPC, FunC, Smali

New config/data/IDL formats (31):
  Just, Astro, Blade, Go Template, Templ, Liquid, Jinja2, Prisma,
  Hyprlang, DotEnv, Diff, WGSL, KDL, JSON5, Jsonnet, RON, Thrift,
  Cap'n Proto, Properties, SSH Config, BibTeX, Starlark, Bicep, CSV,
  Requirements, HLSL, VHDL, SystemVerilog, DeviceTree, Linker Script,
  GN, Kconfig, BitBake, TableGen, Slang, LLVM IR, Smithy, WIT,
  Go Mod, Mermaid, RST, Beancount, Puppet, PO, Regex, JSDoc,
  gitattributes, gitignore, Apex, SOQL, SOSL

Infrastructure:
  - scripts/new-languages.json: manifest for all new languages
  - scripts/generate-lang-code.py: generates boilerplate from manifest
  - scripts/audit-grammar-security.sh: pre-vendoring security scanner
  - Fixed angle-bracket includes in 18 grammars
  - Fixed PureScript scanner const mismatch
  - Fixed VHDL scanner void* API signatures
  - Fixed RST tree_sitter_rst/ subdirectory include paths
  - Copied crystal unicode.c (extra scanner dependency)

All new languages start with minimal lang specs (module_types only).
Function/class/call extraction specs to be refined incrementally.
2026-04-15 21:28:51 +02:00
Martin Vogel d33b9e45d9 Fix RSS not dropping after delete_project: add mem_collect + immediate purge
- delete_project now calls cbm_mem_collect() after closing the database
  to return freed pages to OS immediately
- Set purge_delay=0 (was 1000ms) so mimalloc purges freed pages without delay
- Set purge_decommits=1 explicitly so macOS uses MADV_FREE_REUSABLE
  (immediate RSS accounting) instead of MADV_FREE (lazy, RSS stays high)

Before: deleting Linux kernel index left 8.1G RSS (2.1G dirty pages)
After: dirty pages purged immediately, RSS reflects actual usage
2026-04-07 00:53:39 +02:00
Martin VogelanddLo999 6f268d0f91 Respect nested .gitignore files during indexing, security audit all variants
Nested .gitignore support (fixes #178):
- Load per-subdirectory .gitignore during walk, match paths relative to
  the gitignore's directory via local_rel_path()
- Root and nested gitignores stack independently
- Owned gitignores collected and freed at walk end (avoids use-after-free
  from borrowed pointers on the iterative stack)

Security:
- Run security-strings/install/network + ClamAV + Windows Defender on
  ALL binary variants (standard + UI), not just standard
- Whitelist UI bundle URLs (React, Three.js, Google Fonts, Tailwind, W3C)

Co-Authored-By: dLo999 <dLo999@users.noreply.github.com>
2026-04-06 19:44:16 +02:00
Martin Vogel 64179b8888 Fix tool descriptions: add moderate mode to index_repository, since param to detect_changes 2026-04-06 18:08:47 +02:00
Martin Vogel a515fec7bd Fix update --dry-run: skip version check so dry-run output is shown
check_already_latest() exits early before printing dry-run info when
the running version matches the latest release. Skip this check in
dry-run mode so the user sees what would happen.
2026-04-06 17:34:35 +02:00
Martin Vogel 616a4307df Fix Windows agent detection paths to use home_dir consistently
Zed: AppData/Local/Zed, Kilocode/VSCode: AppData/Roaming/Code/...
Tests now have #ifdef _WIN32 branches matching the detection paths.
2026-04-06 14:01:03 +02:00
Martin Vogel 74c5697d20 Fix ASan leak in corpus token_map and Windows/Linux vector blob assembly
- semantic.c: free strdup'd keys+values in token_map via cbm_ht_foreach
  before cbm_ht_free (44KB leak in 7920 allocations)
- code_vectors_blob.S: add Windows COFF branch (.rdata,"dr") alongside
  macOS Mach-O and Linux ELF sections
2026-04-06 13:43:48 +02:00
Martin Vogel 2350240c1d Decouple security gate from pipeline, fix clang-format-20 and Linux agent detection
Workflow:
- Split _lint.yml (cppcheck + clang-format) from _security.yml
  (security-static + codeql-gate)
- Dry Run: security runs as independent island, not blocking
  lint → test → build → smoke/soak
- Release: security only blocks final verify step

Fixes:
- pass_semantic_edges.c: typedef hyperplane_row_t avoids function-returning-
  array-pointer syntax that clang-format-20 rejects
- cli.c: Linux agent detection uses home_dir-relative .config/ paths
  instead of cbm_app_config_dir() which ignores the test home_dir
2026-04-06 13:27:43 +02:00
Martin VogelandKoolerx a0715ff1eb Add JS/TS IMPORTS resolution, Channel schema, lint cleanup
Features:
- Relative import resolution for JS/TS/Python/Ruby (./foo, ../bar,
  leading dots) via cbm_pipeline_resolve_relative_import in fqn.c
- Generic Channel detection: Socket.IO emit/on, EventEmitter patterns
  produce Channel nodes with EMITS/LISTENS_ON edges and transport
  property (extract_channels.c)
- Constant resolution trick: `const EVENT = "foo"; emit(EVENT)` resolves
  the channel name through a per-file constant table

Lint fixes (337 errors across 16 files):
- Named constants replacing all magic numbers (enums/defines)
- Cognitive complexity reduced via helper extraction (table-driven
  sqlite_writer, pipeline predump passes, graph_buffer dump phases)
- SQLITE_TRANSIENT int-to-ptr workaround in store.c + mcp.c
- clang-format + cppcheck clean

Co-Authored-By: Koolerx <tommy@koolerx.com>
2026-04-06 12:41:31 +02:00
Martin VogelandKoolerx 647af0b57c Add BM25 full-text search + C# Interface extraction fixes
Ports four targeted improvements from #162 (Koolerx):

- FTS5 BM25 ranked search via a new `query` parameter on search_graph.
  Uses a contentless nodes_fts virtual table populated at dump time with
  a cbm_camel_split() SQL function that splits camelCase identifiers
  (updateCloudClient -> update Cloud Client) so tokenized word queries
  match identifier internals. BM25 rank is boosted by node label
  (Function/Method +10, Route +8, Class/Interface/Type/Enum +5) and
  noise labels (File/Folder/Module/Variable) are filtered out. The new
  path is opt-in via the query parameter; regex name_pattern and vector
  semantic_query paths are untouched.

- Enable SQLITE_ENABLE_FTS5 in the vendored sqlite3 build flags.

- Rebuild nodes_fts after incremental reindex. The btree dump path
  bypasses any FTS5 triggers, so the index is wiped and repopulated via
  delete-all + INSERT .. SELECT after each incremental merge.

- Add Interface to the label filter on cbm_registry_add in both the
  parallel and sequential definition passes, so C#/Java class
  declarations like Foo : IBar can resolve IBar to an INHERITS edge
  target during enrichment.

- Add an explicit C# base_list handler to extract_base_classes() that
  iterates named children directly instead of returning the raw node
  text. Without this the fallback path returned ": IExamService" (with
  the leading separator) and registry lookup always failed, so C#
  INHERITS edges to interfaces never resolved.

Co-Authored-By: Koolerx <Koolerx@users.noreply.github.com>
2026-04-06 12:41:30 +02:00
Martin Vogel 8a06d78ac7 Parallelize post-passes, fix mode filtering + semantic edge quality
- Parallelize pass_similarity and pass_semantic_edges via worker pool with
  thread-local edge buffers; sequential final merge since gbuf is not
  thread-safe. Adds cbm_lsh_query_into() as a thread-safe variant with
  caller-provided candidate buffer.

- Add activatable profiling subsystem (CBM_PROFILE=1 env or --profile flag)
  for step-level timing of extract, resolve, corpus build, vector phases,
  and sqlite dump. Zero overhead when disabled.

- Fix cbm_index_mode_t enum mismatch between pipeline.h (FULL=0, MODERATE=1,
  FAST=2) and discover.h (FULL=0, FAST=1). mode=fast silently no-op'd
  fast-discovery filtering because discover.c compared against the wrong
  value. Linux kernel fast mode went 1:40 -> 3:11 as a result; now back to
  1:40. Broaden the filter guard to mode != CBM_MODE_FULL so MODERATE and
  FAST both get aggressive discovery.

- Clamp cbm_sem_combined_score output to [0, 1]. The proximity multiplier
  returns up to 1.10 as a same-file boost which could push the final
  cosine score above 1.0.

- Short-circuit semantic scoring when MinHash jaccard >= 0.95. Exact
  near-clones are already emitted as SIMILAR_TO edges; returning 0 here
  avoids flooding SEMANTICALLY_RELATED with cross-service copy-paste
  boilerplate and frees the edge budget for genuine vocabulary-bridged
  relations.

- Validate search_graph semantic_query as an array of strings and return
  a clear error for a single-string input. Update the tool description
  to spell out the requirement explicitly with an example.

- JSON-escape user-controlled strings (callee names, call arguments,
  URL paths, import local_name) in call/argument properties. Introduces
  cbm_json_escape() in foundation/str_util.

- Skip SQLite pending_byte_page (file offset 0x40000000) during raw page
  writes in sqlite_writer to avoid corrupting databases that cross the
  1 GiB boundary.

- Migrate pretrained vector blob from UniXcoder (51K tokens) to
  nomic-embed-code (40856 tokens x 768d int8). Includes the extraction
  script under scripts/extract_nomic_vectors.py.
2026-04-06 12:41:30 +02:00
Martin Vogel bf700780cc Fix scoring: per-keyword min-cosine replaces merged vector averaging 2026-04-06 12:41:30 +02:00
Martin Vogel e81a796fe6 Embed Nomic nomic-embed-code pretrained vectors (40K tokens × 768d) for semantic search quality
Major quality improvement: replace random index vectors with pre-trained
Nomic nomic-embed-code token embeddings. Tokens like 'error' and 'exception' now start
with similar vectors (learned from millions of code repos) instead of
arbitrary random projections. Co-occurrence enrichment adds project-specific
context on top.

Architecture:
- vendored/nomic/code_vectors.bin: 37.7MB raw int8 vectors
- vendored/nomic/code_vectors_blob.S: assembler .incbin (instant build)
- vendored/nomic/code_vectors.h: extern declarations + pretrained_vec_at()
- vendored/nomic/code_tokens.h: 40856 token strings (575KB)
- semantic.c: cbm_sem_random_index() now looks up pretrained vectors first,
  falls back to sparse random for unknown tokens
- CBM_SEM_DIM raised from 256 to 768 to match Nomic nomic-embed-code

Also: RRI (Reflective Random Indexing), code pattern vocabulary injection,
120+ abbreviation expansions, callee/caller/body token enrichment,
label filter (Function/Method/Class only) in vector search SQL.

Binary size: 136MB → 169MB (+33MB from embedded vectors).
Search quality: keyword queries return relevant error-handling functions.
Domain-specific keyword queries return the expected functions.
2026-04-06 12:41:29 +02:00
Martin Vogel 7a9b7db830 Add semantic_query to search_graph: vector search via cbm_cosine_i8 SQL function
Vector search pipeline (end-to-end):
- store.c: cbm_cosine_i8 custom SQLite function (int8 dot product with
  sqrt magnitude), registered at store open time
- store.c: cbm_store_vector_search() builds merged query vector from
  keywords via base RI vectors (xxHash), int8-quantizes, runs SQL query
  with JOIN nodes ON node_id = id for metadata
- mcp.c: search_graph gains semantic_query param (array of strings),
  returns semantic_results alongside regular results
- sqlite_writer.c: fixed build_vector_record to include node_id in
  record body (matches build_node_record pattern)
- mcp.c: use yyjson_mut_obj_add_strcpy (not add_str) to avoid
  use-after-free when vector results are freed before JSON serialization

Quality note: base RI vectors at query time don't capture co-occurrence
enrichment — results are moderate quality. Storing enriched token vectors
would improve this significantly (future work).
2026-04-04 17:14:47 +02:00
Martin Vogel 8a0ad0489b WIP: Algorithmic semantic embeddings + indexing modes (checkpoint before vector storage) 2026-04-04 16:17:58 +02:00
Martin Vogel 1d30971ff0 Bump vendored deps: Mongoose 7.21, SQLite 3.51.3, mimalloc 3.2.8
Mongoose 7.20 → 7.21:
  Fixes 3 CVEs disclosed 2026-04-02:
  - CVE-2026-5244: preauth RCE via TLS heap buffer overflow
  - CVE-2026-5245: mDNS stack overflow RCE (34-byte UDP packet)
  - CVE-2026-5246: mTLS bypass with P-384 certificates

SQLite 3.49.1 → 3.51.3:
  Fixes WAL-reset database corruption bug (we use WAL mode).
  Also fixes nested EXISTS query errors, POSIX lock deadlock,
  and FTS5 memory error.

mimalloc 2.1.9 → 3.2.8 (v2 → v3):
  Eliminated thread-local segments for better cross-thread sharing,
  lower fragmentation, faster TLS on Windows, improved calloc.
  API change: mi_option_eager_commit → mi_option_arena_eager_commit.

Linux kernel benchmark: 1:42 (no regression). All 2718 tests pass.
2026-04-03 23:01:06 +02:00
Martin Vogel 09ce20afc8 Improve MinHash quality: leaf-only tokens, structural weighting, unique trigram gate
Four changes to reduce false positives from 382K to 58K SIMILAR_TO edges
on the Linux kernel while maintaining ~98% precision:

1. MIN_NODES raised to 30 (leaf tokens) — aligns with BigCloneBench
   standard of 50 raw source tokens / 6 lines minimum clone size

2. collect_ast_tokens now records LEAF nodes only, not internal grammar
   nodes. Leaf-only counting is language-agnostic: leaves correspond to
   actual source tokens regardless of grammar verbosity (C tree-sitter
   produces 2x more internal nodes than Python for the same logic)

3. hash_trigrams tracks unique structural trigram count via hash set.
   Functions with < 32 unique structural trigrams are skipped — too few
   distinct features for K=64 MinHash to produce reliable estimates

4. Structural-weighted MinHash via repetition: each trigram gets weight
   0-3 based on count of non-normalised tokens (I/S/N/T = normalised).
   Weight-0 trigrams (all-normalised, e.g. I|I|I) are pure noise and
   skipped entirely. Weight 1-3 trigrams use repetition-based weighted
   MinHash — higher weight = more hash attempts per seed = more likely
   to dominate the signature. Achieves IDF-like effect without needing
   corpus-wide statistics.

Also adds O(1) hash-set dedup in LSH query (replacing O(n) linear scan)
and bucket size cap of 200 to skip oversized buckets.

Linux kernel: 1:41, similarity 7.7s, 395K fp, 58K edges, ~98% precision.
Tests updated with larger Go functions to meet new thresholds.
2026-04-03 22:35:01 +02:00
Martin Vogel 452f5a7b1f Add MinHash fingerprinting and SIMILAR_TO edges for near-clone detection
Compute K=64 MinHash signatures from normalized AST node-type trigrams
during function extraction, then generate SIMILAR_TO edges via LSH
(b=32, r=2) for function pairs with Jaccard >= 0.95.

- src/simhash/minhash.{h,c}: MinHash compute, Jaccard, hex encode/decode,
  LSH index with band hashing for O(n) candidate generation
- src/pipeline/pass_similarity.c: post-pass reads fingerprints from node
  properties, builds LSH index, emits SIMILAR_TO edges with jaccard and
  same_file metadata. Same-language only, max 10 edges per node.
- internal/cbm/cbm.h: fingerprint fields on CBMDefinition
- internal/cbm/extract_defs.c: compute_fingerprint() hook at 3 extraction
  sites after complexity, skip functions with < 10 AST body nodes
- pass_definitions.c + pass_parallel.c: serialize fingerprint to "fp" hex
  in properties_json for both sequential and parallel pipeline paths
- pipeline.c + pipeline_incremental.c: register pass_similarity in both
  full and incremental post-pass lists
- tests/test_simhash.c: 28 tests across 4 suites (core, LSH, edge gen,
  pipeline integration with generated Go project + incremental)
2026-04-03 20:06:33 +02:00
Martin VogelanddLo999 e07443b75f Add configurable database directory via CBM_CACHE_DIR env var
All hardcoded ~/.cache/codebase-memory-mcp paths now route through
cbm_resolve_cache_dir() in platform.c. Priority: CBM_CACHE_DIR env
var > default ~/.cache/codebase-memory-mcp.

Added db_path_for_project() helper in http_server.c to eliminate 5
copies of the same path construction pattern.

Fixes #154

Co-Authored-By: dLo999 <dLo999@users.noreply.github.com>
2026-04-03 18:06:52 +02:00
Martin VogelanddLo999 54c032528d Skip update when already on latest version
Check GitHub releases/latest redirect header before downloading.
Saves bandwidth and avoids unnecessary index rebuilds.

- "Already up to date" when version matches or is ahead
- --force flag to bypass the check
- Graceful degradation when network is unavailable
- Uses same curl dependency as the download itself

Fixes #142

Co-Authored-By: dLo999 <dLo999@users.noreply.github.com>
2026-04-03 17:41:27 +02:00
Martin VogelandSelene29 3463987728 Replace O(n*e) edge mapping with binary search in layout endpoint
Build sorted node-ID array, binary search each edge's endpoints.
O(n log n + e log n) instead of O(n * e) — eliminates multi-second
hangs on large projects. Rejected edges freed immediately to reduce
peak memory.

Fixes #169

Co-Authored-By: Selene29 <Selene29@users.noreply.github.com>
2026-04-03 17:21:23 +02:00
Martin VogelandSelene29 0dc3d67279 Fix layout JSON: handle invalid UTF-8 and NaN in serialization
One non-UTF-8 node name crashed the entire /api/layout endpoint
(HTTP 500). Force layout can also produce NaN/Inf positions.

- Use YYJSON_WRITE_ALLOW_INVALID_UNICODE (matches MCP serializer)
- Sanitize NaN/Inf: positions default to 0.0, size to 1.0
- Log yyjson error code on serialization failure

Co-Authored-By: Selene29 <Selene29@users.noreply.github.com>
2026-04-03 17:06:39 +02:00
Martin Vogelandslvnlrt b2915b4c32 Fix cbm_find_cli PATH delimiter and S_IXUSR check on Windows
PATH uses ; on Windows, not : — strtok with : splits C:\Users at
the drive letter colon, producing garbage paths. Also skip S_IXUSR
check on Windows since stat() doesn't set Unix permission bits.

Fixes #159

Co-Authored-By: slvnlrt <slvnlrt@users.noreply.github.com>
2026-04-03 16:49:46 +02:00
Martin Vogelandslvnlrt a250ad27f5 Detect actual binary path at runtime in install command
Replaces hardcoded ~/.local/bin/ with OS-native runtime detection:
- Windows: GetModuleFileNameA()
- macOS: _NSGetExecutablePath()
- Linux: readlink("/proc/self/exe")
Falls back to ~/.local/bin/ if detection fails.

Fixes install.ps1 placing binary in $LOCALAPPDATA/Programs/ while
configs point to non-existent ~/.local/bin/ path.

Fixes #158

Co-Authored-By: slvnlrt <slvnlrt@users.noreply.github.com>
2026-04-03 16:41:44 +02:00
Martin Vogel 80e2752c09 Fix KiloCode config paths on Windows and macOS
KiloCode is a VS Code extension — uses the same base config dir.
Apply same platform-aware paths as Zed/VS Code: macOS uses
$HOME/Library/Application Support/Code/, Windows uses %APPDATA%/Code/.
2026-04-03 16:23:36 +02:00
Martin Vogelandjimpark 9b302eeb80 Fix Zed and VS Code config paths on Windows
Add cbm_app_config_dir() and cbm_app_local_dir() platform helpers:
- Windows: %APPDATA% / %LOCALAPPDATA%
- macOS: $HOME for Library/Application Support paths
- Linux: $XDG_CONFIG_HOME or ~/.config

Update all 6 Zed/VS Code path locations (detect, install, uninstall).
macOS uses $HOME directly for Library paths; Windows/Linux use the
new helpers. Consolidates userconfig.c XDG logic into platform.c.

Co-Authored-By: jimpark <jimpark@users.noreply.github.com>
2026-04-03 15:20:49 +02:00
Martin Vogel 05aeb64802 Fix include_connected: run BFS inbound+outbound separately
cbm_store_bfs doesn't support direction="both" — it silently falls
through to outbound only. Run two BFS passes (inbound + outbound)
and merge results, matching how handle_trace_call_path works.

Also fix use-after-free: use strcpy for BFS node names that get
freed before JSON serialization.
2026-04-03 14:52:29 +02:00
9412f0905a Wire up 6 silently-ignored search_graph/architecture/detect_changes params
search_graph: qn_pattern (regex on qualified_name), relationship
(EXISTS filter on edges), exclude_entry_points (filter nodes with
no inbound CALLS but outbound CALLS), include_connected (1-hop
neighbor names in response).

get_architecture: aspects array filters which sections are returned
(structure, dependencies, routes, or all).

detect_changes: scope param ("files" = just changed files, "symbols"
= files + impacted symbols).

Split functions to stay under CC=25 threshold.

Co-Authored-By: ahundt <ahundt@users.noreply.github.com>
Co-Authored-By: maplenk <maplenk@users.noreply.github.com>
2026-04-03 14:36:06 +02:00
Martin Vogelandmaplenk f25dafadff Add include_tests param to trace_path, mark test files in BFS results
When include_tests=false (default), test files are filtered from trace
results. When true, test nodes appear with is_test=true marker. Helps
answer "which tests cover this function's blast radius?"

Also adds tests for include_tests and risk_labels params.

Co-Authored-By: maplenk <maplenk@users.noreply.github.com>
2026-04-03 01:51:32 +02:00
Martin Vogelandhalindrome 7f79ce53a1 Fix watcher: detect dirty state inside git submodules
The watcher's git_is_dirty() only ran git status on the parent repo,
missing uncommitted changes inside submodules. Add a second check via
git submodule foreach --recursive (portable, works on Apple Git which
lacks --recurse-submodules).

Fixes #71

Co-Authored-By: halindrome <halindrome@users.noreply.github.com>
2026-04-03 01:22:51 +02:00
dbab4d372f Wire up risk_labels on trace_path, add --progress CLI flag
risk_labels: adds CRITICAL/HIGH/MEDIUM/LOW classification to BFS
results based on hop distance. Opt-in via risk_labels=true.

--progress: human-readable indexing progress on stderr. Log sink
replaces default output, maps pipeline events to [1/9]..[9/9] phases.

Co-Authored-By: halindrome <halindrome@users.noreply.github.com>
Co-Authored-By: gdilla <gdilla@users.noreply.github.com>
2026-04-02 23:47:40 +02:00