Commit Graph
700 Commits
Author SHA1 Message Date
Martin Vogel a8fc901129 feat(helm): extract Helm/Go-template named templates and include calls
Helm chart helpers (.tpl) and Go templates produced no semantic graph — just a
flat key flood. Wire the existing gotemplate grammar for real structure:

- .tpl files map to the gotemplate language (Helm _helpers.tpl).
- {{ define "chart.fullname" }} becomes a Function node named after the
  template (the name is a string literal, not an identifier, so it's resolved
  in a dedicated walker branch).
- {{ include "x" . }} and {{ template "x" . }} resolve to the referenced
  template name instead of the bare `include` builtin, so they form CALLS
  edges to the define'd Function. template_action is added to the call set.

Lets you trace which charts include which named templates. Tests cover define
-> Function and include/template -> CALLS, plus the .tpl mapping.

Refs #338
2026-06-01 18:41:49 +02:00
Martin Vogel 1e1d40851c feat(lang): add CFML / ColdFusion support (cfscript + tag dialects)
Vendor the MIT-licensed cfmleditor/tree-sitter-cfml grammars and wire both
CFML dialects through the pipeline:

- .cfc components -> cfscript grammar (CBM_LANG_CFSCRIPT): a JS-like grammar, so
  function/method declarations, calls and imports extract with the shared JS/TS
  arrays. Components' functions become Function nodes.
- .cfm templates -> cfml tag grammar (CBM_LANG_CFML): tag-based (HTML-derived).
  Embedded <cfscript> functions extract via function_declaration; tag-based
  <cffunction name="..."> nodes are handled by a dedicated walker branch that
  reads the name attribute (cf_function_tag has no name field). Shared scanner
  headers are vendored at vendored/common/ so the grammar's ../../common/
  includes resolve without editing vendored sources.

Adds an ASCII case-insensitive compare for CFML's case-insensitive attributes.
Tests cover both dialects and the extension mapping. LICENSEs vendored.

Closes #38
2026-06-01 18:28:36 +02:00
Martin Vogel f16f9dcf01 feat(lang): add Qt QML language support
Vendor the MIT-licensed tree-sitter-qmljs grammar (a TypeScript superset with
declarative ui_* nodes) and wire .qml files through the full pipeline: language
enum, extension + display-name mapping, grammar shim, and a language spec that
reuses the JS/TS function/call/branch arrays and adds QML class/field/import
types (ui_inline_component, ui_property, ui_signal, ui_import).

QML files now produce Function nodes (incl. JS functions inside QML objects),
class/interface/enum nodes, imports and CALLS edges, so call chains through a
Qt project's .qml files can be traced. LICENSE vendored alongside the grammar.

Closes #42
2026-06-01 18:07:05 +02:00
Martin Vogel 2cad2fe0c3 feat(extract): fold HCL block labels into node names
HCL/Terraform blocks were named by their bare keyword, so every resource
collapsed to a single "resource" node and blocks were indistinguishable in the
graph. Fold the quoted labels into the name via the block's string_lit ->
template_literal children, so resource "aws_instance" "web" becomes
resource.aws_instance.web (and variable.region, module.vpc, etc). Each block is
now a distinct, query-friendly Class node. The dedicated terraform parser
(cbm_parse_terraform_source) is unchanged.

Closes #337
2026-06-01 17:52:29 +02:00
Martin Vogel f42d77244a feat(extract): verify GDScript/PowerShell/Luau extraction + fix PowerShell function names
GDScript (.gd), PowerShell (.ps1/.psm1/.psd1) and Luau (.luau) were wired into
the grammar table, lang specs and extension map but had no extraction coverage,
so the AST->graph visitor was never proven for them. Add extraction tests that
assert Function/Class nodes and CALLS are produced from representative source.

PowerShell's function_statement has no `name` field — the name is a
`function_name` child node — so resolve_func_name returned null and no Function
node was emitted. Resolve the name from that child, mirroring the Swift path.

