Commit graph

931 commits

Author SHA1 Message Date
Christian C. Berclaz
bc722b9d8f
fix(group): resolve custom manifest links against graph symbols (#1254) 2026-05-03 01:40:29 +01:00
jelsco
368049576b
fix(python): make multi-segment suffix fallback deterministic (#1253) 2026-05-02 11:36:28 +01:00
Gergő Magyar
55d504284f
fix(ci): consolidate Claude review workflow (#1258) 2026-05-02 08:15:46 +01:00
Gergő Magyar
0418cbb347
fix(cli): keep GitNexus ignores inside .gitnexus (#1248)
Some checks are pending
Release Candidate / Publish release candidate to npm (push) Blocked by required conditions
Release Candidate / Check if release candidate should run (push) Waiting to run
Release Candidate / ci (push) Blocked by required conditions
Release Candidate / Build & Push RC Docker images (push) Blocked by required conditions
* fix(cli): keep GitNexus ignores inside .gitnexus

Avoid mutating analyzed repositories' root .gitignore while keeping generated GitNexus state untracked via .gitnexus/.gitignore.

Made-with: Cursor

* fix(cli): also use git info exclude for GitNexus storage

When an analyzed repo has a real .git directory, add .gitnexus/ to .git/info/exclude so local Git metadata ignores generated storage without touching root .gitignore.

Made-with: Cursor

* fix(cli): keep skip-git subdir indexes ignored

Ensure full analyze always writes the internal GitNexus ignore file so parent Git repositories stay clean for --skip-git subdirectory indexes.

Made-with: Cursor
2026-05-01 16:46:05 +01:00
azizur100389
4be4abe8e4
fix(group): contract extractors honour .gitnexusignore via shared IgnoreService (#1185) (#1247)
* fix(group): contract extractors honour .gitnexusignore via shared IgnoreService (#1185)

The HTTP, gRPC, and topic contract extractors each globbed the repo
with a hardcoded `ignore: ['**/node_modules/**', '**/.git/**',
'**/dist/**', '**/build/**', '**/vendor/**']` array, bypassing the
shared `IgnoreService` that the rest of the ingestion pipeline uses
for `.gitnexusignore` and `.gitignore` parsing. Result: a vendored
Python venv (`mentor_env/`), generated stubs, or any user-defined
exclusion silently produced false-positive contracts.

Replace each hardcoded array with `createIgnoreFilter(repoPath)`,
mirroring the canonical pattern in `filesystem-walker.ts`. The 5
hardcoded names are all in `DEFAULT_IGNORE_LIST`, so default
behaviour is preserved; users now also get `.gitnexusignore`
patterns, the rest of the hardcoded list (e.g. `__pycache__`,
`.pytest_cache`), and the `.gitnexusignore` negation semantics
introduced in #771.

The topic extractor additionally filters Go `*_test.go` at the glob
level. That filter is preserved via a small wrapper around
`createIgnoreFilter` that short-circuits before delegating, so
glob-level pruning still applies and the existing `_test.go` skip
test (with new content asserting the pruning is real) still passes.

Tests added to all three `*-extractor.test.ts` files exercising
`.gitnexusignore` honouring end-to-end via real temp directories.

* test(group): exercise gRPC source-scan ignore + add .gitignore-only coverage (#1185)

Addresses two findings from the @claude review on PR #1247:

[medium] The gRPC ignore test claimed to cover both proto-context and
source-scan paths but only wrote a .proto file under mentor_env/.
Added a Python `_pb2_grpc.<Name>Stub(channel)` consumer file under the
same ignored dir (mirroring the canonical pattern from
`test_extract_python_stub_returns_consumer`); without the
`.gitnexusignore` filter that file would emit a consumer contract.
The test now exercises both `createIgnoreFilter` calls inside the gRPC
extractor (`buildProtoContext` + `extract`) in a single run, with both
defence-in-depth path-prefix assertions and a specific
`role: consumer` LeakedService assertion.

[low] Added one shared .gitignore-only test on the HTTP extractor.
`createIgnoreFilter` reads both `.gitignore` and `.gitnexusignore` via
`loadIgnoreRules`, but no extractor-level test exercised the
`.gitignore` path. One shared test is sufficient because all three
extractors consume the same filter object — verified at
`IgnoreService` level already.

The remaining [low] finding — "negation semantics (!pattern) not
tested at extractor level" — is deferred deliberately, not skipped.
Three reasons:

  1. The negation logic (introduced in #771) lives entirely inside
     `createIgnoreFilter`'s `hasExplicitUnignore` ancestor-walk in
     `ignore-service.ts`. The extractors only consume the returned
     filter object — they never inspect patterns, never call
     `hasExplicitUnignore` directly, and have no code path that could
     diverge from the IgnoreService's negation behaviour.

  2. Negation is already locked in by 8 dedicated unit tests in
     `test/unit/ignore-service.test.ts` (the #771 suite), plus the
     `!parent/` + `parent/child/` last-match-wins regression test
     added in PR #1046. An extractor-level negation test would
     re-prove the same code path and would not catch any failure mode
     the existing tests don't already catch.

  3. The bot itself flagged the gap as "Acceptable to leave as
     follow-up referencing existing IgnoreService negation tests" —
     the deferral matches its own recommendation.

If a future change inserts an extractor-side wrapper around the filter
(as topic-extractor.ts already does for `*_test.go`) that could
plausibly affect negation, an extractor-level negation test should be
added at that point — not pre-emptively here.
2026-05-01 16:42:21 +01:00
jelsco
59acfb2261
fix(python): walk ancestors for multi-segment dotted imports (#1241)
* fix(python): walk ancestors for multi-segment dotted imports (#1240)

Single-segment Python imports (`from middleware import X`) already get an
ancestor-directory walk in `resolvePythonImportInternal`, so they resolve
correctly when the importer and the imported module share a parent
directory (e.g. both under `backend/`).

Multi-segment dotted imports (`from services.sync import X`) were only
resolved against the workspace root. In a `backend/`-prefixed repo,
`from services.sync import X` from `backend/routers/cron.py` would not
resolve because `services/sync.py` does not exist at the workspace root —
only `backend/services/sync.py` does. The IMPORTS edge was dropped, the
imported names were never bound, and downstream CALLS edges to those
names were silently lost.

The fix mirrors the single-segment ancestor walk for multi-segment paths
in `resolveAbsoluteFromFiles`, and widens `hasRepoCandidate` to accept
nested `/segment/` matches so it does not bail before the walk runs.

Includes a new fixture and 5 integration tests covering:
- IMPORTS resolution for `from services.sync`, `from services.alerts`,
  `from routers.alerts` from `backend/routers/cron.py`.
- CALLS edge counts for every multi-segment-imported callee.
- Regression check: single-segment ancestor walk
  (`from auth_utils import …`) still resolves correctly.

The django-app-imports regression suite (which prevents `accounts.apps`
from spuriously matching a local `apps.py`) continues to pass — the new
nested-namespace check in `hasRepoCandidate` is bounded by an explicit
`/segment/` substring, and the workspace-root candidate check still
runs first.

* fix(python): scope hasRepoCandidate widening to importer ancestors + tighten ancestor-walk loop

Address review findings from PR #1241:

1. hasRepoCandidate's nested check now requires the matching directory to
   sit on an ancestor of the importer. Previously any nested /SEGMENT/
   path satisfied the gate, which would let a vendored copy of an
   external package (e.g. vendor/django/urls.py) gate-pass an external
   import like 'from django.urls import path' issued from app/main.py.

2. Loop bound in resolveAbsoluteFromFiles tightened from 'i >= 0' to
   'i > 0' to skip a redundant root-candidate recheck (the workspace-root
   direct check above already covers that case).

3. Doc-comment in resolveAbsoluteFromFiles now states the precedence
   order explicitly: workspace root > closest ancestor > suffix fallback.

Tests added:
- Vendored-external false-positive guard (vendor/django/urls.py must not
  resolve from app/main.py).
- Workspace-root vs ancestor precedence (root services/sync.py wins over
  backend/services/sync.py for a backend/routers/cron.py importer).

215/215 python integration tests pass (+4 from this change). tsc --noEmit
green.
2026-05-01 16:27:07 +01:00
Gergo Magyar
26b39560ce fix(ci): configure e2e GitNexus home at runtime
Avoid workflow planning failures by deriving the e2e GitNexus home from RUNNER_TEMP inside a shell step instead of using runner context in job-level env.

Made-with: Cursor
2026-05-01 12:39:02 +01:00
Gergő Magyar
2a1546a8b6
Revert "Revert "chore(deps)(deps): bump uuid from 13.0.0 to 14.0.0 in /gitnex…" (#1250)
This reverts commit d57f15f18d.
2026-05-01 12:33:46 +01:00
Gergő Magyar
ec07467601
fix(ci): seed e2e with a small fixture repo (#1249)
Avoid crashing the e2e job during setup by indexing a tiny temp fixture instead of the full monorepo before Playwright starts.

Made-with: Cursor
2026-05-01 12:29:53 +01:00
dependabot[bot]
e07a95dffb
chore(deps)(deps): bump react-zoom-pan-pinch in /gitnexus-web (#1214)
Bumps [react-zoom-pan-pinch](https://github.com/prc5/react-zoom-pan-pinch) from 3.7.0 to 4.0.3.
- [Release notes](https://github.com/prc5/react-zoom-pan-pinch/releases)
- [Changelog](https://github.com/BetterTyped/react-zoom-pan-pinch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prc5/react-zoom-pan-pinch/compare/v3.7.0...v4.0.3)

---
updated-dependencies:
- dependency-name: react-zoom-pan-pinch
  dependency-version: 4.0.3
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-01 10:32:03 +01:00
Copilot
6372b0bfeb
fix(cli): --skip-git treats cwd as index root instead of walking up to parent git repo (#1245) 2026-05-01 09:49:48 +01:00
dependabot[bot]
c90ffdd2e1
chore(deps)(deps): bump react and @types/react in /gitnexus-web (#1210)
* chore(deps)(deps): bump react and @types/react in /gitnexus-web

Bumps [react](https://github.com/facebook/react/tree/HEAD/packages/react) and [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react). These dependencies needed to be updated together.

Updates `react` from 18.3.1 to 19.2.5
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.5/packages/react)

Updates `@types/react` from 18.3.27 to 19.2.14
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-version: 19.2.14
  dependency-type: direct:development
  update-type: version-update:semver-major
- dependency-name: react
  dependency-version: 19.2.5
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(web): complete React 19 upgrade

Align react-dom and @types/react-dom with React 19 so npm can resolve the web dependency graph without peer conflicts. React 19 types now correctly model refs initialized with null, so widen the affected hook return contracts instead of asserting non-null DOM nodes before mount.

Validation: cd gitnexus-web && npm ci; npx tsc -b --noEmit; npm test; npm run build; npx prettier --check package.json package-lock.json src/hooks/useAutoScroll.ts src/hooks/useSigma.ts; npx eslint . (warnings only, existing baseline); npm run test:e2e (11 passed, 17 skipped).
Made-with: Cursor

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Gergo Magyar <gergomagyar@icloud.com>
2026-05-01 08:42:26 +01:00
Gergő Magyar
71e1e8a3f0
fix(deps): pin tree-sitter-c/cpp to fix Windows segfault (#1242) (#1243)
* fix(deps): pin tree-sitter-c/cpp to fix Windows segfault (#1242)

`tree-sitter-c@0.23.2` ships native prebuilds compiled against tree-sitter
ABI 14 (tree-sitter-cli >=0.24), while GitNexus is pinned to the
tree-sitter@0.21.1 JS runtime. On Windows the JS runtime hits
`Cannot read properties of undefined (reading '161')` inside
`unmarshalNode` and a native segfault in the parse-worker pipeline on
real C codebases (e.g. STM32 headers from the issue reporter).

Two coordinated registry pins fix the root cause without any override
gymnastics or vendoring:

- `tree-sitter-c` -> `0.21.4` (last release built against the
  tree-sitter@0.21 ABI; declared peer `^0.21.0`).
- `tree-sitter-cpp` -> `0.23.2` (last 0.23.x release before
  tree-sitter-cpp added a runtime dep on the broken-ABI
  `tree-sitter-c@^0.23.1`; pinning here lets us drop the previous
  global override entirely).

`npm ls tree-sitter-c` is now clean: single deduped 0.21.4, no
`overridden` annotations, no nested copy.

Parser loader collapsed to one declarative table:

- One `SOURCES` map with `{ load, unavailableNote, optional? }` rows
  for every grammar including TSX. Adding/removing a grammar is one
  entry; `unavailableNote` is mandatory and the type checker enforces
  it, so failures are never silent and never generic.
- Single `loadGrammar(key)` does lazy require + cache + per-failure
  classification. Required failures `console.error` the note and
  rethrow the original (preserves stack); optional failures
  `console.warn` and report the language as Unsupported. One
  warn-once `Set` deduplicates per language key.
- The previous bespoke `warnCUnavailable` + `cWarningEmitted` state
  and 4 conditional spreads in the language map are gone.

Per-grammar `unavailableNote` strings name the package, list the most
likely failure mode for that grammar, and link the relevant tracking
issue (#1013, #1125, #1130, #1242) where applicable.

Tests: new `C parser ABI compatibility (#1242)` block under
parser-loader.test.ts exercises the actual failure paths
(non-trivial parse + tree walk + Query.captures + TreeCursor
descent). The original report's `unmarshalNode` crash sits on
exactly the traversal hot path these tests now cover.

Validation:
- npx tsc --noEmit: clean
- npx vitest run test/unit: 4808 passed, 10 skipped
- npx vitest run test/integration/resolvers/cpp.test.ts: 133/133
- minimal C parse + walk + query + cursor verified manually under
  tree-sitter@0.21.1 + tree-sitter-c@0.21.4 on Win11 x64 / Node 22

Closes #1242. Does not unblock the broader tree-sitter@0.25 upgrade
tracked in #858.

Made-with: Cursor

* chore(ci): redesign tree-sitter upgrade-readiness report (#858)

The daily script that owns the body of #858 used to dump one giant
matrix and leave a human to figure out which grammars are actually
ready to bump. After pinning `tree-sitter-c@0.21.4` and
`tree-sitter-cpp@0.23.2` for #1242, several rows in that matrix now
look like regressions when in fact they are deliberate. The report
now classifies each grammar instead of just listing them.

What changed in `check-tree-sitter-upgrade-readiness.py`:

- New `INTENTIONAL_PINS` table documents grammars deliberately held
  below `npm latest`, with a one-line rationale and a tracking issue
  per row (#1242 for C and C++, #1013 for C#). The script reads pins
  straight from `gitnexus/package.json` so a future bump cannot
  drift away from this report.
- New `_classify_grammar(...)` produces one primary disposition per
  grammar: Ready for 0.25 / Intentionally pinned / Waiting on
  upstream npm release / Blocked on upstream / Could not check.
  The dispositions drive the report layout.
- New `vendored_drift_summary(...)` covers all three vendored
  parsers (`tree-sitter-proto`, `tree-sitter-dart`,
  `tree-sitter-swift`) uniformly: ABI from `parser.c` when present,
  upstream npm + GitHub status, and the rationale extracted from
  each vendor's `_vendoredBy` field. Prebuilt-only vendors
  (Swift today) report `ABI 'prebuilt'` instead of `None`.
- Report layout: top-of-page TL;DR + counts, an actionable
  "What you can do today" section, then one section per
  disposition bucket, then a dedicated "Vendored parsers"
  section. The original raw matrix is preserved inside a
  collapsible `<details>` block so the row-diff bot that watches
  this issue still has stable input.
- `sys.stdout.reconfigure(encoding="utf-8")` so the workflow no
  longer crashes on Windows when the report contains arrows or
  em-dashes.

No workflow / cron changes; the daily job posts the new body the
next time it runs. #858 itself was updated by hand in the meantime
to keep the tracker readable.

Made-with: Cursor

* fix(parser-loader): log C grammar load failures at error severity (#1242)

Addresses review feedback on #1243.

`tree-sitter-c` is in `dependencies` (not `optionalDependencies`) so a
load failure on a supported platform always indicates a real install
problem the user needs to see — corrupted node_modules, unsupported
Node version, or an ABI mismatch with the bundled runtime. Previously
the optional-grammar machinery downgraded that to `console.warn`,
which can be missed in long log streams and silently drops C analysis
for an entire repo.

Decouples log severity from throw behavior:

- `GrammarSource.severity?: 'warn' | 'error'` is a new optional field
  that overrides the default log level for a load failure. Default is
  `error` for required grammars and `warn` for optional ones, matching
  the prior behavior for every existing row.
- `LoadResult` carries the resolved severity through `loadGrammar` so
  `logFailure` no longer derives it from `fatal`.
- `tree-sitter-c` row sets `optional: true, severity: 'error'`. The
  pipeline still degrades gracefully (callers see Unsupported instead
  of a thrown error), but the diagnostic is loud and the
  `unavailableNote` now spells out what to try first
  (`npm rebuild tree-sitter-c`, reinstall) and links the tracker.

No test changes needed: `parser-loader.test.ts` exercises behavior on
the success path and on optional-failure dispatch; severity is a
display-only concern routed through `console.error` vs `console.warn`,
which the existing tests don't assert on.

Made-with: Cursor

* fix(ci): treat intentional pins as 0.25 blockers in readiness report

Addresses review feedback on #1243.

`_classify_grammar` returned bucket `intentional` before checking
`target_compat`, and the per-grammar status loop only added a row to
`blockers` when npm-latest was incompatible with the target runtime.
The combination meant: if every other grammar resolved tomorrow but we
were still holding `tree-sitter-c@0.21.4` and `tree-sitter-cpp@0.23.2`
(both incompatible with `tree-sitter@0.25.x`), the script would emit
"**Ready** — all grammars are 0.25-compatible" and mislead maintainers
into thinking the runtime upgrade was unblocked.

Fix:

- The status loop now adds an entry to `blockers` whenever a grammar
  is in `INTENTIONAL_PINS`, regardless of npm-latest's peer dep. The
  blocker message names the pinned spec, embeds the rationale from
  `INTENTIONAL_PINS`, and tells the reader the pin must be lifted
  before the target runtime upgrade. When the pin is removed (entry
  deleted from `INTENTIONAL_PINS`), the grammar resumes standard
  classification on the next run.
- `bump_now` now excludes intentional pins so they never show up in
  the "What you can do today" section. Bumping an intentional pin
  requires a deliberate edit to both `INTENTIONAL_PINS` and
  `package.json`, not a one-line dependency bump.

Verified locally: TL;DR now reports 8 blockers (6 upstream + 2
intentional) where it previously reported 6, and the verdict
correctly remains **Blocked** even in the hypothetical future where
all upstream blockers clear.

Made-with: Cursor
2026-05-01 08:02:16 +01:00
dependabot[bot]
b278926bb6
chore(deps)(deps): bump onnxruntime-node in /gitnexus (#1213)
Bumps [onnxruntime-node](https://github.com/Microsoft/onnxruntime) from 1.24.3 to 1.25.1.
- [Release notes](https://github.com/Microsoft/onnxruntime/releases)
- [Changelog](https://github.com/microsoft/onnxruntime/blob/main/docs/ReleaseManagement.md)
- [Commits](https://github.com/Microsoft/onnxruntime/compare/v1.24.3...v1.25.1)

---
updated-dependencies:
- dependency-name: onnxruntime-node
  dependency-version: 1.25.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-01 07:22:44 +01:00
dependabot[bot]
275f09d6c0
chore(deps)(deps-dev): bump @types/node in /gitnexus-web (#1212)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.10.9 to 25.6.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.6.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-01 07:22:32 +01:00
dependabot[bot]
b4f9d56f33
chore(deps)(deps): bump mnemonist from 0.40.3 to 0.40.4 in /gitnexus (#1239)
Some checks are pending
Release Candidate / Check if release candidate should run (push) Waiting to run
Release Candidate / ci (push) Blocked by required conditions
Release Candidate / Publish release candidate to npm (push) Blocked by required conditions
Release Candidate / Build & Push RC Docker images (push) Blocked by required conditions
Bumps [mnemonist](https://github.com/yomguithereal/mnemonist) from 0.40.3 to 0.40.4.
- [Release notes](https://github.com/yomguithereal/mnemonist/releases)
- [Changelog](https://github.com/Yomguithereal/mnemonist/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yomguithereal/mnemonist/compare/0.40.3...0.40.4)

---
updated-dependencies:
- dependency-name: mnemonist
  dependency-version: 0.40.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-30 22:14:55 +01:00
Gergő Magyar
6f42253dfd
fix(cli): surface silent finalize-skips so analyze cannot exit 0 without persisting (#1169) (#1237)
* fix(cli): surface silent finalize-skips so analyze cannot exit 0 without persisting (#1169)

Closes #1169.

On Windows, `gitnexus analyze .` was observed to exit with code 0 after
printing only the "GitNexus Analyzer" banner. `.gitnexus/lbug.wal` was
written but `meta.json` was never persisted and the repo was not added
to `~/.gitnexus/registry.json`, so `gitnexus list` / `status` reported
no indexed repository. The reporter confirmed the same shape on both
LadybugDB (1.6.x) and the pre-LadybugDB KuzuDB build (1.4.1), so the
silent finalize-skip is upstream of the DB engine and indistinguishable
from a healthy index from the user's perspective.

This change makes that state a hard, actionable failure regardless of
the upstream root cause.

Behaviour change

- New `assertAnalysisFinalized()` invariant in `repo-manager.ts` checks
  that meta.json exists at `<repo>/.gitnexus/meta.json` AND that the
  global registry has a canonical-path-matching entry. Throws
  `AnalysisNotFinalizedError` (kind: "AnalysisNotFinalizedError") with a
  diagnostic that names the missing artifact and the storage path the
  user should inspect.
- `analyzeCommand` invokes the invariant on the rebuild path (skipped
  on `alreadyUpToDate`), so a future silent finalize-skip surfaces with
  exit code 1 and a recoverable error instead of a silent exit 0.
- `analyzeCommand` installs idempotent `unhandledRejection` and
  `uncaughtException` handlers that bypass the progress bar's console
  redirection by writing to a stderr handle captured at module load.
  This addresses the secondary symptom where the `barLog` redirection
  visually erased stack traces with `\x1b[2K\r` and stripped them via
  `String(err)`.
- The catch block also writes the failing error's full stack via the
  captured stderr, so failure diagnostics survive any downstream
  monkey-patching of `process.stdout`/`stderr`.

Tests

- `test/unit/repo-manager-finalize-invariant.test.ts` (4 tests): cover
  both `missing="meta"` and `missing="registry-entry"`, the happy path,
  and Windows case-insensitive registry path matching.
- `test/integration/cli-e2e.test.ts` adds a regression test that runs
  the real CLI on a fresh repo copy, asserts exit 0, AND verifies
  `meta.json` plus the matching registry entry are both written —
  catches any future regression of the wiring.

Validation

- `npx tsc --noEmit` passes.
- `npx vitest run --project default` passes for all my touched files
  (89 tests across 4 files). The full default suite reports 7188 pass
  with the known native LadybugDB Windows-worker flake unrelated to
  this change.
- `npx prettier --check` clean on the diff.
- `npx eslint` reports only pre-existing `any` warnings on the file;
  no new warnings introduced.
- Live repro on the issue's two-file Python fixture reproduces a
  successful index after the change: meta.json present (742 B), exit 0,
  `gitnexus list` shows the repo.

Rollback

Strictly additive — the success path is unchanged when `meta.json` is
written and the registry is updated. Reverting the four-file diff is
safe; the previous silent-finalize behaviour returns. No persisted
schema or registry shape changes.

DoD

- [x] Runtime wiring is complete on the affected CLI path.
- [x] Requested behavior is correct and existing contracts are preserved.
- [x] Smallest correct solution — one invariant, one helper, two
      handlers; no speculative abstraction.
- [x] Tests prove the changed behavior at unit AND integration level.
- [x] Required validation for `gitnexus/` was run.
- [x] Repo boundaries respected; no language-specific code, no shared
      ingestion changes, no new injection surfaces.
- [x] Diff contains only the intended change — no unrelated churn.

Made-with: Cursor

* fix(cli): enforce analyze finalization on fast path (#1169)

Address PR review feedback by checking finalization even when analyze reports already up to date, and by making the #1169 E2E guard fail on timeout instead of passing silently.

Made-with: Cursor

* test(cli): fix #1169 regression coverage on CI

Normalize macOS temp paths in the registry assertion and update the analyze worker timeout test mock for the new finalization invariant exports.

Made-with: Cursor
2026-04-30 21:36:28 +01:00
Gergo Magyar
b5316c2df1 test(ci): isolate native LadybugDB and CLI e2e flakes
createFTSIndex now short-circuits on the in-process cache before issuing
the native CALL CREATE_FTS_INDEX, so a prior writable session cannot
trigger the macOS WAL/checkpoint duplicate-create path observed on main.
The cache is also primed on the "already exists" recovery and cleared on
re-init/close/drop, keeping ensureFTSIndex semantics identical for
read-only fallbacks.

The lbug-core-adapter close+reopen test moves to the end of the suite so
its native handle churn cannot corrupt later assertions in the same
fixture.

skills-e2e moves into its own sequential vitest project so the heavy
spawnSync-driven CLI fixtures stop competing with the parallel default
project on Windows runners, fixing the C-fixture beforeAll timeout.

Made-with: Cursor
2026-04-30 19:45:26 +01:00
vijaygali
aa7c273093
fix(ingestion): index Python repos with empty __init__.py and >32 KB files (#1163)
* fix(ingestion): index Python repos with empty __init__.py and >32 KB files

Two defensive fixes that let `gitnexus analyze` complete on Python
codebases that previously failed.

scope-extractor: synthesize an empty Module scope when the provider
emits zero captures. Previously threw "no Module scope found", which
fired for any 0-byte `__init__.py` package marker if the bridge's
empty-source guard was bypassed.

python/captures: wrap the parser.parse() and getPythonScopeQuery()
.matches() calls in try/catch. node-tree-sitter throws "Invalid
argument" for sources that overrun internal buffers (observed at the
~32 KB threshold on Windows). Degrade gracefully with a clear
"skipping scope extraction for this file" warning instead of the
opaque "Invalid argument" surfacing through the bridge.

Verified by indexing whittlem/pycryptobot (which has 7 empty
__init__.py and 11 Python files between 34 KB and 158 KB):
2,367 nodes / 4,973 edges, no segfault, queries resolve symbols
inside the 158 KB controllers/PyCryptoBot.py.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(ingestion): harden Python scope extraction fallbacks

Keep failed Python scope extraction on the bridge skip path and build synthetic module scopes before extractor indexes are derived.

Made-with: Cursor

---------

Co-authored-by: Vijay Gali <vgali@vexcelco.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Gergo Magyar <gergomagyar@icloud.com>
2026-04-30 19:24:04 +01:00
Gergo Magyar
78e965bf62 ci: avoid duplicate main push checks
Let release-candidate.yml be the single main-push entry point that reuses CI before publishing, while keeping CI as the direct pull-request gate.

Made-with: Cursor
2026-04-30 19:06:21 +01:00
sburdges-eng
b79278705a
fix(hook): resolve canonical repo root + guard read-only FTS ensure (#1226)
* fix(hook): resolve canonical repo root + guard read-only FTS ensure (#1224)

Two bugs in the Claude Code hook + query layer integration:

1. `findGitNexusDir` (in `gitnexus/hooks/claude/gitnexus-hook.cjs` and
   `gitnexus-claude-plugin/hooks/gitnexus-hook.js`) walked upward from
   cwd looking for a non-registry `.gitnexus/`. In linked git worktrees
   created via `git worktree add`, the canonical repo's `.gitnexus/`
   never sits above the worktree path, so the walk silently fails and
   neither augmentation nor staleness notifications fire.

   Fix: keep the cwd-walk as the fast path, then fall back to
   `git rev-parse --git-common-dir` to resolve the shared `.git/`
   directory (which lives inside the canonical repo across all linked
   worktrees) and walk up from its parent. Returns null cleanly when
   `git` isn't on PATH or cwd isn't inside any working tree.

2. `ensureFTSIndex` in the LadybugDB adapter rethrew when the active
   connection is read-only (e.g. the MCP query pool, which opens DBs
   read-only by design). Defensive callers used to surface five
   "Cannot execute write operations in a read-only database" warnings
   per query.

   Fix: extract `isReadOnlyDbError` (mirroring the existing
   `isDbBusyError` discriminator) and have `ensureFTSIndex` catch the
   read-only error, cache the key, and return silently. Index creation
   is owned by `gitnexus analyze` on a writable connection — the
   ensure call is safely a no-op on the read pool. Lock / busy /
   "already exists" / schema errors continue to propagate.

Tests:
- `test/unit/hooks.test.ts`: new "Linked git worktree resolution"
  block exercises both hooks against a real linked worktree to confirm
  PostToolUse stale notifications fire, plus a negative case when the
  canonical repo has no `.gitnexus/`.
- `test/unit/lbug-readonly-error.test.ts`: new file unit-tests the
  `isReadOnlyDbError` discriminator (positive matches, case
  insensitivity, non-Error inputs, and unrelated errors that must
  still surface — lock contention, "already exists", schema misses).
- `test/integration/lbug-core-adapter.test.ts`: extends the existing
  FTS coverage with an idempotency assertion for `ensureFTSIndex` to
  pin the read-only guard's success-path contract.

Verified with `npx tsc --noEmit` and `vitest run` on the affected
files (hooks + readonly + lbug-core-adapter + bm25-search +
lbug-extension-loader + lbug-embedding-hashes — 136 tests pass).
Build: `npm run build` succeeds.

Closes #1224

* fix(local-backend): cover supported vector path

Add the supported-platform regression assertion for QUERY_VECTOR_INDEX and align the unsupported VECTOR diagnostic wording with platform policy.

Made-with: Cursor

---------

Co-authored-by: Gergo Magyar <gergomagyar@icloud.com>
2026-04-30 18:12:03 +01:00
Gergő Magyar
3f0c74fea0
fix(deps): upgrade @ladybugdb/core to 0.16.0 to resolve native segfaults (#1235)
* fix(deps): upgrade @ladybugdb/core to 0.16.0 to resolve native segfaults

Resolves the SIGSEGV / access-violation (0xC0000005) / exit-139 crashes that
have been reported widely since 1.6.3. The native crashes originate in
@ladybugdb/core 0.15.x — primarily during FTS index creation, VECTOR
extension load, and concurrent query teardown — and are reproducible on
Linux, macOS and Windows. The maintainer-confirmed fix is to bump the
runtime to 0.16.0, which ships nodejs async + memory-management fixes,
extension ABI bump, and macOS Intel binaries.

Adopting 0.16.0 cleanly required three supporting changes; without them
the upgrade itself regresses other paths:

1. maxDBSize must be passed explicitly. 0.16.0 keeps the upstream JSDoc
   note that the default 0 is "introduced temporarily for now to get
   around with the default 8 TB mmap address space limit some
   environment". Constrained CI runners and laptops cannot reserve 8 TB
   and crash with "Buffer manager exception: Mmap for size
   8796093022208 failed." A new gitnexus/src/core/lbug/lbug-config.ts
   centralises a 16 GiB default (overridable via
   GITNEXUS_LBUG_MAX_DB_SIZE) and every Database() construction site
   now passes it.

2. enableCompression default flipped from false to true in 0.16.0. Every
   Database() call site is updated to pass false explicitly so existing
   GitNexus indexes keep the same wire format.

3. Bridge DB sidecar files (.wal, .shadow). 0.16.0 enforces a database-id
   check on .wal / .shadow sidecars and rejects opens whose sidecars
   belong to a different base name. writeBridge now (a) cleans the full
   sidecar set when removing the tmp slot, (b) renames .wal / .shadow
   alongside the main file during the atomic .tmp -> .lbug swap, and
   (c) wraps openBridgeDbReadOnly in a bounded retry on transient
   Win32-Error-33 lock errors. Eager db.init() / conn.init() forces the
   lazy native handle to surface lock contention at the retry site.

Known limitation (not a regression): on Windows the 0.16.0 native binary
does not release the OS file lock until the process exits, so the
close-then-reopen-same-process pattern raises Error 33 after the first
close. Production paths (analyze / serve / mcp each open the DB exactly
once per process) are unaffected, but eight tests that exercise the
pattern are guarded with a process.platform === 'win32' skip; CI's
Linux + macOS shards exercise them as before. Tracking upstream:
kuzudb/kuzu#3872 / #3883 / #4730.

Closes #1136 #1154 #1160 #1162 #1178 #1195 #1196 #1199 #1204 #1206
Refs #1209 (supersedes — Dependabot bump without the supporting fixes)

Made-with: Cursor

* fix(test): isolate LadybugDB native test state

Use per-suite LadybugDB databases in integration helpers so test forks do not reopen a database created by Vitest global setup, and centralize Windows-tolerant native temp cleanup for bridge tests.

* fix(lbug): avoid bridge existence reopen

Reuse the built LadybugDB config in the extension installer and avoid native close/reopen cycles when checking bridge existence on Windows.

Made-with: Cursor

* chore(docs): exclude local lbug plan

Keep the refactor planning note out of the PR while leaving the ignored local copy on disk.

Made-with: Cursor

* refactor(lbug): centralize database construction

Route LadybugDB opens through shared helpers so native constructor defaults stay consistent across core, pool, bridge, and extension install paths.

Made-with: Cursor

---------

Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
2026-04-30 17:40:39 +01:00
Abhigyan Patwari
883091f3e0
Merge pull request #1175 from ReidenXerx/fix/typescript-hof-callbacks-and-jsx-as-call
fix(typescript): capture missed CALLS edges from HOF callbacks and JSX
2026-04-30 21:55:27 +05:30
ReidenXerx
66ad5c4980 fix(typescript): anchor pair-with-arrow @declaration.function on inner arrow
Addresses the medium-severity finding in @abhigyanpatwari's review of #1175:
the four `pair`-with-arrow patterns in `query.ts` anchored
`@declaration.function` on the outer `pair` node instead of the inner
`arrow_function` / `function_expression`. For multi-action object literals
like Zustand's

    persist((set) => ({
      addItem:    (item) => doA(item),
      removeItem: (item) => doB(item),
      fetchData:  ()     => doC(),
    }))

`pass2AttachDeclarations.atPosition(pair.startLine, pair.startCol)`
resolved to the *parent* `(set) => ({...})` callback's scope (because the
pair node starts at the property-key token, before the inner arrow's
`@scope.function` range). All three pair-function defs landed in the
same parent's `ownedDefs`, and `resolveCallerGraphId.ownedDefs.find(...)`
returned the FIRST one — `addItem` — for every walk-up. Calls inside
`removeItem` and `fetchData` mis-attributed to `addItem`; those two
functions had zero outgoing CALLS edges in the registry-primary path.

Single-pair fixtures (`bump` in `store.ts`, `queryFn` in `query-hook.ts`)
masked the defect because there is no ambiguity when only one
Function-like def lives in the parent's `ownedDefs` — `find()` is
deterministic over a single-element set.

Fix: move the `@declaration.function` anchor from the outer `pair` to
the inner `arrow_function` / `function_expression`, mirroring the
`lexical_declaration` patterns above (`const fn = () => {}`). The def
then lands in the arrow's own scope's `ownedDefs`, the
`rangesEqual(anchor.range, innermost.range)` auto-hoist promotes the
binding to the parent scope (so importers + lookups still find the name
in the surrounding scope), and each pair-arrow becomes an independent
caller anchor in the walk.

Tests:

  * Updated `useFeature → fetchData` expectation to `queryFn → fetchData`
    in `typescript-hof-callbacks.test.ts`. The new attribution is
    structurally correct: `fetchData()` is called from inside the named
    pair-arrow `queryFn: () => fetchData()`. The pre-fix expectation
    only worked because the pair-pattern bug rerouted the walk past the
    syntactic owner.

  * Added `multi-action-store.ts` fixture with three pair-arrows
    (`addItem` / `removeItem` / `fetchData`) plus three top-level call
    targets (`doA` / `doB` / `doC`). Four new tests pin per-action
    attribution: positive (each action calls its own target), negative
    (no sibling leakage), exact-set (the full pair set is what we
    expect), and the regression fingerprint (`addItem → doB` MUST be
    empty).

Validation:

  * `REGISTRY_PRIMARY_TYPESCRIPT=1 vitest run` on
    typescript-hof-callbacks (12 tests, +4 new), typescript-jsx-as-call
    (7), typescript (236), typescript-finalize, typescript-cross-file-imports,
    call-attribution-issue-1166 (18), all scope-resolution unit suites:
    886/886 pass on registry-primary AND legacy DAG paths.
  * Legacy DAG attribution was already correct via @abhigyanpatwari's
    `tsExtractFunctionName` pair-parent handling (#1179, merged into this
    PR earlier); this fix brings the registry-primary path to the same
    behavior, restoring parity for multi-action objects.
  * `npx prettier --check .`, `tsc --noEmit`, and `eslint` clean on the
    three modified/added files.

Made-with: Cursor
2026-04-30 18:26:51 +03:00
ReidenXerx
ca3d520293 style(typescript): fix prettier formatting in tsExtractFunctionName
Single line-length fix in `gitnexus/src/core/ingestion/languages/typescript.ts`
flagged by `quality / format` CI on commit ef96603f. The unformatted block came
from the merge of upstream PR #1179 (`fix/issue-1166-calls-edges`) where the
`pair`-with-arrow / `pair`-with-string-key handling was added; prettier wanted
the `.find` callback inlined onto a single line.

No behavior change. Pre-commit hook would have caught this locally if the
husky postinstall step had been able to write `.git/config` on this dev machine.

Made-with: Cursor
2026-04-30 14:50:56 +03:00
Morieity
9cd8c3663f
fix(local-backend): (#1178)skip vector index query on unsupported platforms (#1181) 2026-04-30 07:57:05 +01:00
Gergő Magyar
d57f15f18d
Revert "chore(deps)(deps): bump uuid from 13.0.0 to 14.0.0 in /gitnexus-web (…" (#1222)
This reverts commit d31156288f.
2026-04-30 06:33:39 +01:00
dependabot[bot]
d31156288f
chore(deps)(deps): bump uuid from 13.0.0 to 14.0.0 in /gitnexus-web (#1211) 2026-04-30 05:26:15 +01:00
dependabot[bot]
02ed335ff6
chore(deps): bump release-drafter/release-drafter from 7.2.0 to 7.2.1 (#1208) 2026-04-30 05:02:15 +01:00
dependabot[bot]
52febea560
chore(deps)(deps): bump @langchain/openai in /gitnexus-web (#1215) 2026-04-30 05:01:33 +01:00
ReidenXerx
ef96603fed feat(package): add gitnexus commands for analysis
Introduced new scripts in package.json for GitNexus analysis:
- `gitnexus:refresh`: analyzes with embeddings and skills.
- `gitnexus:full`: forces analysis with embeddings and skills.

No production behavior changes. This enhances the development workflow for GitNexus users.
2026-04-29 16:37:06 +03:00
ReidenXerx
bb6aa0c855 Merge remote-tracking branch 'origin/fix/issue-1166-calls-edges' into fix/typescript-hof-callbacks-and-jsx-as-call 2026-04-29 15:56:24 +03:00
ReidenXerx
851d2ab749 fix(typescript): address review findings — formatting + tighter test assertions
Addresses the automated review findings on PR #1175:

- prettier --write the 3 files flagged by `quality / format` CI check
  (query.ts, typescript-hof-callbacks.test.ts, typescript-jsx-as-call.test.ts).

- [medium] typescript-jsx-as-call.test.ts: tighten the combined HOF+JSX
  assertion from `toBeGreaterThan(0)` to `toHaveLength(1)`. A single
  `<Foo />` is one logical invocation; the bounds-only assertion would
  have masked a duplicate-CALLS-edge regression (e.g. if both
  `jsx_self_closing_element` and a generic call pattern matched the
  same site).

- [medium] typescript-hof-callbacks.test.ts: replace the vacuously-true
  `for (c of calls) expect(...)` Zustand assertion with a structural
  one. Old form passed unconditionally when `calls` was empty (any
  change that silenced ALL CALLS edges from store.ts would have
  slipped through). New form asserts both: (a) at least one File-rooted
  edge exists (proving the `isCallerAnchorLabel` fallback fires), and
  (b) no edge sources from anything else (proving the fallback fires
  exclusively).

- [low] finalize-algorithm.ts (`findExportByName`): rephrase the
  comment to make the language-agnostic nature of the tie-break rule
  explicit. The implementation was already correct for all migrated
  languages; only the comment overplayed the TypeScript specificity.

- [low] captures.ts (arity synthesis): add a comment explaining why
  JSX call anchors (`jsx_self_closing_element` / `jsx_opening_element`)
  intentionally don't synthesize `@reference.arity`. Name-only
  resolution is correct for React (components aren't overloaded in the
  current graph model); a JSX-aware synthesizer counting jsx_attribute
  children would be needed if that ever changes.

No production behavior change. All 8/8 HOF + 7/7 JSX + 236/236
typescript + 11/11 api-deep-flow integration tests still pass.
gitnexus and gitnexus-shared typechecks clean.

Made-with: Cursor
2026-04-29 15:51:01 +03:00
Bennett Tai
07629a39d1
fix(docker): use HEAD probe so SSE heartbeat doesn't time out healthcheck (#1182)
Some checks failed
Release Candidate / Check if release candidate should run (push) Waiting to run
Release Candidate / ci (push) Blocked by required conditions
Release Candidate / Publish release candidate to npm (push) Blocked by required conditions
Release Candidate / Build & Push RC Docker images (push) Blocked by required conditions
CI / quality (push) Has been cancelled
CI / tests (push) Has been cancelled
CI / e2e (push) Has been cancelled
CI / scope-parity (push) Has been cancelled
CI / Save PR Metadata (push) Has been cancelled
CI / CI Gate (push) Has been cancelled
2026-04-29 06:58:17 +01:00
abhigyanpatwari
93a0be2310 fix(ts): attribute calls inside HOF/callback patterns to the right function
Two roots in `findEnclosingFunctionId` (parse-worker) and the parallel
`findEnclosingFunction` (call-processor):

A. `genericFuncName` scanned `arrow_function` / `function_expression`
   children for the first identifier and returned it. For unparenthesized
   arrows like `file => processFile(file)` the first identifier is the
   parameter `file`, so calls inside got attributed to a phantom
   `Function file` ID and emitted dangling CALLS edges that never showed
   up in `(:Function)-[:CALLS]->()` queries.

B. `tsExtractFunctionName` only named arrows whose parent was
   `variable_declarator`. Object-property arrows like
   `addItem: (item) => set(...)` (Zustand stores, TanStack queryFn,
   React Context providers, config objects) live under a `pair`, so they
   were treated as anonymous. With no named ancestor up to the file,
   every call inside fell back to the File and became invisible to
   `context()` / `impact()`.

Fix:
- `genericFuncName` returns null for anonymous JS/TS function-likes —
  the language hook is authoritative.
- `tsExtractFunctionName` resolves names from `pair` parents
  (property_identifier / string keys; computed keys stay anonymous).
- Mirror the new shape in `TYPESCRIPT_QUERIES` / `JAVASCRIPT_QUERIES` /
  the scope-resolution query so pair-with-arrow becomes a Function
  declaration node — call sourceIds resolve to a real graph node.

Adds 18 unit tests pinning attribution and definition behaviour for
plain helpers, `arr.map(x => fn(x))`, Promise constructor callbacks,
Zustand-style nested HOFs, TanStack query factories, string-keyed
pairs, and computed-key anonymity.

Fixes #1166

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 05:33:40 +05:30
ReidenXerx
7be595d317 fix(typescript): capture missed CALLS edges from HOF callbacks and JSX
Two distinct gaps in the TypeScript scope-resolution path were silently
dropping call edges in real-world React + TanStack + Zustand codebases.
On the bug reporter's repo (Sourcerer-fe, 1185 src/ functions), 504
missing Function->Function CALLS edges are now captured (+61.6%) and
the no-outgoing-CALLS orphan rate drops from 73.2% to 60.3%.

HOF / arrow-callback caller-attribution (3 cooperating fixes):
  - typescript/query.ts: @declaration.function anchor moved from the
    wrapping lexical_declaration to the inner arrow_function /
    function_expression, so anchor.range aligns with @scope.function and
    pass2AttachDeclarations lands the def on the arrow's own scope.
  - finalize-algorithm.ts: findExportByName prefers callable / class-
    like defs over Variable when localDefs contains both for the same
    name (TS emits two defs per `const fn = () => {}`).
  - graph-bridge/ids.ts: resolveCallerGraphId's walk-up class-fallback
    now uses isCallerAnchorLabel restricted to Function / Method /
    Constructor / Class / Interface / Struct / Enum, so module-level
    calls fall through to the File node instead of mis-attributing to
    sibling Variable defs (the Zustand `create()(devtools(...))`
    phantom-self-loop regression).

JSX as a CALLS edge (2 cooperating fixes):
  - typescript/query.ts: new TSX_JSX_QUERY_SUFFIX (TSX-grammar only)
    captures jsx_self_closing_element / jsx_opening_element as
    @reference.call.free / @reference.call.member. PascalCase predicate
    filters native HTML elements (<div>, <span>) so they don't emit
    edges to nonexistent targets.
  - typescript/captures.ts: shouldEmitReadMember extended with
    jsx_self_closing_element / jsx_opening_element parent cases to
    suppress phantom ACCESSES edges on member-form JSX names.

Tests: 8 HOF assertions + 7 JSX assertions across two new integration
test files plus 13 minimal fixtures. typescript.test.ts (236),
api-deep-flow.test.ts (11), and scope-resolution / scope-extractor unit
tests (613) pass with no regressions.

Made-with: Cursor
2026-04-28 20:52:07 +03:00
Abhigyan Patwari
dafda284bc
Merge pull request #1159 from abhigyanpatwari/fix/issue-1110-readme-web-ui
Some checks are pending
CI / quality (push) Waiting to run
CI / tests (push) Waiting to run
CI / e2e (push) Waiting to run
CI / scope-parity (push) Waiting to run
CI / Save PR Metadata (push) Blocked by required conditions
CI / CI Gate (push) Blocked by required conditions
Release Candidate / Check if release candidate should run (push) Waiting to run
Release Candidate / ci (push) Blocked by required conditions
Release Candidate / Publish release candidate to npm (push) Blocked by required conditions
Release Candidate / Build & Push RC Docker images (push) Blocked by required conditions
docs(readme): fix misleading Web UI section
2026-04-28 17:33:06 +05:30
abhigyanpatwari
2ff3e64f71 docs(readme): fix misleading Web UI section (#1110)
The "Web UI (browser-based)" section described an old client-side
architecture. Today gitnexus.vercel.app is a thin frontend that
auto-connects to a local `gitnexus serve` backend — there is no
ZIP drag-and-drop and no fully self-contained mode.

- Drop "No server, no install" claim
- Replace "drag & drop a ZIP" tagline with the actual onboarding step
- Add the missing `gitnexus serve` step to the local-dev block

Closes #1110

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 17:15:03 +05:30
Gergő Magyar
2a0c97c178
fix: add platform-aware semantic fallback (#1150)
* fix: add platform-aware semantic fallback

Make VECTOR an optional capability so Windows analysis remains stable while semantic embeddings can fall back to exact scan when native vector indexing is unavailable.

Made-with: Cursor

* fix: remove stale vector pool import

Keep the merge with main lint-clean after VECTOR loading moved out of the read pool.
2026-04-28 12:21:25 +01:00
Gergő Magyar
1f6df5fdbb
fix(swift): use official prebuilt parser runtime (#1130)
* fix(swift): use official prebuilt parser runtime

Vendor the official tree-sitter-swift 0.7.1 runtime package so Swift parsing works without source-building, while keeping the repo on the current tree-sitter runtime until the broader upgrade is ready. Also preserves Swift resolver correctness for overloaded owned functions and extension-backed type duplicates now that Swift is available by default.

Made-with: Cursor

* fix(swift): move duplicate type ordering into provider

Keep Swift extension candidate ordering behind the LanguageProvider contract and cover the Swift 0.7 init scanner path so parser runtime changes do not leak language-specific logic into shared resolution.

Made-with: Cursor

* fix(swift): address parser runtime review

Add explicit Swift prebuild checks and vendor guidance so parser runtime packaging remains observable and maintainable.
2026-04-28 09:57:42 +01:00
CauchYoung
86abc01445
fix(hooks): ignore global registry during staleness checks (#1141)
* fix(hooks): ignore global registry during staleness checks

* test(hooks): cover indexed repos under global registry

---------

Co-authored-by: laplace young <yangqk12@whu.edu.cn>
2026-04-28 09:39:18 +01:00
Ivan Uzun
46586a8319
fix(group): add configurable cross-link path exclusions to reduce false positives (#1093)
* fix(group): add configurable cross-link path exclusions to reduce false positives

Add matching.exclude_links_paths and matching.exclude_links_param_only_paths
to group.yaml config. These filter out noisy HTTP contracts (health checks,
param-only catch-all routes) from cross-link matching while preserving them
in the contract registry for documentation purposes.

Defaults are empty/false for backward compatibility — no behavior change
unless the operator explicitly configures exclusions.

* fix(group): address review findings — filter unmatched, normalize trailing slash, add tests

- Excluded contracts no longer inflate SyncResult.unmatched (isNoisy guard)
- pathPart in buildNoisyContractFilter strips trailing slashes before comparison
- 8 new unit tests for buildNoisyContractFilter covering all code paths
- Config-parser test asserts defaults for new matching fields

* fix(group): normalize configured exclusion paths and add root-path test

- Strip trailing slashes from configured exclude_links_paths at Set-build
  time so root path '/' (which normalizes to '') matches correctly
- Add test: exclude_links_paths: ['/'] suppresses http::GET::/ contracts
- Add new matching fields as commented examples in fixture group.yaml (DoD §2.4)

* docs(group): document exclude_links_paths and exclude_links_param_only_paths config fields

Add JSDoc to MatchingConfig interface, update the microservices guide
YAML example and field notes, and scaffold the new fields (commented out)
in the group create template.
2026-04-28 08:22:14 +01:00
Gergő Magyar
ffa0510f9a
fix(lbug): prevent DuckDB extension install hangs (#1129)
Some checks are pending
CI / quality (push) Waiting to run
CI / tests (push) Waiting to run
CI / e2e (push) Waiting to run
CI / scope-parity (push) Waiting to run
CI / Save PR Metadata (push) Blocked by required conditions
CI / CI Gate (push) Blocked by required conditions
Release Candidate / Check if release candidate should run (push) Waiting to run
Release Candidate / ci (push) Blocked by required conditions
Release Candidate / Publish release candidate to npm (push) Blocked by required conditions
Release Candidate / Build & Push RC Docker images (push) Blocked by required conditions
* fix(lbug): bound DuckDB extension install via ExtensionManager (closes #1128)

`gitnexus analyze` could hang indefinitely (60% / 85% on Windows) when
DuckDB's `INSTALL fts` or `INSTALL VECTOR` was unable to reach
`extensions.duckdb.org`. The DuckDB driver's INSTALL is a synchronous
network call, so any blocked egress would block the Node event loop
forever.

Replace the ad-hoc, in-process INSTALL/LOAD scattered across
`lbug-adapter.ts` and `pool-adapter.ts` with a single
`ExtensionManager` that owns the lifecycle of optional DuckDB
extensions:

* `LOAD` is always tried first — per-connection, idempotent, no network.
* If `LOAD` fails and policy permits, INSTALL runs in a short-lived
  child Node process bounded by `GITNEXUS_LBUG_EXTENSION_INSTALL_TIMEOUT_MS`
  (default 15s). The parent loop keeps spinning; on timeout the child is
  killed with SIGKILL and the capability is flagged unavailable.
* Capabilities and install attempts are cached per process, so a single
  bounded install per extension covers every subsequent call.

Install policy is now an explicit, per-context decision:

* `auto` (default for analyze) — try LOAD, fall back to bounded INSTALL.
* `load-only` — used by `pool-adapter` (serve / MCP read paths) so user
  queries never block on a network install.
* `never` — operator escape hatch for offline / airgapped environments.

`createFTSIndex` and `createVectorIndex` now check the boolean return
value before issuing the index DDL, so missing extensions degrade BM25
and semantic search gracefully without ever throwing during analyze.

Tests:
- New unit suite for `ExtensionManager` covering LOAD-first behavior,
  all three policies, install caching, observability, and warn dedup.
- Existing vector-extension integration tests pass against the new
  boolean return type.
- Existing embedding-pipeline mocks updated to return `true`.

Docs: `gitnexus/README.md` documents `GITNEXUS_LBUG_EXTENSION_INSTALL`
and `GITNEXUS_LBUG_EXTENSION_INSTALL_TIMEOUT_MS` with examples for
offline and slow-network environments.

Made-with: Cursor

* fix(lbug): move DuckDB extension install child into script

Keep the bounded out-of-process INSTALL behavior, but replace the inline child code with a stable packaged ESM script. This makes the child process directly runnable and gives debuggable stack traces without source-vs-dist branching or a runtime transpiler.

Made-with: Cursor
2026-04-27 23:09:17 +01:00
Prashant Pandey
038f2b33ec
Fix typo: capitalize Goliath in README (#1126) 2026-04-27 22:18:26 +01:00
Gergő Magyar
780ee83d52
fix(install): vendor tree-sitter-dart source (#1125)
Avoid remote git/SSH downloads for the Dart grammar during Docker and npm installs by resolving tree-sitter-dart from vendored source and building it during postinstall.

Made-with: Cursor
2026-04-27 21:15:37 +01:00
Gergő Magyar
38ccf7ceb1
fix: recover worker parse stalls (#1121)
* fix(ingestion): recover worker parse stalls

Made-with: Cursor

* test(ingestion): cover worker timeout controls

Made-with: Cursor

* docs: document analyze worker timeout controls

Made-with: Cursor

* fix(ingestion): fail fast after worker pool hard failure

Made-with: Cursor

* test(ingestion): stabilize worker stall recovery tests

Made-with: Cursor

---------

Co-authored-by: GitNexus Maintainer <maintainer@gitnexus.local>
2026-04-27 20:07:03 +01:00
Gergő Magyar
aa7bacd48b
fix(search): load FTS during core DB init (#1123)
* fix(search): load FTS during core DB init

Made-with: Cursor

* test(lbug): rely on core init for FTS extension loading

Made-with: Cursor
2026-04-27 19:43:09 +01:00
Brandy Good
2a799ae369
fix: start MCP bridge correctly when using npx (#1114)
* fix: start MCP bridge correctly when using npx

* test: add MCPBridge command discovery and spawn tests; fix stdin isolation

---------

Co-authored-by: genoshide <genoshide@users.noreply.github.com>
2026-04-27 18:19:02 +01:00
Gergő Magyar
2727a8ca2a
fix(mcp): project tool_map flows from handlers (#1113) 2026-04-27 17:13:02 +01:00
Ali Hamza
77844acb6a
Revert "fix: correct OpenCode skills directory from 'skill' to 'skills'" (#1104)
installOpenCodeSkills() was writing to ~/.config/opencode/skill/gitnexus/
but OpenCode only discovers skills from ~/.config/opencode/skills/*/SKILL.md.
Skills installed by `gitnexus setup` were silently ignored by OpenCode.

- Line 590: path.join(opencodeDir, 'skill') → 'skills'
- Line 587: updated JSDoc comment to match
2026-04-27 14:27:44 +01:00