Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
efe1284
chore: lint, type, and build cleanup (no errors, only warnings remain)
DhineshPonnarasan Mar 31, 2026
ab9567b
fix(ci): use system Python with shared libraries for PyInstaller in m…
DhineshPonnarasan Mar 31, 2026
8d0f69c
fix(ci): install parsing extras for tree-sitter dependencies in build…
DhineshPonnarasan Mar 31, 2026
9360115
fix(ci): add missing tree-sitter and kuzu dependencies to parsing ext…
DhineshPonnarasan Mar 31, 2026
fbdf27a
fix(ci): add redislite, falkordb, and falkordblite to parsing extras …
DhineshPonnarasan Mar 31, 2026
4f102b2
fix(ci): explicitly install missing packages before PyInstaller build
DhineshPonnarasan Mar 31, 2026
b0483af
fix(ci): remove pip install for tree_sitter_* modules, keep redislite…
DhineshPonnarasan Mar 31, 2026
5df46e8
fix(ci): remove falkordblite from pip install, keep only redislite
DhineshPonnarasan Mar 31, 2026
90466de
fix(ci): skip redislite install on Windows runners
DhineshPonnarasan Mar 31, 2026
7ee0a34
fix(ci): set shell: bash for Windows/Mac dependency install step
DhineshPonnarasan Mar 31, 2026
ed5a7e7
fix(ci): move redislite install to its own step with runner.os check
DhineshPonnarasan Mar 31, 2026
1aeeecb
fix: remove redislite from [parsing] extras to prevent install on Win…
DhineshPonnarasan Mar 31, 2026
0c11b08
fix: add platform marker to falkordblite in [parsing] extras to skip …
DhineshPonnarasan Mar 31, 2026
c5e2960
fix: wrap falkordblite, kuzu, and tree_sitter_c_sharp in platform/ver…
DhineshPonnarasan Mar 31, 2026
d103467
fix: remove unmatched bracket and stray 'atexit' from hidden_imports …
DhineshPonnarasan Mar 31, 2026
36a0d8a
fix: move 'atexit' inside hidden_imports and close list, remove stray…
DhineshPonnarasan Mar 31, 2026
717e36b
fix: remove duplicate/invalid falkordblite append and stray bracket f…
DhineshPonnarasan Mar 31, 2026
d01cb48
fix: add datas = [] initialization to resolve NameError in cgc.spec
DhineshPonnarasan Mar 31, 2026
b37915f
ci: ensure falkordb/falkordblite install and directory checks for tre…
DhineshPonnarasan Mar 31, 2026
ac3ede7
ci: remove pip install falkordb (not on PyPI), only install falkordblite
DhineshPonnarasan Mar 31, 2026
29e7fd5
ci: fix Linux build shell block quoting and clarify falkordblite is o…
DhineshPonnarasan Mar 31, 2026
bee0e9f
fix: make FalkorDB dependencies fully optional
DhineshPonnarasan Apr 1, 2026
802f866
ci: remove falkordblite install, add kuzu to test envs, guard FalkorD…
DhineshPonnarasan Apr 1, 2026
b071860
ci: upgrade pyinstaller to >=5.13 for Python 3.12 compatibility
DhineshPonnarasan Apr 1, 2026
3ad3fe7
ci: copy workspace to /tmp/cgc to avoid Linux path-too-long error in …
DhineshPonnarasan Apr 1, 2026
1195905
ci: use Python 3.11 and manylinux pre-built cp311 to fix pyinstaller>…
DhineshPonnarasan Apr 1, 2026
bb0dc50
ci: skip kuzu in manylinux pyinstaller build
DhineshPonnarasan Apr 1, 2026
b8a171c
ci: run Linux PyInstaller build on ubuntu runner
DhineshPonnarasan Apr 1, 2026
283bc98
Merge branch 'main' into chore/lint-type-cleanup-main
DhineshPonnarasan Apr 6, 2026
741a279
Merge branch 'main' into chore/lint-type-cleanup-main
DhineshPonnarasan May 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,31 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python 3.12
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: '3.12'
architecture: 'x64'
cache: 'pip'

