Skip to content

Commit 9826fd1

Browse files
georgeh0claude
andauthored
refactor: consolidate hardcoded file paths into settings helpers (#118)
Add target_sqlite_db_path() and cocoindex_db_path() to settings.py as the single source of truth for database paths, replacing scattered hardcoded "target_sqlite.db" and "cocoindex.db" strings across cli.py, daemon.py, project.py, and config.py. Also use daemon_log_path() for daemon log references and project_settings_path() for settings file references. Remove config.py (unused legacy module) and its tests — no production code imported it. Add settings/index-db location display to `ccc status`. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 33334bc commit 9826fd1

8 files changed

Lines changed: 62 additions & 398 deletions

File tree

CLAUDE.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ Avoid `Any` whenever feasible. Use specific types — including concrete types f
4444

4545
For functions returning multiple values, use `NamedTuple` instead of plain tuples. At call sites, access fields by name (`result.can_reuse`) rather than positional unpacking — this prevents misreading fields in the wrong order.
4646

47+
### Single Source of Truth
48+
49+
When the same value or logic appears in multiple places, consolidate it into one canonical definition. Don't scatter literals, constants, or path construction across files.
50+
51+
### Dead Code
52+
53+
When changes make code unreachable or unused, delete it along with its tests. Don't leave orphaned modules around.
54+
4755
### Testing Guidelines
4856

4957
We prefer end-to-end tests on user-facing APIs, over unit tests on smaller internal functions. With this said, there're cases where unit tests are necessary, e.g. for internal logic with various situations and edge cases, in which case it's usually easier to cover various scenarios with unit tests.
58+
59+
When tests fail, fix the underlying issue. Don't skip, ignore, or exclude to get a green result.

src/cocoindex_code/cli.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212
from .client import DaemonStartError
1313
from .protocol import DoctorCheckResult, IndexingProgress, ProjectStatusResponse, SearchResponse
1414
from .settings import (
15+
cocoindex_db_path,
1516
default_project_settings,
1617
default_user_settings,
1718
find_parent_with_marker,
1819
find_project_root,
20+
project_settings_path,
1921
resolve_db_dir,
2022
save_project_settings,
2123
save_user_settings,
24+
target_sqlite_db_path,
2225
user_settings_path,
2326
)
2427

@@ -284,10 +287,8 @@ def init(
284287
force: bool = _typer.Option(False, "-f", "--force", help="Skip parent directory warning"),
285288
) -> None:
286289
"""Initialize a project for cocoindex-code."""
287-
from .settings import project_settings_path as _project_settings_path
288-
289290
cwd = Path.cwd().resolve()
290-
settings_file = _project_settings_path(cwd)
291+
settings_file = project_settings_path(cwd)
291292

292293
# Always ensure user settings exist
293294
user_path = user_settings_path()
@@ -377,8 +378,15 @@ def status() -> None:
377378
"""Show project status."""
378379
from . import client as _client
379380

380-
project_root = str(require_project_root())
381+
project_root_path = require_project_root()
382+
project_root = str(project_root_path)
381383
print_project_header(project_root)
384+
385+
_typer.echo(f"Settings: {project_settings_path(project_root_path)}")
386+
db_path = target_sqlite_db_path(project_root_path)
387+
if db_path.exists():
388+
_typer.echo(f"Index DB: {db_path}")
389+
382390
print_index_stats(_client.project_status(project_root))
383391

384392

@@ -393,10 +401,10 @@ def reset(
393401
db_dir = resolve_db_dir(project_root)
394402

395403
db_files = [
396-
db_dir / "cocoindex.db",
397-
db_dir / "target_sqlite.db",
404+
cocoindex_db_path(project_root),
405+
target_sqlite_db_path(project_root),
398406
]
399-
settings_file = cocoindex_dir / "settings.yml"
407+
settings_file = project_settings_path(project_root)
400408

401409
# Determine what will be deleted
402410
to_delete = [f for f in db_files if f.exists()]
@@ -503,16 +511,10 @@ def doctor() -> None:
503511
from .settings import (
504512
load_user_settings as _load_user_settings,
505513
)
506-
from .settings import (
507-
project_settings_path as _project_settings_path,
508-
)
509-
from .settings import (
510-
user_settings_path as _user_settings_path,
511-
)
512514

513515
# --- 1. Global settings (local, no daemon needed) ---
514516
_print_section("Global Settings")
515-
settings_path = _user_settings_path()
517+
settings_path = user_settings_path()
516518
_typer.echo(f" Settings: {settings_path}")
517519
try:
518520
user_settings = _load_user_settings()
@@ -570,7 +572,7 @@ def doctor() -> None:
570572
# --- 6. Project settings (local, no daemon needed) ---
571573
if project_root is not None:
572574
_print_section("Project Settings")
573-
ps_path = _project_settings_path(project_root)
575+
ps_path = project_settings_path(project_root)
574576
_typer.echo(f" Settings: {ps_path}")
575577
try:
576578
ps = _load_project_settings(project_root)
@@ -597,10 +599,9 @@ def doctor() -> None:
597599

598600
# --- 8. Log files ---
599601
_print_section("Log Files")
600-
from .daemon import daemon_dir as _daemon_dir
602+
from .daemon import daemon_log_path as _daemon_log_path
601603

602-
log_dir = _daemon_dir()
603-
_typer.echo(f" Daemon logs: {log_dir / 'daemon.log'}")
604+
_typer.echo(f" Daemon logs: {_daemon_log_path()}")
604605
_typer.echo(" Check logs above for further troubleshooting.")
605606

606607

src/cocoindex_code/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,10 @@ def start_daemon() -> subprocess.Popen[bytes]:
343343
Returns the ``Popen`` object so callers can detect early process death
344344
(via ``proc.poll()``) instead of waiting for a full timeout.
345345
"""
346-
from .daemon import daemon_dir
346+
from .daemon import daemon_dir, daemon_log_path
347347

348348
daemon_dir().mkdir(parents=True, exist_ok=True)
349-
log_path = daemon_dir() / "daemon.log"
349+
log_path = daemon_log_path()
350350

351351
ccc_path = _find_ccc_executable()
352352
if ccc_path:

src/cocoindex_code/config.py

Lines changed: 0 additions & 144 deletions
This file was deleted.

src/cocoindex_code/daemon.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
from .settings import (
4949
global_settings_mtime_us,
5050
load_user_settings,
51-
resolve_db_dir,
51+
target_sqlite_db_path,
5252
user_settings_dir,
5353
)
5454
from .shared import Embedder, create_embedder
@@ -346,7 +346,7 @@ async def _check_index_status(project_root_str: str) -> DoctorCheckResult:
346346
from cocoindex.connectors import sqlite as coco_sqlite
347347

348348
project_root = Path(project_root_str)
349-
db_path = resolve_db_dir(project_root) / "target_sqlite.db"
349+
db_path = target_sqlite_db_path(project_root)
350350
details = [f"Index: {db_path}"]
351351

352352
if not db_path.exists():

src/cocoindex_code/project.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,15 @@
2121
SearchResult,
2222
)
2323
from .query import query_codebase
24-
from .settings import resolve_db_dir
24+
from .settings import (
25+
cocoindex_db_path as _cocoindex_db_path,
26+
)
27+
from .settings import (
28+
resolve_db_dir,
29+
)
30+
from .settings import (
31+
target_sqlite_db_path as _target_sqlite_db_path,
32+
)
2533
from .shared import (
2634
CODEBASE_DIR,
2735
EMBEDDER,
@@ -171,7 +179,7 @@ async def search(
171179
offset: int = 0,
172180
) -> list[SearchResult]:
173181
"""Search within this project."""
174-
target_db = resolve_db_dir(self._project_root) / "target_sqlite.db"
182+
target_db = _target_sqlite_db_path(self._project_root)
175183
results = await query_codebase(
176184
query=query,
177185
target_sqlite_db_path=target_db,
@@ -261,14 +269,14 @@ async def create(
261269
db_dir = resolve_db_dir(project_root)
262270
db_dir.mkdir(parents=True, exist_ok=True)
263271

264-
cocoindex_db_path = db_dir / "cocoindex.db"
265-
target_sqlite_db_path = db_dir / "target_sqlite.db"
272+
cocoindex_db = _cocoindex_db_path(project_root)
273+
target_sqlite_db = _target_sqlite_db_path(project_root)
266274

267-
settings = coco.Settings.from_env(cocoindex_db_path)
275+
settings = coco.Settings.from_env(cocoindex_db)
268276

269277
context = coco.ContextProvider()
270278
context.provide(CODEBASE_DIR, project_root)
271-
context.provide(SQLITE_DB, coco_sqlite.connect(str(target_sqlite_db_path), load_vec=True))
279+
context.provide(SQLITE_DB, coco_sqlite.connect(str(target_sqlite_db), load_vec=True))
272280
context.provide(EMBEDDER, embedder)
273281

274282
env = coco.Environment(settings, context_provider=context)

src/cocoindex_code/settings.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,20 @@ def _reset_db_path_mapping_cache() -> None:
194194
_db_path_mapping = None
195195

196196

197+
_TARGET_SQLITE_DB_NAME = "target_sqlite.db"
198+
_COCOINDEX_DB_NAME = "cocoindex.db"
199+
200+
201+
def target_sqlite_db_path(project_root: Path) -> Path:
202+
"""Return the path to the vector index SQLite database for a project."""
203+
return resolve_db_dir(project_root) / _TARGET_SQLITE_DB_NAME
204+
205+
206+
def cocoindex_db_path(project_root: Path) -> Path:
207+
"""Return the path to the CocoIndex state database for a project."""
208+
return resolve_db_dir(project_root) / _COCOINDEX_DB_NAME
209+
210+
197211
def user_settings_dir() -> Path:
198212
"""Return ``~/.cocoindex_code/``.
199213
@@ -238,7 +252,7 @@ def find_legacy_project_root(start: Path) -> Path | None:
238252
"""
239253
current = start.resolve()
240254
while True:
241-
if (current / _SETTINGS_DIR_NAME / "cocoindex.db").exists():
255+
if (current / _SETTINGS_DIR_NAME / _COCOINDEX_DB_NAME).exists():
242256
return current
243257
parent = current.parent
244258
if parent == current:

0 commit comments

Comments
 (0)