Closes #186
Closes #35
Closes #39
2026-06-01 01:16:48 +02:00
Martin Vogel 10ce652152 feat(extract): extract C/C++ preprocessor macros as Macro nodes
#define directives were not represented in the graph. Object-like macros
(preproc_def) and function-like macros (preproc_function_def) are now emitted
as Macro nodes with a DEFINES edge from the file. A function-like macro keeps
its parameter list as the signature; the macro body is not descended into.
Applies to all C-preprocessor languages (C, C++, CUDA, GLSL, Objective-C, ISPC).

Closes #375
2026-06-01 00:59:36 +02:00
Martin Vogel 955b87d3fd feat(arch): replace single-level Louvain with multi-level Leiden community detection
The previous community detection ran a single local-moving pass with no
aggregation or refinement, so it fragmented graphs into hundreds of tiny,
sometimes internally-disconnected clusters (e.g. 275 on a mid-size repo).

Implement the Leiden algorithm (Traag, Waltman & van Eck 2019,
arXiv:1810.08473): local moving (fast, queue-based) -> refinement -> graph
aggregation, repeated until the partition can no longer be coarsened. The
refinement phase re-derives each community bottom-up from singletons, merging
only along edges, which guarantees every reported community is internally
connected. Aggregation seeds each level from the prior move-phase partition so
coarse structure carries over. A resolution parameter controls granularity.

Internals use a CSR graph (cbm_lg_t); self-loops are folded into the weighted
degree rather than materialised, so the modularity gain uses degree for the
null model and the adjacency for connectivity. cbm_louvain is preserved as a
thin wrapper over cbm_leiden(resolution=1.0) for API compatibility.

Tests: multi-level collapse (32-node clique chain -> few connected
communities), resolution control (path graph granularity), and a connectivity
checker proving the refinement guarantee; existing Louvain tests still pass.

Closes #57
2026-06-01 00:48:38 +02:00
Martin Vogel eb50569bed fix(extract): capture arrow methods returned from JS/TS factory functions
walk_defs stopped descending into a function body once the function itself
was extracted, so arrow methods of an object literal returned from a factory
(the Zustand actions-slice pattern) were never visited. Let JS/TS/TSX descend
into function bodies (as Wolfram already did) and resolve an arrow's name from
a 'pair' parent's key, so { addItem: (...) => {...} } is captured as a Function.
Anonymous nested arrows have no resolvable name and are skipped, so no noise.