- name: Install dependencies (Windows/Mac)


- name: Ensure extra dependencies and check directories (Windows/Mac)
if: runner.os != 'Linux'
shell: bash
run: |
python -m pip install --upgrade pip setuptools wheel
pip install .[parsing]
pip install "pyinstaller>=5.13"
# Optionally check for directories (will not fail if missing)
if [ ! -d tree_sitter_c_sharp ]; then echo "tree_sitter_c_sharp directory not found, skipping clone"; fi
if [ ! -d kuzu ]; then echo "kuzu directory not found, skipping clone"; fi

- name: Install redislite (Non-Windows only)
if: runner.os != 'Windows'
run: pip install redislite

python -m pip install --upgrade pip setuptools wheel build
pip install .
pip install pyinstaller
Expand All @@ -49,8 +64,21 @@ jobs:
run: |
pyinstaller cgc.spec --clean

- name: Ensure extra dependencies and check directories (Linux)
- name: Install dependencies (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
python -m pip install --upgrade pip setuptools wheel
pip install . "pyinstaller>=5.13"
pip install tree_sitter_yaml tree_sitter_embedded_template
# Optionally check for directories (will not fail if missing)
if [ ! -d tree_sitter_c_sharp ]; then echo "tree_sitter_c_sharp directory not found, skipping clone"; fi
if [ ! -d kuzu ]; then echo "kuzu directory not found, skipping clone"; fi

- name: Build with PyInstaller (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
python -m pip install --upgrade pip setuptools wheel build
pip install .
Expand Down
6 changes: 1 addition & 5 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,5 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -e .
pip install pytest

- name: Run end-to-end tests
run: |
chmod +x tests/run_tests.sh
pip install pytest kuzu
./tests/run_tests.sh e2e
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
pip install -r requirements.txt
pip install build
pip install .[dev]
pip install kuzu

- name: Build package
run: python -m build
Expand Down
45 changes: 36 additions & 9 deletions cgc.spec
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import sys
import os
import importlib.util
from pathlib import Path
from PyInstaller.utils.hooks import collect_data_files, collect_submodules, collect_all

Expand Down Expand Up @@ -35,6 +36,15 @@ print(f"Searching for dependencies in: {[str(p) for p in search_paths]}")
# ── 1. Component Lists (Binaries, Datas, Hidden Imports) ───────────────────
binaries = []
datas = []


def module_available(name):
try:
return importlib.util.find_spec(name) is not None
except (ImportError, ModuleNotFoundError, ValueError):
return False


hidden_imports = [
'codegraphcontext',
'codegraphcontext.cli',
Expand Down Expand Up @@ -108,7 +118,6 @@ hidden_imports = [
'codegraphcontext.utils.debug_log',
'codegraphcontext.utils.tree_sitter_manager',
'codegraphcontext.utils.visualize_graph',

'kuzu',
'falkordb',
'redislite',
Expand Down Expand Up @@ -139,12 +148,16 @@ hidden_imports = [
'httpcore',
'importlib',
'asyncio',

'pkg_resources',
'threading',
'subprocess',
'socket',
'atexit',
]
# Only add falkordblite if not on Windows and Python >= 3.12
if not is_win and sys.version_info >= (3, 12) and module_available('falkordblite'):
hidden_imports.append('falkordblite')


# Bin extensions by platform
Expand Down Expand Up @@ -180,16 +193,27 @@ add_binary('tree_sitter_language_pack/bindings', ext)
# other tree-sitter bindings
add_binary('tree_sitter_yaml', ext)
add_binary('tree_sitter_embedded_template', ext)
add_binary('tree_sitter_c_sharp', ext)

# Only add tree_sitter_c_sharp if present (skip on Windows if not needed)
if not is_win:
try:
add_binary('tree_sitter_c_sharp', ext)
except Exception as e:
print(f"WARNING: Could not bundle 'tree_sitter_c_sharp': {e}")


# KùzuDB complete collection
# We use find_pkg_dir to add the entire folder to datas, ensuring we don't miss any .so, .pyd, or .dylib files
kuzu_dir = find_pkg_dir('kuzu')
if kuzu_dir:
print(f"Force bundling entire Kuzu directory: {kuzu_dir}")
datas.append((str(kuzu_dir), 'kuzu'))
else:
print("WARNING: Could not find 'kuzu' directory to bundle!")
# Only add kuzu if present and not on Windows
if not is_win:
try:
kuzu_dir = find_pkg_dir('kuzu')
if kuzu_dir:
print(f"Force bundling entire Kuzu directory: {kuzu_dir}")
datas.append((str(kuzu_dir), 'kuzu'))
else:
print("WARNING: Could not find 'kuzu' directory to bundle!")
except Exception as e:
print(f"WARNING: Could not bundle 'kuzu': {e}")
# ── 2. Bundle Logic (Aggressive FalkorDB Collection) ──────────────────────────

# Native dependencies detection
Expand Down Expand Up @@ -218,6 +242,9 @@ binaries.extend(find_all_native_binaries())
# Tricky packages collection (redislite, falkordb, falkordblite)
if not is_win:
for pkg in ['redislite', 'falkordb', 'falkordblite']:
if not module_available(pkg):
print(f"Warning: optional package not installed, skipping bundle collection: {pkg}")
continue
try:
t_datas, t_binaries, t_hiddenimports = collect_all(pkg)
datas += t_datas
Expand Down
8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ dependencies = [
"nbformat",
"nbconvert>=7.16.6",
"pathspec>=0.12.1",
"falkordb>=0.1.0",
"requests>=2.28.0",
"protobuf>=3.20,<3.21",
"falkordblite>=0.1.0; sys_platform != 'win32' and python_version >= '3.12'",
Expand All @@ -40,6 +39,13 @@ dependencies = [

[project.optional-dependencies]
parsing = [
"tree-sitter>=0.21.0",
"tree-sitter-language-pack>=0.6.0",
"tree-sitter-c-sharp>=0.21.0",
"tree_sitter_yaml",
"tree_sitter_embedded_template",
"tree_sitter_c_sharp",
"kuzu",
"tree-sitter>=0.21.0; python_version != '3.13'",
"tree-sitter-language-pack>=0.6.0,!=1.6.3; python_version != '3.13'",
"tree-sitter-c-sharp>=0.21.0; python_version != '3.13'",
Expand Down
13 changes: 9 additions & 4 deletions src/codegraphcontext/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -863,11 +863,16 @@ def doctor():
else:
# FalkorDB
try:
import falkordb
console.print(f" [green]✓[/green] FalkorDB Lite is installed")
except ImportError:
from codegraphcontext.core import _is_falkordb_available

if _is_falkordb_available():
console.print(f" [green]✓[/green] FalkorDB Lite is installed")
else:
console.print(f" [yellow]⚠[/yellow] FalkorDB Lite not installed (Python 3.12+ only)")
console.print(f" FalkorDB support is optional; KùzuDB remains available.")
except Exception:
console.print(f" [yellow]⚠[/yellow] FalkorDB Lite not installed (Python 3.12+ only)")
console.print(f" Run: pip install falkordblite")
console.print(f" FalkorDB support is optional; KùzuDB remains available.")
except Exception as e:
console.print(f" [red]✗[/red] Database check error: {e}")
all_checks_passed = False
Expand Down
8 changes: 5 additions & 3 deletions src/codegraphcontext/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ def _is_falkordb_available() -> bool:
if sys.version_info < (3, 12):
return False
try:
import redislite
return hasattr(redislite, 'falkordb_client')
except ImportError:
return (
importlib.util.find_spec("redislite.falkordb_client") is not None
and importlib.util.find_spec("falkordb") is not None
)
except (ImportError, ModuleNotFoundError, ValueError):
return False

def _is_falkordb_remote_configured() -> bool:
Expand Down
3 changes: 3 additions & 0 deletions tests/unit/core/test_database_falkordb_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import pytest
from unittest.mock import MagicMock, patch, PropertyMock

# Skip the entire module when the falkordb client is not installed
pytest.importorskip("falkordb")


class TestFalkorDBRemoteManager:
"""
Expand Down
16 changes: 12 additions & 4 deletions website/api/bundle-status.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
// api/bundle-status.ts
// Checks the status of a bundle generation request

export default async function handler(req: any, res: any) {
import type { NextApiRequest, NextApiResponse } from 'next';

type Bundle = {
repo: string;
download_url: string;
[key: string]: unknown;
};

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { repo, run_id } = req.query;

if (!repo && !run_id) {
Expand Down Expand Up @@ -53,7 +61,7 @@ export default async function handler(req: any, res: any) {
}

const manifest = await manifestResponse.json();
const bundle = manifest.bundles?.find((b: any) => b.repo === repo);
const bundle = manifest.bundles?.find((b: Bundle) => b.repo === repo);

if (bundle) {
return res.status(200).json({
Expand All @@ -69,11 +77,11 @@ export default async function handler(req: any, res: any) {
}
}

} catch (err: any) {
} catch (err) {
console.error('Error checking bundle status:', err);
return res.status(500).json({
error: 'Failed to check bundle status',
details: err.message
details: err instanceof Error ? err.message : String(err)
});
}
}
Expand Down
41 changes: 32 additions & 9 deletions website/api/bundles.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
// api/bundles.ts
// Fetches all available bundles from GitHub Releases

export default async function handler(req: any, res: any) {
import type { NextApiRequest, NextApiResponse } from 'next';

type Bundle = {
name: string;
repo: string;
bundle_name?: string;
version?: string;
commit: string;
size: string;
download_url: string;
generated_at: string;
category?: string;
description?: string;
stars?: number;
[key: string]: unknown;
};

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
const org = process.env.GITHUB_REPOSITORY?.split('/')[0] || 'CodeGraphContext';
const repo = process.env.GITHUB_REPOSITORY?.split('/')[1] || 'CodeGraphContext';

const allBundles: any[] = [];
const allBundles: Bundle[] = [];

// 1. Fetch on-demand bundles from manifest
try {
Expand All @@ -18,7 +35,7 @@ export default async function handler(req: any, res: any) {
if (manifestResponse.ok) {
const manifest = await manifestResponse.json();
if (manifest.bundles && Array.isArray(manifest.bundles)) {
allBundles.push(...manifest.bundles.map((b: any) => ({
allBundles.push(...manifest.bundles.map((b: Bundle) => ({
...b,
category: 'On-Demand',
source: 'on-demand'
Expand Down Expand Up @@ -47,7 +64,7 @@ export default async function handler(req: any, res: any) {
const releases = await releasesResponse.json();

// Find releases with tag pattern "bundles-YYYYMMDD"
const weeklyReleases = releases.filter((r: any) =>
const weeklyReleases = releases.filter((r: { tag_name: string }) =>
r.tag_name.startsWith('bundles-') && r.tag_name !== 'bundles-latest'
);

Expand All @@ -56,9 +73,15 @@ export default async function handler(req: any, res: any) {
const latestWeekly = weeklyReleases[0];

// Parse bundle files from assets
const weeklyBundles = latestWeekly.assets
.filter((asset: any) => asset.name.endsWith('.cgc'))
.map((asset: any) => {
interface Asset {
name: string;
size: number;
browser_download_url: string;
updated_at: string;
}
const weeklyBundles = (latestWeekly.assets as Asset[])
.filter((asset: Asset) => asset.name.endsWith('.cgc'))
.map((asset: Asset) => {
const nameParts = asset.name.replace('.cgc', '').split('-');
const name = nameParts[0];
const version = nameParts[1] || 'latest';
Expand Down Expand Up @@ -96,11 +119,11 @@ export default async function handler(req: any, res: any) {
updated_at: new Date().toISOString()
});

} catch (err: any) {
} catch (err) {
console.error('Error fetching bundles:', err);
return res.status(500).json({
error: 'Failed to fetch bundles',
details: err.message
details: err instanceof Error ? err.message : String(err)
});
}
}
Expand Down
4 changes: 3 additions & 1 deletion website/api/pypi.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// api/pypi.ts

export default async function handler(req: any, res: any) {
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const path = req.url?.replace("/api/pypi", "") || "";

try {
Expand Down
Loading
Loading