code-explore 0.3.0__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {code_explore-0.3.0 → code_explore-0.4.0}/PKG-INFO +1 -1
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/api/main.py +1 -1
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/cli/main.py +64 -3
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/static/app.js +1 -1
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/static/index.html +1 -1
- {code_explore-0.3.0 → code_explore-0.4.0}/pyproject.toml +1 -1
- {code_explore-0.3.0 → code_explore-0.4.0}/.editorconfig +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/.github/workflows/pages.yml +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/.github/workflows/publish.yml +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/.gitignore +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/README.md +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/__init__.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/analyzer/__init__.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/analyzer/dependencies.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/analyzer/language.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/analyzer/metrics.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/analyzer/patterns.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/api/__init__.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/cli/__init__.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/cli/config_cmd.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/config.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/database.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/indexer/__init__.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/indexer/embeddings.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/models.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/scanner/__init__.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/scanner/git_info.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/scanner/local.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/scanner/readme.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/search/__init__.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/search/filters.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/search/fulltext.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/search/hybrid.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/search/semantic.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/static/style.css +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/summarizer/__init__.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/summarizer/ollama.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/code_explore/tagger/__init__.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/docs/CNAME +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/docs/index.html +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/install.cmd +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/install.ps1 +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/install.sh +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/tests/__init__.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/tests/conftest.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/tests/test_cli.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/tests/test_config.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/tests/test_config_cli.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/tests/test_database.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/tests/test_models.py +0 -0
- {code_explore-0.3.0 → code_explore-0.4.0}/tests/test_search_hybrid.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-explore
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Developer knowledge base CLI — scan, index, and search your programming projects
|
|
5
5
|
Project-URL: Homepage, https://github.com/aipioneers/code-explore
|
|
6
6
|
Project-URL: Repository, https://github.com/aipioneers/code-explore
|
|
@@ -14,7 +14,7 @@ from code_explore.database import init_db, save_project, get_project, get_all_pr
|
|
|
14
14
|
from code_explore.models import Project, ProjectSource, ProjectStatus, SearchFacets
|
|
15
15
|
from code_explore.search.filters import apply_filters, filter_projects, compute_facets
|
|
16
16
|
|
|
17
|
-
app = FastAPI(title="Code Explore", version="0.
|
|
17
|
+
app = FastAPI(title="Code Explore", version="0.4.0", description="Developer knowledge base API")
|
|
18
18
|
|
|
19
19
|
app.add_middleware(
|
|
20
20
|
CORSMiddleware,
|
|
@@ -34,8 +34,11 @@ def scan(
|
|
|
34
34
|
path: str = typer.Argument(..., help="Root directory to scan for repositories"),
|
|
35
35
|
depth: int = typer.Option(4, "--depth", "-d", help="Maximum directory depth"),
|
|
36
36
|
force: bool = typer.Option(False, "--force", "-f", help="Re-scan existing projects"),
|
|
37
|
+
no_ai: bool = typer.Option(False, "--no-ai", help="Skip AI summaries and tags (requires Ollama)"),
|
|
38
|
+
no_embed: bool = typer.Option(False, "--no-embed", help="Skip vector embeddings"),
|
|
39
|
+
model: str | None = typer.Option(None, "--model", "-m", help="Ollama model name"),
|
|
37
40
|
) -> None:
|
|
38
|
-
"""Scan
|
|
41
|
+
"""Scan repositories, analyze, summarize, and index — all in one step."""
|
|
39
42
|
from code_explore.scanner.local import scan_local_repos
|
|
40
43
|
from code_explore.scanner.git_info import extract_git_info, get_git_head
|
|
41
44
|
from code_explore.scanner.readme import read_readme, list_key_files
|
|
@@ -51,7 +54,16 @@ def scan(
|
|
|
51
54
|
console.print(f"[red]Error:[/red] Path does not exist: {root}")
|
|
52
55
|
raise typer.Exit(1)
|
|
53
56
|
|
|
54
|
-
|
|
57
|
+
steps = ["scan", "analyze"]
|
|
58
|
+
if not no_ai:
|
|
59
|
+
steps.append("summarize + tag")
|
|
60
|
+
if not no_embed:
|
|
61
|
+
steps.append("embed")
|
|
62
|
+
console.print(Panel(
|
|
63
|
+
f"Scanning [bold cyan]{root}[/bold cyan] (depth={depth})\n"
|
|
64
|
+
f"Steps: {' → '.join(steps)}",
|
|
65
|
+
title="Code Explore",
|
|
66
|
+
))
|
|
55
67
|
|
|
56
68
|
repos = asyncio.run(scan_local_repos(root, max_depth=depth))
|
|
57
69
|
|
|
@@ -60,6 +72,7 @@ def scan(
|
|
|
60
72
|
raise typer.Exit(0)
|
|
61
73
|
|
|
62
74
|
results: list[Project] = []
|
|
75
|
+
new_or_changed: list[Project] = []
|
|
63
76
|
|
|
64
77
|
with Progress(
|
|
65
78
|
SpinnerColumn(),
|
|
@@ -68,6 +81,7 @@ def scan(
|
|
|
68
81
|
MofNCompleteColumn(),
|
|
69
82
|
console=console,
|
|
70
83
|
) as progress:
|
|
84
|
+
# Phase 1: Scan & analyze
|
|
71
85
|
task = progress.add_task("Analyzing repositories...", total=len(repos))
|
|
72
86
|
|
|
73
87
|
for repo_path in repos:
|
|
@@ -117,8 +131,55 @@ def scan(
|
|
|
117
131
|
|
|
118
132
|
save_project(project)
|
|
119
133
|
results.append(project)
|
|
134
|
+
new_or_changed.append(project)
|
|
120
135
|
progress.update(task, advance=1)
|
|
121
136
|
|
|
137
|
+
# Phase 2: AI summaries & tags (all projects that need them)
|
|
138
|
+
if not no_ai:
|
|
139
|
+
from code_explore.summarizer.ollama import summarize_project
|
|
140
|
+
|
|
141
|
+
ai_candidates = [p for p in results if not p.summary or not p.ai_tags]
|
|
142
|
+
if ai_candidates:
|
|
143
|
+
ai_task = progress.add_task("AI summaries & tags...", total=len(ai_candidates))
|
|
144
|
+
summarized = 0
|
|
145
|
+
tagged = 0
|
|
146
|
+
|
|
147
|
+
for project in ai_candidates:
|
|
148
|
+
progress.update(ai_task, description=f"Summarizing [cyan]{project.name}[/cyan]")
|
|
149
|
+
needs_summary = not project.summary
|
|
150
|
+
needs_tags = not project.ai_tags
|
|
151
|
+
|
|
152
|
+
if model:
|
|
153
|
+
summary, tags, concepts, ai_tags = summarize_project(project, model=model)
|
|
154
|
+
else:
|
|
155
|
+
summary, tags, concepts, ai_tags = summarize_project(project)
|
|
156
|
+
|
|
157
|
+
if summary and needs_summary:
|
|
158
|
+
project.summary = summary
|
|
159
|
+
project.tags = tags
|
|
160
|
+
project.concepts = concepts
|
|
161
|
+
summarized += 1
|
|
162
|
+
if ai_tags and needs_tags:
|
|
163
|
+
project.ai_tags = ai_tags
|
|
164
|
+
tagged += 1
|
|
165
|
+
if summary or ai_tags:
|
|
166
|
+
save_project(project)
|
|
167
|
+
progress.update(ai_task, advance=1)
|
|
168
|
+
|
|
169
|
+
# Phase 3: Embeddings (all projects)
|
|
170
|
+
if not no_embed:
|
|
171
|
+
from code_explore.indexer.embeddings import index_project as embed_project
|
|
172
|
+
from datetime import datetime
|
|
173
|
+
|
|
174
|
+
embed_task = progress.add_task("Generating embeddings...", total=len(results))
|
|
175
|
+
for project in results:
|
|
176
|
+
progress.update(embed_task, description=f"Embedding [cyan]{project.name}[/cyan]")
|
|
177
|
+
embed_project(project)
|
|
178
|
+
project.status = ProjectStatus.INDEXED
|
|
179
|
+
project.indexed_at = datetime.now()
|
|
180
|
+
save_project(project)
|
|
181
|
+
progress.update(embed_task, advance=1)
|
|
182
|
+
|
|
122
183
|
table = Table(title=f"Scanned {len(results)} Projects")
|
|
123
184
|
table.add_column("Name", style="cyan", no_wrap=True)
|
|
124
185
|
table.add_column("Language", style="green")
|
|
@@ -321,7 +382,7 @@ def show(
|
|
|
321
382
|
def index(
|
|
322
383
|
model: str | None = typer.Option(None, "--model", "-m", help="Ollama model name for summarization"),
|
|
323
384
|
) -> None:
|
|
324
|
-
"""
|
|
385
|
+
"""Re-generate AI summaries and embeddings for existing projects."""
|
|
325
386
|
from code_explore.indexer.embeddings import index_project as embed_project, index_all_projects
|
|
326
387
|
from code_explore.summarizer.ollama import summarize_project
|
|
327
388
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|