This is page 3 of 17. Use http://codebase.md/shashankss1205/codegraphcontext?lines=false&page={x} to view the full context.
# Directory Structure
```
├── .cgcignore
├── .github
│ ├── FUNDING.yml
│ └── workflows
│ ├── e2e-tests.yml
│ ├── post_discord_invite.yml
│ ├── test.yml
│ └── update-contributors.yml
├── .gitignore
├── CLI_Commands.md
├── CONTRIBUTING.md
├── contributors.md
├── docs
│ ├── docs
│ │ ├── architecture.md
│ │ ├── cli.md
│ │ ├── contributing_languages.md
│ │ ├── contributing.md
│ │ ├── cookbook.md
│ │ ├── core.md
│ │ ├── future_work.md
│ │ ├── images
│ │ │ ├── 1.png
│ │ │ ├── 11.png
│ │ │ ├── 12.png
│ │ │ ├── 13.png
│ │ │ ├── 14.png
│ │ │ ├── 16.png
│ │ │ ├── 19.png
│ │ │ ├── 2.png
│ │ │ ├── 20.png
│ │ │ ├── 21.png
│ │ │ ├── 22.png
│ │ │ ├── 23.png
│ │ │ ├── 24.png
│ │ │ ├── 26.png
│ │ │ ├── 28.png
│ │ │ ├── 29.png
│ │ │ ├── 3.png
│ │ │ ├── 30.png
│ │ │ ├── 31.png
│ │ │ ├── 32.png
│ │ │ ├── 33.png
│ │ │ ├── 34.png
│ │ │ ├── 35.png
│ │ │ ├── 36.png
│ │ │ ├── 38.png
│ │ │ ├── 39.png
│ │ │ ├── 4.png
│ │ │ ├── 40.png
│ │ │ ├── 41.png
│ │ │ ├── 42.png
│ │ │ ├── 43.png
│ │ │ ├── 44.png
│ │ │ ├── 5.png
│ │ │ ├── 6.png
│ │ │ ├── 7.png
│ │ │ ├── 8.png
│ │ │ ├── 9.png
│ │ │ ├── Indexing.gif
│ │ │ ├── tool_images
│ │ │ │ ├── 1.png
│ │ │ │ ├── 2.png
│ │ │ │ └── 3.png
│ │ │ └── Usecase.gif
│ │ ├── index.md
│ │ ├── installation.md
│ │ ├── license.md
│ │ ├── server.md
│ │ ├── tools.md
│ │ ├── troubleshooting.md
│ │ ├── use_cases.md
│ │ └── watching.md
│ ├── mkdocs.yml
│ └── site
│ ├── 404.html
│ ├── architecture
│ │ └── index.html
│ ├── assets
│ │ ├── images
│ │ │ └── favicon.png
│ │ ├── javascripts
│ │ │ ├── bundle.79ae519e.min.js
│ │ │ ├── bundle.79ae519e.min.js.map
│ │ │ ├── lunr
│ │ │ │ ├── min
│ │ │ │ │ ├── lunr.ar.min.js
│ │ │ │ │ ├── lunr.da.min.js
│ │ │ │ │ ├── lunr.de.min.js
│ │ │ │ │ ├── lunr.du.min.js
│ │ │ │ │ ├── lunr.el.min.js
│ │ │ │ │ ├── lunr.es.min.js
│ │ │ │ │ ├── lunr.fi.min.js
│ │ │ │ │ ├── lunr.fr.min.js
│ │ │ │ │ ├── lunr.he.min.js
│ │ │ │ │ ├── lunr.hi.min.js
│ │ │ │ │ ├── lunr.hu.min.js
│ │ │ │ │ ├── lunr.hy.min.js
│ │ │ │ │ ├── lunr.it.min.js
│ │ │ │ │ ├── lunr.ja.min.js
│ │ │ │ │ ├── lunr.jp.min.js
│ │ │ │ │ ├── lunr.kn.min.js
│ │ │ │ │ ├── lunr.ko.min.js
│ │ │ │ │ ├── lunr.multi.min.js
│ │ │ │ │ ├── lunr.nl.min.js
│ │ │ │ │ ├── lunr.no.min.js
│ │ │ │ │ ├── lunr.pt.min.js
│ │ │ │ │ ├── lunr.ro.min.js
│ │ │ │ │ ├── lunr.ru.min.js
│ │ │ │ │ ├── lunr.sa.min.js
│ │ │ │ │ ├── lunr.stemmer.support.min.js
│ │ │ │ │ ├── lunr.sv.min.js
│ │ │ │ │ ├── lunr.ta.min.js
│ │ │ │ │ ├── lunr.te.min.js
│ │ │ │ │ ├── lunr.th.min.js
│ │ │ │ │ ├── lunr.tr.min.js
│ │ │ │ │ ├── lunr.vi.min.js
│ │ │ │ │ └── lunr.zh.min.js
│ │ │ │ ├── tinyseg.js
│ │ │ │ └── wordcut.js
│ │ │ └── workers
│ │ │ ├── search.2c215733.min.js
│ │ │ └── search.2c215733.min.js.map
│ │ └── stylesheets
│ │ ├── main.484c7ddc.min.css
│ │ ├── main.484c7ddc.min.css.map
│ │ ├── palette.ab4e12ef.min.css
│ │ └── palette.ab4e12ef.min.css.map
│ ├── cli
│ │ └── index.html
│ ├── contributing
│ │ └── index.html
│ ├── contributing_languages
│ │ └── index.html
│ ├── cookbook
│ │ └── index.html
│ ├── core
│ │ └── index.html
│ ├── future_work
│ │ └── index.html
│ ├── images
│ │ ├── 1.png
│ │ ├── 11.png
│ │ ├── 12.png
│ │ ├── 13.png
│ │ ├── 14.png
│ │ ├── 16.png
│ │ ├── 19.png
│ │ ├── 2.png
│ │ ├── 20.png
│ │ ├── 21.png
│ │ ├── 22.png
│ │ ├── 23.png
│ │ ├── 24.png
│ │ ├── 26.png
│ │ ├── 28.png
│ │ ├── 29.png
│ │ ├── 3.png
│ │ ├── 30.png
│ │ ├── 31.png
│ │ ├── 32.png
│ │ ├── 33.png
│ │ ├── 34.png
│ │ ├── 35.png
│ │ ├── 36.png
│ │ ├── 38.png
│ │ ├── 39.png
│ │ ├── 4.png
│ │ ├── 40.png
│ │ ├── 41.png
│ │ ├── 42.png
│ │ ├── 43.png
│ │ ├── 44.png
│ │ ├── 5.png
│ │ ├── 6.png
│ │ ├── 7.png
│ │ ├── 8.png
│ │ ├── 9.png
│ │ ├── Indexing.gif
│ │ ├── tool_images
│ │ │ ├── 1.png
│ │ │ ├── 2.png
│ │ │ └── 3.png
│ │ └── Usecase.gif
│ ├── index.html
│ ├── installation
│ │ └── index.html
│ ├── license
│ │ └── index.html
│ ├── search
│ │ └── search_index.json
│ ├── server
│ │ └── index.html
│ ├── sitemap.xml
│ ├── sitemap.xml.gz
│ ├── tools
│ │ └── index.html
│ ├── troubleshooting
│ │ └── index.html
│ ├── use_cases
│ │ └── index.html
│ └── watching
│ └── index.html
├── funding.json
├── images
│ ├── 1.png
│ ├── 11.png
│ ├── 12.png
│ ├── 13.png
│ ├── 14.png
│ ├── 16.png
│ ├── 19.png
│ ├── 2.png
│ ├── 20.png
│ ├── 21.png
│ ├── 22.png
│ ├── 23.png
│ ├── 24.png
│ ├── 26.png
│ ├── 28.png
│ ├── 29.png
│ ├── 3.png
│ ├── 30.png
│ ├── 31.png
│ ├── 32.png
│ ├── 33.png
│ ├── 34.png
│ ├── 35.png
│ ├── 36.png
│ ├── 38.png
│ ├── 39.png
│ ├── 4.png
│ ├── 40.png
│ ├── 41.png
│ ├── 42.png
│ ├── 43.png
│ ├── 44.png
│ ├── 5.png
│ ├── 6.png
│ ├── 7.png
│ ├── 8.png
│ ├── 9.png
│ ├── Indexing.gif
│ ├── tool_images
│ │ ├── 1.png
│ │ ├── 2.png
│ │ └── 3.png
│ └── Usecase.gif
├── LICENSE
├── MANIFEST.in
├── organizer
│ ├── CONTRIBUTING_LANGUAGES.md
│ ├── cookbook.md
│ ├── docs.md
│ ├── language_specific_nodes.md
│ ├── Tools_Exploration.md
│ └── troubleshoot.md
├── pyproject.toml
├── README.md
├── scripts
│ ├── generate_lang_contributors.py
│ ├── post_install_fix.sh
│ ├── test_all_parsers.py
│ └── update_language_parsers.py
├── SECURITY.md
├── src
│ └── codegraphcontext
│ ├── __init__.py
│ ├── __main__.py
│ ├── cli
│ │ ├── __init__.py
│ │ ├── cli_helpers.py
│ │ ├── config_manager.py
│ │ ├── main.py
│ │ ├── setup_macos.py
│ │ └── setup_wizard.py
│ ├── core
│ │ ├── __init__.py
│ │ ├── database_falkordb.py
│ │ ├── database.py
│ │ ├── falkor_worker.py
│ │ ├── jobs.py
│ │ └── watcher.py
│ ├── prompts.py
│ ├── server.py
│ ├── tools
│ │ ├── __init__.py
│ │ ├── advanced_language_query_tool.py
│ │ ├── code_finder.py
│ │ ├── graph_builder.py
│ │ ├── languages
│ │ │ ├── c.py
│ │ │ ├── cpp.py
│ │ │ ├── csharp.py
│ │ │ ├── go.py
│ │ │ ├── java.py
│ │ │ ├── javascript.py
│ │ │ ├── kotlin.py
│ │ │ ├── php.py
│ │ │ ├── python.py
│ │ │ ├── ruby.py
│ │ │ ├── rust.py
│ │ │ ├── scala.py
│ │ │ ├── swift.py
│ │ │ ├── typescript.py
│ │ │ └── typescriptjsx.py
│ │ ├── package_resolver.py
│ │ ├── query_tool_languages
│ │ │ ├── c_toolkit.py
│ │ │ ├── cpp_toolkit.py
│ │ │ ├── csharp_toolkit.py
│ │ │ ├── go_toolkit.py
│ │ │ ├── java_toolkit.py
│ │ │ ├── javascript_toolkit.py
│ │ │ ├── python_toolkit.py
│ │ │ ├── ruby_toolkit.py
│ │ │ ├── rust_toolkit.py
│ │ │ ├── scala_toolkit.py
│ │ │ ├── swift_toolkit.py
│ │ │ └── typescript_toolkit.py
│ │ └── system.py
│ └── utils
│ ├── debug_log.py
│ └── tree_sitter_manager.py
├── tests
│ ├── __init__.py
│ ├── conftest.py
│ ├── sample_project
│ │ ├── advanced_calls.py
│ │ ├── advanced_classes.py
│ │ ├── advanced_classes2.py
│ │ ├── advanced_functions.py
│ │ ├── advanced_imports.py
│ │ ├── async_features.py
│ │ ├── callbacks_decorators.py
│ │ ├── circular1.py
│ │ ├── circular2.py
│ │ ├── class_instantiation.py
│ │ ├── cli_and_dunder.py
│ │ ├── complex_classes.py
│ │ ├── comprehensions_generators.py
│ │ ├── context_managers.py
│ │ ├── control_flow.py
│ │ ├── datatypes.py
│ │ ├── dynamic_dispatch.py
│ │ ├── dynamic_imports.py
│ │ ├── edge_cases
│ │ │ ├── comments_only.py
│ │ │ ├── docstring_only.py
│ │ │ ├── empty.py
│ │ │ ├── hardcoded_secrets.py
│ │ │ ├── long_functions.py
│ │ │ └── syntax_error.py
│ │ ├── function_chains.py
│ │ ├── generators.py
│ │ ├── import_reexports.py
│ │ ├── mapping_calls.py
│ │ ├── module_a.py
│ │ ├── module_b.py
│ │ ├── module_c
│ │ │ ├── __init__.py
│ │ │ ├── submodule1.py
│ │ │ └── submodule2.py
│ │ ├── namespace_pkg
│ │ │ └── ns_module.py
│ │ ├── pattern_matching.py
│ │ └── typing_examples.py
│ ├── sample_project_c
│ │ ├── cgc_sample
│ │ ├── include
│ │ │ ├── config.h
│ │ │ ├── math
│ │ │ │ └── vec.h
│ │ │ ├── module.h
│ │ │ ├── platform.h
│ │ │ └── util.h
│ │ ├── Makefile
│ │ ├── README.md
│ │ └── src
│ │ ├── main.c
│ │ ├── math
│ │ │ └── vec.c
│ │ ├── module.c
│ │ └── util.c
│ ├── sample_project_cpp
│ │ ├── class_features.cpp
│ │ ├── classes.cpp
│ │ ├── control_flow.cpp
│ │ ├── edge_cases.cpp
│ │ ├── enum_struct_union.cpp
│ │ ├── exceptions.cpp
│ │ ├── file_io.cpp
│ │ ├── function_chain.cpp
│ │ ├── function_chain.h
│ │ ├── function_types.cpp
│ │ ├── main.cpp
│ │ ├── main.exe
│ │ ├── namespaces.cpp
│ │ ├── raii_example.cpp
│ │ ├── README.md
│ │ ├── sample_project.exe
│ │ ├── stl_usage.cpp
│ │ ├── templates.cpp
│ │ └── types_variable_assignments.cpp
│ ├── sample_project_csharp
│ │ ├── README.md
│ │ └── src
│ │ └── Example.App
│ │ ├── Attributes
│ │ │ └── CustomAttributes.cs
│ │ ├── Example.App.csproj
│ │ ├── Models
│ │ │ ├── Person.cs
│ │ │ ├── Point.cs
│ │ │ ├── Role.cs
│ │ │ └── User.cs
│ │ ├── OuterClass.cs
│ │ ├── Program.cs
│ │ ├── Services
│ │ │ ├── GreetingService.cs
│ │ │ ├── IGreetingService.cs
│ │ │ └── LegacyService.cs
│ │ └── Utils
│ │ ├── CollectionHelper.cs
│ │ └── FileHelper.cs
│ ├── sample_project_go
│ │ ├── advanced_types.go
│ │ ├── basic_functions.go
│ │ ├── embedded_composition.go
│ │ ├── error_handling.go
│ │ ├── generics.go
│ │ ├── go.mod
│ │ ├── goroutines_channels.go
│ │ ├── interfaces.go
│ │ ├── packages_imports.go
│ │ ├── README.md
│ │ ├── structs_methods.go
│ │ └── util
│ │ └── helpers.go
│ ├── sample_project_java
│ │ ├── out
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ ├── annotations
│ │ │ │ └── Logged.class
│ │ │ ├── Main.class
│ │ │ ├── misc
│ │ │ │ ├── Outer.class
│ │ │ │ └── Outer$Inner.class
│ │ │ ├── model
│ │ │ │ ├── Role.class
│ │ │ │ └── User.class
│ │ │ ├── service
│ │ │ │ ├── AbstractGreeter.class
│ │ │ │ ├── GreetingService.class
│ │ │ │ └── impl
│ │ │ │ └── GreetingServiceImpl.class
│ │ │ └── util
│ │ │ ├── CollectionUtils.class
│ │ │ └── IOHelper.class
│ │ ├── README.md
│ │ ├── sources.txt
│ │ └── src
│ │ └── com
│ │ └── example
│ │ └── app
│ │ ├── annotations
│ │ │ └── Logged.java
│ │ ├── Main.java
│ │ ├── misc
│ │ │ └── Outer.java
│ │ ├── model
│ │ │ ├── Role.java
│ │ │ └── User.java
│ │ ├── service
│ │ │ ├── AbstractGreeter.java
│ │ │ ├── GreetingService.java
│ │ │ └── impl
│ │ │ └── GreetingServiceImpl.java
│ │ └── util
│ │ ├── CollectionUtils.java
│ │ └── IOHelper.java
│ ├── sample_project_javascript
│ │ ├── arrays.js
│ │ ├── asyncAwait.js
│ │ ├── classes.js
│ │ ├── dom.js
│ │ ├── errorHandling.js
│ │ ├── events.js
│ │ ├── exporter.js
│ │ ├── fetchAPI.js
│ │ ├── fixtures
│ │ │ └── js
│ │ │ └── accessors.js
│ │ ├── functions.js
│ │ ├── importer.js
│ │ ├── objects.js
│ │ ├── promises.js
│ │ ├── README.md
│ │ └── variables.js
│ ├── sample_project_kotlin
│ │ ├── AdvancedClasses.kt
│ │ ├── Annotations.kt
│ │ ├── Coroutines.kt
│ │ ├── EdgeCases.kt
│ │ ├── Functions.kt
│ │ ├── Main.kt
│ │ ├── Properties.kt
│ │ └── User.kt
│ ├── sample_project_misc
│ │ ├── index.html
│ │ ├── README.md
│ │ ├── styles.css
│ │ ├── tables.css
│ │ └── tables.html
│ ├── sample_project_php
│ │ ├── classes_objects.php
│ │ ├── database.php
│ │ ├── edgecases.php
│ │ ├── error_handling.php
│ │ ├── file_handling.php
│ │ ├── functions.php
│ │ ├── generators_iterators.php
│ │ ├── globals_superglobals.php
│ │ ├── Inheritance.php
│ │ ├── interface_traits.php
│ │ └── README.md
│ ├── sample_project_ruby
│ │ ├── class_example.rb
│ │ ├── enumerables.rb
│ │ ├── error_handling.rb
│ │ ├── file_io.rb
│ │ ├── inheritance_example.rb
│ │ ├── main.rb
│ │ ├── metaprogramming.rb
│ │ ├── mixins_example.rb
│ │ ├── module_example.rb
│ │ └── tests
│ │ ├── test_mixins.py
│ │ └── test_sample.rb
│ ├── sample_project_rust
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src
│ │ ├── basic_functions.rs
│ │ ├── concurrency.rs
│ │ ├── error_handling.rs
│ │ ├── generics.rs
│ │ ├── iterators_closures.rs
│ │ ├── lib.rs
│ │ ├── lifetimes_references.rs
│ │ ├── modules.rs
│ │ ├── smart_pointers.rs
│ │ ├── structs_enums.rs
│ │ └── traits.rs
│ ├── sample_project_scala
│ │ ├── Animals.scala
│ │ ├── Complex.scala
│ │ ├── Functional.scala
│ │ ├── Geometry.scala
│ │ ├── Main.scala
│ │ ├── PackageObject.scala
│ │ ├── Script.sc
│ │ ├── Services.scala
│ │ ├── Shapes.scala
│ │ ├── Utils.scala
│ │ └── Variables.scala
│ ├── sample_project_swift
│ │ ├── Generics.swift
│ │ ├── Main.swift
│ │ ├── README.md
│ │ ├── Shapes.swift
│ │ ├── User.swift
│ │ └── Vehicles.swift
│ ├── sample_project_typescript
│ │ ├── package.json
│ │ ├── README.md
│ │ ├── sample_tsx.tsx
│ │ ├── src
│ │ │ ├── advanced-types.ts
│ │ │ ├── async-promises.ts
│ │ │ ├── classes-inheritance.ts
│ │ │ ├── decorators-metadata.ts
│ │ │ ├── error-validation.ts
│ │ │ ├── functions-generics.ts
│ │ │ ├── index.ts
│ │ │ ├── modules-namespaces.ts
│ │ │ ├── types-interfaces.ts
│ │ │ └── utilities-helpers.ts
│ │ └── tsconfig.json
│ ├── test_cpp_parser.py
│ ├── test_database_validation.py
│ ├── test_end_to_end.py
│ ├── test_graph_indexing_js.py
│ ├── test_graph_indexing.py
│ ├── test_kotlin_parser.py
│ ├── test_swift_parser.py
│ ├── test_tree_sitter
│ │ ├── __init__.py
│ │ ├── class_instantiation.py
│ │ ├── complex_classes.py
│ │ └── test_file.py
│ ├── test_tree_sitter_manager.py
│ └── test_typescript_parser.py
├── visualize_graph.py
├── website
│ ├── .example.env
│ ├── .gitignore
│ ├── api
│ │ └── pypi.ts
│ ├── bun.lockb
│ ├── components.json
│ ├── eslint.config.js
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── public
│ │ ├── favicon.ico
│ │ ├── placeholder.svg
│ │ └── robots.txt
│ ├── README.md
│ ├── src
│ │ ├── App.css
│ │ ├── App.tsx
│ │ ├── assets
│ │ │ ├── function-calls.png
│ │ │ ├── graph-total.png
│ │ │ ├── hero-graph.jpg
│ │ │ └── hierarchy.png
│ │ ├── components
│ │ │ ├── ComparisonTable.tsx
│ │ │ ├── CookbookSection.tsx
│ │ │ ├── DemoSection.tsx
│ │ │ ├── ExamplesSection.tsx
│ │ │ ├── FeaturesSection.tsx
│ │ │ ├── Footer.tsx
│ │ │ ├── HeroSection.tsx
│ │ │ ├── InstallationSection.tsx
│ │ │ ├── MoveToTop.tsx
│ │ │ ├── ShowDownloads.tsx
│ │ │ ├── ShowStarGraph.tsx
│ │ │ ├── SocialMentionsTimeline.tsx
│ │ │ ├── TestimonialSection.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── ThemeToggle.tsx
│ │ │ └── ui
│ │ │ ├── accordion.tsx
│ │ │ ├── alert-dialog.tsx
│ │ │ ├── alert.tsx
│ │ │ ├── aspect-ratio.tsx
│ │ │ ├── avatar.tsx
│ │ │ ├── badge.tsx
│ │ │ ├── breadcrumb.tsx
│ │ │ ├── button.tsx
│ │ │ ├── calendar.tsx
│ │ │ ├── card.tsx
│ │ │ ├── carousel.tsx
│ │ │ ├── chart.tsx
│ │ │ ├── checkbox.tsx
│ │ │ ├── collapsible.tsx
│ │ │ ├── command.tsx
│ │ │ ├── context-menu.tsx
│ │ │ ├── dialog.tsx
│ │ │ ├── drawer.tsx
│ │ │ ├── dropdown-menu.tsx
│ │ │ ├── form.tsx
│ │ │ ├── hover-card.tsx
│ │ │ ├── input-otp.tsx
│ │ │ ├── input.tsx
│ │ │ ├── label.tsx
│ │ │ ├── menubar.tsx
│ │ │ ├── navigation-menu.tsx
│ │ │ ├── orbiting-circles.tsx
│ │ │ ├── pagination.tsx
│ │ │ ├── popover.tsx
│ │ │ ├── progress.tsx
│ │ │ ├── radio-group.tsx
│ │ │ ├── resizable.tsx
│ │ │ ├── scroll-area.tsx
│ │ │ ├── select.tsx
│ │ │ ├── separator.tsx
│ │ │ ├── sheet.tsx
│ │ │ ├── sidebar.tsx
│ │ │ ├── skeleton.tsx
│ │ │ ├── slider.tsx
│ │ │ ├── sonner.tsx
│ │ │ ├── switch.tsx
│ │ │ ├── table.tsx
│ │ │ ├── tabs.tsx
│ │ │ ├── textarea.tsx
│ │ │ ├── toast.tsx
│ │ │ ├── toaster.tsx
│ │ │ ├── toggle-group.tsx
│ │ │ ├── toggle.tsx
│ │ │ ├── tooltip.tsx
│ │ │ └── use-toast.ts
│ │ ├── hooks
│ │ │ ├── use-mobile.tsx
│ │ │ └── use-toast.ts
│ │ ├── index.css
│ │ ├── lib
│ │ │ └── utils.ts
│ │ ├── main.tsx
│ │ ├── pages
│ │ │ ├── Index.tsx
│ │ │ └── NotFound.tsx
│ │ └── vite-env.d.ts
│ ├── tailwind.config.ts
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ ├── vercel.json
│ └── vite.config.ts
└── windows_setup_guide.md
```
# Files
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.sv.min.js:
--------------------------------------------------------------------------------
```javascript
/*!
* Lunr languages, `Swedish` language
* https://github.com/MihaiValentin/lunr-languages
*
* Copyright 2014, Mihai Valentin
* http://www.mozilla.org/MPL/
*/
/*!
* based on
* Snowball JavaScript Library v0.3
* http://code.google.com/p/urim/
* http://snowball.tartarus.org/
*
* Copyright 2010, Oleg Mazko
* http://www.mozilla.org/MPL/
*/
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){function e(){var e,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o<a&&(o=a)}}function t(){var e,r=w.limit_backward;if(w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.in_grouping_b(d,98,121)&&w.slice_del()}}function i(){var e=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}function s(){var e,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.slice_from("lös");break;case 3:w.slice_from("full")}w.limit_backward=r}}var a,o,u=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],c=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}});
```
--------------------------------------------------------------------------------
/scripts/post_install_fix.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
set -e
echo "Running Post Install fix for CodeGraphContext..."
detect_shell_config() {
# Windows PowerShell detection
if [[ "$OS" == "Windows_NT" ]] && [[ -n "$PROFILE" ]]; then
echo "$PROFILE"
return
fi
# Unix/Linux/Mac shell detection
if [ "$SHELL" = "/bin/bash" ] || [ "$SHELL" = "/usr/bin/bash" ]; then
echo "$HOME/.bashrc"
elif [ "$SHELL" = "/bin/zsh" ] || [ "$SHELL" = "/usr/bin/zsh" ]; then
echo "$HOME/.zshrc"
elif [ -n "$BASH_VERSION" ]; then
echo "$HOME/.bashrc"
elif [ -n "$ZSH_VERSION" ]; then
echo "$HOME/.zshrc"
else
echo "$HOME/.profile"
fi
}
# Add to PATH for Windows PowerShell
fix_windows_path() {
local profile_file="$1"
local path_line='$env:PATH = "$env:USERPROFILE\.local\bin;$env:PATH"'
echo "Using PowerShell profile: $profile_file"
# Create profile directory if needed
local profile_dir=$(dirname "$profile_file")
mkdir -p "$profile_dir" 2>/dev/null || true
# Check if already configured
if [[ -f "$profile_file" ]] && grep -q ".local" "$profile_file"; then
echo "PATH is already configured in PowerShell profile"
else
echo "Adding to PowerShell PATH..."
echo "" >> "$profile_file"
echo "# Added by CodeGraphContext" >> "$profile_file"
echo "$path_line" >> "$profile_file"
echo "Added PATH to PowerShell profile"
fi
# Add to current session (Windows style)
export PATH="$USERPROFILE/.local/bin:$PATH"
echo "⚠️ Please restart PowerShell or run: . \$PROFILE"
}
# Add to PATH for Linux/Mac
fix_unix_path() {
local config_file="$1"
local path_line='export PATH="$HOME/.local/bin:$PATH"'
echo "Using shell config: $config_file"
# check if PATH is already configured
if [ -f "$config_file" ] && grep -q ".local/bin" "$config_file"; then
echo "PATH is already configured in $config_file"
else
echo "Adding ~/.local/bin to PATH..."
echo "" >> "$config_file"
echo "# Added by CodeGraphContext" >> "$config_file"
echo "$path_line" >> "$config_file"
echo "Added PATH to $config_file"
fi
# Source the config for current session
echo "Sourcing/Reloading shell config for current session..."
export PATH="$HOME/.local/bin:$PATH"
# source it
if [ -f "$config_file" ]; then
source "$config_file" 2>/dev/null || true
fi
}
# Main PATH fixing function
fix_path() {
local config_file=$(detect_shell_config)
# Check if we're on Windows
if [[ "$OS" == "Windows_NT" ]] && [[ -n "$PROFILE" ]]; then
fix_windows_path "$config_file"
else
fix_unix_path "$config_file"
fi
}
check_cgc() {
if command -v cgc >/dev/null 2>&1; then
return 0
else
return 1
fi
}
# Get potential cgc locations based on platform
get_cgc_locations() {
if [[ "$OS" == "Windows_NT" ]]; then
# Windows locations
echo "$USERPROFILE/.local/bin/cgc.exe"
echo "$USERPROFILE/.local/bin/cgc"
echo "$HOME/.local/bin/cgc.exe"
echo "$HOME/.local/bin/cgc"
else
# Linux/Mac locations
echo "$HOME/.local/bin/cgc"
fi
}
# Main execution
if check_cgc; then
echo "✅ cgc (CodeGraphContext) is already available!"
else
echo "⚠️ cgc command not found, fixing PATH..."
# Check if cgc exists in expected locations
cgc_found=false
for cgc_path in $(get_cgc_locations); do
if [[ -f "$cgc_path" ]]; then
cgc_found=true
echo "📍 Found cgc at: $cgc_path"
break
fi
done
if [[ "$cgc_found" == true ]]; then
fix_path
# Check again
if check_cgc; then
echo "✅ cgc command (CodeGraphContext) is now available to use!"
echo "You can now run: cgc neo4j setup"
else
if [[ "$OS" == "Windows_NT" ]]; then
echo "⚠️ Please restart PowerShell or run: . \$PROFILE"
else
echo "❌ There seems to still be an issue... Please reload your terminal manually."
fi
fi
else
if [[ "$OS" == "Windows_NT" ]]; then
echo "❌ cgc not found in expected Windows locations. Please reinstall:"
echo " pip install codegraphcontext"
else
echo "❌ cgc not found in ~/.local/bin. Please reinstall:"
echo " pip install codegraphcontext"
fi
fi
fi
```
--------------------------------------------------------------------------------
/docs/docs/cli.md:
--------------------------------------------------------------------------------
```markdown
# CLI Reference
The CodeGraphContext CLI provides a comprehensive command-line interface to manage the server, index your code, search, analyzing and interact with the code graph.
## 1. Project Management
Use these commands to manage the repositories in your code graph.
| Command | Arguments | Description |
| :--- | :--- | :--- |
| **`cgc index`** | `[path]` <br> `--force` | Adds a repository to the graph. Default path is current directory. Use `--force` to re-index from scratch. <br> *(Alias: `cgc i`)* |
| **`cgc list`** | None | Lists all repositories currently indexed in the database. <br> *(Alias: `cgc ls`)* |
| **`cgc delete`** | `[path]` <br> `--all` | Removes a repository from the graph. Use `--all` to wipe everything. <br> *(Alias: `cgc rm`)* |
| **`cgc stats`** | `[path]` | Shows indexing statistics (node counts) for the DB or a specific repo. |
| **`cgc clean`** | None | Removes orphaned nodes and cleans up the database. |
| **`cgc add-package`** | `<name> <lang>` | Manually adds an external package node (e.g., `cgc add-package requests python`). |
## 2. Watching & Monitoring
Automatically track changes and keep your code graph up-to-date.
| Command | Arguments | Description |
| :--- | :--- | :--- |
| **`cgc watch`** | `[path]` | Watches a directory for file changes and automatically re-indexes. Runs in foreground. Default path is current directory. <br> *(Alias: `cgc w`)* |
| **`cgc unwatch`** | `<path>` | Stops watching a previously watched directory. (Primarily for MCP mode) |
| **`cgc watching`** | None | Lists all directories currently being watched for changes. (Primarily for MCP mode) |
## 3. Code Analysis
Understand the structure, quality, and relationships of your code.
| Command | Arguments | Description |
| :--- | :--- | :--- |
| **`cgc analyze calls`** | `<func_name>` <br> `--file` | Shows **outgoing** calls: what functions does this function call? |
| **`cgc analyze callers`** | `<func_name>` <br> `--file` | Shows **incoming** calls: who calls this function? |
| **`cgc analyze chain`** | `<start> <end>` <br> `--depth` | Finds the call path between two functions. Default depth is 5. |
| **`cgc analyze deps`** | `<module>` <br> `--no-external` | Inspects dependencies (imports and importers) for a module. |
| **`cgc analyze tree`** | `<class_name>` <br> `--file` | Visualizes the Class Inheritance hierarchy for a given class. |
| **`cgc analyze complexity`**| `[path]` <br> `--threshold` <br> `--limit` | Lists functions with high Cyclomatic Complexity. Default threshold: 10. |
| **`cgc analyze dead-code`** | `--exclude` | Finds potentially unused functions (0 callers). Use `--exclude` for decorators. |
## 4. Discovery & Search
Find code elements when you don't know the exact structure.
| Command | Arguments | Description |
| :--- | :--- | :--- |
| **`cgc find name`** | `<name>` <br> `--type` | Finds code elements (Class, Function) by their **exact** name. |
| **`cgc find pattern`** | `<pattern>` <br> `--case-sensitive` | Finds elements using fuzzy substring matching (e.g. "User" finds "UserHelper"). |
| **`cgc find type`** | `<type>` <br> `--limit` | Lists all nodes of a specific type (e.g. `function`, `class`, `module`). |
## 5. Configuration & Setup
Manage your environment and database connections.
| Command | Arguments | Description |
| :--- | :--- | :--- |
| **`cgc mcp setup`** | None | Configures your IDE/MCP Client. Creates `mcp.json`. <br> *(Alias: `cgc m`)* |
| **`cgc neo4j setup`** | None | Wizard to configure a Neo4j connection. <br> *(Alias: `cgc n`)* |
| **`cgc config show`** | None | Displays current configuration values. |
| **`cgc config set`** | `<key> <value>` | Sets a config value (e.g. `DEFAULT_DATABASE`). |
| **`cgc config reset`** | None | Resets configuration to defaults. |
| **`cgc config db`** | `<backend>` | Quick switch between `neo4j` and `falkordb`. |
## 6. Utilities & Runtime
Helper commands for developers and the MCP server.
| Command | Arguments | Description |
| :--- | :--- | :--- |
| **`cgc doctor`** | None | Runs system diagnostics (DB connection, dependencies, permissions). |
| **`cgc visualize`** | `[query]` | Generates a link to open the Neo4j Browser. <br> *(Alias: `cgc v`)* |
| **`cgc query`** | `<query>` | Executes a raw Cypher query directly against the DB. |
| **`cgc mcp start`** | None | Starts the MCP Server (used by IDEs). |
| **`cgc mcp tools`** | None | Lists all available MCP tools supported by the server. |
| **`cgc start`** | None | **Deprecated**. Use `cgc mcp start` instead. |
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.da.min.js:
--------------------------------------------------------------------------------
```javascript
/*!
* Lunr languages, `Danish` language
* https://github.com/MihaiValentin/lunr-languages
*
* Copyright 2014, Mihai Valentin
* http://www.mozilla.org/MPL/
*/
/*!
* based on
* Snowball JavaScript Library v0.3
* http://code.google.com/p/urim/
* http://snowball.tartarus.org/
*
* Copyright 2010, Oleg Mazko
* http://www.mozilla.org/MPL/
*/
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){var e,r=f.cursor+3;if(d=f.limit,0<=r&&r<=f.limit){for(a=r;;){if(e=f.cursor,f.in_grouping(w,97,248)){f.cursor=e;break}if(f.cursor=e,e>=f.limit)return;f.cursor++}for(;!f.out_grouping(w,97,248);){if(f.cursor>=f.limit)return;f.cursor++}d=f.cursor,d<a&&(d=a)}}function n(){var e,r;if(f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(c,32),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del();break;case 2:f.in_grouping_b(p,97,229)&&f.slice_del()}}function t(){var e,r=f.limit-f.cursor;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.find_among_b(l,4)?(f.bra=f.cursor,f.limit_backward=e,f.cursor=f.limit-r,f.cursor>f.limit_backward&&(f.cursor--,f.bra=f.cursor,f.slice_del())):f.limit_backward=e)}function s(){var e,r,i,n=f.limit-f.cursor;if(f.ket=f.cursor,f.eq_s_b(2,"st")&&(f.bra=f.cursor,f.eq_s_b(2,"ig")&&f.slice_del()),f.cursor=f.limit-n,f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(m,5),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del(),i=f.limit-f.cursor,t(),f.cursor=f.limit-i;break;case 2:f.slice_from("løs")}}function o(){var e;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.out_grouping_b(w,97,248)?(f.bra=f.cursor,u=f.slice_to(u),f.limit_backward=e,f.eq_v_b(u)&&f.slice_del()):f.limit_backward=e)}var a,d,u,c=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],l=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],w=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],p=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],f=new i;this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var r=f.cursor;return e(),f.limit_backward=r,f.cursor=f.limit,n(),f.cursor=f.limit,t(),f.cursor=f.limit,s(),f.cursor=f.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}});
```
--------------------------------------------------------------------------------
/docs/docs/tools.md:
--------------------------------------------------------------------------------
```markdown
# Tools
The `tools` directory contains the logic for code analysis, including building the graph, finding code, and extracting imports.
## `GraphBuilder`
The `GraphBuilder` class in `graph_builder.py` is responsible for parsing the source code and building the graph representation that is stored in the Neo4j database.
### `TreeSitterParser`
`GraphBuilder` uses the `TreeSitterParser` class, which is a generic parser wrapper for a specific language using the tree-sitter library. This allows CodeGraphContext to support multiple programming languages in a modular way.
### Graph Building Process
The graph building process consists of several steps:
1. **Pre-scan for Imports:** A quick scan of all files to build a global map of where every symbol is defined.
2. **Parse Files:** Each file is parsed in detail to extract its structure, including functions, classes, variables, and imports.
3. **Add Nodes to Graph:** The extracted code elements are added to the graph as nodes.
4. **Create Relationships:** Relationships between the nodes are created, such as `CALLS` for function calls and `INHERITS` for class inheritance.
## `CodeFinder`
The `CodeFinder` class in `code_finder.py` provides functionality to search for specific code elements and analyze their relationships within the indexed codebase.
### Key Methods
- `find_by_function_name()`: Finds functions by name.
- `find_by_class_name()`: Finds classes by name.
- `find_by_variable_name()`: Finds variables by name.
- `find_by_content()`: Finds code by content matching in source or docstrings.
- `find_related_code()`: Finds code related to a query using multiple search strategies.
- `analyze_code_relationships()`: Analyzes different types of code relationships, such as callers, callees, importers, and class hierarchies.
## `ImportExtractor`
The `ImportExtractor` class in `import_extractor.py` is a utility for extracting package and module imports from source code files of various programming languages. It uses the most appropriate parsing technique for each language, such as AST for Python and regular expressions for JavaScript.
# Tools Exploration
There are a total of 14 tools available to the users, and here we have attached illustrative demos for each one of them.
## find_code Tool
The `find_code` tool allows users to search for code snippets, functions, classes, and variables within the codebase using natural language queries. This tool helps developers understand and navigate large codebases efficiently.
Below is an embedded link to a demo video showcasing the usage of the `find_code` tool in action.
[](https://drive.google.com/file/d/1ojCDIIAwcir9e3jgHHIVC5weZ9nuIQcs/view?usp=drive_link)
---
## watch_directory Tool
The `watch_directory` tool allows users to monitor a specified directory for file changes, additions, or deletions in real-time. It helps developers automate workflows such as triggering scripts, updating indexes, or syncing files whenever changes occur in the directory.
Below is an embedded link to a demo video showcasing the usage of the `watch_directory` tool in a development environment.
[](https://drive.google.com/file/d/1OEjcS2iwwymss99zLidbeBjcblferKBX/view?usp=drive_link)
---
## analyze_code_relationships Tool
The `analyze_code_relationships` tool in CodeGraphContext is designed to let users query and explore the various relationships between code elements in a codebase, represented as a graph in Neo4j.
### Relationship Types That Can Be Analyzed
- **CALLS:** Finds which functions call or are called by a function.
- **CALLED_BY:** Finds all functions that directly or indirectly call a target function (inverse of CALLS).
- **INHERITS_FROM:** Finds class inheritance relationships; which classes inherit from which.
- **CONTAINS:** Shows containment (which classes/functions are inside which modules or files).
- **IMPLEMENTS:** Shows which classes implement an interface.
- **IMPORTS:** Identifies which files or modules import a specific module.
- **DEFINED_IN:** Locates where an entity (function/class) is defined.
- **HAS_ARGUMENT:** Shows relationships from functions to their arguments.
- **DECLARES:** Finds variables declared in functions or classes.
Below is an embedded link to a demo video showcasing the usage of the `analyse_code_relationships` tool.
[](https://drive.google.com/file/d/154M_lTPbg9_Gj9bd2ErnAVbJArSbcb2M/view?usp=drive_link)
---
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.no.min.js:
--------------------------------------------------------------------------------
```javascript
/*!
* Lunr languages, `Norwegian` language
* https://github.com/MihaiValentin/lunr-languages
*
* Copyright 2014, Mihai Valentin
* http://www.mozilla.org/MPL/
*/
/*!
* based on
* Snowball JavaScript Library v0.3
* http://code.google.com/p/urim/
* http://snowball.tartarus.org/
*
* Copyright 2010, Oleg Mazko
* http://www.mozilla.org/MPL/
*/
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,r=w.cursor+3;if(a=w.limit,0<=r||r<=w.limit){for(s=r;;){if(e=w.cursor,w.in_grouping(d,97,248)){w.cursor=e;break}if(e>=w.limit)return;w.cursor=e+1}for(;!w.out_grouping(d,97,248);){if(w.cursor>=w.limit)return;w.cursor++}a=w.cursor,a<s&&(a=s)}}function i(){var e,r,n;if(w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(m,29),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:n=w.limit-w.cursor,w.in_grouping_b(c,98,122)?w.slice_del():(w.cursor=w.limit-n,w.eq_s_b(1,"k")&&w.out_grouping_b(d,97,248)&&w.slice_del());break;case 3:w.slice_from("er")}}function t(){var e,r=w.limit-w.cursor;w.cursor>=a&&(e=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,w.find_among_b(u,2)?(w.bra=w.cursor,w.limit_backward=e,w.cursor=w.limit-r,w.cursor>w.limit_backward&&(w.cursor--,w.bra=w.cursor,w.slice_del())):w.limit_backward=e)}function o(){var e,r;w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(l,11),e?(w.bra=w.cursor,w.limit_backward=r,1==e&&w.slice_del()):w.limit_backward=r)}var s,a,m=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],u=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],c=[119,125,149,1],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,i(),w.cursor=w.limit,t(),w.cursor=w.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}});
```
--------------------------------------------------------------------------------
/docs/docs/troubleshooting.md:
--------------------------------------------------------------------------------
```markdown
# CodeGraphContext Troubleshooting Guide
Use this checklist whenever `cgc mcp setup` or `cgc mcp start` doesn’t behave as expected. It keeps the happy path short, but includes the fallback steps when something goes wrong.
## 1. Prerequisites at a glance
- **Windows + PowerShell** commands below assume the `py` launcher. Adapt to `python3` if you're on macOS/Linux.
- **Python 3.12+** (recommended for FalkorDB Lite support). Run `py -3.12 --version` to confirm.
- **Database Options:**
- **FalkorDB Lite** (default for Unix/Linux/macOS, Python 3.12+): No setup required, works out of the box.
- **Neo4j** (required for Windows, optional for others): Requires Docker, WSL, or native installation. Setup via `cgc neo4j setup`.
## 2. Create and activate a virtual environment
From the repository root (`CodeGraphContext/`):
```powershell
py -3.11 -m venv venv
.\venv\Scripts\python.exe -m pip install --upgrade pip
```
- On Windows, Neo4j driver 6.x can crash with `AttributeError: socket.EAI_ADDRFAMILY`. If you see that, run:
```powershell
.\venv\Scripts\python.exe -m pip install "neo4j<6"
```
## 3. Run the Neo4j setup wizard (optional for Unix, required for Windows)
**Note:** If you're on Unix/Linux/macOS with Python 3.12+, FalkorDB Lite is already your default database. You can skip this step unless you prefer Neo4j.
**For Windows users or those preferring Neo4j**, launch the wizard:
```powershell
.\venv\Scripts\cgc.exe neo4j setup
```
> **Tip:** If you want the wizard to spin up a local Neo4j instance for you, make sure **Docker Desktop** is installed and running before you launch `cgc neo4j setup`. If Docker isn't running, the setup wizard will fail when it tries to install Neo4j locally.
What happens next:
- The wizard checks for Docker. If it's running, it can auto-provision a local Neo4j instance for you.
- Alternatively, you can supply credentials for an existing Neo4j AuraDB database.
- At the end, it generates:
- `mcp.json` in your project directory (stores the MCP server command + env vars).
- `~/.codegraphcontext/.env` containing `NEO4J_URI`, `NEO4J_USERNAME`, `NEO4J_PASSWORD`.
Make sure the Docker container (or remote Neo4j) is still running before you start the server.
## 4. Start the MCP server
Once the wizard completes successfully:
```powershell
.\venv\Scripts\cgc.exe mcp start
```
Expected output includes:
```text
Starting CodeGraphContext Server...
...
MCP Server is running. Waiting for requests...
```
If you instead see:
```text
Configuration Error: Neo4j credentials must be set via environment variables
```
then either no credentials were saved, or the wizard was skipped—see the manual alternative below.
## 5. Manual credential setup (fallback)
If you prefer not to use the wizard or need to fix a broken configuration:
1. Create a `mcp.json` (or edit the one that exists) in the repository root:
```json
{
"mcpServers": {
"CodeGraphContext": {
"command": "cgc",
"args": ["mcp", "start"],
"env": {
"NEO4J_URI": "neo4j+s://YOUR-HOSTNAME:7687",
"NEO4J_USERNAME": "neo4j",
"NEO4J_PASSWORD": "super-secret-password"
}
}
}
}
```
2. (Optional) Also create `%USERPROFILE%\.codegraphcontext\.env` with the same key/value pairs. The CLI loads that file automatically.
3. Re-run:
```powershell
.\venv\Scripts\cgc.exe mcp start
```
## 6. Common issues & fixes
| Symptom | Likely Cause | Fix |
| --- | --- | --- |
| `Configuration Error: Neo4j credentials must be set…` | `mcp.json`/`.env` missing or empty | Run `cgc neo4j setup` again **with Docker running**, or create the files manually (section 5). |
| `AttributeError: socket.EAI_ADDRFAMILY` | Neo4j 6.x bug on Windows | Install the 5.x driver: `.\venv\Scripts\python.exe -m pip install "neo4j<6"` and retry. |
| Setup wizard fails while pulling Docker image | Docker Desktop not running or Docker permissions missing | Start Docker Desktop, wait for it to report “Running”, then rerun `cgc neo4j setup`. |
| Server exits immediately with no log | Neo4j instance is offline | Check Docker container status or AuraDB dashboard; restart Neo4j and call `cgc mcp start` again. |
## 7. After the server is running
- Keep the virtual environment active whenever you run `cgc` commands.
- Use `pytest` from the same env to run tests:
```powershell
.\venv\Scripts\pytest
```
- Front-end website lives under `website/` if you need to run `npm run dev`.
When in doubt, re-run the wizard with Docker active—it regenerates the configuration files without touching your code. Let me know if any section needs clarifying! :)
```
--------------------------------------------------------------------------------
/tests/sample_project_go/goroutines_channels.go:
--------------------------------------------------------------------------------
```go
// goroutines_channels.go - Demonstrates Go concurrency patterns
package main
import (
"fmt"
"sync"
"time"
)
// SimpleGoroutine demonstrates basic goroutine
func SimpleGoroutine(id int) {
fmt.Printf("Goroutine %d starting\n", id)
time.Sleep(time.Millisecond * 100)
fmt.Printf("Goroutine %d done\n", id)
}
// ChannelSender sends data to a channel
func ChannelSender(ch chan<- int, values []int) {
for _, v := range values {
ch <- v
}
close(ch)
}
// ChannelReceiver receives data from a channel
func ChannelReceiver(ch <-chan int, done chan<- bool) {
sum := 0
for v := range ch {
sum += v
}
fmt.Printf("Sum: %d\n", sum)
done <- true
}
// BufferedChannelExample demonstrates buffered channels
func BufferedChannelExample() {
ch := make(chan string, 3)
ch <- "first"
ch <- "second"
ch <- "third"
fmt.Println(<-ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
}
// SelectExample demonstrates select statement
func SelectExample(ch1, ch2 chan string) string {
select {
case msg1 := <-ch1:
return fmt.Sprintf("Received from ch1: %s", msg1)
case msg2 := <-ch2:
return fmt.Sprintf("Received from ch2: %s", msg2)
case <-time.After(time.Second):
return "Timeout"
}
}
// Worker demonstrates worker pool pattern
func Worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for job := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, job)
time.Sleep(time.Millisecond * 50)
results <- job * 2
}
}
// WorkerPool creates a pool of workers
func WorkerPool(numWorkers int, numJobs int) []int {
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
var wg sync.WaitGroup
// Start workers
for w := 1; w <= numWorkers; w++ {
wg.Add(1)
go Worker(w, jobs, results, &wg)
}
// Send jobs
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
// Wait and collect results
go func() {
wg.Wait()
close(results)
}()
var output []int
for result := range results {
output = append(output, result)
}
return output
}
// Counter demonstrates mutex for safe concurrent access
type Counter struct {
mu sync.Mutex
value int
}
// Increment safely increments counter
func (c *Counter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
// GetValue safely gets counter value
func (c *Counter) GetValue() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
// RWMutexExample demonstrates read-write mutex
type ConcurrentMap struct {
mu sync.RWMutex
data map[string]int
}
// Set adds or updates a value
func (cm *ConcurrentMap) Set(key string, value int) {
cm.mu.Lock()
defer cm.mu.Unlock()
cm.data[key] = value
}
// Get retrieves a value
func (cm *ConcurrentMap) Get(key string) (int, bool) {
cm.mu.RLock()
defer cm.mu.RUnlock()
val, ok := cm.data[key]
return val, ok
}
// OnceExample demonstrates sync.Once
var once sync.Once
var instance *Singleton
type Singleton struct {
data string
}
// GetSingleton returns singleton instance
func GetSingleton() *Singleton {
once.Do(func() {
fmt.Println("Creating singleton instance")
instance = &Singleton{data: "singleton data"}
})
return instance
}
// PipelineStage1 first stage of pipeline
func PipelineStage1(input <-chan int, output chan<- int) {
for num := range input {
output <- num * 2
}
close(output)
}
// PipelineStage2 second stage of pipeline
func PipelineStage2(input <-chan int, output chan<- int) {
for num := range input {
output <- num + 10
}
close(output)
}
// Pipeline demonstrates pipeline pattern
func Pipeline(numbers []int) []int {
stage1 := make(chan int)
stage2 := make(chan int)
// Input
go func() {
for _, num := range numbers {
stage1 <- num
}
close(stage1)
}()
// Stage 1
go PipelineStage1(stage1, stage2)
// Collect results
var results []int
for result := range stage2 {
results = append(results, result)
}
return results
}
// FanOut sends data to multiple channels
func FanOut(input <-chan int, outputs []chan<- int) {
for val := range input {
for _, out := range outputs {
out <- val
}
}
for _, out := range outputs {
close(out)
}
}
// FanIn merges multiple channels into one
func FanIn(inputs ...<-chan int) <-chan int {
output := make(chan int)
var wg sync.WaitGroup
for _, input := range inputs {
wg.Add(1)
go func(ch <-chan int) {
defer wg.Done()
for val := range ch {
output <- val
}
}(input)
}
go func() {
wg.Wait()
close(output)
}()
return output
}
func demonstrateConcurrency() {
// Simple goroutines
for i := 1; i <= 3; i++ {
go SimpleGoroutine(i)
}
// Worker pool
results := WorkerPool(3, 5)
fmt.Println("Results:", results)
time.Sleep(time.Second)
}
```
--------------------------------------------------------------------------------
/tests/sample_project_javascript/classes.js:
--------------------------------------------------------------------------------
```javascript
/**
* Sample JavaScript file demonstrating class definitions and methods
* This file tests class declarations, methods, static methods, and inheritance
*/
// Basic class declaration
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
// Instance method
greet() {
return `Hello, I'm ${this.name} and I'm ${this.age} years old`;
}
/**
* Method with JSDoc documentation
* @param {number} years - Number of years to add
* @returns {void}
*/
celebrateBirthday(years = 1) {
this.age += years;
console.log(`Happy birthday! Now ${this.age} years old`);
}
// Getter method
get info() {
return `${this.name} (${this.age})`;
}
// Setter method
set info(value) {
const [name, age] = value.split(' ');
this.name = name;
this.age = parseInt(age);
}
// Static method
static createAdult(name) {
return new Person(name, 18);
}
// Static method with parameters
static compare(person1, person2) {
return person1.age - person2.age;
}
}
// Class inheritance
class Employee extends Person {
constructor(name, age, jobTitle, salary) {
super(name, age);
this.jobTitle = jobTitle;
this.salary = salary;
}
// Override parent method
greet() {
return `${super.greet()}. I work as a ${this.jobTitle}`;
}
// New method specific to Employee
work() {
console.log(`${this.name} is working as a ${this.jobTitle}`);
}
// Method with complex parameters
updateSalary(newSalary, reason = 'performance review') {
const oldSalary = this.salary;
this.salary = newSalary;
console.log(`Salary updated from ${oldSalary} to ${newSalary} due to ${reason}`);
}
// Static method in child class
static createIntern(name, age) {
return new Employee(name, age, 'Intern', 0);
}
}
// Class with private fields (modern JavaScript)
class BankAccount {
#balance = 0;
#accountNumber;
constructor(accountNumber, initialBalance = 0) {
this.#accountNumber = accountNumber;
this.#balance = initialBalance;
}
// Public method accessing private field
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
return this.#balance;
}
throw new Error('Amount must be positive');
}
// Public method accessing private field
withdraw(amount) {
if (amount > 0 && amount <= this.#balance) {
this.#balance -= amount;
return this.#balance;
}
throw new Error('Invalid withdrawal amount');
}
// Getter for private field
get balance() {
return this.#balance;
}
// Private method
#validateTransaction(amount) {
return amount > 0 && amount <= this.#balance;
}
}
// Class with static properties and methods
class MathUtils {
static PI = 3.14159;
static E = 2.71828;
static add(a, b) {
return a + b;
}
static multiply(a, b) {
return a * b;
}
static circleArea(radius) {
return MathUtils.PI * radius * radius;
}
}
// Class expression assigned to variable
const AnonymousClass = class {
constructor(value) {
this.value = value;
}
getValue() {
return this.value;
}
};
// Mixin pattern using classes
const Flyable = (Base) => class extends Base {
fly() {
console.log(`${this.name} is flying!`);
}
};
const Swimmable = (Base) => class extends Base {
swim() {
console.log(`${this.name} is swimming!`);
}
};
// Class using mixins
class Duck extends Swimmable(Flyable(Person)) {
constructor(name) {
super(name, 0); // Ducks don't have human age
this.species = 'Duck';
}
quack() {
console.log(`${this.name} says: Quack!`);
}
}
// Function that creates and uses class instances
function demonstrateClasses() {
const person = new Person('Alice', 30);
const employee = new Employee('Bob', 25, 'Developer', 75000);
const account = new BankAccount('12345', 1000);
const duck = new Duck('Donald');
// Call various methods
console.log(person.greet());
console.log(employee.greet());
employee.work();
account.deposit(500);
console.log('Balance:', account.balance);
duck.quack();
duck.fly();
duck.swim();
return {
person,
employee,
account,
duck
};
}
// Export classes
export { Person, Employee, BankAccount, MathUtils, Duck };
export default demonstrateClasses;
```
--------------------------------------------------------------------------------
/website/src/components/ui/toast.tsx:
--------------------------------------------------------------------------------
```typescript
import * as React from "react";
import * as ToastPrimitives from "@radix-ui/react-toast";
import { cva, type VariantProps } from "class-variance-authority";
import { X } from "lucide-react";
import { cn } from "@/lib/utils";
const ToastProvider = ToastPrimitives.Provider;
const ToastViewport = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Viewport>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Viewport
ref={ref}
className={cn(
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
className,
)}
{...props}
/>
));
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
const toastVariants = cva(
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
{
variants: {
variant: {
default: "border bg-background text-foreground",
destructive: "destructive group border-destructive bg-destructive text-destructive-foreground",
},
},
defaultVariants: {
variant: "default",
},
},
);
const Toast = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => {
return <ToastPrimitives.Root ref={ref} className={cn(toastVariants({ variant }), className)} {...props} />;
});
Toast.displayName = ToastPrimitives.Root.displayName;
const ToastAction = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Action>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Action
ref={ref}
className={cn(
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors group-[.destructive]:border-muted/40 hover:bg-secondary group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 group-[.destructive]:focus:ring-destructive disabled:pointer-events-none disabled:opacity-50",
className,
)}
{...props}
/>
));
ToastAction.displayName = ToastPrimitives.Action.displayName;
const ToastClose = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Close>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Close
ref={ref}
className={cn(
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity group-hover:opacity-100 group-[.destructive]:text-red-300 hover:text-foreground group-[.destructive]:hover:text-red-50 focus:opacity-100 focus:outline-none focus:ring-2 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
className,
)}
toast-close=""
{...props}
>
<X className="h-4 w-4" />
</ToastPrimitives.Close>
));
ToastClose.displayName = ToastPrimitives.Close.displayName;
const ToastTitle = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Title>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Title ref={ref} className={cn("text-sm font-semibold", className)} {...props} />
));
ToastTitle.displayName = ToastPrimitives.Title.displayName;
const ToastDescription = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Description>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Description ref={ref} className={cn("text-sm opacity-90", className)} {...props} />
));
ToastDescription.displayName = ToastPrimitives.Description.displayName;
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
type ToastActionElement = React.ReactElement<typeof ToastAction>;
export {
type ToastProps,
type ToastActionElement,
ToastProvider,
ToastViewport,
Toast,
ToastTitle,
ToastDescription,
ToastClose,
ToastAction,
};
```
--------------------------------------------------------------------------------
/src/codegraphcontext/core/jobs.py:
--------------------------------------------------------------------------------
```python
# src/codegraphcontext/core/jobs.py
"""
This module defines the data structures and manager for handling long-running,
background jobs, such as code indexing.
"""
import uuid
import threading
from datetime import datetime, timedelta
from dataclasses import dataclass, asdict
from enum import Enum
from typing import Any, Dict, List, Optional
from pathlib import Path
class JobStatus(Enum):
"""Enumeration for the possible statuses of a background job."""
PENDING = "pending"
RUNNING = "running"
COMPLETED = "completed"
FAILED = "failed"
CANCELLED = "cancelled"
@dataclass
class JobInfo:
"""
A data class to hold all information about a single background job.
This makes it easy to track the job's progress, status, and results.
"""
job_id: str
status: JobStatus
start_time: datetime
end_time: Optional[datetime] = None
total_files: int = 0
processed_files: int = 0
current_file: Optional[str] = None
estimated_duration: Optional[float] = None
actual_duration: Optional[float] = None
errors: List[str] = None
result: Optional[Dict[str, Any]] = None
path: Optional[str] = None
is_dependency: bool = False
def __post_init__(self):
"""Ensures the errors list is initialized after the object is created."""
if self.errors is None:
self.errors = []
@property
def progress_percentage(self) -> float:
"""Calculates the completion percentage of the job."""
if self.total_files == 0:
return 0.0
return (self.processed_files / self.total_files) * 100
@property
def estimated_time_remaining(self) -> Optional[float]:
"""Calculates the estimated time remaining based on the average time per file."""
if self.status != JobStatus.RUNNING or self.processed_files == 0:
return None
elapsed = (datetime.now() - self.start_time).total_seconds()
avg_time_per_file = elapsed / self.processed_files
remaining_files = self.total_files - self.processed_files
return remaining_files * avg_time_per_file
class JobManager:
"""
A thread-safe manager for creating, updating, and retrieving information
about background jobs. It stores job information in memory.
"""
def __init__(self):
self.jobs: Dict[str, JobInfo] = {}
self.lock = threading.Lock() # A lock to ensure thread-safe access to the jobs dictionary.
def create_job(self, path: str, is_dependency: bool = False) -> str:
"""Creates a new job, assigns it a unique ID, and stores it."""
job_id = str(uuid.uuid4())
with self.lock:
self.jobs[job_id] = JobInfo(
job_id=job_id,
status=JobStatus.PENDING,
start_time=datetime.now(),
path=path,
is_dependency=is_dependency
)
return job_id
def update_job(self, job_id: str, **kwargs):
"""Updates the information for a specific job in a thread-safe manner."""
with self.lock:
if job_id in self.jobs:
job = self.jobs[job_id]
for key, value in kwargs.items():
if hasattr(job, key):
setattr(job, key, value)
def get_job(self, job_id: str) -> Optional[JobInfo]:
"""Retrieves the information for a single job."""
with self.lock:
return self.jobs.get(job_id)
def list_jobs(self) -> List[JobInfo]:
"""Returns a list of all jobs currently in the manager."""
with self.lock:
return list(self.jobs.values())
def find_active_job_by_path(self, path: str) -> Optional[JobInfo]:
"""Finds the most recent, currently active (pending or running) job for a given path."""
with self.lock:
path_obj = Path(path).resolve()
matching_jobs = sorted(
[job for job in self.jobs.values() if job.path and Path(job.path).resolve() == path_obj],
key=lambda j: j.start_time,
reverse=True
)
for job in matching_jobs:
if job.status in [JobStatus.PENDING, JobStatus.RUNNING]:
return job
return None
def cleanup_old_jobs(self, max_age_hours: int = 24):
"""Removes old, completed jobs from memory to prevent memory leaks."""
cutoff_time = datetime.now() - timedelta(hours=max_age_hours)
with self.lock:
jobs_to_remove = [
job_id for job_id, job in self.jobs.items()
if job.end_time and job.end_time < cutoff_time
]
for job_id in jobs_to_remove:
del self.jobs[job_id]
```
--------------------------------------------------------------------------------
/website/src/components/ui/command.tsx:
--------------------------------------------------------------------------------
```typescript
import * as React from "react";
import { type DialogProps } from "@radix-ui/react-dialog";
import { Command as CommandPrimitive } from "cmdk";
import { Search } from "lucide-react";
import { cn } from "@/lib/utils";
import { Dialog, DialogContent } from "@/components/ui/dialog";
const Command = React.forwardRef<
React.ElementRef<typeof CommandPrimitive>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
>(({ className, ...props }, ref) => (
<CommandPrimitive
ref={ref}
className={cn(
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
className,
)}
{...props}
/>
));
Command.displayName = CommandPrimitive.displayName;
interface CommandDialogProps extends DialogProps {}
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
return (
<Dialog {...props}>
<DialogContent className="overflow-hidden p-0 shadow-lg">
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
{children}
</Command>
</DialogContent>
</Dialog>
);
};
const CommandInput = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Input>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
>(({ className, ...props }, ref) => (
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<CommandPrimitive.Input
ref={ref}
className={cn(
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
/>
</div>
));
CommandInput.displayName = CommandPrimitive.Input.displayName;
const CommandList = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.List>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
>(({ className, ...props }, ref) => (
<CommandPrimitive.List
ref={ref}
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
{...props}
/>
));
CommandList.displayName = CommandPrimitive.List.displayName;
const CommandEmpty = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Empty>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
>((props, ref) => <CommandPrimitive.Empty ref={ref} className="py-6 text-center text-sm" {...props} />);
CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
const CommandGroup = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Group>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Group
ref={ref}
className={cn(
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
className,
)}
{...props}
/>
));
CommandGroup.displayName = CommandPrimitive.Group.displayName;
const CommandSeparator = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Separator ref={ref} className={cn("-mx-1 h-px bg-border", className)} {...props} />
));
CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
const CommandItem = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50",
className,
)}
{...props}
/>
));
CommandItem.displayName = CommandPrimitive.Item.displayName;
const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
return <span className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)} {...props} />;
};
CommandShortcut.displayName = "CommandShortcut";
export {
Command,
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandShortcut,
CommandSeparator,
};
```
--------------------------------------------------------------------------------
/scripts/update_language_parsers.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Script to update all language parsers to use the new tree-sitter 0.25+ API.
This script:
1. Adds import for execute_query
2. Removes query dictionary initialization
3. Replaces query.captures() with execute_query()
"""
import re
from pathlib import Path
# Language files to update
LANGUAGE_FILES = [
"javascript.py",
"typescript.py",
"go.py",
"rust.py",
"c.py",
"cpp.py",
"java.py",
"ruby.py",
"csharp.py",
]
LANGUAGES_DIR = Path(__file__).resolve().parent.parent / "src" / "codegraphcontext" / "tools" / "languages"
def update_imports(content: str) -> str:
"""Add execute_query import if not present."""
if "from codegraphcontext.utils.tree_sitter_manager import execute_query" in content:
return content
# Find the last import statement
import_pattern = r"(from codegraphcontext\.utils\.debug_log import[^\n]+)"
match = re.search(import_pattern, content)
if match:
# Add our import after the debug_log import
new_import = match.group(1) + "\nfrom codegraphcontext.utils.tree_sitter_manager import execute_query"
content = content.replace(match.group(1), new_import)
return content
def remove_query_dict_init(content: str) -> str:
"""Remove self.queries dictionary initialization."""
# Pattern to match the queries dictionary initialization
pattern = r"\s+self\.queries\s*=\s*\{[^}]+\}\s*"
content = re.sub(pattern, "\n", content, flags=re.DOTALL)
return content
def replace_query_usage(content: str, query_dict_name: str) -> str:
"""Replace query.captures() with execute_query()."""
# Pattern 1: self.queries.get('name') or self.queries['name']
# Replace: query = self.queries.get('lambda_assignments')
# With: query_str = LANG_QUERIES.get('lambda_assignments')
content = re.sub(
r"query\s*=\s*self\.queries\.get\('([^']+)'\)",
r"query_str = " + query_dict_name + ".get('\\1')",
content
)
content = re.sub(
r"query\s*=\s*self\.queries\['([^']+)'\]",
r"query_str = " + query_dict_name + "['\\1']",
content
)
# Pattern 2: if not query: return []
# Replace with: if not query_str: return []
content = content.replace("if not query:", "if not query_str:")
# Pattern 3: query.captures(node)
# Replace with: execute_query(self.language, query_str, node)
content = re.sub(
r"query\.captures\(([^)]+)\)",
r"execute_query(self.language, query_str, \1)",
content
)
# Pattern 4: In pre_scan functions, replace parser_wrapper.language.query(query_str)
content = re.sub(
r"query\s*=\s*parser_wrapper\.language\.query\(query_str\)",
"",
content
)
# Pattern 5: In pre_scan functions, replace query.captures with execute_query
content = re.sub(
r"for\s+([^,]+),\s+([^)]+)\s+in\s+query\.captures\(tree\.root_node\):",
r"for \1, \2 in execute_query(parser_wrapper.language, query_str, tree.root_node):",
content
)
content = re.sub(
r"for\s+([^,]+),\s+([^)]+)\s+in\s+query\.captures\(([^)]+)\):",
r"for \1, \2 in execute_query(parser_wrapper.language, query_str, \3):",
content
)
return content
def get_query_dict_name(content: str) -> str:
"""Detect the query dictionary name (e.g., PY_QUERIES, JS_QUERIES, etc.)."""
match = re.search(r"([A-Z_]+QUERIES)\s*=\s*\{", content)
if match:
return match.group(1)
return "QUERIES"
def update_language_file(file_path: Path):
"""Update a single language file."""
print(f"Updating {file_path.name}...")
content = file_path.read_text()
original_content = content
# Detect query dictionary name
query_dict_name = get_query_dict_name(content)
print(f" Query dict name: {query_dict_name}")
# Apply transformations
content = update_imports(content)
content = remove_query_dict_init(content)
content = replace_query_usage(content, query_dict_name)
# Write back if changed
if content != original_content:
file_path.write_text(content)
print(f" ✓ Updated {file_path.name}")
else:
print(f" - No changes needed for {file_path.name}")
def main():
"""Update all language parser files."""
print("Updating language parsers for tree-sitter 0.25+ compatibility\n")
for lang_file in LANGUAGE_FILES:
file_path = LANGUAGES_DIR / lang_file
if file_path.exists():
try:
update_language_file(file_path)
except Exception as e:
print(f" ✗ Error updating {lang_file}: {e}")
else:
print(f" ✗ File not found: {lang_file}")
print("\n✓ All language parsers updated!")
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/visualize_graph.py:
--------------------------------------------------------------------------------
```python
import os
import json
import platform
from pathlib import Path
if platform.system() == "Windows":
raise RuntimeError(
"CodeGraphContext uses redislite/FalkorDB, which does not support Windows.\n"
"Please run the project using WSL or Docker."
)
from redislite import FalkorDB
def generate_visualization():
db_path = os.path.expanduser('~/.codegraphcontext/falkordb.db')
if not os.path.exists(db_path):
print(f"Error: Database not found at {db_path}")
return
print(f"Reading graph from {db_path}...")
f = FalkorDB(db_path)
g = f.select_graph('codegraph')
# Fetch nodes
nodes_res = g.query("MATCH (n) RETURN id(n), labels(n)[0], n.name, n.path")
nodes = []
for row in nodes_res.result_set:
node_id, label, name, path = row
# Format label and name for display
display_name = name if name else (os.path.basename(path) if path else label)
nodes.append({
"id": node_id,
"label": display_name,
"group": label,
"title": f"Type: {label}\nPath: {path}"
})
# Fetch relationships
edges_res = g.query("MATCH (s)-[r]->(t) RETURN id(s), type(r), id(t)")
edges = []
for row in edges_res.result_set:
source, rel_type, target = row
edges.append({
"from": source,
"to": target,
"label": rel_type,
"arrows": "to"
})
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>CGC Graph Visualization</title>
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<style type="text/css">
body {{
margin: 0;
padding: 0;
background-color: #1a1a1a;
color: #ffffff;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
overflow: hidden;
}}
#mynetwork {{
width: 100vw;
height: 100vh;
}}
.header {{
position: absolute;
top: 20px;
left: 20px;
z-index: 10;
background: rgba(0,0,0,0.7);
padding: 15px;
border-radius: 8px;
border: 1px solid #444;
pointer-events: none;
}}
h1 {{ margin: 0; font-size: 1.5em; color: #00d4ff; }}
.stats {{ font-size: 0.9em; color: #aaa; margin-top: 5px; }}
</style>
</head>
<body>
<div class="header">
<h1>CodeGraphContext Visualizer</h1>
<div class="stats">Nodes: {len(nodes)} | Relationships: {len(edges)}</div>
<div style="font-size: 0.8em; margin-top: 10px; color: #888;">Drag to move | Scroll to zoom</div>
</div>
<div id="mynetwork"></div>
<script type="text/javascript">
var nodes = new vis.DataSet({json.dumps(nodes)});
var edges = new vis.DataSet({json.dumps(edges)});
var container = document.getElementById('mynetwork');
var data = {{
nodes: nodes,
edges: edges
}};
var options = {{
nodes: {{
shape: 'dot',
size: 16,
font: {{ color: '#ffffff', size: 12 }},
borderWidth: 2,
shadow: true
}},
edges: {{
width: 2,
color: {{ color: '#666666', highlight: '#00d4ff' }},
font: {{ size: 10, align: 'middle', color: '#aaaaaa' }},
smooth: {{ type: 'continuous' }}
}},
groups: {{
Repository: {{ color: {{ background: '#e91e63', border: '#c2185b' }} }},
File: {{ color: {{ background: '#2196f3', border: '#1976d2' }} }},
Function: {{ color: {{ background: '#4caf50', border: '#388e3c' }} }},
Class: {{ color: {{ background: '#ff9800', border: '#f57c00' }} }},
Module: {{ color: {{ background: '#9c27b0', border: '#7b1fa2' }} }},
Variable: {{ color: {{ background: '#607d8b', border: '#455a64' }} }}
}},
physics: {{
forceAtlas2Based: {{
gravitationalConstant: -26,
centralGravity: 0.005,
springLength: 230,
springConstant: 0.18
}},
maxVelocity: 146,
solver: 'forceAtlas2Based',
timestep: 0.35,
stabilization: {{ iterations: 150 }}
}}
}};
var network = new vis.Network(container, data, options);
</script>
</body>
</html>
"""
target_path = Path.cwd() / "graph_viz.html"
with open(target_path, "w") as f:
f.write(html_content)
print(f"\n✅ Visualization generated successfully!")
print(f"👉 Open this file in your browser: file://{target_path.absolute()}")
if __name__ == "__main__":
generate_visualization()
```
--------------------------------------------------------------------------------
/scripts/generate_lang_contributors.py:
--------------------------------------------------------------------------------
```python
import subprocess
import os
from collections import defaultdict
# Get the absolute path of the script's directory, then go up to the project root.
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_ROOT = os.path.dirname(SCRIPT_DIR)
# Define files to track per language. Paths are relative to the project root.
files_by_lang = {
"c": ["src/codegraphcontext/tools/languages/c.py"],
"cpp": ["src/codegraphcontext/tools/languages/cpp.py"],
"go": ["src/codegraphcontext/tools/languages/go.py"],
"java": ["src/codegraphcontext/tools/languages/java.py"],
"javascript": ["src/codegraphcontext/tools/languages/javascript.py"],
"python": ["src/codegraphcontext/tools/languages/python.py"],
"ruby": ["src/codegraphcontext/tools/languages/ruby.py"],
"rust": ["src/codegraphcontext/tools/languages/rust.py"],
"typescript": ["src/codegraphcontext/tools/languages/typescript.py"],
}
def get_contributor_stats(files):
"""
Returns a dictionary of contributors with commit count, lines added, and lines deleted.
This is done by parsing the output of 'git log'.
"""
data = defaultdict(lambda: {"commits": 0, "added": 0, "deleted": 0, "email": ""})
try:
# Use 'git log' with '--numstat' to get file changes, author name, and email in one go.
log_output = subprocess.check_output(
["git", "log", "--no-merges", "--numstat", "--pretty=format:---%n%an%n%ae", "--"] + files,
text=True,
cwd=PROJECT_ROOT
).strip()
except subprocess.CalledProcessError as e:
print(f"Error fetching git log for files {files}: {e}")
return data
if not log_output:
return data
commits = log_output.split('---')[1:]
for commit in commits:
lines = commit.strip().split('\n')
author = lines[0].strip()
email = lines[1].strip()
if not author:
continue
data[author]["commits"] += 1
data[author]["email"] = email
for line in lines[2:]:
if not line.strip():
continue
parts = line.split("\t")
if len(parts) >= 3:
added, deleted, _ = parts
added = int(added) if added != "-" else 0
deleted = int(deleted) if deleted != "-" else 0
data[author]["added"] += added
data[author]["deleted"] += deleted
return data
def get_username_from_email(email):
if email.endswith('@users.noreply.github.com'):
return email.split('+')[1].split('@')[0]
return None
def get_repo_url():
try:
url = subprocess.check_output(
["git", "remote", "get-url", "origin"],
text=True,
cwd=PROJECT_ROOT
).strip()
if url.endswith(".git"):
url = url[:-4]
if url.startswith("[email protected]:"):
url = url.replace("[email protected]:", "https://github.com/")
return url
except Exception:
return None
def generate_markdown_table(lang, stats, repo_url, files):
"""
Generates a Markdown table for contributors
"""
table = f"## {lang.capitalize()} Contributors\n\n"
table += "| Rank | Contributor | Commits | Lines Added | Lines Deleted | Link to Contributions |\n"
table += "|---|---|---|---|---|---|\n"
for rank, (author, vals) in enumerate(sorted(stats.items(), key=lambda x: (x[1]["commits"], x[1]["added"]), reverse=True), 1):
email = vals["email"]
username = get_username_from_email(email)
if username:
profile_str = f"[{author}](https://github.com/{username})"
author_for_link = username
else:
profile_str = author
author_for_link = email
contribution_links = []
for file_path in files:
file_name = os.path.basename(file_path)
link = f"[{file_name}]({repo_url}/commits/main/{file_path}?author={author_for_link})"
contribution_links.append(link)
links_str = ", ".join(contribution_links)
table += f"| {rank} | {profile_str} | {vals['commits']} | {vals['added']} | {vals['deleted']} | {links_str} |\n"
return table
def main():
repo_url = get_repo_url()
if not repo_url:
print("Could not determine repository URL. Contribution links will not be generated.")
output_file = os.path.join(PROJECT_ROOT, "contributors.md")
with open(output_file, "w") as f:
f.write("# Language Contributors\n\n")
f.write("This file is auto-generated. Do not edit manually.\n\n")
for lang, files in files_by_lang.items():
stats = get_contributor_stats(files)
if stats:
table = generate_markdown_table(lang, stats, repo_url, files)
f.write(table + "\n\n")
print(f"Contributor stats generated in {output_file}")
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/website/src/components/ui/navigation-menu.tsx:
--------------------------------------------------------------------------------
```typescript
import * as React from "react";
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
import { cva } from "class-variance-authority";
import { ChevronDown } from "lucide-react";
import { cn } from "@/lib/utils";
const NavigationMenu = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Root
ref={ref}
className={cn("relative z-10 flex max-w-max flex-1 items-center justify-center", className)}
{...props}
>
{children}
<NavigationMenuViewport />
</NavigationMenuPrimitive.Root>
));
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
const NavigationMenuList = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.List>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.List
ref={ref}
className={cn("group flex flex-1 list-none items-center justify-center space-x-1", className)}
{...props}
/>
));
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
const NavigationMenuItem = NavigationMenuPrimitive.Item;
const navigationMenuTriggerStyle = cva(
"group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50",
);
const NavigationMenuTrigger = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Trigger
ref={ref}
className={cn(navigationMenuTriggerStyle(), "group", className)}
{...props}
>
{children}{" "}
<ChevronDown
className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180"
aria-hidden="true"
/>
</NavigationMenuPrimitive.Trigger>
));
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
const NavigationMenuContent = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Content
ref={ref}
className={cn(
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto",
className,
)}
{...props}
/>
));
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
const NavigationMenuLink = NavigationMenuPrimitive.Link;
const NavigationMenuViewport = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
>(({ className, ...props }, ref) => (
<div className={cn("absolute left-0 top-full flex justify-center")}>
<NavigationMenuPrimitive.Viewport
className={cn(
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
className,
)}
ref={ref}
{...props}
/>
</div>
));
NavigationMenuViewport.displayName = NavigationMenuPrimitive.Viewport.displayName;
const NavigationMenuIndicator = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Indicator
ref={ref}
className={cn(
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
className,
)}
{...props}
>
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
</NavigationMenuPrimitive.Indicator>
));
NavigationMenuIndicator.displayName = NavigationMenuPrimitive.Indicator.displayName;
export {
navigationMenuTriggerStyle,
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuContent,
NavigationMenuTrigger,
NavigationMenuLink,
NavigationMenuIndicator,
NavigationMenuViewport,
};
```
--------------------------------------------------------------------------------
/tests/sample_project_typescript/src/types-interfaces.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Basic Types and Interfaces
* Demonstrates TypeScript's core type system including primitives,
* interfaces, type aliases, unions, intersections, and advanced type patterns
*/
// ========== Primitive Types ==========
export const stringValue: string = "Hello TypeScript";
export const numberValue: number = 42;
export const booleanValue: boolean = true;
export const nullValue: null = null;
export const undefinedValue: undefined = undefined;
export const symbolValue: symbol = Symbol("unique");
export const bigintValue: bigint = 100n;
// ========== Array and Tuple Types ==========
export const numberArray: number[] = [1, 2, 3, 4];
export const stringArray: Array<string> = ["a", "b", "c"];
export const mixedTuple: [string, number, boolean] = ["hello", 42, true];
export const namedTuple: [name: string, age: number] = ["Alice", 30];
// ========== Object Types ==========
export const basicObject: { name: string; age: number } = {
name: "John",
age: 25
};
// ========== Interface Definitions ==========
export interface User {
readonly id: number;
name: string;
email?: string; // Optional property
readonly createdAt: Date;
preferences: UserPreferences;
}
export interface UserPreferences {
theme: "light" | "dark";
notifications: boolean;
language: string;
}
// Interface inheritance
export interface AdminUser extends User {
permissions: string[];
lastLogin?: Date;
}
// Interface with index signature
export interface Dictionary<T = any> {
[key: string]: T;
}
// Interface with call signature
export interface StringProcessor {
(input: string): string;
description: string;
}
// Interface with construct signature
export interface Constructable {
new (name: string): { name: string };
}
// ========== Type Aliases ==========
export type Status = "pending" | "approved" | "rejected";
export type ID = string | number;
export type EventHandler<T> = (event: T) => void;
// Generic type alias
export type Response<T> = {
data: T;
error: string | null;
timestamp: Date;
};
// Mapped type alias
export type Optional<T> = {
[K in keyof T]?: T[K];
};
// ========== Union Types ==========
export type StringOrNumber = string | number;
export type Theme = "light" | "dark" | "auto";
export function formatValue(value: StringOrNumber): string {
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toString();
}
// Discriminated union
export type Shape =
| { kind: "circle"; radius: number }
| { kind: "rectangle"; width: number; height: number }
| { kind: "triangle"; base: number; height: number };
export function calculateArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "rectangle":
return shape.width * shape.height;
case "triangle":
return (shape.base * shape.height) / 2;
default:
const _exhaustive: never = shape;
throw new Error(`Unhandled shape: ${_exhaustive}`);
}
}
// ========== Intersection Types ==========
export type PersonalInfo = {
name: string;
age: number;
};
export type ContactInfo = {
email: string;
phone: string;
};
export type Employee = PersonalInfo & ContactInfo & {
employeeId: string;
department: string;
};
// ========== Conditional Types ==========
export type NonNullable<T> = T extends null | undefined ? never : T;
export type ArrayElement<T> = T extends (infer U)[] ? U : never;
// ========== Template Literal Types ==========
export type EventName<T extends string> = `on${Capitalize<T>}`;
export type CSSProperty = `--${string}`;
// ========== Utility Types Usage ==========
export type PartialUser = Partial<User>;
export type RequiredUser = Required<User>;
export type UserEmail = Pick<User, "email">;
export type UserWithoutId = Omit<User, "id">;
export type UserKeys = keyof User;
export type UserValues = User[keyof User];
// ========== Complex Type Examples ==========
export interface GenericRepository<T, K extends keyof T> {
findById(id: T[K]): Promise<T | null>;
findAll(): Promise<T[]>;
create(entity: Omit<T, K>): Promise<T>;
update(id: T[K], updates: Partial<T>): Promise<T>;
delete(id: T[K]): Promise<void>;
}
// Recursive type
export interface TreeNode<T> {
value: T;
children: TreeNode<T>[];
parent?: TreeNode<T>;
}
// Function type with overloads
export interface Logger {
(message: string): void;
(level: "info" | "warn" | "error", message: string): void;
(level: "info" | "warn" | "error", message: string, data: any): void;
}
// ========== Implementation Examples ==========
const user: User = {
id: 1,
name: "Alice Johnson",
email: "[email protected]",
createdAt: new Date(),
preferences: {
theme: "dark",
notifications: true,
language: "en"
}
};
const adminUser: AdminUser = {
...user,
permissions: ["read", "write", "delete"],
lastLogin: new Date()
};
const shapes: Shape[] = [
{ kind: "circle", radius: 5 },
{ kind: "rectangle", width: 10, height: 6 },
{ kind: "triangle", base: 8, height: 4 }
];
export const typeExamples = {
user,
adminUser,
shapes,
areas: shapes.map(calculateArea)
};
```
--------------------------------------------------------------------------------
/src/codegraphcontext/prompts.py:
--------------------------------------------------------------------------------
```python
# src/codegraphcontext/prompts.py
"""
This file contains the system prompt for the language model.
This prompt provides the core instructions, principles, and standard operating
procedures for the AI assistant, guiding it on how to effectively use the tools
provided by this MCP server.
"""
LLM_SYSTEM_PROMPT = """# AI Pair Programmer Instructions
## 1. Your Role and Goal
You are an expert AI pair programmer. Your primary goal is to help a developer understand, write, and refactor code within their **local project**. Your defining feature is your connection to a local Model Context Protocol (MCP) server, which gives you real-time, accurate information about the codebase.
**Always prioritize using this MCP tools when they can simplify or enhance your workflow compared to guessing.**
## 2. Your Core Principles
### Principle I: Ground Your Answers in Fact
**Your CORE DIRECTIVE is to use the provided tools to gather facts from the MCP server *before* answering questions or generating code.** Do not guess. Your value comes from providing contextually-aware, accurate assistance.
### Principle II: Be an Agent, Not Just a Planner
**Your goal is to complete the user's task in the fewest steps possible.**
* If the user's request maps directly to a single tool, **execute that tool immediately.**
* Do not create a multi-step plan for a one-step task. The Standard Operating Procedures (SOPs) below are for complex queries that require reasoning and combining information from multiple tools.
**Example of what NOT to do:**
> **User:** "Start watching the `my-project` folder."
> **Incorrect Plan:**
> 1. Check if `watchdog` is installed.
> 2. Use the `watch_directory` tool on `my-project`.
> 3. Update a todo list.
**Example of the CORRECT, direct action:**
> **User:** "Start watching the `my-project` folder."
> **Correct Action:** Immediately call the `watch_directory` tool.
> ```json
> {
> "tool_name": "watch_directory",
> "arguments": { "path": "my-project" }
> }
> ```
## 3. Tool Manifest & Usage
| Tool Name | Purpose & When to Use |
| :--------------------------- | :------------------------------------------------------------------------------------------------------------------------------------ |
| **`find_code`** | **Your primary search tool.** Use this first for almost any query about locating code. t |
| **`analyze_code_relationships`** | **Your deep analysis tool.** Use this after locating a specific item. Use query types like `find_callers` or `find_callees`. |
| **`add_code_to_graph`** | **Your indexing tool.** Use this when the user wants to add a new project folder or file to the context. |
| **`add_package_to_graph`** | **Your dependency indexing tool.** Use this to add a `pip` package to the context. |
| **`list_jobs`** & **`check_job_status`** | **Your job monitoring tools.** |
| **`watch_directory`** | **Your live-update tool.** Use this if the user wants to automatically keep the context updated as they work. |
| **`execute_cypher_query`** | **Expert Fallback Tool.** Use this *only* when other tools cannot answer a very specific or complex question about the code graph. Requires knowledge of Cypher. |
## 4. Standard Operating Procedures (SOPs) for Complex Tasks
**Note:** Follow these methodical workflows for **complex requests** that require multiple steps of reasoning or combining information from several tools. For direct commands, refer to Principle II and act immediately.
### SOP-1: Answering "Where is...?" or "How does...?" Questions
1. **Locate:** Use `find_code` to find the relevant code.
2. **Analyze:** Use `analyze_code_relationships` to understand its usage.
3. **Synthesize:** Combine the information into a clear explanation.
### SOP-2: Generating New Code
1. **Find Context:** Use `find_code` to find similar, existing code to match the style.
2. **Find Reusable Code:** Use `find_code` to locate specific helper functions the user wants you to use.
3. **Generate:** Write the code using the correct imports and signatures.
### SOP-3: Refactoring or Analyzing Impact
1. **Identify & Locate:** Use `find_code` to get the canonical path of the item to be changed.
2. **Assess Impact:** Use `analyze_code_relationships` with the `find_callers` query type to find all affected locations.
3. **Report Findings:** Present a clear list of all affected files.
### SOP-4: Using the Cypher Fallback
1. **Attempt Standard Tools:** First, always try to use `find_code` and `analyze_code_relationships`.
2. **Identify Failure:** If the standard tools cannot answer a complex, multi-step relationship query (e.g., "Find all functions that are called by a method in a class that inherits from 'BaseHandler'"), then and only then, resort to the fallback.
3. **Formulate & Execute:** Construct a Cypher query to find the answer and execute it using `execute_cypher_query`.
4. **Present Results:** Explain the results to the user based on the query output.
"""
```
--------------------------------------------------------------------------------
/tests/test_cpp_parser.py:
--------------------------------------------------------------------------------
```python
"""
Test script for the enhanced C++ parser.
"""
import json
import sys
from pathlib import Path
def test_parser():
"""Test the C++ parser with a sample file."""
test_cpp_code = '''
class TestClass : public BaseClass {
private:
int privateVar;
std::string name;
protected:
double protectedVar;
public:
/**
* Constructor for TestClass
* @param value Initial value
*/
TestClass(int value) : privateVar(value) {}
/// Gets the private variable value
int getValue() const {
return privateVar;
}
/**
* Complex method with parameters
*/
virtual void complexMethod(int x, const std::string& str, double y = 3.14) override {
if (x > 0) {
for (int i = 0; i < x; i++) {
processData(i);
}
}
}
};
namespace MyNamespace {
enum Color {
RED,
GREEN,
BLUE
};
/**
* Standalone function
*/
static inline int calculate(int a, int b) {
return a + b;
}
}
// Global variable
int globalCounter = 0;
#include <iostream>
#include <string>
#include "custom_header.h"
'''
test_file = Path("test_sample.cpp")
test_file.write_text(test_cpp_code)
print("=" * 60)
print("Testing Enhanced C++ Parser")
print("=" * 60)
try:
from tree_sitter import Language, Parser
import tree_sitter_cpp as tscpp
class MockGenericParser:
def __init__(self):
self.language = Language(tscpp.language())
self.parser = Parser(self.language)
from cpp_parser_enhanced import CppTreeSitterParser
generic_wrapper = MockGenericParser()
cpp_parser = CppTreeSitterParser(generic_wrapper)
print(f"\n Parsing: {test_file}")
result = cpp_parser.parse(test_file)
print("\n" + "=" * 60)
print("PARSING RESULTS")
print("=" * 60)
print(f"\n File: {result['file_path']}")
print(f" Language: {result['lang']}")
print(f"\n Functions Found: {len(result['functions'])}")
for func in result['functions']:
print(f"\n Function: {func['name']}")
print(f" Lines: {func['line_number']}-{func['end_line']}")
print(f" Return Type: {func['return_type']}")
print(f" Parameters: {len(func['args'])}")
for param in func['args']:
default = f" = {param['default']}" if param['default'] else ""
print(f" - {param['type']} {param['name']}{default}")
print(f" Modifiers: {', '.join(func['modifiers']) if func['modifiers'] else 'None'}")
print(f" Complexity: {func['complexity']}")
print(f" Calls: {[c['name'] for c in func['calls']]}")
if func['docstring']:
print(f" Docstring: {func['docstring'][:50]}...")
print(f"\n Classes Found: {len(result['classes'])}")
for cls in result['classes']:
print(f"\n Class: {cls['name']}")
print(f" Lines: {cls['line_number']}-{cls['end_line']}")
print(f" Base Classes: {cls['bases']}")
print(f" Template: {cls['is_template']}")
print(f" Methods: {len(cls['methods'])}")
for method in cls['methods']:
print(f" - {method['access']}: {method['return_type']} {method['name']}()")
print(f" Members: {len(cls['members'])}")
for member in cls['members']:
print(f" - {member['access']}: {member['type']} {member['name']}")
if cls['docstring']:
print(f" Docstring: {cls['docstring'][:50]}...")
print(f"\n Namespaces Found: {len(result['namespaces'])}")
for ns in result['namespaces']:
print(f" - {ns['name']} (lines {ns['line_number']}-{ns['end_line']})")
print(f"\n Enums Found: {len(result['enums'])}")
for enum in result['enums']:
print(f" - {enum['name']}: {enum['values']}")
print(f"\n Global Variables: {len(result['variables'])}")
for var in result['variables']:
print(f" - {var['type']} {var['name']} (line {var['line_number']})")
print(f"\n Imports Found: {len(result['imports'])}")
for imp in result['imports']:
import_type = "system" if imp.get('is_system') else "local"
print(f" - {imp['name']} ({import_type})")
print(f"\n Function Calls: {len(result['function_calls'])}")
for call in result['function_calls'][:10]:
print(f" - {call['name']} (line {call['line_number']})")
output_file = Path("test_result.json")
with open(output_file, 'w') as f:
json.dump(result, f, indent=2)
print(f"\n Full results saved to: {output_file}")
print("\n" + "=" * 60)
print("TEST COMPLETED SUCCESSFULLY!")
print("=" * 60)
assert True
except Exception as e:
print(f"\n ERROR: {e}")
import traceback
traceback.print_exc()
assert True
finally:
if test_file.exists():
test_file.unlink()
print(f"\n cleaned up test file")
if __name__ == "__main__":
success = test_parser()
sys.exit(0 if success else 1)
```
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
```python
import subprocess
import json
import os
import time
import pytest
# Path to the sample project used in tests
SAMPLE_PROJECT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "sample_project"))
# SAMPLE_PROJECT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "sample_project_javascript"))
# Helper function to call a tool, now shared across all tests
def call_tool(server, name, args):
request = {
"jsonrpc": "2.0",
"id": int(time.time()),
"method": "tools/call",
"params": {"name": name, "arguments": args}
}
response = server(request)
if "result" in response:
content = json.loads(response["result"]["content"][0]["text"])
return content
elif "error" in response:
return response
else:
raise ValueError(f"Unexpected response format: {response}")
@pytest.fixture(scope="module")
def server():
"""
A module-scoped fixture that starts the cgc server once for all tests
in this file and provides a communication helper function.
"""
print("\n--- Setting up server fixture ---")
process = None
try:
print("Starting cgc server process...")
process = subprocess.Popen(
["cgc", "start"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
cwd=os.path.join(os.path.dirname(__file__), ".."))
print("Waiting for server to be ready...")
for line in iter(process.stderr.readline, ''):
print(f"STDERR: {line.strip()}")
if "MCP Server is running" in line:
print("Server is ready.")
break
def send_receive(request):
print(f"--> Sending request: {json.dumps(request)}")
process.stdin.write(json.dumps(request) + "\n")
process.stdin.flush()
while True:
response_line = process.stdout.readline()
print(f"<-- Received line: {response_line.strip()}")
try:
return json.loads(response_line)
except json.JSONDecodeError:
continue
print("Initializing server connection...")
init_request = {"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {}}
init_response = send_receive(init_request)
assert init_response.get("id") == 1 and "result" in init_response, "Initialization failed"
print("Server connection initialized.")
yield send_receive
finally:
print("\n--- Tearing down server fixture ---")
if process:
print("Terminating server process.")
process.terminate()
process.wait()
print("Server process terminated.")
def pytest_addoption(parser):
parser.addoption(
"--no-reindex", action="store_true", default=False, help="Skip re-indexing the project for tests"
)
@pytest.fixture(scope="module")
def indexed_project(server, request):
"""
Ensures the sample project is indexed before running tests.
"""
if not request.config.getoption("--no-reindex"):
print("\n--- Ensuring project is indexed ---")
delete_result = call_tool(server, "delete_repository", {"repo_path": SAMPLE_PROJECT_PATH})
print(f"Delete result: {delete_result}")
add_result = call_tool(server, "add_code_to_graph", {"path": SAMPLE_PROJECT_PATH})
assert add_result.get("success") is True, f"add_code_to_graph failed: {add_result.get('error')}"
job_id = add_result.get("job_id")
assert job_id is not None, "add_code_to_graph did not return a job_id"
print(f"Started indexing job with ID: {job_id}")
start_time = time.time()
timeout = 180
while True:
if time.time() - start_time > timeout:
pytest.fail(f"Job {job_id} did not complete within {timeout} seconds.")
status_result = call_tool(server, "check_job_status", {"job_id": job_id})
job_status = status_result.get("job", {}).get("status")
print(f"Current job status: {job_status}")
if job_status == "completed":
print("Job completed successfully.")
break
assert job_status not in ["failed", "cancelled"], f"Job failed with status: {job_status}"
time.sleep(2)
else:
print("\n--- Skipping re-indexing as per --no-reindex flag ---")
return server
class CodeGraph:
"""
A wrapper class that provides a .query() method to execute Cypher
against the indexed graph, compatible with our tests.
"""
def __init__(self, server_communicator):
self.server = server_communicator
def query(self, cypher_query: str):
response = call_tool(self.server, "execute_cypher_query", {"cypher_query": cypher_query})
if response.get("success"):
return response.get("results", [])
else:
error_details = response.get('error', 'Unknown error')
raise RuntimeError(f"Cypher query failed: {error_details}\nQuery was: {cypher_query}")
@pytest.fixture(scope="module")
def graph(indexed_project):
"""
Provides a CodeGraph object to query the indexed project.
Depends on indexed_project to ensure the graph is ready.
"""
print("\n--- Creating CodeGraph query wrapper ---")
return CodeGraph(indexed_project)
```
--------------------------------------------------------------------------------
/tests/test_swift_parser.py:
--------------------------------------------------------------------------------
```python
import pytest
from pathlib import Path
import sys
import os
# Ensure src is in path
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src")))
from codegraphcontext.tools.languages.swift import SwiftTreeSitterParser
from codegraphcontext.tools.graph_builder import TreeSitterParser
from codegraphcontext.utils.tree_sitter_manager import get_tree_sitter_manager
@pytest.fixture
def parser():
"""Returns an instance of the Swift parser via generic wrapper."""
return TreeSitterParser('swift')
@pytest.fixture
def sample_project_path():
"""Returns the path to the sample Swift project."""
return Path(__file__).parent / "sample_project_swift"
def test_parse_main_swift(parser, sample_project_path):
"""Test parsing of Main.swift."""
file_path = sample_project_path / "Main.swift"
result = parser.parse(file_path, is_dependency=False)
assert result["file_path"] == str(file_path)
# Check Classes
classes = {c["name"] for c in result["classes"]}
assert "Main" in classes
assert "Calculator" in classes
# Check Functions in Main
main_functions = [f for f in result["functions"] if f.get("class_context") == "Main"]
method_names = {m["name"] for m in main_functions}
assert "run" in method_names
# Check Calculator functions
calc_functions = [f for f in result["functions"] if f.get("class_context") == "Calculator"]
calc_method_names = {m["name"] for m in calc_functions}
assert "add" in calc_method_names
assert "subtract" in calc_method_names
assert "multiply" in calc_method_names
def test_parse_user_swift(parser, sample_project_path):
"""Test parsing of User.swift (Struct and Protocol)."""
file_path = sample_project_path / "User.swift"
result = parser.parse(file_path, is_dependency=False)
# Check Protocol
protocols = {p["name"] for p in result["protocols"]}
assert "Greeter" in protocols
# Check Struct
structs = {s["name"]: s for s in result["structs"]}
assert "User" in structs
user_struct = structs["User"]
# Verify protocol conformance
assert "Greeter" in user_struct.get("bases", [])
# Check methods
user_methods = [f for f in result["functions"] if f.get("class_context") == "User"]
method_names = {m["name"] for m in user_methods}
assert "greet" in method_names
assert "isAdult" in method_names
def test_parse_shapes_swift(parser, sample_project_path):
"""Test parsing of Shapes.swift (Protocol conformance)."""
file_path = sample_project_path / "Shapes.swift"
result = parser.parse(file_path, is_dependency=False)
# Check Protocol
protocols = {p["name"] for p in result["protocols"]}
assert "Shape" in protocols
# Check Classes
classes = {c["name"]: c for c in result["classes"]}
assert "Circle" in classes
assert "Triangle" in classes
# Check Structs
structs = {s["name"]: s for s in result["structs"]}
assert "Rectangle" in structs
# Verify protocol conformance
assert "Shape" in classes["Circle"].get("bases", [])
assert "Shape" in structs["Rectangle"].get("bases", [])
assert "Shape" in classes["Triangle"].get("bases", [])
def test_parse_vehicles_swift(parser, sample_project_path):
"""Test parsing of Vehicles.swift (Enums and Inheritance)."""
file_path = sample_project_path / "Vehicles.swift"
result = parser.parse(file_path, is_dependency=False)
# Check Enums
enums = {e["name"] for e in result["enums"]}
assert "VehicleType" in enums
assert "Result" in enums
# Check Classes
classes = {c["name"]: c for c in result["classes"]}
assert "Vehicle" in classes
assert "Car" in classes
# Verify inheritance
car_class = classes["Car"]
assert "Vehicle" in car_class.get("bases", [])
def test_parse_generics_swift(parser, sample_project_path):
"""Test parsing of Generics.swift (Generic types and protocols)."""
file_path = sample_project_path / "Generics.swift"
result = parser.parse(file_path, is_dependency=False)
# Check Classes
classes = {c["name"] for c in result["classes"]}
assert "Stack" in classes
# Check Protocols
protocols = {p["name"] for p in result["protocols"]}
assert "Container" in protocols
# Check Structs
structs = {s["name"] for s in result["structs"]}
assert "IntCollection" in structs
# Check functions (generic swap function)
functions = [f for f in result["functions"] if f.get("class_context") is None]
function_names = {f["name"] for f in functions}
assert "swap" in function_names
def test_import_resolution(parser, sample_project_path):
"""Test that imports are correctly extracted."""
file_path = sample_project_path / "Main.swift"
result = parser.parse(file_path, is_dependency=False)
imports = result.get("imports", [])
assert len(imports) > 0
# Check for Foundation import
import_names = {imp.get("name", "") for imp in imports}
assert "Foundation" in import_names
def test_function_calls(parser, sample_project_path):
"""Test that function calls are detected."""
file_path = sample_project_path / "Main.swift"
result = parser.parse(file_path, is_dependency=False)
calls = result.get("function_calls", [])
assert len(calls) > 0
# Check for specific method calls
call_names = {c["name"] for c in calls}
assert "greet" in call_names
assert "add" in call_names
```
--------------------------------------------------------------------------------
/website/src/components/ui/select.tsx:
--------------------------------------------------------------------------------
```typescript
import * as React from "react";
import * as SelectPrimitive from "@radix-ui/react-select";
import { Check, ChevronDown, ChevronUp } from "lucide-react";
import { cn } from "@/lib/utils";
const Select = SelectPrimitive.Root;
const SelectGroup = SelectPrimitive.Group;
const SelectValue = SelectPrimitive.Value;
const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className,
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDown className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
));
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const SelectScrollUpButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollUpButton
ref={ref}
className={cn("flex cursor-default items-center justify-center py-1", className)}
{...props}
>
<ChevronUp className="h-4 w-4" />
</SelectPrimitive.ScrollUpButton>
));
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
const SelectScrollDownButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollDownButton
ref={ref}
className={cn("flex cursor-default items-center justify-center py-1", className)}
{...props}
>
<ChevronDown className="h-4 w-4" />
</SelectPrimitive.ScrollDownButton>
));
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className,
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
));
SelectContent.displayName = SelectPrimitive.Content.displayName;
const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label ref={ref} className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)} {...props} />
));
SelectLabel.displayName = SelectPrimitive.Label.displayName;
const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
className,
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
));
SelectItem.displayName = SelectPrimitive.Item.displayName;
const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
));
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
};
```
--------------------------------------------------------------------------------
/src/codegraphcontext/tools/system.py:
--------------------------------------------------------------------------------
```python
# src/codegraphcontext/tools/system.py
import logging
from dataclasses import asdict
from typing import Any, Dict
from datetime import datetime, timedelta
from neo4j.exceptions import CypherSyntaxError
from ..core.database import DatabaseManager
from ..core.jobs import JobManager, JobStatus
from ..utils.debug_log import debug_log
logger = logging.getLogger(__name__)
class SystemTools:
"""Handles system-level tools like job management and direct DB queries."""
def __init__(self, db_manager: DatabaseManager, job_manager: JobManager):
self.db_manager = db_manager
self.job_manager = job_manager
def check_job_status_tool(self, job_id: str) -> Dict[str, Any]:
"""Tool to check job status"""
try:
job = self.job_manager.get_job(job_id)
if not job:
return {"error": f"Job {job_id} not found"}
job_dict = asdict(job)
if job.status == JobStatus.RUNNING:
if job.estimated_time_remaining:
remaining = job.estimated_time_remaining
job_dict["estimated_time_remaining_human"] = (
f"{int(remaining // 60)}m {int(remaining % 60)}s"
if remaining >= 60 else f"{int(remaining)}s"
)
if job.start_time:
elapsed = (datetime.now() - job.start_time).total_seconds()
job_dict["elapsed_time_human"] = (
f"{int(elapsed // 60)}m {int(elapsed % 60)}s"
if elapsed >= 60 else f"{int(elapsed)}s"
)
elif job.status == JobStatus.COMPLETED and job.start_time and job.end_time:
duration = (job.end_time - job.start_time).total_seconds()
job_dict["actual_duration_human"] = (
f"{int(duration // 60)}m {int(duration % 60)}s"
if duration >= 60 else f"{int(duration)}s"
)
job_dict["start_time"] = job.start_time.strftime("%Y-%m-%d %H:%M:%S")
if job.end_time:
job_dict["end_time"] = job.end_time.strftime("%Y-%m-%d %H:%M:%S")
job_dict["status"] = job.status.value
return {"success": True, "job": job_dict}
except Exception as e:
return {"error": f"Failed to check job status: {str(e)}"}
def list_jobs_tool(self) -> Dict[str, Any]:
"""Tool to list all jobs"""
try:
jobs = self.job_manager.list_jobs()
jobs_data = []
for job in sorted(jobs, key=lambda j: j.start_time, reverse=True):
job_dict = asdict(job)
job_dict["status"] = job.status.value
job_dict["start_time"] = job.start_time.isoformat()
if job.end_time:
job_dict["end_time"] = job.end_time.isoformat()
jobs_data.append(job_dict)
return {"success": True, "jobs": jobs_data, "total_jobs": len(jobs_data)}
except Exception as e:
return {"error": f"Failed to list jobs: {str(e)}"}
def execute_cypher_query_tool(self, cypher_query: str) -> Dict[str, Any]:
"""Tool to execute a read-only Cypher query."""
if not cypher_query:
return {"error": "Cypher query cannot be empty."}
forbidden_keywords = ['CREATE', 'MERGE', 'DELETE', 'SET', 'REMOVE', 'DROP', 'CALL apoc']
if any(keyword in cypher_query.upper() for keyword in forbidden_keywords):
return {"error": "This tool only supports read-only queries."}
try:
with self.db_manager.get_driver().session() as session:
result = session.run(cypher_query)
records = [record.data() for record in result]
return {
"success": True,
"query": cypher_query,
"record_count": len(records),
"results": records
}
except CypherSyntaxError as e:
return {"error": "Cypher syntax error.", "details": str(e)}
except Exception as e:
return {"error": "An unexpected error occurred.", "details": str(e)}
def find_dead_code_tool(self) -> Dict[str, Any]:
"""Finds potentially unused functions (dead code)."""
# This logic was moved from CodeFinder to be a system diagnostic tool
try:
with self.db_manager.get_driver().session() as session:
result = session.run("""
MATCH (func:Function)
WHERE func.is_dependency = false
AND NOT func.name STARTS WITH '_'
AND NOT func.name IN ['main', 'setup', 'run']
OPTIONAL MATCH (caller:Function)-[:CALLS]->(func)
WHERE caller.is_dependency = false
WITH func, count(caller) as caller_count
WHERE caller_count = 0
RETURN func.name as function_name, func.file_path as file_path, func.line_number as line_number
ORDER BY func.file_path, func.line_number
LIMIT 50
""")
return {
"success": True,
"results": {
"potentially_unused_functions": [dict(record) for record in result],
"note": "These functions might be entry points or called dynamically."
}
}
except Exception as e:
return {"error": f"Failed to find dead code: {str(e)}"}
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.nl.min.js:
--------------------------------------------------------------------------------
```javascript
/*!
* Lunr languages, `Dutch` language
* https://github.com/MihaiValentin/lunr-languages
*
* Copyright 2014, Mihai Valentin
* http://www.mozilla.org/MPL/
*/
/*!
* based on
* Snowball JavaScript Library v0.3
* http://code.google.com/p/urim/
* http://snowball.tartarus.org/
*
* Copyright 2010, Oleg Mazko
* http://www.mozilla.org/MPL/
*/
!function(r,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():e()(r.lunr)}(this,function(){return function(r){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");r.nl=function(){this.pipeline.reset(),this.pipeline.add(r.nl.trimmer,r.nl.stopWordFilter,r.nl.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(r.nl.stemmer))},r.nl.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",r.nl.trimmer=r.trimmerSupport.generateTrimmer(r.nl.wordCharacters),r.Pipeline.registerFunction(r.nl.trimmer,"trimmer-nl"),r.nl.stemmer=function(){var e=r.stemmerSupport.Among,i=r.stemmerSupport.SnowballProgram,n=new function(){function r(){for(var r,e,i,o=C.cursor;;){if(C.bra=C.cursor,r=C.find_among(b,11))switch(C.ket=C.cursor,r){case 1:C.slice_from("a");continue;case 2:C.slice_from("e");continue;case 3:C.slice_from("i");continue;case 4:C.slice_from("o");continue;case 5:C.slice_from("u");continue;case 6:if(C.cursor>=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(e=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=e);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=e;else if(n(e))break}else if(n(e))break}function n(r){return C.cursor=r,r>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,d=_,t()||(_=C.cursor,_<3&&(_=3),t()||(d=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var r;;)if(C.bra=C.cursor,r=C.find_among(p,3))switch(C.ket=C.cursor,r){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return d<=C.cursor}function a(){var r=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-r,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var r;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.slice_del(),w=!0,a())))}function m(){var r;u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.eq_s_b(3,"gem")||(C.cursor=C.limit-r,C.slice_del(),a())))}function f(){var r,e,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,r=C.find_among_b(h,5))switch(C.bra=C.cursor,r){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(j,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(e=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-e,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,r=C.find_among_b(k,6))switch(C.bra=C.cursor,r){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(z,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var d,_,w,b=[new e("",-1,6),new e("á",0,1),new e("ä",0,1),new e("é",0,2),new e("ë",0,2),new e("í",0,3),new e("ï",0,3),new e("ó",0,4),new e("ö",0,4),new e("ú",0,5),new e("ü",0,5)],p=[new e("",-1,3),new e("I",0,2),new e("Y",0,1)],g=[new e("dd",-1,-1),new e("kk",-1,-1),new e("tt",-1,-1)],h=[new e("ene",-1,2),new e("se",-1,3),new e("en",-1,2),new e("heden",2,1),new e("s",-1,3)],k=[new e("end",-1,1),new e("ig",-1,2),new e("ing",-1,1),new e("lijk",-1,3),new e("baar",-1,4),new e("bar",-1,5)],v=[new e("aa",-1,-1),new e("ee",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(r){C.setCurrent(r)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var e=C.cursor;return r(),C.cursor=e,o(),C.limit_backward=e,C.cursor=C.limit,f(),C.cursor=C.limit_backward,s(),!0}};return function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}}(),r.Pipeline.registerFunction(r.nl.stemmer,"stemmer-nl"),r.nl.stopWordFilter=r.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),r.Pipeline.registerFunction(r.nl.stopWordFilter,"stopWordFilter-nl")}});
```
--------------------------------------------------------------------------------
/website/src/components/TestimonialSection.tsx:
--------------------------------------------------------------------------------
```typescript
import { OrbitingCircles } from "./ui/orbiting-circles";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { useMemo, useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
const avatars = [
{ imageUrl: "https://avatars.githubusercontent.com/u/161715841?v=4", profileUrl: "https://github.com/athaxv" },
{ imageUrl: "https://avatars.githubusercontent.com/u/20110627?v=4", profileUrl: "https://github.com/tomonarifeehan" },
{ imageUrl: "https://avatars.githubusercontent.com/u/106103625?v=4", profileUrl: "https://github.com/BankkRoll" },
{ imageUrl: "https://avatars.githubusercontent.com/u/59228569?v=4", profileUrl: "https://github.com/safethecode" },
{ imageUrl: "https://avatars.githubusercontent.com/u/59442788?v=4", profileUrl: "https://github.com/sanjay-mali" },
{ imageUrl: "https://avatars.githubusercontent.com/u/89768406?v=4", profileUrl: "https://github.com/itsarghyadas" },
];
export default function TestimonialSection() {
const reviews = useMemo(() => [
{ quote: "Seems an interesting solution to the context problem in large codebases🤩", author: "Stunning-Worth-5022", role: "Reddit User" },
{ quote: "As a person with aphantasia you just made me realize how badly I really needed to be able to visualize my code base this way. Thanks boss!", author: "jphree", role: "Reddit User" },
{ quote: "Very cool and smart idea.A lot of codebases are messy.", author: "qa_anaaq", role: "Reddit User" },
{ quote: "Love this idea - and perfect timing. Keen to track and follow the outcomes based on real user experience.", author: "future-coder84", role: "Reddit User" },
{ quote: "Sounds amazing. I’ll spin it up.", author: "stormthulu", role: "Reddit User" },
{ quote: "Awesome work!", author: "martijnvann", role: "Reddit User" },
], []);
const [index, setIndex] = useState(0);
const next = () => setIndex((i) => (i + 1) % reviews.length);
const prev = () => setIndex((i) => (i - 1 + reviews.length) % reviews.length);
return (
<section className="py-24 px-4" data-aos="fade-in">
<div className="container mx-auto max-w-6xl">
<div className="text-center mb-16" data-aos="fade-down">
<h2 className="text-4xl md:text-5xl font-bold mb-6 bg-gradient-to-r from-primary via-primary to-accent bg-clip-text text-transparent py-2">
What Teams Are Saying
</h2>
<p className="text-xl text-muted-foreground max-w-3xl mx-auto">
Real feedback from engineers and leaders using CodeGraphContext.
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
<div className="relative mx-auto h-[400px] lg:h-[500px] w-full flex items-center justify-center overflow-hidden" data-aos="zoom-in">
<OrbitingCircles iconSize={56} radius={180} speed={1.4}>
{avatars.map((avatar, i) => (
<a key={i} href={avatar.profileUrl} target="_blank" rel="noopener noreferrer">
<img src={avatar.imageUrl} alt={`avatar-${i}`} className="w-14 h-14 rounded-full border-2 border-white shadow-md dark:border-neutral-800" />
</a>
))}
</OrbitingCircles>
<OrbitingCircles iconSize={44} radius={100} reverse speed={2}>
{avatars.slice(1, 5).map((avatar, i) => (
<a key={i} href={avatar.profileUrl} target="_blank" rel="noopener noreferrer">
<img src={avatar.imageUrl} alt={`avatar-inner-${i}`} className="w-11 h-11 rounded-full border-2 border-white shadow-md dark:border-neutral-800" />
</a>
))}
</OrbitingCircles>
</div>
<div data-aos="fade-left" data-aos-delay="200">
<Card className="dark:bg-card/50 shadow-sm min-h-[300px] flex flex-col justify-between">
<CardHeader>
<CardTitle className="text-3xl md:text-4xl font-bold bg-gradient-primary bg-clip-text text-transparent py-2">
Teams Love It
</CardTitle>
<AnimatePresence mode="wait">
<motion.div
key={index}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.3 }}
>
<CardDescription className="text-base md:text-lg text-muted-foreground pt-4">
“{reviews[index].quote}”
</CardDescription>
</motion.div>
</AnimatePresence>
</CardHeader>
<CardContent>
<div className="flex items-center justify-between gap-4">
<AnimatePresence mode="wait">
<motion.div
key={index}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.3, delay: 0.1 }}
>
<p className="font-semibold">{reviews[index].author}</p>
<p className="text-sm text-muted-foreground">{reviews[index].role}</p>
</motion.div>
</AnimatePresence>
<div className="flex gap-2">
<Button onClick={prev} size="icon" variant="outline"><ChevronLeft className="h-4 w-4" /></Button>
<Button onClick={next} size="icon"><ChevronRight className="h-4 w-4" /></Button>
</div>
</div>
</CardContent>
</Card>
</div>
</div>
</div>
</section>
)
}
```
--------------------------------------------------------------------------------
/website/src/index.css:
--------------------------------------------------------------------------------
```css
html,
body {
width: 100%;
overflow-x: hidden;
}
#root {
width: 100%;
overflow-x: hidden;
}
@tailwind base;
@tailwind components;
@tailwind utilities;
/* CodeGraphContext Design System - Dark theme with graph-inspired colors */
@layer base {
:root {
/* Dark background with subtle warmth */
--background: 222 47% 5%;
--foreground: 210 40% 98%;
/* Cards with subtle transparency */
--card: 222 47% 8%;
--card-foreground: 210 40% 98%;
--popover: 222 47% 8%;
--popover-foreground: 210 40% 98%;
/* Graph-inspired primary colors - deep purple-blue */
--primary: 263 70% 65%;
--primary-foreground: 222 47% 5%;
/* Secondary with graph node accent */
--secondary: 222 47% 12%;
--secondary-foreground: 210 40% 98%;
/* Muted tones for subtlety */
--muted: 222 47% 10%;
--muted-foreground: 215 20% 65%;
/* Bright cyan accent for highlights */
--accent: 180 100% 70%;
--accent-foreground: 222 47% 5%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 222 47% 15%;
--input: 222 47% 12%;
--ring: 263 70% 65%;
--radius: 0.75rem;
/* Custom graph colors */
--graph-node-1: 263 70% 65%;
--graph-node-2: 180 100% 70%;
--graph-node-3: 142 76% 65%;
--graph-edge: 222 47% 25%;
/* Gradients */
--gradient-primary: linear-gradient(135deg, hsl(263 70% 65%), hsl(180 100% 70%));
--gradient-hero: linear-gradient(135deg, hsl(222 47% 5%) 0%, hsl(222 47% 8%) 100%);
--gradient-card: linear-gradient(135deg, hsl(222 47% 8%) 0%, hsl(222 47% 10%) 100%);
/* Shadows with graph glow */
--shadow-glow: 0 0 40px hsl(263 70% 65% / 0.15);
--shadow-card: 0 10px 30px -10px hsl(222 47% 2% / 0.3);
/* Animations */
--transition-smooth: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
--transition-bounce: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
.light {
/* Light mode fallback - CodeGraphContext works best in dark */
--background: 0 0% 95%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 263 70% 55%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 16.9%;
--accent: 180 100% 40%;
--accent-foreground: 210 40% 98%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 263 70% 55%;
--gradient-primary: linear-gradient(135deg, hsl(263, 49%, 40%), hsl(180, 45%, 47%));
}
.theme {
--animate-orbit: orbit calc(var(--duration)*1s) linear infinite;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground overflow-x-hidden;
background: hsl(var(--background));
background-image:
radial-gradient(circle at 20% 20%, hsl(263 70% 65% / 0.05) 0%, transparent 50%),
radial-gradient(circle at 80% 80%, hsl(180 100% 70% / 0.05) 0%, transparent 50%);
}
/* Smooth scrolling */
html {
scroll-behavior: smooth;
}
/* Custom animations */
@keyframes graph-pulse {
0%, 100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.7;
transform: scale(1.05);
}
}
@keyframes float-up {
0% {
opacity: 0;
transform: translateY(30px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes code-highlight {
0% { background-color: transparent; }
50% { background-color: hsl(263 70% 65% / 0.1); }
100% { background-color: transparent; }
}
.animate-graph-pulse {
animation: graph-pulse 2s ease-in-out infinite;
}
.animate-float-up {
animation: float-up 0.6s ease-out forwards;
}
.animate-code-highlight {
animation: code-highlight 2s ease-in-out infinite;
}
/* Orbiting circles animation (Tailwind v3 friendly) */
.animate-orbit {
animation: orbit calc(var(--duration) * 1s) linear infinite;
}
@keyframes orbit {
0% {
transform: rotate(calc(var(--angle) * 1deg))
translateY(calc(var(--radius) * 1px))
rotate(calc(var(--angle) * -1deg));
}
100% {
transform: rotate(calc(var(--angle) * 1deg + 360deg))
translateY(calc(var(--radius) * 1px))
rotate(calc((var(--angle) * -1deg) - 360deg));
}
}
/* Graph visualization styles */
.graph-node {
@apply rounded-full border-2 border-primary/20 transition-all duration-300;
background: hsl(var(--gradient-primary));
box-shadow: var(--shadow-glow);
}
.graph-edge {
@apply stroke-graph-edge transition-all duration-300;
stroke-width: 2;
stroke-dasharray: 5,5;
animation: dash 20s linear infinite;
}
@keyframes dash {
to {
stroke-dashoffset: -100;
}
}
/* Code block styling */
.code-block {
@apply bg-card border border-border rounded-lg p-4 font-mono text-sm;
background: var(--gradient-card);
box-shadow: var(--shadow-card);
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
@theme inline {
@keyframes orbit {
0% {
transform: rotate(calc(var(--angle) * 1deg)) translateY(calc(var(--radius) * 1px)) rotate(calc(var(--angle) * -1deg));
}
100% {
transform: rotate(calc(var(--angle) * 1deg + 360deg)) translateY(calc(var(--radius) * 1px)) rotate(calc((var(--angle) * -1deg) - 360deg));
}
}
}
```
--------------------------------------------------------------------------------
/tests/sample_project_rust/src/lifetimes_references.rs:
--------------------------------------------------------------------------------
```rust
// lifetimes_references.rs - Demonstrates Rust lifetimes and references
use std::fmt::Display;
/// Function with explicit lifetime annotation
pub fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
/// Multiple lifetime parameters
pub fn first_word<'a, 'b>(x: &'a str, _y: &'b str) -> &'a str {
x.split_whitespace().next().unwrap_or(x)
}
/// Lifetime with struct
#[derive(Debug)]
pub struct ImportantExcerpt<'a> {
pub part: &'a str,
}
impl<'a> ImportantExcerpt<'a> {
/// Lifetime elision in method
pub fn level(&self) -> i32 {
3
}
/// Method with lifetime annotation
pub fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("Attention please: {}", announcement);
self.part
}
}
/// Struct with multiple lifetime parameters
#[derive(Debug)]
pub struct Context<'a, 'b> {
pub primary: &'a str,
pub secondary: &'b str,
}
impl<'a, 'b> Context<'a, 'b> {
pub fn new(primary: &'a str, secondary: &'b str) -> Self {
Self { primary, secondary }
}
pub fn get_primary(&self) -> &'a str {
self.primary
}
pub fn get_secondary(&self) -> &'b str {
self.secondary
}
}
/// Static lifetime
pub fn static_string() -> &'static str {
"This string has static lifetime"
}
/// Generic with lifetime and trait bound
pub fn longest_with_announcement<'a, T>(
x: &'a str,
y: &'a str,
announcement: T,
) -> &'a str
where
T: Display,
{
println!("Announcement: {}", announcement);
if x.len() > y.len() {
x
} else {
y
}
}
/// Reference to slice
pub fn first_element<'a, T>(slice: &'a [T]) -> Option<&'a T> {
slice.first()
}
/// Mutable reference with lifetime
pub fn append_exclamation<'a>(s: &'a mut String) -> &'a str {
s.push('!');
s.as_str()
}
/// Struct holding references
#[derive(Debug)]
pub struct Book<'a> {
pub title: &'a str,
pub author: &'a str,
pub year: u32,
}
impl<'a> Book<'a> {
pub fn new(title: &'a str, author: &'a str, year: u32) -> Self {
Self { title, author, year }
}
pub fn display(&self) -> String {
format!("{} by {} ({})", self.title, self.author, self.year)
}
}
/// Lifetime bounds
pub struct Ref<'a, T: 'a> {
reference: &'a T,
}
impl<'a, T> Ref<'a, T> {
pub fn new(reference: &'a T) -> Self {
Self { reference }
}
pub fn get(&self) -> &'a T {
self.reference
}
}
/// Higher-ranked trait bounds (HRTBs)
pub fn call_with_ref<F>(f: F)
where
F: for<'a> Fn(&'a str) -> &'a str,
{
let s = String::from("Hello");
let result = f(&s);
println!("Result: {}", result);
}
/// Lifetime elision example 1
pub fn get_first_word(s: &str) -> &str {
s.split_whitespace().next().unwrap_or("")
}
/// Lifetime elision example 2
pub fn parse_pair(s: &str) -> (&str, &str) {
let parts: Vec<&str> = s.split(',').collect();
if parts.len() >= 2 {
(parts[0], parts[1])
} else {
("", "")
}
}
/// Struct with owned and borrowed data
#[derive(Debug)]
pub struct MixedData<'a> {
pub owned: String,
pub borrowed: &'a str,
}
impl<'a> MixedData<'a> {
pub fn new(owned: String, borrowed: &'a str) -> Self {
Self { owned, borrowed }
}
pub fn combine(&self) -> String {
format!("{} {}", self.owned, self.borrowed)
}
}
/// Iterator with lifetime
pub struct StrSplitter<'a> {
remainder: &'a str,
delimiter: char,
}
impl<'a> StrSplitter<'a> {
pub fn new(s: &'a str, delimiter: char) -> Self {
Self {
remainder: s,
delimiter,
}
}
}
impl<'a> Iterator for StrSplitter<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
if self.remainder.is_empty() {
return None;
}
match self.remainder.find(self.delimiter) {
Some(pos) => {
let result = &self.remainder[..pos];
self.remainder = &self.remainder[pos + 1..];
Some(result)
}
None => {
let result = self.remainder;
self.remainder = "";
Some(result)
}
}
}
}
/// Lifetime with enum
#[derive(Debug)]
pub enum Either<'a, 'b> {
Left(&'a str),
Right(&'b str),
}
impl<'a, 'b> Either<'a, 'b> {
pub fn get_value(&self) -> &str {
match self {
Either::Left(s) => s,
Either::Right(s) => s,
}
}
}
/// Combining lifetimes
pub fn combine_strings<'a>(strings: &'a [&'a str], separator: &str) -> String {
strings.join(separator)
}
/// Reference counting considerations (not strictly lifetimes but related)
use std::rc::Rc;
pub struct SharedData {
pub data: Rc<String>,
}
impl SharedData {
pub fn new(s: String) -> Self {
Self {
data: Rc::new(s),
}
}
pub fn clone_ref(&self) -> SharedData {
Self {
data: Rc::clone(&self.data),
}
}
}
/// Comparing references with different lifetimes
pub fn compare_lengths<'a, 'b>(s1: &'a str, s2: &'b str) -> bool {
s1.len() > s2.len()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_longest() {
let s1 = "hello";
let s2 = "hi";
assert_eq!(longest(s1, s2), "hello");
}
#[test]
fn test_important_excerpt() {
let text = "This is a test. This is important.";
let excerpt = ImportantExcerpt { part: text };
assert_eq!(excerpt.level(), 3);
}
#[test]
fn test_book() {
let book = Book::new("1984", "George Orwell", 1949);
assert!(book.display().contains("1984"));
}
#[test]
fn test_str_splitter() {
let text = "a,b,c";
let splitter = StrSplitter::new(text, ',');
let parts: Vec<&str> = splitter.collect();
assert_eq!(parts, vec!["a", "b", "c"]);
}
}
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.de.min.js:
--------------------------------------------------------------------------------
```javascript
/*!
* Lunr languages, `German` language
* https://github.com/MihaiValentin/lunr-languages
*
* Copyright 2014, Mihai Valentin
* http://www.mozilla.org/MPL/
*/
/*!
* based on
* Snowball JavaScript Library v0.3
* http://code.google.com/p/urim/
* http://snowball.tartarus.org/
*
* Copyright 2010, Oleg Mazko
* http://www.mozilla.org/MPL/
*/
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.de=function(){this.pipeline.reset(),this.pipeline.add(e.de.trimmer,e.de.stopWordFilter,e.de.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.de.stemmer))},e.de.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.de.trimmer=e.trimmerSupport.generateTrimmer(e.de.wordCharacters),e.Pipeline.registerFunction(e.de.trimmer,"trimmer-de"),e.de.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,n){return!(!v.eq_s(1,e)||(v.ket=v.cursor,!v.in_grouping(p,97,252)))&&(v.slice_from(r),v.cursor=n,!0)}function i(){for(var r,n,i,s,t=v.cursor;;)if(r=v.cursor,v.bra=r,v.eq_s(1,"ß"))v.ket=v.cursor,v.slice_from("ss");else{if(r>=v.limit)break;v.cursor=r+1}for(v.cursor=t;;)for(n=v.cursor;;){if(i=v.cursor,v.in_grouping(p,97,252)){if(s=v.cursor,v.bra=s,e("u","U",i))break;if(v.cursor=s,e("y","Y",i))break}if(i>=v.limit)return void(v.cursor=n);v.cursor=i+1}}function s(){for(;!v.in_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}for(;!v.out_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}return!1}function t(){m=v.limit,l=m;var e=v.cursor+3;0<=e&&e<=v.limit&&(d=e,s()||(m=v.cursor,m<d&&(m=d),s()||(l=v.cursor)))}function o(){for(var e,r;;){if(r=v.cursor,v.bra=r,!(e=v.find_among(h,6)))return;switch(v.ket=v.cursor,e){case 1:v.slice_from("y");break;case 2:case 5:v.slice_from("u");break;case 3:v.slice_from("a");break;case 4:v.slice_from("o");break;case 6:if(v.cursor>=v.limit)return;v.cursor++}}}function c(){return m<=v.cursor}function u(){return l<=v.cursor}function a(){var e,r,n,i,s=v.limit-v.cursor;if(v.ket=v.cursor,(e=v.find_among_b(w,7))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:v.slice_del(),v.ket=v.cursor,v.eq_s_b(1,"s")&&(v.bra=v.cursor,v.eq_s_b(3,"nis")&&v.slice_del());break;case 3:v.in_grouping_b(g,98,116)&&v.slice_del()}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(f,4))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:if(v.in_grouping_b(k,98,116)){var t=v.cursor-3;v.limit_backward<=t&&t<=v.limit&&(v.cursor=t,v.slice_del())}}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(_,8))&&(v.bra=v.cursor,u()))switch(e){case 1:v.slice_del(),v.ket=v.cursor,v.eq_s_b(2,"ig")&&(v.bra=v.cursor,r=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-r,u()&&v.slice_del()));break;case 2:n=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-n,v.slice_del());break;case 3:if(v.slice_del(),v.ket=v.cursor,i=v.limit-v.cursor,!v.eq_s_b(2,"er")&&(v.cursor=v.limit-i,!v.eq_s_b(2,"en")))break;v.bra=v.cursor,c()&&v.slice_del();break;case 4:v.slice_del(),v.ket=v.cursor,e=v.find_among_b(b,2),e&&(v.bra=v.cursor,u()&&1==e&&v.slice_del())}}var d,l,m,h=[new r("",-1,6),new r("U",0,2),new r("Y",0,1),new r("ä",0,3),new r("ö",0,4),new r("ü",0,5)],w=[new r("e",-1,2),new r("em",-1,1),new r("en",-1,2),new r("ern",-1,1),new r("er",-1,1),new r("s",-1,3),new r("es",5,2)],f=[new r("en",-1,1),new r("er",-1,1),new r("st",-1,2),new r("est",2,1)],b=[new r("ig",-1,1),new r("lich",-1,1)],_=[new r("end",-1,1),new r("ig",-1,2),new r("ung",-1,1),new r("lich",-1,3),new r("isch",-1,2),new r("ik",-1,2),new r("heit",-1,3),new r("keit",-1,4)],p=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32,8],g=[117,30,5],k=[117,30,4],v=new n;this.setCurrent=function(e){v.setCurrent(e)},this.getCurrent=function(){return v.getCurrent()},this.stem=function(){var e=v.cursor;return i(),v.cursor=e,t(),v.limit_backward=e,v.cursor=v.limit,a(),v.cursor=v.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.de.stemmer,"stemmer-de"),e.de.stopWordFilter=e.generateStopWordFilter("aber alle allem allen aller alles als also am an ander andere anderem anderen anderer anderes anderm andern anderr anders auch auf aus bei bin bis bist da damit dann das dasselbe dazu daß dein deine deinem deinen deiner deines dem demselben den denn denselben der derer derselbe derselben des desselben dessen dich die dies diese dieselbe dieselben diesem diesen dieser dieses dir doch dort du durch ein eine einem einen einer eines einig einige einigem einigen einiger einiges einmal er es etwas euch euer eure eurem euren eurer eures für gegen gewesen hab habe haben hat hatte hatten hier hin hinter ich ihm ihn ihnen ihr ihre ihrem ihren ihrer ihres im in indem ins ist jede jedem jeden jeder jedes jene jenem jenen jener jenes jetzt kann kein keine keinem keinen keiner keines können könnte machen man manche manchem manchen mancher manches mein meine meinem meinen meiner meines mich mir mit muss musste nach nicht nichts noch nun nur ob oder ohne sehr sein seine seinem seinen seiner seines selbst sich sie sind so solche solchem solchen solcher solches soll sollte sondern sonst um und uns unse unsem unsen unser unses unter viel vom von vor war waren warst was weg weil weiter welche welchem welchen welcher welches wenn werde werden wie wieder will wir wird wirst wo wollen wollte während würde würden zu zum zur zwar zwischen über".split(" ")),e.Pipeline.registerFunction(e.de.stopWordFilter,"stopWordFilter-de")}});
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.du.min.js:
--------------------------------------------------------------------------------
```javascript
/*!
* Lunr languages, `Dutch` language
* https://github.com/MihaiValentin/lunr-languages
*
* Copyright 2014, Mihai Valentin
* http://www.mozilla.org/MPL/
*/
/*!
* based on
* Snowball JavaScript Library v0.3
* http://code.google.com/p/urim/
* http://snowball.tartarus.org/
*
* Copyright 2010, Oleg Mazko
* http://www.mozilla.org/MPL/
*/
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");console.warn('[Lunr Languages] Please use the "nl" instead of the "du". The "nl" code is the standard code for Dutch language, and "du" will be removed in the next major versions.'),e.du=function(){this.pipeline.reset(),this.pipeline.add(e.du.trimmer,e.du.stopWordFilter,e.du.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.du.stemmer))},e.du.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.du.trimmer=e.trimmerSupport.generateTrimmer(e.du.wordCharacters),e.Pipeline.registerFunction(e.du.trimmer,"trimmer-du"),e.du.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e,r,i,o=C.cursor;;){if(C.bra=C.cursor,e=C.find_among(b,11))switch(C.ket=C.cursor,e){case 1:C.slice_from("a");continue;case 2:C.slice_from("e");continue;case 3:C.slice_from("i");continue;case 4:C.slice_from("o");continue;case 5:C.slice_from("u");continue;case 6:if(C.cursor>=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(r=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=r);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=r;else if(n(r))break}else if(n(r))break}function n(e){return C.cursor=e,e>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,f=_,t()||(_=C.cursor,_<3&&(_=3),t()||(f=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var e;;)if(C.bra=C.cursor,e=C.find_among(p,3))switch(C.ket=C.cursor,e){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return f<=C.cursor}function a(){var e=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-e,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var e;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.slice_del(),w=!0,a())))}function m(){var e;u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.eq_s_b(3,"gem")||(C.cursor=C.limit-e,C.slice_del(),a())))}function d(){var e,r,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,e=C.find_among_b(h,5))switch(C.bra=C.cursor,e){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(z,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(r=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-r,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,e=C.find_among_b(k,6))switch(C.bra=C.cursor,e){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(j,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var f,_,w,b=[new r("",-1,6),new r("á",0,1),new r("ä",0,1),new r("é",0,2),new r("ë",0,2),new r("í",0,3),new r("ï",0,3),new r("ó",0,4),new r("ö",0,4),new r("ú",0,5),new r("ü",0,5)],p=[new r("",-1,3),new r("I",0,2),new r("Y",0,1)],g=[new r("dd",-1,-1),new r("kk",-1,-1),new r("tt",-1,-1)],h=[new r("ene",-1,2),new r("se",-1,3),new r("en",-1,2),new r("heden",2,1),new r("s",-1,3)],k=[new r("end",-1,1),new r("ig",-1,2),new r("ing",-1,1),new r("lijk",-1,3),new r("baar",-1,4),new r("bar",-1,5)],v=[new r("aa",-1,-1),new r("ee",-1,-1),new r("oo",-1,-1),new r("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(e){C.setCurrent(e)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var r=C.cursor;return e(),C.cursor=r,o(),C.limit_backward=r,C.cursor=C.limit,d(),C.cursor=C.limit_backward,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.du.stemmer,"stemmer-du"),e.du.stopWordFilter=e.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),e.Pipeline.registerFunction(e.du.stopWordFilter,"stopWordFilter-du")}});
```
--------------------------------------------------------------------------------
/docs/docs/watching.md:
--------------------------------------------------------------------------------
```markdown
# Live File Watching
CodeGraphContext can automatically monitor your codebase for changes and update the code graph in real-time as you develop.
## Quick Start
Start watching your project directory:
```bash
cgc watch .
```
You'll see:
```
🔍 Watching /path/to/your/project for changes...
✓ Already indexed (no initial scan needed)
👀 Monitoring for file changes... (Press Ctrl+C to stop)
💡 Tip: Open a new terminal window to continue working
```
## How It Works
The watcher uses file system events to detect when you:
- Create new files
- Modify existing files
- Delete files
- Move/rename files
When changes are detected, CodeGraphContext automatically:
1. Re-parses the affected files
2. Updates the code graph
3. Maintains all relationships and dependencies
## Commands
### `cgc watch [path]`
Start watching a directory for changes.
**Examples:**
```bash
cgc watch . # Watch current directory
cgc watch /path/to/project # Watch specific directory
cgc w . # Shortcut alias
```
**Behavior:**
- Runs in the foreground (blocking mode)
- Performs initial scan if directory is not yet indexed
- Monitors for all file system changes
- Uses 2-second debouncing to batch rapid changes
- Press `Ctrl+C` to stop
### `cgc watching`
List all directories currently being watched.
```bash
cgc watching
```
**Note:** This command is primarily for MCP server mode. For CLI watch mode, check the terminal where you ran `cgc watch`.
### `cgc unwatch <path>`
Stop watching a directory.
```bash
cgc unwatch /path/to/project
```
**Note:** This command is primarily for MCP server mode. For CLI watch mode, simply press `Ctrl+C` in the watch terminal.
## Best Practices
### Development Workflow
1. Start watching at the beginning of your coding session
2. Open a new terminal tab/window for your actual work
3. Code normally - changes are automatically tracked
4. Stop watching (Ctrl+C) when you're done
### Performance Tips
- The watcher uses debouncing (2-second delay) to avoid excessive re-indexing
- Only modified files and their dependencies are re-processed
- Large projects may take a moment to process changes
### When to Use Watch Mode
✅ **Good for:**
- Active development sessions
- Refactoring work
- Keeping AI assistants up-to-date with latest code
- Live code analysis during development
❌ **Not needed for:**
- One-time indexing
- CI/CD pipelines
- Read-only code analysis
- Batch processing
## Example Workflow
Here's a typical development session using watch mode:
```bash
# Terminal 1: Start the watcher
$ cd ~/my-project
$ cgc watch .
🔍 Watching /home/user/my-project for changes...
✓ Already indexed (no initial scan needed)
👀 Monitoring for file changes... (Press Ctrl+C to stop)
💡 Tip: Open a new terminal window to continue working
# ... watcher runs and shows updates as you code ...
[21:15:32] 📝 Modified: src/utils.py (re-indexing...)
[21:15:32] ✓ Updated graph (3 nodes, 2 relationships)
[21:16:45] 📝 Created: src/new_feature.py (re-indexing...)
[21:16:45] ✓ Updated graph (8 nodes, 5 relationships)
```
```bash
# Terminal 2: Do your development work
$ cd ~/my-project
$ code . # Open your editor
$ git checkout -b new-feature # Work normally
$ # ... make changes, save files ...
$ # The watcher in Terminal 1 automatically picks up changes!
```
## Troubleshooting
### Watcher not detecting changes
- Ensure the path is correct and accessible
- Check file permissions
- Some editors use atomic writes which may not trigger events
- Try restarting the watcher
### High CPU usage
- The watcher may be processing too many files
- Consider watching a smaller directory
- Check for file loops or symlinks
- Verify you're not watching `node_modules` or similar large directories
### Changes not appearing
- Wait for the debounce interval (2 seconds)
- Check the watcher output for errors
- Verify the file type is supported (Python, JavaScript, TypeScript, etc.)
- Ensure the file is within the watched directory
### "Already watching" message
If you see this message, it means the directory is already being watched. This can happen if:
- You're running multiple watch commands
- The MCP server is already watching this directory
- A previous watch session didn't terminate cleanly
**Solution:** Stop all watch processes and start fresh.
## MCP Server vs CLI Watch Mode
CodeGraphContext supports two watch modes:
### CLI Watch Mode (This Guide)
- **Command:** `cgc watch .`
- **Runs:** In foreground (blocking)
- **Use case:** Active development sessions
- **Control:** Press `Ctrl+C` to stop
- **Best for:** Single project, focused development
### MCP Server Watch Mode
- **Command:** Via MCP tools (`watch_directory`, `unwatch_directory`, `list_watched_paths`)
- **Runs:** In background (as part of MCP server)
- **Use case:** IDE integration, multiple projects
- **Control:** MCP tool calls
- **Best for:** AI assistant integration, persistent watching
## Technical Details
- **Library**: Uses `watchdog` for cross-platform file monitoring
- **Debouncing**: 2-second delay to batch rapid changes
- **Scope**: Watches recursively, respects `.gitignore`
- **Performance**: Only re-indexes changed files and affected relationships
- **Thread-safe**: Uses background threads for file monitoring
- **Graceful shutdown**: Properly cleans up on `Ctrl+C`
## Integration with AI Assistants
Watch mode is particularly powerful when combined with AI coding assistants:
1. **Start watching your project:**
```bash
cgc watch .
```
2. **Configure your AI assistant** to use the CodeGraphContext MCP server
3. **Code normally** - your AI assistant always has the latest code context
4. **Ask questions** about your code, and the AI will have up-to-date information
This creates a seamless development experience where your AI assistant stays synchronized with your codebase in real-time!
## See Also
- [CLI Reference](cli.md) - Complete list of CLI commands
- [MCP Tools](mcp-tools.md) - MCP server tools including watch functionality
- [Installation](installation.md) - Getting started with CodeGraphContext
```