Closes #341
2026-05-31 23:45:35 +02:00
Martin Vogel 1a636f1962 feat(r): box::use/library imports + module\$fn calls (#218, #219)
R had no import extraction at all (not in the import dispatch), so library(),
require(), source() AND box::use() all produced zero IMPORTS edges; and
module\$fn() calls were dropped because the call-callee resolver did not handle
R extract_operator function nodes.

#218: add parse_r_imports — recursively scan for call nodes and emit IMPORTS for
library/require/requireNamespace/loadNamespace/source (first arg) and for each
box::use(mod[syms], pkg/path[syms], ...) argument (module path = the spec text
before the [symbols] list). AST node types confirmed via a tree-sitter-R probe.

#219: handle extract_operator (R \$) as a call function node in
extract_callee_from_fields → emit "module.fn" so module\$fn() yields a CALLS
edge like other member calls.

Tests cover box::use + library + source imports and the \$-call; r_collect_imports
added to the recursion whitelist.
2026-05-31 23:07:50 +02:00
Martin Vogel d67329efbf test(smoke): update Antigravity E2E to 2026 CLI layout
The Phase 8 agent-install E2E checked the pre-unification Antigravity paths
(~/.gemini/antigravity/), which broke after the config-path fix. Point the
stub setup at ~/.gemini/antigravity-cli/ and assert the MCP server lands in
the shared ~/.gemini/config/mcp_config.json with AGENTS.md under
~/.gemini/antigravity-cli/. Verified end-to-end (smoke ALL PASSED).
2026-05-31 21:42:42 +02:00
Martin Vogel db6e99c0ea fix(discover): map .blade.php to Blade by default (#258)
Laravel Blade templates (*.blade.php) fell through to the single-extension
lookup and were mis-classified as PHP, so the PHP extractor tried to parse
Blade syntax. Add a built-in compound-extension table (checked before the
single-extension fallback and alongside user config) mapping .blade.php to
CBM_LANG_BLADE, so Blade files are discovered and parsed with the Blade
grammar. Combined with the now-non-blocking discovery gate (c29e6d5), this
resolves the "agent stuck on Blade files" report. Plain .php is unaffected.
2026-05-31 21:15:57 +02:00
Martin Vogel 13bd10812a fix(install): correct Antigravity CLI config paths (2026 unification)
Antigravity support targeted the pre-unification layout, so it never actually
configured the CLI:
- detection probed ~/.gemini/antigravity/ — the CLI now installs under
  ~/.gemini/antigravity-cli/ (brain/, mcp/, settings.json)
- MCP config was written to ~/.gemini/antigravity/mcp_config.json — Antigravity
  reads the SHARED ~/.gemini/config/mcp_config.json (mcpServers, command/args)
- the SessionStart hook + AGENTS.md targeted the stale dir

Point detection at ~/.gemini/antigravity-cli/, write the MCP server to the
shared ~/.gemini/config/mcp_config.json (creating ~/.gemini/config if needed),
and place AGENTS.md + the SessionStart reminder under ~/.gemini/antigravity-cli/.
Install, uninstall, install --plan, the detection test, and the README table
updated.
2026-05-31 21:02:51 +02:00
Martin Vogel 3be9ace6d5 fix(cypher): drop dead-store assignments flagged by cppcheck
The buffer-full guards in parse_node (label alternation) and with_proj_key
assigned to ll/kl right before break — never read again. cppcheck 2.20.0
(--ci) flags these as unreadVariable and fails the lint gate. Replace with a
bare break. No behavior change.
2026-05-31 21:02:51 +02:00
Martin Vogel a2cd1e7c07 fix(cypher): resync on unsupported WITH/RETURN expression (#373)
split(f.path,'/')[0] and similar unknown function-call / index
expressions left their trailing tokens unconsumed, desyncing the parser into
a misleading default star projection (columns f.name/f.qualified_name/
f.label, one blank row per node). parse_return_item now consumes the balanced
parentheses/brackets of an unknown call so the parser stays in sync: the
requested RETURN/WITH column shape is preserved (aliases intact), sibling
aggregates like count(*) still compute, and the unsupported expression simply
projects empty instead of corrupting the whole projection. Existing scalar
forms (labels(), toInteger()) are unaffected.
2026-05-31 20:40:55 +02:00
Martin Vogel 869341c709 feat(cypher): support COUNT(DISTINCT x) (#239)
count(DISTINCT x) was a parse error ("expected token type 85, got 9").
parse_aggregate_item now consumes an optional DISTINCT inside the call and
records it on the return item. Both aggregation paths track the set of unique
values per group and emit its size for COUNT(DISTINCT): the RETURN path reuses
the existing collect_lists machinery; the WITH path gains distinct_lists/
distinct_n fields. Plain COUNT and the other aggregates are unchanged.

Unit test: COUNT(DISTINCT f.label)=1 (all same label), count(f.label)=4
(non-distinct), COUNT(DISTINCT f.name)=4 (unique names). Smoke suite adds a
count(DISTINCT) query_graph check.
2026-05-31 20:22:55 +02:00
Martin Vogel 2a5515e586 feat(cypher): support label alternation MATCH (n:A|B) (#242)
openCypher node-label alternation was unsupported (parse error after the
first label). parse_node now consumes `:A|B|C` into a single "A|B|C" label
string (mirroring the existing relationship-type alternation). The seed path
unions per-label results (scan_alternation_labels), and target/hop label
filters use label_alt_matches, which ORs over the alternatives. Single-label
matching is unchanged.

Unit test (Function|Module → 5 rows; Function|Class → 4) plus a query_graph
alternation check in the smoke suite. Relationship-type alternation tests
remain green.
2026-05-31 20:11:12 +02:00
Martin Vogel b30e6d6443 feat(cypher): support label tests in WHERE — WHERE n:Label (#241)
openCypher label predicates in WHERE clauses were a parse error
("expected token type 67, got 73"). Parse `var:Label` in the WHERE leaf as
a condition with op=HAS_LABEL/value=Label, and evaluate it against the bound
node label in eval_condition (honoring NOT). Composes with AND/OR and works
in count(...) queries.

Unit test covers true/false/negated label predicates; smoke suite adds a
query_graph WHERE-label check.
2026-05-31 20:02:23 +02:00
Martin Vogel 3014867cb3 feat(cypher): apply WITH DISTINCT deduplication (#238)
The DISTINCT keyword on a WITH clause was parsed (r->distinct) but never
applied, so WITH DISTINCT silently returned duplicate rows. Add a dedup pass
in execute_with_clause that drops projected rows whose full value tuple
duplicates an earlier one (first occurrence kept), gated on wc->distinct.
No-op for the aggregation path (which already collapses per group).

Unit test (4 same-label functions collapse to 1 row; control without DISTINCT
keeps 4) plus a query_graph WITH DISTINCT check added to the smoke suite.
2026-05-31 19:53:25 +02:00
Martin Vogel 6c71244e63 feat(hooks): SessionStart reminders for Codex, Gemini CLI, Antigravity (#330)
Codex, Gemini CLI, and Antigravity all gained lifecycle-hook support, so give
them the same non-blocking SessionStart reminder Claude Code has — stdout is
injected as session context, nudging the agent to use codebase-memory-mcp
graph tools before grep.

- Codex: append a sentinel-delimited [[hooks.SessionStart]] block to
  ~/.codex/config.toml (idempotent upsert, preserves other content, removable).
- Gemini CLI: SessionStart hook in ~/.gemini/settings.json, reusing the shared
  JSON hook upsert (alongside the existing BeforeTool reminder).
- Antigravity: same JSON hook in ~/.gemini/antigravity/settings.json (it shares
  Gemini hook semantics).

The reminder command is written to be valid both as a TOML single-quoted
literal and a JSON string (no single quotes, no newlines). Wired into install,
uninstall, and the install --plan receipt. remove_hooks_json now prunes an
emptied event key so removal leaves no stale "<Event>": [] cruft. README
Multi-Agent table updated. Tests cover Codex upsert/idempotency/removal and
Gemini parity.
2026-05-31 19:39:31 +02:00
Martin Vogel 4c38c5a275 feat(install): add install --plan machine-readable receipt (#388)
An installer that configures MCP entries, instruction files, Skills, and hooks
across many agents should let callers see what it will mutate before it does.
`--dry-run` already lists planned writes in human-readable form; this adds the
machine-readable `agent.install.plan.v1` JSON receipt the issue asked for.

`install --plan` runs the real install dispatch in record-only mode — a global
g_install_plan recorder that each write-site function appends to (at the same
point it would write) while all mutations are disabled — then emits JSON with
agents_detected, config_files_planned, instruction_files_planned,
hooks_planned, writes_started:false, network_after_install:false, and
next_safe_command. Because the plan is recorded on the actual install code
path, it cannot drift from real behavior. No config is written, no index
deleted, no network used.

cbm_build_install_plan_json is exposed for testing; the test asserts the
receipt content AND that building it creates no config files.
2026-05-31 18:15:40 +02:00
Martin Vogel 70e3ed70ac fix(adr): unify manage_adr onto the SQLite store shared with the UI (#256)
manage_adr (MCP/CLI) wrote/read ADRs as a file at <root>/.codebase-memory/adr.md,
while the UI /api/adr endpoints used the SQLite project_summaries table via
cbm_store_adr_get/store. Writes through one interface were invisible to the other.

Route manage_adr through cbm_store_adr_get/store (the same backend the UI uses),
so update/get/sections all operate on the shared store. Add a one-time migration:
if the store has no ADR but the legacy adr.md file exists, import it on first
access so nothing is lost on upgrade. The legacy file reader is retained solely
for that migration.
2026-05-31 17:59:05 +02:00
Martin Vogel 6657044026 fix(ui): warn on stderr when --ui requested without embedded UI (#350)
A binary built without the embedded frontend (CBM_EMBEDDED_FILE_COUNT == 0)
accepted --ui=true, persisted it to config, but never started the HTTP server
— the only signal was a ui.no_assets warning routed to the log-file sink, which
a user running `--ui=true` on a terminal never sees. Detect an explicit
--ui=true on a non-UI binary and print a clear stderr message pointing to the
UI release asset / cbm-with-ui build, so the silent no-op is explained.
2026-05-31 17:43:24 +02:00
Martin Vogel f5573f17ce test(discover): guard vendor/ root-gitignore exclusion (#234)
The v0.6.0 behavior where a vendor/ directory in the root .gitignore was
still indexed is fixed on the v0.7.0 discovery rework. Add a faithful
regression test (PHP project, untracked vendor/ in root .gitignore) asserting
nothing under vendor/ is discovered, so it cannot regress.
2026-05-31 17:35:52 +02:00
Martin Vogel 5595ce47f9 fix(naming): derive only validator-safe project names (#349)
cbm_project_name_from_path replaced only "/" and ":" with "-", leaving
spaces, "@", "+", unicode, etc. intact. resolve_store (via project_db_path)
gates on cbm_validate_project_name, which allows only [A-Za-z0-9._-]. So a
repo like "/home/u/my project" was indexed and shown by list_projects (which
opens the .db file directly), yet index_status/search_graph reported
project-not-found because resolve_store rejected the space.

Normalize every rejected character to "-", collapse consecutive dots (the
validator forbids ".."), and strip leading dots, so a derived name always
satisfies cbm_validate_project_name and round-trips through resolve_store.
2026-05-31 17:22:02 +02:00
Martin Vogel 3bc1d586d6 fix(search_code): error on invalid regex instead of silent empty (#283)
With regex=true, a syntactically invalid pattern (e.g. unclosed group) made
the underlying grep fail, which handle_search_code reported as an empty result
set — indistinguishable from a legitimate no-match. Validate the user pattern
with cbm_regcomp up front and return an explicit "invalid regex" error so
callers can tell a broken pattern from zero matches. regex=false is unaffected.
2026-05-31 16:22:31 +02:00
Martin Vogel 30dfa952d9 fix(install): emit fish-native PATH syntax for fish configs (#319)
cbm_ensure_path appended `export PATH="<dir>:$PATH"` to every shell rc,
including config.fish — which is a syntax error in fish and broke users
fish config. Detect a .fish target and emit `fish_add_path <dir>` instead
(idempotent, prepends only if absent). POSIX shells are unchanged.
2026-05-31 16:13:47 +02:00
Martin Vogel 7fad5bc87b ci(dry-run): stop scarce Intel-macOS runner from gating smoke/soak
GitHub is sunsetting Intel-macOS runners, so the macos-15-intel build leg is
repeatedly cancelled before it can be allocated, turning the aggregate build
result non-success and skipping the smoke + soak jobs even though every other
build/test passed.

Mark only the macos-15-intel matrix leg continue-on-error, and relax the
smoke/soak gate to run unless builds were skipped or a leg genuinely failed
(tolerating a cancelled aggregate caused solely by the non-blocking Intel leg).
All other platforms remain required.
2026-05-31 16:06:06 +02:00
Martin Vogel 5f3847c0e5 fix(grpc): anchor Route emission on stub suffix; preserve service name (#294)
emit_grpc_edge produced two classes of bad output:

1. Wrong service name: the suffix list stripped "ServiceClient"/"ServiceGrpc"
   before "Client"/"Grpc", so FooServiceClient collapsed to "Foo" instead of
   the proto-declared "FooService" — breaking cross-repo Route matching.

2. Phantom Routes: extract_grpc_service_method returned true for any
   "<recv>.<method>" call, so ordinary receiver vars (_provider.GetGroup,
   _builder.AddSomeService) became __grpc__provider/... Routes matching no
   .proto anywhere.

Strip only the trailing stub/client token (Client/Stub/Grpc/BlockingStub/…),
preserving "Service", and require that a recognized suffix was actually present
before emitting — the suffix match is the gRPC stub-type signal. Plain receiver
vars no longer yield Routes.

extract_grpc_service_method is no longer static (declared in pipeline_internal.h)
so it is unit-testable.
2026-05-31 14:44:54 +02:00
Martin Vogel 61453e928f test(hooks): guard PreToolUse gate shim against predictable temp file (#384)
The symlink-attack vector (predictable /tmp/cbm-code-discovery-gate-$PPID)
was removed in c29e6d5 when the blocking bash gate became a stateless
compiled augmenter writing to stdout only. Add a regression guard so a
predictable temp/state file can never be reintroduced: assert the emitted
gate shim contains no /tmp path and no $PPID, and delegates to hook-augment.

Export cbm_install_hook_gate_script (was static) so the security property
is directly testable.
2026-05-31 13:32:08 +02:00
Martin Vogel f88d0315ac fix(install): detect Cursor IDE and register MCP config (#222)
Cursor was never in the editor-detection table, so install/update only
ever wrote the VS Code config and silently skipped ~/.cursor/mcp.json,
even when Cursor was present. Uninstall removed the Cursor entry but a
subsequent install never re-created it.

Detect ~/.cursor/ as the Cursor agent, register the MCP server in
~/.cursor/mcp.json (mcpServers format, same as Windsurf/Gemini) on
install, remove it on uninstall, and list Cursor in detected agents.
2026-05-31 13:21:31 +02:00
Martin Vogel 4abcaa43e7 fix(mcp): preserve JSON-RPC string ids instead of coercing to int (#253)
JSON-RPC 2.0 §4 permits string request ids, and several MCP clients
(including Claude Desktop) send a string id for "initialize". The parser
coerced string ids via strtol, yielding 0 for any non-numeric id, so the
response echoed the wrong id and the client could not correlate it.

Carry the string id verbatim through parse -> dispatch -> response
(new id_str field on the request/response structs) and emit it as a JSON
string. Numeric ids are unchanged. The method-not-found error path now
echoes the original id too.
2026-05-31 13:10:52 +02:00
Martin Vogel 9dcc0e3c59 ci: remove temporary Windows repro harness
#394 group triaged: #266/#274/#331/#347/#348 verified fixed on v0.7.0 in
Windows CI; #227/#367 (SMB) pending reporter retest. Removing the throwaway
workflow.
2026-05-31 12:59:09 +02:00
Martin Vogel 0485d3f3b1 fix(cli): probe Windows PATHEXT variants in find_in_path (#221)
Agent CLIs on Windows are installed as .cmd/.ps1/.exe shims (e.g. opencode
via mise/npm), but find_in_path only probed the bare name, so they weren't
detected. Try .exe/.cmd/.bat/.ps1 per PATH entry on Windows.

Relates to #221 (opencode not detected). The install-time taskkill 'eq'
error from the same report is addressed separately — cbm_kill_other_instances
now uses _spawnvp with an argv array rather than a shell string.
2026-05-31 12:54:58 +02:00
Martin Vogel d198403e21 ci(temp): Windows repro harness for #394 group
Indexes a repo at a C:\ drive-letter path (subdirs + .cbmignore +
.mjs/.js) on windows-latest and dumps diagnostics for #347/#227/#367/
#331/#266/#274/#348. Temporary — delete after the run.
2026-05-31 12:51:20 +02:00
Martin Vogel c1dabc988b fix(store): accept lowercase drive letters in root_path integrity check
The projects.root_path integrity check only accepted '/' or an uppercase
'A'-'Z' first character. On Windows, drive letters are commonly lowercase
(c:/repo, y:/share), so such a path was flagged store.corrupt and the DB
was auto-deleted on open — a likely cause of the mapped-drive DB deletion
in #227/#367. Accept 'a'-'z' as well.

Relates to #227, #367.
2026-05-31 12:50:19 +02:00
Martin Vogel 684045708f test(cypher): regression guards for #240/#237/#252/#305 (already supported)
Confirmed working in the current query_graph evaluator and locked in:
- #240 labels() function with AS alias
- #237 DISTINCT applied before ORDER BY + LIMIT
- #252 toInteger()
- #305 count(*) with AS alias

Closes #240. Closes #237. Closes #252. Closes #305.
2026-05-31 12:38:05 +02:00
Martin Vogel 2de984bdb6 fix(discover): map .mjs/.cjs (JS) and .mts/.cts (TS) extensions (#197)
.mjs (ES modules) and .cjs (CommonJS) were absent from the extension
table, so those files were never assigned a language — they weren't
indexed (no graph nodes) and search_code returned 0 for any pattern in
them. Add .mjs/.cjs → JavaScript and .mts/.cts → TypeScript.

Verified end-to-end: a function in a .mjs file is now extracted and found
by search_code. Closes #197.
2026-05-31 12:10:29 +02:00
Martin Vogel 48a9b2c2a9 test(c-lsp): regression for #220 (C++ CALLS attributed to function)
#220: C++ CALLS edges originated from the Module node instead of the
enclosing Function, breaking function-level trace_path. The cross-LSP
resolver now sets caller_qn = enclosing_func_qn; the test asserts a call
(doWork→helper) is attributed to doWork, not the module.

Closes #220.
2026-05-31 11:57:50 +02:00
Martin Vogel 53be053d3f fix(search): treat wildcard-free file_pattern as a path substring (#200)
search_graph file_pattern always returned 0 for a bare name like
"offer-server": cbm_glob_to_like produced the literal "offer-server",
so `file_path LIKE 'offer-server'` only matched a path equal to it, never
"src/offer-server/x.js". When the pattern contains no glob wildcards
(* or ?), wrap the LIKE as %pattern% so it matches anywhere in the path.
Explicit globs keep their semantics.

Closes #200.
2026-05-31 11:48:25 +02:00
Martin Vogel bf3fc711bc test(extraction): regression guards for #382 (Java annotations) + #213 (large TS)
#382 — Java Method nodes now carry decorators (@GetMapping) and a non-empty
signature; verified by extract_java_method_annotations_issue382.
#213 — a 256 KB / 4000-function TS file now yields Function nodes instead of
a childless File node (fixed by the tree-sitter read-buffer padding);
verified by extract_large_ts_has_functions_issue213.

Closes #382. Closes #213.
2026-05-31 03:25:48 +02:00
Martin Vogel 7e4745ddd1 test(py-lsp): regression for #228 (cross-file classmethod on class)
#228: a class/static method invoked on a cross-file imported class name
(ActionRecordX.build_from_text(...)) produced no CALLS edge, so the
method looked like dead code (in/out degree 0). The v0.7.0 py_lsp
cross-file resolver handles this; the test feeds the exact pattern through
cbm_run_py_lsp_cross and asserts the call resolves.

Closes #228.
2026-05-31 03:14:17 +02:00
Martin Vogel d0e1e77825 ci: remove temporary bucket-B repro harness
The #336 (Icinga2/Linux) and #385 (KiCad/Windows) reproductions are done —
both index cleanly on v0.7.0 on their reported platforms. Removing the
throwaway workflow.
2026-05-31 00:51:14 +02:00
Martin Vogel 6c6b8c82b8 ci(temp): build bucket-B repro inline per-platform (avoid macos infra cancel)
The reused _build.yml builds all platforms; a cancelled macos-15-intel
runner skipped the icinga2/kicad index jobs. Build inline in each job so
the Linux (#336) and Windows (#385) repros don't depend on unrelated
platforms. Still temporary — delete after the run.
2026-05-31 00:42:46 +02:00
Martin Vogel d848347c61 test(ts-lsp): scale regression for #344/#340 (lsp_cross >1189 defs)
Issues #344/#340 reported a scale-dependent SIGSEGV in the TS cross-file
LSP pass once the collected def array exceeded ~1189 entries. The v0.7.0
cross-LSP rewrite registers defs through the arena (no fixed-size def
array), so the threshold no longer exists. This test drives
cbm_run_ts_lsp_cross with a 4000-entry def array under -fsanitize=address
and resolves cleanly, locking in the fix.

Closes #344. Closes #340.
2026-05-31 00:34:29 +02:00
Martin Vogel c6c1d77c43 ci(temp): bucket-B crash repro harness (#336 icinga2 / #385 kicad)
Temporary workflow_dispatch harness: builds current-main binaries and
indexes Icinga2 on Linux (fast) and KiCad on Windows (moderate) to check
whether the reported crashes still reproduce on v0.7.0. To be removed
after the run.
2026-05-31 00:24:57 +02:00
Martin Vogel ba49137165 test(c-lsp): xxhash-header extraction guard (issue #355 proxy)
Issue #355 reported a segfault extracting a macro-heavy xxhash C header
(dhw/xx_hash.h, not available to us). Add a guard that runs the vendored
xxhash.h (~7.5k lines, same macro-dense family) through C extraction under
ASan. It passes on current main — the C-LSP crash hardening (#322/#323/
#360) appears to cover this class. Kept as a regression guard; #355 stays
open pending the reporter's confirmation/file.
2026-05-30 23:44:10 +02:00
Martin Vogel de069d117e test(mcp): ASan regression for issue #235 (bad-project buffer overflow)
Passing an unrecognised project name triggered a buffer overflow while
building the available-projects error list: collect_db_project_names did
snprintf(out+offset, out_sz-offset, ...) with no bound, so once the
listed names exceeded the 4 KB projects buffer, (out_sz - offset)
underflowed (unsigned) to a huge size and snprintf wrote past the buffer.

Fixed in 21c73b5 (PR #352) with an offset>=out_sz bounds check + clamp.
This test fills a temp CBM_CACHE_DIR with 40 long-named .db files
(~5 KB of names) and issues a bad-project search_graph call; the test
build runs under -fsanitize=address so the old underflow would abort here.

Closes #235.
2026-05-30 23:34:00 +02:00
Martin Vogel 7dafde46dc test(c-lsp): regression for issue #312 (defaulted template param + auto)
A C++ function template with a defaulted type param and an `auto`
parameter, called with matching arg count, previously segfaulted in the
definitions pass (unbound `U` flowed through type substitution as NULL).
Fixed by the cbm_type_substitute NULL-preservation guard; this locks in
a reproduction so it can't regress.

Closes #312.
2026-05-30 23:21:35 +02:00
DeusData 25ba4472d5 Delete docs/TS_LSP_INTEGRATION_PLAN.md 2026-05-30 23:14:46 +02:00
DeusData fd5cbedd1a Delete docs/PLAN_PHP_LSP_INTEGRATION.md 2026-05-30 23:14:26 +02:00