Commit graph

931 commits

Author SHA1 Message Date
Roshan Warrier
fe87ff8f74
fix(symbol-table): index constructors in methodByOwner (#694) 2026-04-08 06:32:02 +01:00
Deepak Chauhan
be2401061e
[cli] Add qualified class lookups to SymbolTable (#716)
Some checks are pending
CI / quality (push) Waiting to run
CI / tests (push) Waiting to run
CI / e2e (push) Waiting to run
CI / Save PR Metadata (push) Blocked by required conditions
CI / CI Gate (push) Blocked by required conditions
2026-04-07 22:57:18 +01:00
Deepak Chauhan
b73233d232
feat(symbol-table): add class name lookup index (#707) 2026-04-07 13:29:50 +01:00
Tushar Dhawas (Kyo)
1c8ae5eb46
refactor: extract CLASS_LIKE_TYPES constant (#693)
* refactor: extract CLASS_LIKE_TYPES constant

* chore: apply prettier formatting
2026-04-07 11:56:03 +01:00
Zander Raycraft
b73928f732
scarf (#688)
Some checks are pending
CI / quality (push) Waiting to run
CI / tests (push) Waiting to run
CI / e2e (push) Waiting to run
CI / Save PR Metadata (push) Blocked by required conditions
CI / CI Gate (push) Blocked by required conditions
2026-04-06 18:39:43 -05:00
Dmytro Semchuk
19faf3b326
fix(docs): fix codex duplicate typo in main readme file (#687) 2026-04-06 22:20:35 +01:00
Gergő Magyar
cb772b9e29
feat: lookupMethodByOwner index for O(1) cross-class chain resolution (#665)
Add eagerly-populated methodByOwner index to SymbolTable, keyed by
ownerNodeId\0methodName. Used by walkMixedChain as a fast path for
resolving intermediate method calls in cross-class chains like
user.getAddress().getCity().getZipCode(), avoiding expensive fuzzy
lookups when the owner type is already known.

Handles overloaded methods: returns the first match when all overloads
share the same returnType, undefined when return types differ (ambiguous).

- Add lookupMethodByOwner to SymbolTable interface + implementation
- Add resolveMethodByOwner helper in call-processor.ts
- Add fast path in walkMixedChain before resolveCallTarget fallback
- Add Java cross-class chain fixture + 6 integration tests
- Add 148 unit tests for methodByOwner index behavior
2026-04-06 10:20:04 +01:00
ivkond
10f8815639
fix(ignore): respect negation patterns in .gitnexusignore (#654)
* fix(ignore): respect negation patterns in .gitnexusignore childrenIgnored

childrenIgnored checked `ig.ignores(rel) || ig.ignores(rel + '/')` which
short-circuited on the bare path — directory-only negation patterns like
`!iOS/` were missed because `ig.ignores('iOS')` treats the path as a file.
Now only checks with trailing slash since childrenIgnored is only called
for directories. Bare-name patterns (e.g. `local`) still match per gitignore spec.

Fixes #596

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

* test(ignore): add edge-case for bare `!dir` negation pattern

Verifies that `!iOS` (without trailing slash) also un-ignores the iOS/
directory — confirms the `ignore` package normalizes both `!dir` and
`!dir/` forms consistently when tested with a trailing-slash path.

Addresses non-blocking review suggestion on #654.

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

* docs(ignore): link ignore package docs for bare-name normalization

Adds references to the `ignore` package documentation in both the
childrenIgnored comment and the bare-negation test, explaining why
`!iOS` (without trailing slash) also re-includes the iOS/ directory.

Addresses non-blocking review suggestion on #654.

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 08:32:47 +01:00
Abhigyan Patwari
6ead5e5986
fix(setup): prefer global gitnexus binary over npx for MCP config (#653) 2026-04-06 07:46:10 +01:00
Abhigyan Patwari
14791ded4a
fix(server): return clean CORS rejection instead of 500 error (#646) 2026-04-06 07:45:19 +01:00
tantk
9eeb20bb04
fix: replace Array.push(...spread) with loop to prevent stack overflow (#650)
Some checks are pending
CI / quality (push) Waiting to run
CI / tests (push) Waiting to run
CI / e2e (push) Waiting to run
CI / Save PR Metadata (push) Blocked by required conditions
CI / CI Gate (push) Blocked by required conditions
* fix: replace Array.push(...spread) with loop to prevent stack overflow

On large codebases (78K+ C files), deferred arrays in
runChunkedParseAndResolve accumulate 100K+ entries. The spread
operator in push(...array) puts every element on the call stack
as a function argument, exceeding the maximum call stack size.

Replace all 11 occurrences of `arr.push(...other)` with
`for (const _item of other) arr.push(_item)` which uses
constant stack space regardless of array size.

Fixes #649

* fix: also replace push(...spread) in parsing-processor.ts

* style: format pipeline.ts to match prettier config

---------

Co-authored-by: tian kian tan <tan@example.com>
2026-04-05 21:54:09 +01:00
Gergő Magyar
5a7c0fdbb1
feat: same-arity overload disambiguation via type-hash suffix (#651) (#658)
* feat: same-arity overload disambiguation via type-hash suffix (#651)

Add ~type1,type2 suffix to Method/Constructor node IDs when same-arity
overloads with different parameter types exist in the same class. Also add
$const suffix for C++ const-qualified method overloads via new isConst field.

Key changes:
- typeTagForId() detects same-arity collisions and appends ~typeTag
- constTagForId() detects const/non-const collisions and appends $const
- TS/JS excluded from type-hashing (overload signatures collapse to impl body)
- Sequential findEnclosingFunction fixed: falls through on ambiguous same-class
  candidates instead of picking first; fallback path includes typeTag + constTag
- Per-call-site integration tests across Java, C#, Kotlin, C++, TypeScript
- Cross-file + chain resolution tests for all 5 languages
- C++ isConst extraction via tree-sitter type_qualifier in function_declarator

1710 integration + 18 unit tests pass.

* fix: preserve generic/template args in type-hash, perf + type safety fixes

- Add rawType field to ParameterInfo preserving full type text (vector<int>)
  while type stays simplified (vector). typeTagForId uses rawType for tags.
- Populate rawType in all 11 language method extractors
- Add buildCollisionGroups() to pre-group methods by name#arity (O(N) once
  per class instead of O(N) per method call)
- Cache method extraction in call-processor findEnclosingFunction fallback
- Fix null guards on getLanguageFromFilename in all findEnclosing paths
- Tighten SKIP_TYPE_HASH_LANGUAGES to ReadonlySet<SupportedLanguages>
- Document ID stability invariant on first overload introduction
- C++ integration tests: template overloads (vector<int> vs vector<string>),
  cross-file template + chain resolution, out-of-class method definitions

1718 integration + 20 unit tests pass.

* fix: add rawType to method-extraction unit test assertions

All 26 parameter .toEqual() assertions in method-extraction.test.ts
needed the new rawType field added to match ParameterInfo schema change.

* perf: cache tempMap/groups per class, consolidate extractFromNode

- Cache derived method map + collision groups per classNode.id in
  parsing-processor (avoids rebuild per method in same class)
- Replace per-call extractFromNode with cached class extraction +
  funcName:line lookup in call-processor fallback (avoids AST walk
  per call site)
- Remove dead clearEnclosingFunctionCache export, fix JSDoc

* test: add sequential-path integration test for same-arity overloads

Add skipWorkers option to PipelineOptions to force sequential parsing.
New test suite verifies type-hash disambiguation produces identical
results through the sequential path (parsing-processor + call-processor
findEnclosingFunction) as the worker path.
2026-04-05 21:51:55 +01:00
Gergő Magyar
0561d24efd
feat: METHOD_IMPLEMENTS edges, overload disambiguation, MethodExtractor unification (#574) (#642) 2026-04-04 18:41:47 +01:00
Abhigyan Patwari
153262304c
fix(mcp): unify stdout silencing to prevent embedder/pool-adapter conflicts (#645) 2026-04-04 11:56:49 +01:00
Abhigyan Patwari
16cf4c503e
fix(web): replace aggressive heartbeat disconnect with graceful reconnection (#643) 2026-04-04 11:56:35 +01:00
Abhigyan Patwari
57951a197b
fix(web): scope all backend calls to the active repo, not always the first (#644) 2026-04-04 11:55:34 +01:00
Gergő Magyar
63fc4c795f
feat: MethodExtractor configs for Python, PHP, Swift, Dart, Rust, Ruby (#624)
* feat: MethodExtractor configs for Python, PHP, Swift, Dart, Rust, Ruby with exhaustive integration tests

Add per-language MethodExtractionConfig for all remaining tree-sitter languages
(RFC #568 PR 2). Each config follows the established createMethodExtractor()
factory pattern — no new types, no parse-worker changes.

Configs:
- Python: @abstractmethod, @staticmethod/@classmethod, *args/**kwargs, type hints, _/__ visibility
- PHP: abstract/final/static keywords, PHP 8 #[] attributes, __construct/__destruct
- Swift: 5-level visibility, protocol-as-abstract, static/class methods, @ attributes
- Dart: _ convention visibility, abstract (no body), method_signature unwrapping
- Rust: pub visibility, &self receiver, trait_item + impl_item, #[] attributes
- Ruby: positional visibility via sibling-walk, singleton_method as static

Integration fixtures (18 directories) covering 3 resolution patterns:
- Method enrichment: parameterTypes, isAbstract, isFinal, annotations on graph nodes
- Overload dispatch: arity-based CALLS resolution via parameterTypes
- Abstract dispatch: abstract/concrete method distinction (Python, PHP, Rust, Swift)

Go deferred — requires factory changes for receiver-based method extraction.

Closes #571

* fix: address code review findings across 6 MethodExtractor configs

Fix all actionable items from the PR #624 deep-dive review:

Dart (critical — fixes 6 CI failures):
- isDartStatic: check children first, siblings as fallback
- isDartAbstract: handle declaration nodes for abstract methods
- extractSingleParam: detect required keyword as sibling token
- Add declaration to methodNodeTypes, mixin_declaration to typeDeclarationNodes
- Add member call query for variable assignments in tree-sitter-queries

Python:
- hasDecorator now matches dotted paths (e.g. @abc.abstractmethod)
- Fix version comment from ^0.23.6 to 0.23.4

PHP:
- Add enum_declaration to typeDeclarationNodes (PHP 8.1+)
- Add version comment for 0.23.12

Swift:
- Add isOverride using hasKeyword/hasModifier pattern

Rust:
- Fix version comment from ^0.23.2 to 0.23.1

Also: identifier fallback in generic.ts for mixin owner names,
Dart integration test label fix (Method vs Function), version
comment for tree-sitter-dart 1.0.0.

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

* fix: Dart extension_declaration and Ruby module_function support

Dart:
- Add extension_declaration to typeDeclarationNodes and extension_body
  to bodyNodeTypes — extension methods are now extracted into the graph
- Add extension_declaration and mixin_declaration to CLASS_CONTAINER_TYPES
  for HAS_METHOD edge resolution

Ruby:
- module_function now maps to visibility 'private' in extractRubyVisibility
- module_function methods marked isStatic via backward-walk in isStatic
- Override semantics: private/public after module_function resets isStatic

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

* feat(go): Go MethodExtractor config with receiver-based extraction

Add Go as the 13th language with a per-language MethodExtractor config.
Go methods are top-level (not nested in struct bodies), so this adds
extractFromNode() to the MethodExtractor interface for direct method
node extraction without an enclosing class.

Config extracts:
- Name from field_identifier (methods) / identifier (functions)
- Return type including multi-return (first type from parameter_list)
- Parameters with variadic support
- Visibility via uppercase/lowercase convention
- Receiver type with pointer unwrapping (*User → User)
- isStatic for functions (no receiver)

Infrastructure:
- extractOwnerName optional hook on MethodExtractionConfig
- extractFromNode on MethodExtractor (factory auto-implements)
- Parse-worker uses extractFromNode when no enclosing class found
- method_declaration added to CLASS_CONTAINER_TYPES

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

* test: method enrichment integration tests for 7 languages + TS abstract class fix

Add method-enrichment integration test fixtures and test blocks for
Go, C++, Java, Kotlin, TypeScript, JavaScript, and C#. Each fixture
tests: class detection, HAS_METHOD edges, EXTENDS edges, isAbstract,
isStatic, annotations, parameterTypes, and CALLS edge resolution.

Fixes found during testing:
- Remove method_declaration from CLASS_CONTAINER_TYPES (added for Go
  but broke Java/C# HAS_METHOD edge resolution — method_declaration
  is also Java's method node type)
- Add abstract_class_declaration query to TypeScript tree-sitter
  queries (was missing, so abstract classes were invisible to pipeline)

1699 integration tests pass across 20 test files, 0 regressions.

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

* style: format typeDeclarationNodes array for better readability in PHP config

* fix: Go interface methods + Rust impl-for-Struct owner resolution

Go:
- Add method_elem to methodNodeTypes so interface method signatures
  are extractable as abstract methods
- Integration test: Animal interface detected, Speak isAbstract,
  CALLS edges from app.go

Rust:
- Add extractOwnerName to resolve impl Trait for Struct to the
  concrete Struct (not the Trait) — fixes method misattribution
- Fix findEnclosingClassId to generate Struct: label (not Impl:)
  for impl blocks so HAS_METHOD edges resolve to struct nodes
- Tighten abstract-dispatch test: assert SqlRepo owns find/save

generic.ts:
- Fix extractOwnerName fallback: when hook returns a value, skip
  both name-field and type_identifier scan (was overwriting result)

1703 integration tests pass, 0 regressions.

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

* fix: code review response — Rust impl label, Swift params, Dart async, sequential methodExtractor

Address code review findings from PR #624:

- ast-helpers: Rust `impl Trait for Struct` uses Struct label (matches existing
  graph node), plain `impl Struct` uses Impl label (matches definition.impl)
- swift: fix parameter type extraction (user_type not type_annotation), detect
  default values as function_declaration siblings, add version comment
- dart: isDartAsync now detects async*/sync* generators, add clarifying comment
  for declaration nodes in extension bodies
- python: correct isFinal comment (PEP 591 @typing.final exists, just not modeled)
- parsing-processor: port methodExtractor enrichment to sequential path so
  isAbstract/isStatic/visibility/annotations/isFinal populate on <15-file repos
- tests: remove silent `if (prop !== undefined)` guards, assert properties
  directly, fix label queries (Dart Method vs Function, Swift Method for protocol
  methods), add Rust HAS_METHOD sourceLabel tests, Swift parameterTypes tests,
  and Dart async/sync* integration tests with fixture

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

* fix: Rust grammar gap + qualified method IDs to resolve same-file collisions

Phase 1 — Rust grammar:
- Add function_signature_item query to RUST_QUERIES so abstract trait methods
  (fn speak(&self) -> String;) become graph nodes with isAbstract=true

Phase 2 — Qualified method IDs:
- findEnclosingClassInfo returns {classId, className} for AST-based class lookup
- Both parsing paths (sequential + worker) qualify method/property IDs with
  enclosing class: Method:file:ClassName.method instead of Method:file:method
- extractFuncNameFromSourceId handles ClassName.method format
- Fixes silent data loss when same-name methods in different classes shared a
  file (e.g., Animal.speak and Dog.speak both now exist as distinct graph nodes)

Test updates:
- Rust: abstract+concrete trait methods both verified, function count adjusted
- Python: static method disambiguation now emits 2 CALLS edges (correct — no
  more ID collision masking the second call)

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

* fix: owner-aware resolution for qualified method IDs

Address Codex adversarial review findings after qualified ID change:

- findEnclosingFunction: disambiguate candidates by ownerId when multiple
  same-name methods exist in file; qualify fallback-generated IDs
- findEnclosingFunctionId (worker): qualify sourceIds with enclosing class
  name so CALLS source attribution matches definition-phase node IDs
- buildExportedTypeMapFromGraph: use lookupExactAll + nodeId match instead
  of lookupExactFull which returns first definition for bare name

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

* fix: methodExtractor variadic arity, return type preservation, PHP abstract dispatch

Three bugs in the methodExtractor enrichment path broke 17 integration tests:

1. Variadic parameterCount: buildMethodProps and parse-worker set
   parameterCount = info.parameters.length even for variadic functions,
   causing arity filtering to reject valid calls. Now checks isVariadic
   and sets parameterCount = undefined (matching extractMethodSignature).

2. C++ bare `...` token: extractCppParameters only iterated named
   children, missing the unnamed `...` token in C-style variadics like
   log_entry(const char* fmt, ...). Added fallback scan of all children.

3. Return type stripping: All 11 language extractReturnType functions
   used extractSimpleTypeName() which strips generic parameters
   (List<User> → "List", Task<User> → "Task"). Changed to .text?.trim()
   to preserve full generic types needed for for-loop iterable resolution,
   async-await binding, and return-type inference.

Also fixes PHP abstract dispatch test that matched SqlRepository instead
of the interface due to ambiguous filePath.includes('Repository') filter,
and adds parent-walk fallback in PHP isAbstract for extractFromNode path.

* chore: remove plan and review artifacts from PR

* fix: address Round 4 review findings + infrastructure improvements

- Ruby: add singleton_class support for class << self methods (4 new tests)
- PHP: add enum_declaration to CLASS_CONTAINER_TYPES
- Dart: add mixin/extension labels to CONTAINER_TYPE_TO_LABEL
- Swift: add TODO for unverifiable struct/enum node types on Node 22
- C#: add grammar version comment (0.23.1)
- Ruby: fix version comment range to pin (0.23.1)
- Rust/ast-helpers: add cross-reference comments for impl_item duplication
- ast-helpers: document CLASS_CONTAINER_TYPES ↔ typeDeclarationNodes invariant
- generic.ts: replace Array.includes with Set for O(1) dedup in addNestedBodies
- Go/Python/Ruby: align isAbstract signature with 2-param interface contract
- CLAUDE.md: fix malformed backtick around gitnexus:start HTML comment
- parsing-processor: add per-class method extraction cache (eliminates O(N*M))
- ast-helpers: add scoped_type_identifier to impl_item resolution
- call-processor: add dev-mode warnings at silent candidates[0] fallbacks
- MCP context(): surface methodMetadata for Method/Function/Constructor nodes
- resources.ts: update schema to list all stored Method properties

* fix: singleton_class HAS_METHOD edge regression in findEnclosingClassInfo

singleton_class (class << self) was added to CLASS_CONTAINER_TYPES but
has no name field — its receiver `self` has node type 'self', not
'identifier'. findEnclosingClassInfo now walks up to the enclosing
class/module to inherit its name, matching ruby.ts:extractOwnerName.

Also fixes findEnclosingClassNode in parse-worker.ts to skip
singleton_class and return the actual class/module node.

Adds integration test assertions for from_habitat (class << self method):
HAS_METHOD edge from Animal, isStatic=true, parameterCount=1.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 16:11:31 +01:00
Abhigyan Patwari
5c4fca21c3
Merge pull request #626 from ivkond/feat/intra-repo-service-tracking-clean
[group] Intra-repo service communication tracking
2026-04-03 17:04:24 +05:30
Nguyen Hai Son
dd0f5eed7d
feat(vue): Vue SFC support + destructured call result tracking (#604)
* feat(vue): add Vue SFC (.vue) support for indexing

Vue Single File Components are now fully supported in the indexing pipeline.
The implementation extracts <script> / <script setup> blocks from .vue files
and parses them using the existing TypeScript tree-sitter grammar — no new
npm dependencies required.

Key changes:
- SFC script extractor: regex-based extraction of <script setup lang="ts">
  blocks with correct line offset mapping back to the .vue file
- Vue language provider: reuses TypeScript queries, type config, field
  extractors, and named binding extraction
- Import resolution: .vue added to EXTENSIONS so `import Foo from './Foo'`
  resolves to Foo.vue; Vue import resolver delegates to TS resolver for
  tsconfig path alias support
- Export detection: <script setup> top-level bindings are implicitly exported
- Template component detection: PascalCase tags in <template> emit CALLS edges
- Line offsets applied to all emitted positions (startLine, endLine, route
  lineNumbers, decorator positions) in both worker and sequential paths

Validated on a 3,553-file Vue project:
  Before: 24,693 nodes | 73,614 edges | 0 symbols from .vue
  After:  30,495 nodes | 112,324 edges | 5,213 symbols from .vue
          18,682 imports from .vue | 5,826 vue-to-vue imports

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

* feat(typescript): track destructured call results in TypeEnv

Extend `extractPendingAssignment` to handle object destructuring from
function calls and await expressions:

  const { isMaker } = useUserRole()
  const { data } = await fetchData()
  const { name } = repo.getProfile()

Previously, only `const { x } = someVariable` (identifier RHS) produced
TypeEnv bindings. Call-expression RHS was silently skipped, leaving
destructured properties untracked.

The fix emits a synthetic `callResult` item plus N `fieldAccess` items
per destructured property, which the existing fixpoint resolver processes
in 2 iterations. No changes needed to type-env.ts, PendingAssignment
types, or call-processor — the existing infrastructure handles it.

Also extracts a `collectDestructuredFields` helper to share the
object_pattern property iteration logic between the identifier and
call-expression branches.

Note: Full property-type resolution requires the callee to have a
declared returnType in the SymbolTable. Arrow-function composables
without type annotations (common in Vue/React) won't resolve property
types until return-type inference is added in a future change.

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

* fix(vue): address PR review issues for Vue SFC support

- Extract duplicated isVueSetupTopLevel to vue-sfc-extractor.ts shared
  utility, removing identical copies from parse-worker.ts and
  parsing-processor.ts
- Fix VUE_BUILT_INS to be a superset of TS BUILT_INS by importing and
  spreading the TypeScript set, preventing spurious unresolved calls for
  standard built-ins (Symbol, BigInt, WeakMap, array methods, etc.)
- Add Vue template component CALLS edge resolution in both sequential
  and worker paths (call-processor.ts), matching PascalCase template
  tags against imported .vue file basenames via the import map
- Add integration test for template PascalCase CALLS edges
  (App.vue → Button.vue)
- Add integration test for isExported: false on non-setup <script>
  blocks (OldStyle.vue options API)
- Add comment explaining TEMPLATE_RE greedy regex behavior for nested
  template tags
- Fix stale language count comment (14 → 15) and remove dead code
  branch in test

Made-with: Cursor

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 14:18:55 +05:30
Chirag Nighut
e3d73a7aed
Java method reference (#622) 2026-04-02 15:16:35 +01:00
ivkond
255e3e79eb fix(group): address 4 HIGH-priority issues from PR #626 review
1. Path traversal via group name — add validateGroupName() with regex
   [a-zA-Z0-9][a-zA-Z0-9_-]*, called in getGroupDir (defense in depth)

2. gRPC proto regex can't handle nested braces — replace serviceRe with
   extractServiceBlocks() brace-depth counter (init depth=1, skip
   malformed protos)

3. Service boundary detector directory exclusions — add EXCLUDED_DIRS
   set (vendor, target, build, dist, __pycache__, .venv, venv, .tox,
   .mypy_cache, .gradle, .mvn, out, bin) replacing inline node_modules

4. Double-close of LadybugDB pools — remove blanket closeLbug() from
   cli/group.ts; sync.ts per-id cleanup is sufficient

Tests: 22 new tests across 5 files. Full suite: 4706 passed, 0 failed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 12:55:33 +03:00
ivkond
be4458b650 docs: add design spec and implementation plan for PR #626 HIGH fixes
Spec covers 4 HIGH-priority issues from review: path traversal via
group name, gRPC proto regex nested braces, service boundary detector
directory exclusions, double-close of LadybugDB pools.

Plan: 6 tasks with TDD, ordered by complexity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 12:55:18 +03:00
ivkond
4fed097abb feat(group): add sync pipeline, CLI, MCP tools, and monorepo fixture
Wire extractors into the sync pipeline with service boundary detection.
GroupService provides high-level API for all group operations.

- Sync pipeline: orchestrates extraction (HTTP, gRPC, topics) with
  service boundary assignment and exact matching
- GroupService: groupList, groupSync, groupContracts, groupQuery,
  groupStatus (groupImpact deferred to cross-repo follow-up PR)
- CLI: group create/add/remove/list/sync/contracts/query/status
- MCP tools: group_list, group_sync, group_contracts, group_query,
  group_status
- Monorepo fixture: 3 services (auth/orders/gateway) connected via
  gRPC + Kafka + HTTP — all intra-repo cross-links discovered
- Documentation: CLI commands and MCP tools added to both READMEs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:40:31 +03:00
ivkond
4fa395f4b6 feat(group): add service boundary detection and contract extractors
Service communication detection for microservice monorepos:

- ServiceBoundaryDetector: auto-detects service boundaries via markers
  (package.json, go.mod, Dockerfile, pom.xml, Cargo.toml, build.gradle,
  pyproject.toml, etc.)
- HttpRouteExtractor: graph-assisted (Strategy A) with source-scan
  fallback (Strategy B) for Spring, Express, Laravel, FastAPI providers
  and fetch/axios consumers
- GrpcExtractor: parses .proto files, detects Go/Java/Python/TS gRPC
  servers (RegisterXxxServer, @GrpcService, add_XxxServicer_to_server,
  @GrpcMethod) and clients (NewXxxClient, newBlockingStub, XxxStub)
- TopicExtractor: Kafka (@KafkaListener, producer.send), RabbitMQ
  (@RabbitListener, channel.publish/consume), NATS (nc.Subscribe/Publish)
  across Java, Node, Go, and Python

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:40:12 +03:00
ivkond
52277247fe feat(group): add group infrastructure and contract matching
Core foundation for repository group analysis:
- Type system: ContractType, ExtractedContract, StoredContract, CrossLink
  with optional `service` field for intra-repo matching
- Config parser for group.yaml (repos, detection flags, matching thresholds)
- Contract registry storage with atomic writes
- Exact matching engine with per-type normalization (HTTP, gRPC, topic)
  and intra-repo support (different services within same repo can match)
- Extract LadybugDB pool-adapter from MCP backend for reuse by sync pipeline
- Git staleness checker for group status reporting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:39:43 +03:00
Gergő Magyar
ba5de0bde4
feat(cpp): C/C++ MethodExtractor config with pure virtual detection (#617)
* feat(cpp): C/C++ MethodExtractor config with pure virtual detection (#572)

- Pure virtual (= 0) detected as isAbstract via token scanning
- virtual/final/override via hasKeyword and virtual_specifier children
- Access specifier visibility via backward sibling walk (public:/private:/protected:)
- Pointer/reference parameter types extracted correctly
- Constructor and destructor support via declaration node type
- Static detection via storage_class_specifier
- 16 new tests covering all acceptance criteria

* fix(cpp): isVirtual infers from override/final + out-of-class resolution

- isVirtual returns true for override/final methods (C++ mandates these
  are virtual)
- Add findClassNodeByQualifiedName to parse-worker: resolves Foo::bar()
  back to the Foo class declaration for method extractor enrichment
- Handles pointer/ref return types, constructors, destructors
- Integration test for virtual/static/constructor inline methods
- 233 unit+integration tests pass, 97 C++ resolver tests pass

* fix(cpp): address review — deep pointers, templates, unions, trailing returns

- Fix extractParamName: recursive unwrap for int** ptr → "ptr" (not "**ptr")
- Fix findFunctionDeclarator: recursive unwrap for multi-level pointer chains
- Template methods: generic extractor unwraps template_declaration to inner node
- union_specifier: added to typeDeclarationNodes, visibility defaults to public
- Trailing return type: auto foo() -> T now extracts T instead of "auto"
- Fix version comment: ^0.22.4 → ^0.23.4 to match package.json
- 4 new tests: double pointer params, template methods, union methods, trailing returns

* fix(cpp): template method visibility + union isTypeDeclaration test

extractCppVisibility now walks from the template_declaration parent
when the node is wrapped by a template, restoring correct access-
specifier resolution for templated class methods.

Also adds missing isTypeDeclaration assertion for union_specifier and
expands the template method test with explicit visibility checks.

* fix(cpp): address deep gap analysis review findings

- findClassNodeByQualifiedName: recursive pointer/reference
  declarator unwrap, fixing out-of-class linking for deep pointer
  return types (e.g. int** Foo::bar())
- findClassNodeByQualifiedName: recurse into namespace_definition
  blocks so namespace-wrapped classes resolve correctly
- Suppress = delete / = default special members from extraction
  via delete_method_clause / default_method_clause node detection
- Update known-gaps: namespace-wrapped classes, const-overload collapse
- Add tree-sitter-c version comment for consistency
- toBeFalsy() → toBe(undefined) for precise isVirtual assertion
- Tests: = delete, = default, = 0 non-regression, operator overloads,
  deep pointer return types, default visibility (class vs struct),
  multiple access specifier sections
2026-04-01 18:07:11 +01:00
Abhigyan Patwari
dc86ea96dc chore: release v1.5.3 — update CHANGELOG and package-lock
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 21:35:24 +05:30
Abhigyan Patwari
d1adc8331a chore: release v1.6.0 — update CHANGELOG and package-lock
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 21:32:11 +05:30
Abhigyan Patwari
80d363f145
fix(wiki): Azure OpenAI compat and HTML viewer script injection (#618)
* fix(wiki): Azure OpenAI compat and HTML viewer script injection

- Use max_completion_tokens instead of deprecated max_tokens for all models
- Skip sending temperature for Azure provider (some models reject non-default values)
- Simplify Azure interactive setup: endpoint + deployment + key (3 prompts instead of 7)
- Escape </script> in embedded JSON to prevent premature script tag closure

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

* fix(test): align wiki-llm-client test with max_completion_tokens change

The test expected max_tokens for non-reasoning models, but the source
now uses max_completion_tokens for all models since max_tokens is
deprecated by newer OpenAI models.

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

---------

Co-authored-by: Abhigyan Patwari <abhigyan@Abhigyans-MacBook-Air.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 21:30:43 +05:30
Gergő Magyar
12be2025f1
feat(ts,js): TypeScript/JavaScript MethodExtractor config (#588)
* feat(ts,js): MethodExtractor config for TypeScript and JavaScript (#570)

Add per-language method extraction config following the established
JVM and C# patterns. Shared config base mirrors the field extractor's
typescript-javascript.ts pattern — TS-only node types are harmless
no-ops for JS.

Key features:
- isAbstract for abstract class methods and interface methods
- Parameter extraction with isOptional (?:, defaults) and isVariadic (...)
- Decorator extraction from preceding body-level siblings
- isAsync and isOverride detection
- Visibility via accessibility_modifier two-pass pattern
- Return type extraction unwrapping type_annotation

* test(ts,js): add override, getter/setter, destructured param tests

Address code review findings:
- Add override method detection test
- Add getter/setter extraction test
- Add destructured parameter with type annotation test
- Tighten constructor and private method assertions

* refactor(ts,js): address code review findings

- Replace O(M*N) decorator index scan with previousNamedSibling walk
- Remove dead findVisibility 'modifiers' fallback (TS uses
  accessibility_modifier, not a modifiers wrapper)
- Document call_signature/construct_signature as known gaps
- Document that TS constructors are method_definition nodes
- Remove unused findVisibility import

* fix(ts,js): type guard before cast, add generator/computed/overload tests

- Use type guard pattern (Set.has check before as-cast) in visibility
  extraction to ensure string is validated before narrowing
- Add generator method test (*items()) — confirms extraction works
- Add computed property name test ([Symbol.iterator]) — documents
  bracket-in-name behavior as intentional
- Add class-level method overload test — verifies overload signatures
  + implementation are all extracted

* fix(ts,js): detect #private methods as visibility 'private'

ES2022 private class methods (#name) use private_property_identifier
as their name node type. Detect this and return 'private' visibility
instead of the default 'public'.

* fix(ts,js): address review findings + close ingestion gaps

- hasKeyword/findVisibility: skip name field child to prevent false
  positives on soft-keyword method names (e.g. `abstract()`, `static()`)
- extractTsJsParameters: filter TS `this` parameter (compile-time only)
- extractMethodSignature: mirror `this`-param skip in fallback path
- tree-sitter queries: capture abstract_method_signature,
  method_signature, and private_property_identifier for TS; add
  private_property_identifier for JS
- Remove dead childForFieldName('name') fallbacks and typeFromAnnotation
  fallback
- Add 10+ unit tests, 4 integration tests through query pipeline

* test(ts): update HAS_METHOD count for interface method_signature capture

The new method_signature query now captures ILogger.log() as a Method
node with a HAS_METHOD edge, increasing the expected count from 4 to 5.

* fix(ts,js): address second review — async generator test, declare module gap

- Add async generator method test (async *values() → isAsync: true)
- Document declare module/global augmentation as known gap
2026-04-01 14:09:59 +01:00
Abhigyan Patwari
dcf40da3a8 fix: ensure import rewrites survive npm publish lifecycle
npm runs `prepare` after `prepack` during publish, so the previous
`prepare: tsc` overwrote the rewritten imports before packing.
Both `prepare` and `prepack` now run the full build script so the
tarball always contains rewritten relative imports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 17:28:14 +05:30
Abhigyan Patwari
c617350c58 chore: release v1.5.1 — update CHANGELOG and package-lock
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 17:05:08 +05:30
Abhigyan Patwari
71255a096c
fix: bundle gitnexus-shared into CLI dist (#613)
* fix(ci): build gitnexus-shared before publish, use CHANGELOG for release notes

The publish workflow was missing the gitnexus-shared build step that
the setup-gitnexus composite action provides. Since PR #536 unified
the ingestion pipeline, gitnexus imports types from gitnexus-shared,
so it must be built first.

Also replaces generate_release_notes with CHANGELOG.md extraction so
GitHub Releases use the reviewed changelog entry instead of a flat
PR title list.

Made-with: Cursor

* fix: bundle gitnexus-shared into CLI dist to fix module resolution

gitnexus-shared was declared as a file: dependency but never published
to npm, causing ERR_MODULE_NOT_FOUND for users installing gitnexus
globally. The build script now copies gitnexus-shared/dist into
dist/_shared/ and rewrites bare specifiers to relative paths.

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

* fix: move gitnexus-shared to devDependencies, use tsc for prepare

gitnexus-shared must remain available for tsc to resolve imports during
development/CI, but is not needed at runtime since it's bundled into
dist/_shared/. Moving it to devDependencies keeps it out of production
installs while allowing compilation. The prepare script now runs plain
tsc (no shared bundling needed for local dev).

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

---------

Co-authored-by: Abhigyan Patwari <abhigyan@Abhigyans-MacBook-Air.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 17:04:39 +05:30
Gergo Magyar
39322e37df fix(ci): build gitnexus-shared before npm ci in publish workflow
The publish job failed because npm ci triggers the prepare script (tsc)
before gitnexus-shared types are available. Add the same build step
that the setup-gitnexus composite action uses in CI.
2026-04-01 07:35:46 +01:00
Abhigyan Patwari
0e6f8f1720
chore: release v1.5.0 — update CHANGELOG and package-lock (#611)
Made-with: Cursor

Co-authored-by: Abhigyan Patwari <abhigyan@Abhigyans-MacBook-Air.local>
2026-04-01 11:24:38 +05:30
Abhigyan Patwari
113dadf945 chore: bump version to 1.5.0
Made-with: Cursor
2026-04-01 10:34:46 +05:30
Abhigyan Patwari
af421cc9a3
feat(web): repo landing screen with selectable repo cards (#607)
* feat(web): add repo landing screen with selectable repo cards

Instead of auto-loading the first indexed repo when the backend is
detected, show a landing screen that lets users choose which repo
to explore or analyze a new one. This addresses the UX gap where
users with multiple indexed repos had no way to pick—they were
always sent to the first one found.

- New RepoLanding component with clickable repo cards (name, stats,
  indexed date) and an embedded RepoAnalyzer for new repos
- DropZone gains a 'landing' phase between server detection and
  graph loading
- Shared connectToRepo handler replaces the old handleAnalyzeComplete
  for both repo selection and post-analysis connection

Made-with: Cursor

* fix(web): update e2e flow for repo landing screen

The new landing screen intentionally stops auto-loading the first indexed
repo, so the existing Playwright tests were still waiting for the explorer
to appear automatically. Update the specs to select a repo from the landing
screen before asserting on the graph, and add a stable test id for repo cards.

Also format DropZone to satisfy the Prettier CI check.

Made-with: Cursor

* fix(e2e): use waitFor instead of instant isVisible for landing card

locator.isVisible() is a non-retrying instant check — the landing card
hadn't rendered yet when it was called, causing the click to be silently
skipped. Switch to waitFor which properly polls until the element appears.

Made-with: Cursor

---------

Co-authored-by: Abhigyan Patwari <abhigyan@Abhigyans-MacBook-Air.local>
2026-04-01 10:34:10 +05:30
Gergő Magyar
c72890d59d
feat(csharp): C# MethodExtractor config (#582)
* feat(csharp): add C# MethodExtractor config (#573)

Add C# method extraction config mirroring the JVM pattern from PR #576.
Wire csharpMethodConfig into the C# language provider and add 18 tests
covering classes, interfaces, abstract classes, structs, records,
constructors, params/out/ref/optional parameters, sealed methods,
attributes, and visibility modifiers.

* fix(csharp): add destructor, operator, conversion operator, and in-param support

- Add destructor_declaration, operator_declaration, and
  conversion_operator_declaration to methodNodeTypes
- Custom extractName for operators (e.g., "operator +", "implicit operator double")
- Fix extractReturnType for operator declarations (use type field, not returns)
- Add in modifier to parameter extraction (alongside out/ref)
- Add 4 new tests: destructor, operator+, implicit conversion, in parameter

* fix(csharp): add ref param test and document compound visibility limitation

- Add test for ref parameter modifier (was only testing out)
- Document that protected internal / private protected resolve to first modifier

* feat(csharp): support compound visibilities (protected internal, private protected)

- Add 'protected internal' and 'private protected' to FieldVisibility union
- Detect compound modifiers in both C# method and field extractors via
  collectModifierTexts helper scanning adjacent modifier nodes
- Add 2 tests for compound visibility detection

* feat(csharp): primary constructors, virtual/override/async, primary fields

Address all known limitations from review:

- Primary constructor support (C# 12): add extractPrimaryConstructor to
  MethodExtractionConfig and extractPrimaryFields to FieldExtractionConfig.
  Record params become public readonly properties; class params become
  private captured fields.
- Add isVirtual, isOverride, isAsync optional fields to MethodInfo,
  MethodExtractionConfig, NodeProperties, and parse-worker propagation.
- Detect virtual/override/async modifiers in C# method config.
- Move collectModifierTexts to shared helpers.ts (deduplicate).
- Fix destructor name to ~ClassName (disambiguates from constructor).
- Add expression-bodied method test.
- 118 tests total across method + field extraction suites, all passing.

* fix(csharp): review round 2 — annotations, record_struct, grammar pin

- Fix primary constructor annotations: use [] instead of extracting
  class-level attributes (C# has no syntax for ctor-specific attributes)
- Add record_struct_declaration to typeDeclarationNodes in both method
  and field extractors, CLASS_CONTAINER_TYPES, and isRecord visibility check
- Pin tree-sitter-c-sharp version (^0.23.1) in params comment

* fix(csharp): complete record_struct query + label mapping, sealed override test

- Add record_struct_declaration capture patterns to tree-sitter-queries.ts
  (type definition + primary constructor)
- Add record_struct_declaration → 'Struct' in CONTAINER_TYPE_TO_LABEL
- Assert isOverride: true alongside isFinal in sealed override test

* fix(csharp): record_struct label mismatch, add record struct + documented limitation tests

- Fix record_struct_declaration query tag: @definition.struct (not @definition.record)
  to match CONTAINER_TYPE_TO_LABEL and prevent broken HAS_METHOD edges
- Add 3 record struct tests: isTypeDeclaration, method extraction, primary constructor
- Add documented limitation tests: partial method (isAbstract: false), generic type
  parameter stripping (name excludes <T>)

* fix(csharp): remove record_struct_declaration — not a real tree-sitter node type

tree-sitter-c-sharp 0.23.1 parses 'record struct' as record_declaration
(absorbs the 'struct' keyword as an unnamed child token). The non-existent
record_struct_declaration in queries caused TSQueryErrorNodeType, breaking
ALL C# file processing.

Remove from: tree-sitter-queries.ts, typeDeclarationNodes in both
extractors, CLASS_CONTAINER_TYPES, and CONTAINER_TYPE_TO_LABEL.
Record struct types are already handled via record_declaration.

* feat(csharp): add isPartial support, filter targeted attributes, static ctor test

- Add isPartial optional field to MethodInfo, MethodExtractionConfig,
  NodeProperties, and parse-worker propagation pipeline
- Detect partial modifier in C# config — marks both declaration-only
  and implemented partial methods
- Filter targeted attribute lists (e.g. [return: MarshalAs(...)]) in
  extractCSharpAnnotations — only untargeted attributes collected
- Add static constructor test (isStatic: true, same name as class)
- Add 3 partial method tests: declaration-only, with body, coexisting pair
- Document record_struct/record_class as defensive dead code in
  export-detection.ts (grammar absorbs keywords into record_declaration)

* fix(csharp): this param for extension methods, dedup visibility, test fixes

- Handle this modifier on extension method parameters (type prefixed
  as 'this string', consistent with out/ref/in handling)
- Deduplicate visibility logic in extractPrimaryConstructor — reuse
  csharpMethodConfig.extractVisibility instead of inline compound check
- Fix record struct test title to reflect actual grammar behavior
- Add conversion operator returnType assertion
- Add extension method this parameter test

* fix(csharp): primary constructor line points to param list, empty name guard

- Use paramList.startPosition instead of ownerNode.startPosition for
  primary constructor line number (avoids methodInfoCache key collision)
- Guard against empty param names from tree-sitter error recovery nodes
2026-03-30 08:41:17 +01:00
agung widhiatmojo
be210c7c61
docs: add gitnexus-shared build step before gitnexus-web (#585)
gitnexus-web imports from gitnexus-shared, which requires npm run build
to generate dist/. Without this step, npm run dev fails with module
resolution errors.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 08:40:47 +01:00
Subham Kundu
8d7aa94381
chore: add enterprise offering section to README, ignore local_docs/ (#579)
* chore: add enterprise offering section to README, ignore local_docs/

* chore: normalize em dash to hyphen in README enterprise section

* docs: expand enterprise section with commercial licensing and feature details
2026-03-29 14:55:17 +05:30
Subham Kundu
d90d1ba96f
fix(eval): exclude litellm 1.82.7 and 1.82.8 due to compatibility issues (#580) 2026-03-29 05:23:37 +01:00
Gergő Magyar
313b13fade
feat(java,kotlin): MethodExtractor abstraction with per-language configs (#576) 2026-03-28 21:31:08 +00:00
Gabriel J Campbell
b03413dcf9
feat: added skip-agents-md cli flag (#517)
* feat: added skip-agents-md cli flag

* fix: apply prettier formatting

* feat: added skip-agents-md cli flag

* fix: apply prettier formatting

* feat: add skipAgentsMd option to skip AGENTS.md and CLAUDE.md updates

* fixed bad merge
2026-03-28 21:23:59 +00:00
Abhigyan Patwari
9f69c43100
feat(wiki): Azure OpenAI support for wiki command (#562)
* feat(wiki): extend LLMConfig/CLIConfig with Azure and reasoning model fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(wiki): restore cursor model resolution, fix LLMProvider type, clean up regex

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(wiki): remove stale LLMProvider type alias from repo-manager

* fix(wiki): fix Azure auth header, api-version param, reasoning model params, content_filter error

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(wiki): tighten Azure detection, reasoning model regex, content_filter gating

- isReasoningModel: new regex matches only o1/o3 bare + any oN-mini/oN-preview; bare o4/o5/etc now return false
- isAzureProvider: use URL hostname matching to block spoofed subdomain URLs
- callLLM: warn on Azure legacy /deployments/ URL without api-version
- callLLM: gate content_filter error to azure===true; also catch ResponsibleAIPolicyViolation
- tests: add afterEach stub cleanup, spoofed-URL, bare-o4, non-Azure content_filter, and URL-only Azure auto-detect tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(wiki): detect content_filter finish_reason in SSE stream and throw clear error

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(wiki): skip delta accumulation after content_filter, use provider-neutral error message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(wiki): add Azure OpenAI option to interactive setup wizard

Inserts Azure as option [3] in the provider menu (shifting Custom to [4]
and Cursor to [5]), adds guided Azure setup flow with resource/deployment
prompts, v1/legacy URL format selection, reasoning-model flag, and
content_filter error handling in the catch block.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(wiki): store explicit false for non-reasoning Azure deployments, trim resource name inputs

- isReasoningModelDeployment now stores false (not undefined) when user says no
- Always include isReasoningModel in saved azureConfig (no conditional guard needed)
- Trim resourceName and deploymentName prompt inputs to avoid whitespace issues
- Improve reasoning model note to mention Azure requirement

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(wiki): add --api-version and --reasoning-model CLI flags for Azure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(wiki): include apiVersion and reasoningModel in hasCLIOverrides guard

* fix(wiki): default provider to 'openai' in resolveLLMConfig when not configured

* style: apply prettier formatting

* fix(wiki): address PR review — remove unrelated files, harden inputs

- Remove evidence/, fix-adapter.js, and planning doc accidentally included
- URL-encode apiVersion in buildRequestUrl to prevent query string injection
- Add --no-reasoning-model flag to allow CLI override of saved config
- Simplify verbose ternary in Azure wizard prompt

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

* fix(wiki): use execFileSync for EDITOR to prevent shell injection

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 00:23:41 +05:30
Gergő Magyar
ddb6a704b3
refactor: reduce explicit any types (#566)
* refactor: replace NodeProperties index signature any with unknown

Change [key: string]: any to [key: string]: unknown in NodeProperties.
Remove 19 redundant (node.properties as any) casts in csv-generator.ts
— all accessed properties are already declared on the type.

* refactor: replace any with SyntaxNode across ingestion layer

Mechanical substitution — all tree-sitter AST node parameters and
variables typed as any are now properly typed as SyntaxNode.

- ast-helpers.ts: 13 any → SyntaxNode
- parsing-processor.ts: 8 any → SyntaxNode
- parse-worker.ts: 40 any → SyntaxNode/TreeSitterLanguage/Parser.Query
- php.ts: 11 any → SyntaxNode

Also adds TreeSitterLanguage type alias for optional grammar loading.

* refactor: eliminate remaining any in ingestion layer

- call-processor, call-routing, c-cpp: SyntaxNode substitutions
- parse-worker: typed WorkerIncomingMessage discriminated union
- worker-pool: typed WorkerOutgoingMessage + Error handler
- ast-cache, import-processor: targeted cast for Tree.delete()
- community-processor: graphology AbstractGraph types, LeidenModule
  interface for vendored leiden code

Ingestion layer: 130 → 7 any warnings remaining.
2026-03-28 17:11:24 +00:00
Chirag Nighut
e2de9271fc
feat(java): method references, worker overload disambiguation, interface dispatch (#540)
* feat(java): method references + worker overload disambiguation (TypeEnv + argTypes)

Fix two Java gaps: (1) method references (obj::method) via
  tree-sitter @call + parseJavaMethodReference wired through extractLanguageCallSiteSeed for parse-worker and call-processor; (2) overloaded calls with typed
  non-literal args by extending OverloadHints with TypeEnv for identifiers and adding ExtractedCall.argTypes from extractCallArgTypes on the worker path with
  matchCandidatesByArgTypes (inferJvmLiteralType remains for literals).

* test(csharp): expect interface-dispatch edge for IRepository.Save in heritage fixture

* refactor(ingestion): move parseJavaMethodReference to call-sites/java.ts

* refactor(ingestion): defer worker call resolution until implementor map is complete

* style: prettier + remove unused import for CI quality checks

Made-with: Cursor

* fix(ingestion): implementor map for C# base_list + sequential pipeline path

- buildImplementorMap: treat extends rows as implements when resolveExtendsType
  says IMPLEMENTS (worker heritage mirrors parse-worker, all base_list as extends)
- Worker path: pass ctx into buildImplementorMap(deferredWorkerHeritage, ctx)
- Sequential path: extract heritage before processCalls and pass implementor map
  so small repos get interface-dispatch CALLS (fixes csharp-proj integration test)

Made-with: Cursor

* perf(pipeline): accumulate sequential implementor map without O(E) per chunk

- Merge buildImplementorMap(chunk heritage) into one map each sequential chunk so
  work is O(heritage) per chunk and interface dispatch sees prior chunks (worker parity)
- Drop unused globalImplementorMap + redundant merge after worker pass

Made-with: Cursor
2026-03-28 16:59:28 +00:00
Gergő Magyar
acf6fbdd39
feat: configure eslint with unused import removal (#564)
* feat: configure eslint with unused import removal

Add ESLint v9 (flat config) for code quality:
- eslint-plugin-unused-imports for auto-removing dead imports
- @typescript-eslint for TypeScript-aware linting
- eslint-plugin-react-hooks for React hooks rules
- eslint-config-prettier to avoid formatting conflicts
- lint-staged runs eslint --fix before prettier on .ts/.tsx
- CI lint job added to ci-quality.yml

* refactor: remove unused imports via eslint --fix

Auto-fixed by eslint-plugin-unused-imports. No logic changes.

* chore: add eslint fix commit to .git-blame-ignore-revs
2026-03-28 15:28:09 +00:00
Gergő Magyar
bf09eab95b
feat: configure prettier with pre-commit hook (#563)
* feat: configure prettier with pre-commit hook integration

Add prettier, lint-staged, and prettier-plugin-tailwindcss at the repo
root with husky pre-commit hook integration. Moves husky from
gitnexus/ to root package.json for reliable hook installation.

- Root package.json with prepare/format/format:check scripts
- .prettierrc with endOfLine:lf and tailwindStylesheet for TW v4
- .prettierignore excluding fixtures, vendor, generated, *.d.ts, *.md
- .gitattributes enforcing LF line endings for Windows consistency
- Pre-commit hook uses direct node_modules/.bin/ paths (no npx)

* style: apply prettier formatting to entire codebase

One-time bulk format. No logic changes.
Use .git-blame-ignore-revs to skip this commit in git blame.

* chore: add .git-blame-ignore-revs for prettier format commit

* perf: pre-commit hook runs only tests related to staged files

Use vitest --related to scope test execution to tests that import
the changed files, instead of running the full suite on every commit.

* perf: remove vitest from pre-commit hook, keep in CI only

Pre-commit now runs lint-staged + tsc only. Tests run in CI
(ci-tests.yml) where they belong — keeps commits fast.

* ci: add prettier format check to quality workflow

PRs will now fail if code isn't formatted with prettier.
2026-03-28 14:58:04 +00:00
Gergő Magyar
fd7fb5bf1f
feat: unify web and cli ingestion pipeline (#536)
* feat: add server-side ingestion API (POST /api/analyze, SSE progress)

Extract core analysis orchestration from CLI into shared run-analyze.ts
module. Add server-side analyze endpoints so the web app can trigger
ingestion via HTTP instead of running the full pipeline in-browser.

New files:
- src/core/run-analyze.ts — shared runFullAnalysis() orchestrator
- src/server/analyze-job.ts — job manager (single-slot, dedup, SSE events)
- src/server/analyze-worker.ts — forked child process (8GB heap, IPC)
- src/server/git-clone.ts — shallow clone/pull with SSRF protection

API endpoints:
- POST /api/analyze — start analysis (returns 202 + jobId)
- GET /api/analyze/:jobId — poll job status
- GET /api/analyze/:jobId/progress — SSE progress stream

Security: URL validation blocks private IPs and non-HTTP schemes.
Path validation requires absolute paths. Git stderr not leaked to API.

* feat(web): add server-side analyze UI (Phase 2)

Add "Analyze on Server" flow to the web app's Server tab so users
can trigger server-side ingestion from the browser. On completion,
the graph is automatically loaded via the existing connectToServer flow.

New files:
- AnalyzeProgress.tsx — progress bar with phase label, elapsed time, cancel

Modified files:
- backend.ts — startAnalyze(), streamAnalyzeProgress() SSE client
- DropZone.tsx — analyze URL input + button below Connect section
- App.tsx — onServerAnalyze handler wires analyze -> connect flow

* feat: add job cancellation, timeout, and child process tracking (Phase 3)

- DELETE /api/analyze/:jobId — cancel running analysis (SIGTERM to worker)
- 30-minute timeout kills long-running workers automatically
- Child process refs tracked in JobManager for cleanup on shutdown
- dispose() kills all active children on SIGINT/SIGTERM
- Web cancel button now calls server DELETE endpoint
- cancelAnalyze() added to web backend client

* refactor(web): remove browser ingestion pipeline (Phase 4)

Delete 16 duplicated ingestion files, 2 unused service files
(git-clone, zip), and tree-sitter parser-loader from gitnexus-web.
All ingestion now runs server-side via POST /api/analyze.

Deleted (18 files, ~5,000 lines):
- core/ingestion/*.ts (16 pipeline processors)
- core/tree-sitter/parser-loader.ts (WASM tree-sitter loader)
- services/git-clone.ts (isomorphic-git client-side clone)
- services/zip.ts (JSZip extraction)

Simplified:
- DropZone.tsx — server-only (removed ZIP/GitHub tabs)
- ingestion.worker.ts — removed runPipeline/runPipelineFromFiles
- useAppState.tsx — removed pipeline callbacks
- App.tsx — removed handleFileSelect/handleGitClone
- main.tsx — removed Buffer polyfill for isomorphic-git
- types/pipeline.ts — removed PipelineResult/serialize helpers

Kept: cluster-enricher.ts (LLM enrichment, still used by worker)

Dependencies now removable: web-tree-sitter, isomorphic-git,
@isomorphic-git/lightning-fs, jszip (estimated 3-4MB bundle savings)

* refactor(web): sync graph schema from CLI + delete WASM grammars

Sync graph/types.ts and lbug/schema.ts from the CLI (source of truth)
to the web module so the browser LadybugDB can handle all node and
relationship types the server pipeline produces.

Synced types: Route, Tool, Section node labels; HANDLES_ROUTE, FETCHES,
HANDLES_TOOL, ENTRY_POINT_OF, WRAPS, QUERIES relationship types;
description fields on Function/Class/Interface/Method/CodeElement.

Deleted: public/wasm/ directory (14 tree-sitter WASM grammars + core).
Removed deps: web-tree-sitter, isomorphic-git, @isomorphic-git/lightning-fs,
jszip, buffer, @types/jszip (~3-4MB bundle savings).

* feat: create gitnexus-shared package for unified type definitions

Create a new gitnexus-shared package that is the single source of truth
for types shared between the CLI and web modules:

- SupportedLanguages enum (15 languages)
- Graph types: NodeLabel, NodeProperties, RelationshipType, GraphNode, GraphRelationship
- Schema constants: NODE_TABLES, REL_TYPES, REL_TABLE_NAME, EMBEDDING_TABLE_NAME
- Pipeline types: PipelinePhase, PipelineProgress

Both gitnexus (CLI) and gitnexus-web import from gitnexus-shared via
file: dependency. Each package re-exports and extends with platform-specific
additions (CLI: KnowledgeGraph with mutation methods; Web: simpler KnowledgeGraph).

This ensures types can never drift between packages — adding a new
language, node type, or relationship type in gitnexus-shared automatically
propagates to both consumers.

* refactor: import shared types directly from gitnexus-shared at call sites

Replace all re-export patterns with direct imports from gitnexus-shared.
72 files updated across CLI and web:

- SupportedLanguages: 49 CLI files now import from 'gitnexus-shared'
  instead of '../config/supported-languages.js'
- GraphNode, GraphRelationship, NodeLabel: 22 CLI + 10 web files now
  import from 'gitnexus-shared' instead of local re-export wrappers
- NODE_TABLES: api.ts imports from 'gitnexus-shared'
- PipelineProgress: useAppState.tsx imports from 'gitnexus-shared'

Local types.ts files now only define platform-specific KnowledgeGraph
(CLI has mutation methods, web has add-only). No more re-exports.

* fix: update lock files for gitnexus-shared, remove stale vite polyfills

Add gitnexus-shared@1.0.0 to lock files so npm ci succeeds in CI.
Remove buffer polyfill and global define from vite.config.ts (isomorphic-git was removed).

* fix(security): add write guard to HTTP /api/query, fix CORS proxy bypass

- Add isWriteQuery() check to POST /api/query handler — blocks CREATE,
  DELETE, SET, MERGE, DROP, etc. via HTTP API (guard was only in MCP
  pool adapter and browser-side, not the HTTP server path)
- Extend CYPHER_WRITE_RE with CALL, INSTALL, LOAD keywords
- Fix CORS proxy subdomain bypass: endsWith('github.com') allowed
  'evil-github.com'. Now requires exact match or '.github.com' suffix

* feat(server): enhance /api/search with enrichment, add /api/grep, strip graph content

- POST /api/search: add mode param (hybrid|semantic|bm25), server-side
  enrichment returns connections/cluster/processes per result in one call
  (collapses 31 sequential HTTP calls to 1 for the agent search tool)
- GET /api/grep: regex search across indexed file contents, eliminates
  need to transfer all file contents to browser
- GET /api/graph: strip content field by default (80-95% payload
  reduction). Use ?includeContent=true for backward compat
- Add LRU cache invalidation hook point for future caching

* feat(server): add /api/embed endpoint for server-side embedding generation

- POST /api/embed: triggers embedding pipeline via onnxruntime-node
  with JobManager for single-slot concurrency, timeout, and dedup
- GET /api/embed/:jobId: poll job status
- GET /api/embed/:jobId/progress: SSE stream with heartbeat, event IDs,
  and X-Accel-Buffering:no header for proxy compatibility
- DELETE /api/embed/:jobId: cancel running embedding job
- Maps embedding pipeline phases (ready→complete, error→failed) to
  JobManager status conventions

* feat(web): create consolidated BackendClient module

Single HTTP client replacing backend.ts, server-connection.ts, and
worker HTTP helpers. Includes:
- Typed methods: runQuery, search (enriched), grep, readFile, connect
- Generic streamSSE<T> utility extracted from analyze progress pattern
- BackendError with discriminated code field (network/server/client/timeout)
- Embed API: startEmbeddings, streamEmbeddingProgress, cancelEmbeddings
- Search with mode param (hybrid|semantic|bm25) and enrichment

* refactor(web): rewrite Graph RAG tools for backend-only HTTP queries

- Search tool: uses enriched /api/search (1 call replaces 31 sequential queries)
- Cypher tool: removes browser-side embedding; {{QUERY_VECTOR}} routes to
  /api/search with mode:'semantic' instead of local transformers.js
- Grep tool: uses /api/grep instead of in-memory fileContents map
- Read tool: uses /api/file instead of fileContents map lookup
- Impact tool: getCallSiteSnippet now async via /api/file
- createGraphRAGTools now accepts GraphRAGBackend interface instead of
  7 separate function params + fileContents map
- createGraphRAGAgent simplified to (config, backend, context?)
- Removed imports: embedder, lbug/schema (replaced with gitnexus-shared)
- Net: -205 lines

* refactor(web): delete WASM infrastructure, remove 7 packages (-5242 lines)

Delete browser-side LadybugDB, embeddings, search, and worker:
- gitnexus-web/src/core/lbug/ (adapter, csv-generator, schema, query-result)
- gitnexus-web/src/core/embeddings/ (embedder, pipeline, text-gen, types)
- gitnexus-web/src/core/search/ (bm25-index, hybrid-search)
- gitnexus-web/src/workers/ingestion.worker.ts (828 lines)
- gitnexus-web/src/services/server-connection.ts (merged into backend-client)
- gitnexus-web/src/types/lbug-wasm.d.ts

Remove packages: @ladybugdb/wasm-core, @huggingface/transformers,
comlink, minisearch, vite-plugin-wasm, vite-plugin-top-level-await,
vite-plugin-static-copy

Update vite.config.ts: remove WASM plugins, COOP/COEP headers,
worker config, optimizeDeps exclude

Update imports: App.tsx, DropZone, Header, AnalyzeProgress,
BackendRepoSelector, useBackend → backend-client

* refactor(web): replace Worker/Comlink with direct BackendClient calls

- useAppState: remove Worker instantiation, Comlink.wrap, apiRef.
  All queries now go through BackendClient HTTP functions directly.
- Agent runs on main thread (I/O-bound LLM streaming, not CPU-bound)
- initializeAgent: creates GraphRAGAgent with GraphRAGBackend interface
  bound to BackendClient methods (runQuery, search, grep, readFile)
- startEmbeddings: calls POST /api/embed + SSE progress instead of
  running browser-side transformers.js pipeline
- switchRepo: no longer loads graph into WASM DB or extracts fileContents
- App.tsx: handleServerConnect simplified (no fileContents, no loadServerGraph)
- Delete old backend.ts (replaced by backend-client.ts)
- Net: -396 lines

* fix(web): fix await-in-map build error in agent streaming

Move dynamic import of AIMessage outside .map() callback to avoid
"await can only be used inside an async function" build error.

* fix(web): remove stale apiRef references that broke chat functionality

sendChatMessage referenced apiRef.current (deleted Worker ref) which
would throw TypeError. Replaced with agentRef.current guard since agent
now runs on main thread.

* fix(server): dispose embedJobManager on shutdown, fix job mutation

- Add embedJobManager.dispose() to shutdown handler (was missing,
  causing cleanup timer to keep Node process alive)
- Replace direct job.repoName/status mutation with updateJob() to
  ensure SSE event emission for initial status change

* fix(server): parameterize Cypher, harden grep, unify SSE endpoints

- Search enrichment: replace string interpolation with executePrepared()
  using $nid parameter binding to prevent Cypher injection
- Add executePrepared() to core lbug-adapter (prepare/execute pattern)
- /api/grep: add 200-char pattern length limit (ReDoS protection),
  search files on disk instead of loading entire corpus into memory
  (constant memory usage regardless of repo size)
- Extract mountSSEProgress() shared helper for SSE streaming — both
  analyze and embed endpoints now have consistent heartbeat (30s),
  event IDs (reconnection support), and X-Accel-Buffering header

* refactor(web): remove dead code from Worker-era architecture

- Remove loadServerGraph no-op function, interface member, and all consumers
- Remove testArrayParams stub and interface member
- Remove fileContents state from GraphStateProvider (never populated in
  server-side architecture)
- Remove forceDevice parameter from startEmbeddings (server-side, no device choice)
- Replace phantom EmbeddingProgress type with inline { phase, percent }
- Replace resolvePathFromContents (needed fileContents Map) with graph-based
  file path resolution using filePathIndex built from graph nodes
- Fix: AI citation grounding ([[file.ts:10]]) now works via graph node lookup
  instead of broken fileContents-based resolution

* fix(web): use streamAgentResponse for full tool_call/reasoning streaming

Replace naive agent.stream() loop that only handled content chunks with
streamAgentResponse() generator from agent.ts. This properly routes:
- reasoning tokens (before/between tool calls)
- tool_call events (name, args, status)
- tool_result events (completed tool output)
- content tokens (final answer after all tools done)

Previously the onChunk handler for tool_call/tool_result/reasoning was
dead code since the streaming loop only emitted content events.

* fix(web): resolve CI type errors from dead code removal

- Import GraphNode/GraphRelationship from gitnexus-shared in graph.ts
  (not re-exported from local types.ts)
- Add Route, Tool entries to NODE_COLORS and NODE_SIZES constants
- Add PipelineResult type to web types/pipeline.ts
- Remove fileContents from CodeReferencesPanel and RightPanel
- Remove testArrayParams and forceDevice from EmbeddingStatus
- Remove forceDevice args from startEmbeddings() calls in App.tsx
- Fix embeddingProgress property accesses for simplified type

* fix(ci): add setup-gitnexus-web action, build shared once per job

- Remove prepare script from gitnexus-shared (tsc not available during
  npm ci of consuming packages)
- Create .github/actions/setup-gitnexus-web composite action: builds
  gitnexus-shared then runs npm ci for gitnexus-web
- setup-gitnexus action: already builds gitnexus-shared for CLI jobs
- ci-quality typecheck-web: uses setup-gitnexus-web (DRY)
- ci-e2e: uses setup-gitnexus-web (DRY)
- ci-tests: gitnexus-shared already built by setup-gitnexus, just
  install web deps without rebuilding

* fix(ci): use prepare script so gitnexus-shared builds during npm ci

Move typescript from devDependencies to dependencies in gitnexus-shared
so the prepare script (tsc) works when npm resolves file: deps during
npm ci. No GHA modifications needed — npm handles the build lifecycle
automatically.

Remove manual gitnexus-shared build steps from setup-gitnexus and
setup-gitnexus-web actions.

* fix(ci): build gitnexus-shared explicitly in setup actions

The file: dependency protocol doesn't reliably run prepare scripts
because devDependencies aren't installed first. Instead of fragile
lifecycle hacks, build gitnexus-shared explicitly in both setup actions:
- setup-gitnexus: npm install && npm run build in gitnexus-shared/
- setup-gitnexus-web: same, before npm ci in gitnexus-web/
- ci-tests: shared already built by setup-gitnexus, web just npm ci

No prepare script, no dist in git, no typescript as a prod dependency.

* fix: remove CALL from CYPHER_WRITE_RE — breaks FTS and vector search

CALL is used by read-only procedures: CALL QUERY_FTS_INDEX(...) and
CALL QUERY_VECTOR_INDEX(...). Adding it to the write guard blocked all
FTS search, causing 3 test failures. The database is opened in read-only
mode as defense-in-depth against write procedures via CALL.

Keep INSTALL and LOAD in the blocklist (genuinely dangerous).

* fix(web): update vercel.json for gitnexus-shared, remove COOP/COEP

- Add installCommand that builds gitnexus-shared before installing
  web deps (Vercel doesn't know about the monorepo file: dependency)
- Remove Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy
  headers (no longer needed — WASM LadybugDB removed)

* fix(web): update tests for deleted modules

- Delete csv-generator.test.ts (tests deleted WASM-only csv-generator)
- Update security-guards.test.ts: import NODE_TABLES/REL_TYPES from
  gitnexus-shared instead of deleted src/core/lbug/schema
- Update server-connection.test.ts: import normalizeServerUrl from
  backend-client, remove extractFileContents tests (function deleted)

* fix(e2e): remove Server tab click — UI is now server-only

The DropZone no longer has ZIP/GitHub/Server tabs (browser ingestion
was removed). The server URL input is directly visible on the landing
page. Update e2e test to skip the tab click and go straight to input.

All 5 e2e tests pass locally.

* refactor: use gitnexus-shared for PipelinePhase/PipelineProgress types

CLI was duplicating PipelinePhase and PipelineProgress locally instead
of importing from gitnexus-shared. Updated all consumers to import
directly. Also removed dead code: SerializablePipelineResult,
serializePipelineResult(), deserializePipelineResult().

* fix(server): address PR #536 review — security, race conditions, dead code

- Fix path traversal in POST /api/analyze: split into isAbsolute + normalize check
- Add shared repo lock (activeRepoPaths) preventing concurrent analyze+embed on same repo
- Fix 202 response returning actual job.status instead of hardcoded 'queued'
- Add 30-minute timeout for embedding jobs (was missing unlike analyze jobs)
- Fix DropZone calling startAnalyze without setting backend URL first
- Add SSE reconnect with exponential backoff (3 retries) and Last-Event-ID
- Fix normalizeServerUrl to return base URL (no /api suffix) — clear contract
- Delete dead code: proxy.ts, server-graph-hydration.ts, pipeline.ts re-export barrel
- Update LoadingOverlay to import PipelineProgress directly from gitnexus-shared

* fix(server): fix repo lock key mismatch and embed cancel race

- Use getStoragePath(targetPath) as lock key in analyze handler to match
  embed handler's entry.storagePath — keys now always align
- Guard embed completion: don't overwrite 'failed' with 'complete' when
  job was cancelled while pipeline was still running
- Remove unused jobType parameter from acquireRepoLock
- Log backend.init() errors instead of silently swallowing

* fix: add gitnexus-shared as a local dependency in package-lock.json

* refactor: move language detection to gitnexus-shared, add syntax highlighting for all 15 languages

Move getLanguageFromFilename() from CLI to gitnexus-shared with COBOL
support added. Add getSyntaxLanguageFromFilename() for Prism-compatible
syntax highlighting covering all 15 code languages plus auxiliary
formats (json, yaml, markdown, html, css, bash, sql, xml).

Refactor CodeReferencesPanel to use shared function instead of a local
30-line switch. Delete dead gitnexus-web/src/config/supported-languages.ts
(web already imports SupportedLanguages from gitnexus-shared).

* feat(web): add first-time user onboarding with auto server detection

Replace the manual "Connect to Server" panel with an automatic onboarding
flow that guides first-time users through starting the GitNexus server.

Server detection:
- useBackend hook polls via setTimeout chain (3s, no overlap)
- Page Visibility API pauses polling when tab is hidden
- SSE heartbeat (/api/heartbeat) for instant disconnect detection

Onboarding UI (OnboardingGuide.tsx):
- Step-by-step flow: copy command → run → auto-connect
- Smart command: shows `gitnexus serve` in dev, `npx gitnexus@latest serve` in prod
- Node.js version auto-detected from package.json via Vite define
- Faux terminal windows with copy-to-clipboard, platform tabs, polling indicator

Transitions (DropZone.tsx):
- Crossfade wrapper with snapshot pattern for smooth phase transitions
- Three phases: onboarding → success (1.2s hold) → loading → graph
- Auto-recovery: falls back to onboarding if server dies or connect fails

Server changes:
- GET /api/heartbeat: SSE endpoint for liveness detection
- GET /api/info: version, launch context, Node.js version
- npm run serve script for local development
- app.disable('x-powered-by') hardening

* feat(web): add repo analysis UI, SSE heartbeat, and review fixes

Repo analysis:
- AnalyzeOnboarding: empty-state card when server has zero repos
- RepoAnalyzer: GitHub URL + Local Folder tabs with browse button
- Header repo dropdown: click project badge to switch repos or analyze new
- DropZone 'analyze' phase integrated into Crossfade transitions

Reliability fixes from 5-agent review:
- Polling: stop scheduling timers when tab hidden, restart on visibility return
- Heartbeat: exponential backoff (1s/2s/4s, 3 retries) prevents graph loss on blip
- RepoAnalyzer: completion timer tracked in ref, cleaned up on unmount
- DropZone: standardized card padding (p-7), heading sizes (text-lg)

Accessibility:
- prefers-reduced-motion global CSS rule (WCAG 2.3.3)
- focus-visible rings on CopyButton
- cursor-pointer on all Header buttons
- Consistent rounded-xl on all dropdowns

Cleanup:
- Deleted dead AnalyzeSheet.tsx (219 LOC) and BackendRepoSelector.tsx (89 LOC)
- Fixed AnalyzeProgress lucide import (lucide-react → @/lib/lucide-icons)

* fix(server): resolve analyze worker fork crash in dev mode

The forked analyze worker was crashing immediately with exit code 1
when running via `npm run serve` (tsx). Two issues:

1. Worker path resolved to `analyze-worker.js` but only `.ts` exists
   in the source directory — the `.js` file is only in `dist/`.

2. On Windows, bare `--import tsx` in execArgv fails because Node's
   ESM resolver for --import uses the child's CWD, not the parent's
   node_modules. Windows also rejects raw paths as `d:` is not a
   valid URL scheme.

Fix: detect dev vs prod via `import.meta.url` extension. In dev mode,
resolve `tsx/esm` to an absolute `file://` URL via `pathToFileURL()`
anchored to the parent's `createRequire` context. This works on all
platforms and doesn't depend on the child's CWD or PATH.

Also captures child stderr for better crash diagnostics.

Verified: `POST /api/analyze` with GitHub URL completes successfully
in dev mode (tsx) — status goes from cloning → analyzing → complete.

* fix(server): add worker auto-retry, error handling, and crash diagnostics

Worker resilience:
- Auto-retry up to 2 times with exponential backoff (1s, 2s) on crash
- SSE progress shows "Retrying after crash (1/2)..." during retry
- Captures child stderr for crash diagnostics in failure message
- AnalyzeJob tracks retryCount per job

Server error handling:
- app.listen wrapped in Promise so EADDRINUSE/EACCES propagate cleanly
- serve.ts catches startup errors with friendly messages and exit code 1
- EADDRINUSE gets actionable guidance (stop other process or --port flag)
- Global uncaughtException/unhandledRejection handlers prevent silent exits
- DEBUG=1 env var shows full stack traces

* feat: add e2e tests for onboarding flows, worker retry, and error handling

E2E tests (onboarding.spec.ts — 11 tests):
- Flow 1: OnboardingGuide shown when server unreachable (6 tests)
- Flow 2: Auto-connect with success card, analyze phase for zero repos
- Flow 3: Analyze form — GitHub URL validation, Local Folder tab, tab switching
- Flow 4: Repo dropdown in exploring view (skipped without live server)

Updated server-connect.spec.ts:
- Replaced manual Connect button flow with auto-connect waitForGraphLoaded

Server resilience:
- Worker auto-retry (2 attempts with exponential backoff) on crash
- Friendly error messages for serve startup failures (EADDRINUSE etc.)
- Global uncaughtException/unhandledRejection handlers prevent silent exits
- app.listen wrapped in Promise for proper error propagation

* refactor(shared): enforce exhaustive language coverage via Record types

Replace the if/else chain in getLanguageFromFilename with two exhaustive
Record<SupportedLanguages, ...> maps:

- EXTENSION_MAP: every language → its file extensions
- SYNTAX_MAP: every language → its Prism syntax identifier

Adding a new member to the SupportedLanguages enum without adding it to
both maps now produces a TypeScript compile error:

  Property '[SupportedLanguages.NewLang]' is missing in type...

This matches the existing pattern in languages/index.ts (providers table)
which already uses `satisfies Record<SupportedLanguages, LanguageProvider>`.

Three compile-time enforcement points now exist:
1. EXTENSION_MAP in language-detection.ts (file extensions)
2. SYNTAX_MAP in language-detection.ts (Prism syntax identifiers)
3. providers in languages/index.ts (LanguageProvider instances)

* feat(web): load source code from server and scroll to selected line

CodeReferencesPanel now fetches file content via GET /api/file when a
node is selected, instead of showing "Code not available in memory".

- Fetches via readFile() from backend-client when selectedFilePath changes
- Shows loading spinner while fetching
- After content loads, auto-scrolls to the selected node's startLine
- Highlights the selected line range with a cyan left border
- Cancels in-flight fetch if selection changes before it completes

Also: refactored language-detection.ts to use exhaustive Record types
(EXTENSION_MAP and SYNTAX_MAP) so adding a new SupportedLanguages enum
member without implementing extensions/syntax is a compile error.

* feat: buffered file reading for Code Inspector

Server: GET /api/file now supports ?startLine=N&endLine=M for reading
a line range instead of the entire file. Returns { content, startLine,
endLine, totalLines }.

Client: readFile() returns ReadFileResult with metadata. When selecting
a symbol (function, class, method), fetches only ±50 lines around the
symbol's startLine/endLine instead of the full file. File nodes still
fetch the entire file.

SyntaxHighlighter startingLineNumber set from the buffer offset so line
numbers are correct even for partial reads.

* fix: adapt readFile callers to new ReadFileResult return type

tools.ts: readFile comes from GraphRAGBackend interface which returns
Promise<string> (the adapter in useAppState extracts .content), so
revert the { content } destructuring back to plain string assignment.

useAppState.tsx: wrap backendReadFile with { repo } options object
and extract .content to satisfy the GraphRAGBackend interface.

* fix(web): ensure new repos appear in list immediately after analysis

Two fixes:

1. DropZone: handleAnalyzeComplete now passes the repoName through to
   connectToServer so the specific newly-analyzed repo loads — not the
   server's default first repo.

2. App.tsx: fetchRepos() is now awaited BEFORE handleServerConnect in
   both the DropZone and Header flows. This ensures the repo list is
   populated before the exploring view renders, so the new repo appears
   in the header dropdown immediately without a page reload.

* feat: delete repos, re-analyze with force, select after analysis

Server — DELETE /api/repo:
- Acquires repo lock first (409 if analyze/embed in flight)
- Closes LadybugDB, deletes index + clone dir, unregisters, re-inits
- Lock released in finally block

Server — analyze complete:
- backend.init() must succeed before SSE complete fires
- If backend.init() fails, job is marked failed (not complete)

Web — Header repo dropdown:
- Re-analyze: calls POST /api/analyze with force=true, shows spinning
  icon + inline progress bar via SSE
- Delete: acquires lock, aborts any running re-analysis SSE for same
  repo, refreshes list, switches to next repo
- After analysis completes: refreshes repo list, connects to the
  specific repo by name, loads graph, shows in explorer
- Retry with 1.5s backoff on 404 (server may still be reinitializing)

Type safety:
- err: any → err: unknown + instanceof BackendError in retry loop
- Added missing BackendRepo + BackendError imports in App.tsx
2026-03-28 14:07:11 +00:00
Juan Pablo Maddoni
c27c9f612c
fix/opencode mcp gitnexus timeout (#363) 2026-03-27 12:18:01 -05:00