codespine 0.5.8__tar.gz → 0.5.10__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.
- {codespine-0.5.8 → codespine-0.5.10}/PKG-INFO +1 -1
- {codespine-0.5.8 → codespine-0.5.10}/codespine/__init__.py +1 -1
- {codespine-0.5.8 → codespine-0.5.10}/codespine/cli.py +28 -8
- {codespine-0.5.8 → codespine-0.5.10}/codespine/db/store.py +16 -4
- {codespine-0.5.8 → codespine-0.5.10}/codespine.egg-info/PKG-INFO +1 -1
- {codespine-0.5.8 → codespine-0.5.10}/pyproject.toml +1 -1
- {codespine-0.5.8 → codespine-0.5.10}/LICENSE +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/README.md +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/analysis/__init__.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/analysis/community.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/analysis/context.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/analysis/coupling.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/analysis/crossmodule.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/analysis/deadcode.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/analysis/flow.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/analysis/impact.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/config.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/db/__init__.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/db/schema.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/diff/__init__.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/diff/branch_diff.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/indexer/__init__.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/indexer/call_resolver.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/indexer/engine.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/indexer/java_parser.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/indexer/symbol_builder.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/mcp/__init__.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/mcp/server.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/noise/__init__.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/noise/blocklist.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/overlay/__init__.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/overlay/git_state.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/overlay/merge.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/overlay/store.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/search/__init__.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/search/bm25.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/search/fuzzy.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/search/hybrid.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/search/rrf.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/search/vector.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/watch/__init__.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine/watch/watcher.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine.egg-info/SOURCES.txt +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine.egg-info/dependency_links.txt +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine.egg-info/entry_points.txt +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine.egg-info/requires.txt +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/codespine.egg-info/top_level.txt +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/gindex.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/setup.cfg +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/tests/test_branch_diff_normalize.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/tests/test_call_resolver.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/tests/test_community_detection.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/tests/test_deadcode.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/tests/test_index_and_hybrid.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/tests/test_java_parser.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/tests/test_multimodule_index.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/tests/test_overlay.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/tests/test_search_ranking.py +0 -0
- {codespine-0.5.8 → codespine-0.5.10}/tests/test_store_recovery.py +0 -0
|
@@ -77,6 +77,19 @@ def _dead_result_count(dead_result: list[dict] | None) -> int:
|
|
|
77
77
|
return sum(1 for item in dead_result if isinstance(item, dict) and "_stats" not in item)
|
|
78
78
|
|
|
79
79
|
|
|
80
|
+
def _bar(done: int, total: int, width: int = 20) -> str:
|
|
81
|
+
"""Return an ASCII progress bar like [████████░░░░] 40%."""
|
|
82
|
+
if total <= 0:
|
|
83
|
+
return f"[{'░' * width}] ---%"
|
|
84
|
+
frac = min(done / total, 1.0)
|
|
85
|
+
filled = int(width * frac)
|
|
86
|
+
return f"[{'█' * filled}{'░' * (width - filled)}] {int(frac * 100):3d}%"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _spinner_char() -> str:
|
|
90
|
+
return "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"[int(time.perf_counter() * 8) % 10]
|
|
91
|
+
|
|
92
|
+
|
|
80
93
|
@click.group()
|
|
81
94
|
def main() -> None:
|
|
82
95
|
"""CodeSpine CLI."""
|
|
@@ -141,7 +154,7 @@ def analyse(path: str, full: bool, deep: bool, embed: bool, allow_running: bool)
|
|
|
141
154
|
|
|
142
155
|
# Shared progress state (reset per module)
|
|
143
156
|
parse_state = {"shown": False, "indexed": 0, "total": 0, "last_ts": 0.0, "printed_zero": False}
|
|
144
|
-
call_state = {"shown": False, "count": 0, "last_ts": 0.0}
|
|
157
|
+
call_state = {"shown": False, "count": 0, "last_ts": 0.0, "started_at": 0.0}
|
|
145
158
|
|
|
146
159
|
def _reset_state() -> None:
|
|
147
160
|
for k in list(parse_state):
|
|
@@ -171,22 +184,28 @@ def analyse(path: str, full: bool, deep: bool, embed: bool, allow_running: bool)
|
|
|
171
184
|
if total == 0:
|
|
172
185
|
return
|
|
173
186
|
if indexed == total or (now - parse_state["last_ts"]) >= 0.2:
|
|
174
|
-
click.echo(f"\rParsing code...
|
|
187
|
+
click.echo(f"\rParsing code... {_bar(indexed, total)} {indexed}/{total} ", nl=False)
|
|
175
188
|
parse_state["shown"] = True
|
|
176
189
|
parse_state["last_ts"] = now
|
|
177
190
|
return
|
|
178
191
|
if event == "resolve_calls_start" and parse_state["shown"]:
|
|
179
192
|
click.echo()
|
|
180
193
|
parse_state["shown"] = False
|
|
181
|
-
|
|
194
|
+
call_state["started_at"] = now
|
|
195
|
+
_phase("Tracing calls...", "starting...")
|
|
182
196
|
return
|
|
183
197
|
if event == "resolve_calls_start":
|
|
184
|
-
|
|
198
|
+
call_state["started_at"] = now
|
|
199
|
+
_phase("Tracing calls...", "starting...")
|
|
185
200
|
return
|
|
186
201
|
if event == "resolve_calls_progress":
|
|
187
202
|
call_state["count"] = int(payload.get("calls_resolved", 0))
|
|
188
203
|
if (now - call_state["last_ts"]) >= 0.25:
|
|
189
|
-
|
|
204
|
+
elapsed_s = now - call_state["started_at"]
|
|
205
|
+
click.echo(
|
|
206
|
+
f"\r{_spinner_char()} Tracing calls... {call_state['count']:>6} resolved {elapsed_s:.1f}s ",
|
|
207
|
+
nl=False,
|
|
208
|
+
)
|
|
190
209
|
call_state["shown"] = True
|
|
191
210
|
call_state["last_ts"] = now
|
|
192
211
|
return
|
|
@@ -194,7 +213,8 @@ def analyse(path: str, full: bool, deep: bool, embed: bool, allow_running: bool)
|
|
|
194
213
|
if call_state["shown"]:
|
|
195
214
|
click.echo()
|
|
196
215
|
call_state["shown"] = False
|
|
197
|
-
|
|
216
|
+
elapsed_s = (now - call_state["started_at"]) if call_state["started_at"] else 0.0
|
|
217
|
+
_phase("Tracing calls...", f"{int(payload.get('calls_resolved', 0))} calls resolved ({elapsed_s:.1f}s)")
|
|
198
218
|
return
|
|
199
219
|
if event == "resolve_types_start":
|
|
200
220
|
_phase("Analyzing types...", "running")
|
|
@@ -226,11 +246,11 @@ def analyse(path: str, full: bool, deep: bool, embed: bool, allow_running: bool)
|
|
|
226
246
|
# ── Helper for in-place progress updates ────────────────────────────
|
|
227
247
|
def _live_phase(label: str, status: str) -> None:
|
|
228
248
|
"""Overwrite the current line with a status update."""
|
|
229
|
-
click.echo(f"\r{label:<
|
|
249
|
+
click.echo(f"\r{_spinner_char()} {label:<28} {status:<48}", nl=False)
|
|
230
250
|
|
|
231
251
|
def _finish_phase(label: str, result: str) -> None:
|
|
232
252
|
"""Finalise an in-place phase line and move to the next line."""
|
|
233
|
-
click.echo(f"\r{label:<
|
|
253
|
+
click.echo(f"\r✓ {label:<28} {result:<48}")
|
|
234
254
|
|
|
235
255
|
# ── Cross-module call linking ──────────────────────────────────────
|
|
236
256
|
if is_multi and len(modules_with_ids) > 1:
|
|
@@ -28,6 +28,11 @@ _RECOVERABLE_DB_ERROR_MARKERS = (
|
|
|
28
28
|
"corrupt",
|
|
29
29
|
"corrupted",
|
|
30
30
|
"invalid database",
|
|
31
|
+
# Kuzu internal error: abrupt process termination (Ctrl+C) during a write
|
|
32
|
+
# leaves the WAL in an inconsistent state; Kuzu raises this as an
|
|
33
|
+
# IndexError from its internal unordered_map when re-opening the path.
|
|
34
|
+
"unordered_map",
|
|
35
|
+
"key not found",
|
|
31
36
|
)
|
|
32
37
|
|
|
33
38
|
|
|
@@ -500,14 +505,21 @@ class GraphStore:
|
|
|
500
505
|
def rebuild_empty_db(self) -> None:
|
|
501
506
|
self._recycle_conn()
|
|
502
507
|
path = SETTINGS.db_path
|
|
508
|
+
self._remove_db_path(path)
|
|
509
|
+
# Kuzu may retain stale internal state from a previous failed open of
|
|
510
|
+
# this path (e.g. after Ctrl+C mid-write). If re-opening the just-
|
|
511
|
+
# deleted path raises, fall back to a clean /tmp location so the
|
|
512
|
+
# command succeeds rather than leaving the user stuck.
|
|
503
513
|
try:
|
|
504
|
-
self.
|
|
505
|
-
except
|
|
514
|
+
self.db = self._open_db(path)
|
|
515
|
+
except Exception as exc:
|
|
506
516
|
fallback = os.path.join("/tmp", ".codespine_db")
|
|
517
|
+
LOGGER.warning(
|
|
518
|
+
"Could not open fresh DB at %s after rebuild (%s); falling back to %s",
|
|
519
|
+
path, exc, fallback,
|
|
520
|
+
)
|
|
507
521
|
self._remove_db_path(fallback)
|
|
508
522
|
self.db = self._open_db(fallback)
|
|
509
|
-
else:
|
|
510
|
-
self.db = self._open_db(path)
|
|
511
523
|
self._tls = threading.local()
|
|
512
524
|
ensure_schema(self._conn())
|
|
513
525
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|