Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
8 changes: 5 additions & 3 deletions api/flask_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

from __future__ import annotations

from typing import Any, overload
from typing import Any, cast, overload

from flask import Response, current_app, jsonify

from utils.exclusion_rules import RuleTokens

def exclusion_rules() -> list[list[Any]]:

def exclusion_rules() -> list[RuleTokens]:
"""Return loaded exclusion rules from app config (empty list when unset)."""
return current_app.config.get("EXCLUSION_RULES") or []
return cast(list[RuleTokens], current_app.config.get("EXCLUSION_RULES") or [])


@overload
Expand Down
2 changes: 1 addition & 1 deletion requirements-lock.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ fpdf2==2.8.7 # via -r requirements.txt
itsdangerous==2.2.0 # via flask
jinja2==3.1.6 # via flask
markupsafe==3.0.3 # via flask, jinja2, werkzeug
pillow==12.2.0 # via -r requirements.txt, fpdf2
pillow==12.3.0 # via -r requirements.txt, fpdf2
werkzeug==3.1.8 # via flask
4 changes: 2 additions & 2 deletions services/cli_tabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
from api.flask_config import json_response

from utils.cli_chat_reader import list_cli_projects, messages_to_bubbles, traverse_blobs
from utils.exclusion_rules import build_searchable_text, is_excluded_by_rules
from utils.exclusion_rules import RuleTokens, build_searchable_text, is_excluded_by_rules
from utils.workspace_path import get_cli_chats_path

_logger = logging.getLogger(__name__)


def get_cli_workspace_tabs(
workspace_id: str, rules: list[Any],
workspace_id: str, rules: list[RuleTokens],
) -> Response | tuple[Response, int]:
"""Return Flask JSON response with tabs for a Cursor CLI project.

Expand Down
12 changes: 6 additions & 6 deletions services/export_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
cursor_cli_session_to_markdown,
cursor_ide_chat_to_markdown,
)
from utils.exclusion_rules import build_searchable_text, is_excluded_by_rules
from utils.exclusion_rules import RuleTokens, build_searchable_text, is_excluded_by_rules
from utils.path_helpers import to_epoch_ms
from utils.text_extract import extract_text_from_bubble, slug
from utils.workspace_path import get_cli_chats_path
Expand Down Expand Up @@ -130,7 +130,7 @@ def build_workspace_display_maps(

def prepare_workspace_orchestration(
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
*,
nocache: bool = False,
workspace_entries: list[dict[str, Any]] | None = None,
Expand Down Expand Up @@ -169,7 +169,7 @@ def prepare_workspace_orchestration(

def load_global_db_export_data(
orch: WorkspaceOrchestration,
rules: list[Any],
rules: list[RuleTokens],
*,
nocache: bool = False,
) -> GlobalDbExportData | None:
Expand Down Expand Up @@ -222,7 +222,7 @@ def _collect_ide_export_entries(
*,
orch: WorkspaceOrchestration,
db_data: GlobalDbExportData,
exclusion_rules: list[Any],
exclusion_rules: list[RuleTokens],
since: SinceMode,
last_export_ms: int,
today: str,
Expand Down Expand Up @@ -363,7 +363,7 @@ def _collect_ide_export_entries(

def _collect_cli_export_entries(
*,
exclusion_rules: list[Any],
exclusion_rules: list[RuleTokens],
since: SinceMode,
last_export_ms: int,
today: str,
Expand Down Expand Up @@ -487,7 +487,7 @@ def _collect_cli_export_entries(
def collect_export_entries(
*,
workspace_path: str,
exclusion_rules: list[Any],
exclusion_rules: list[RuleTokens],
since: SinceMode,
last_export_ms: int,
out_dir: str,
Expand Down
14 changes: 7 additions & 7 deletions services/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
)
from services.workspace_resolver import infer_invalid_workspace_aliases
from utils.cli_chat_reader import list_cli_projects, messages_to_bubbles, traverse_blobs
from utils.exclusion_rules import build_searchable_text, is_excluded_by_rules
from utils.exclusion_rules import RuleTokens, build_searchable_text, is_excluded_by_rules
from utils.text_extract import extract_text_from_bubble
from utils.path_helpers import (
get_workspace_display_name,
Expand Down Expand Up @@ -368,7 +368,7 @@ def workspace_for_composer(self, composer: Composer) -> str:

def _load_search_workspace_assigner(
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
workspace_entries: list[dict[str, Any]],
) -> _SearchWorkspaceAssigner | None:
ctx = resolve_workspace_context_cached(
Expand Down Expand Up @@ -428,7 +428,7 @@ def search_global_storage(
workspace_path: str,
query: str,
query_lower: str,
rules: list[Any],
rules: list[RuleTokens],
parse_warnings: ParseWarningCollector,
*,
since_ms: int | None = None,
Expand Down Expand Up @@ -478,7 +478,7 @@ def _search_global_storage_via_index(
workspace_path: str,
query: str,
query_lower: str,
rules: list[Any],
rules: list[RuleTokens],
parse_warnings: ParseWarningCollector,
*,
since_ms: int | None = None,
Expand Down Expand Up @@ -651,7 +651,7 @@ def _search_global_storage_live_scan(
workspace_path: str,
query: str,
query_lower: str,
rules: list[Any],
rules: list[RuleTokens],
parse_warnings: ParseWarningCollector,
*,
since_ms: int | None = None,
Expand Down Expand Up @@ -828,7 +828,7 @@ def search_legacy_workspaces(
query: str,
query_lower: str,
search_type: str,
rules: list[Any],
rules: list[RuleTokens],
*,
since_ms: int | None = None,
) -> list[SearchResult]:
Expand Down Expand Up @@ -961,7 +961,7 @@ def search_cli_sessions(
cli_chats_path: str,
query: str,
query_lower: str,
rules: list[Any],
rules: list[RuleTokens],
parse_warnings: ParseWarningCollector | None = None,
*,
since_ms: int | None = None,
Expand Down
11 changes: 6 additions & 5 deletions services/search_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
open_global_db,
)
from utils.path_helpers import to_epoch_ms
from utils.exclusion_rules import RuleTokens
from utils.workspace_path import get_cli_chats_path

__all__ = [
Expand Down Expand Up @@ -127,7 +128,7 @@ def index_search_enabled() -> bool:
)


def _storage_fingerprint(workspace_path: str, rules: list[Any]) -> dict[str, Any]:
def _storage_fingerprint(workspace_path: str, rules: list[RuleTokens]) -> dict[str, Any]:
entries = collect_workspace_entries(workspace_path)
gdb = global_storage_db_path(workspace_path)
cli_path = get_cli_chats_path()
Expand Down Expand Up @@ -228,7 +229,7 @@ def _create_schema(conn: sqlite3.Connection) -> None:

def build_search_index(
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
*,
force: bool = False,
) -> bool:
Expand Down Expand Up @@ -358,7 +359,7 @@ def build_search_index(
return False


def ensure_search_index(workspace_path: str, rules: list[Any]) -> None:
def ensure_search_index(workspace_path: str, rules: list[RuleTokens]) -> None:
"""Build index synchronously if missing or stale."""
if not index_search_enabled():
return
Expand All @@ -377,7 +378,7 @@ def ensure_search_index(workspace_path: str, rules: list[Any]) -> None:

def start_search_index_background(
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
*,
poll_seconds: int = 60,
) -> None:
Expand Down Expand Up @@ -549,7 +550,7 @@ def query_composer_rows_in_window(
return {row["composer_id"]: row for row in rows}


def index_is_usable(workspace_path: str, rules: list[Any]) -> bool:
def index_is_usable(workspace_path: str, rules: list[RuleTokens]) -> bool:
"""True when the on-disk index matches the current Cursor storage fingerprint."""
if not index_search_enabled() or _resolve_active_index_db_path() is None:
return False
Expand Down
6 changes: 4 additions & 2 deletions services/summary_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
from pathlib import Path
from typing import Any

from utils.exclusion_rules import RuleTokens

_logger = logging.getLogger(__name__)

CACHE_VERSION = 1
Expand Down Expand Up @@ -46,7 +48,7 @@ def nocache_enabled(*, request_nocache: bool = False) -> bool:
)


def _rules_digest(rules: list[Any]) -> str:
def _rules_digest(rules: list[RuleTokens]) -> str:
try:
payload = json.dumps(rules, sort_keys=True, ensure_ascii=False)
except (TypeError, ValueError):
Expand All @@ -68,7 +70,7 @@ def fingerprint_workspace_storage(
workspace_entries: list[dict[str, Any]],
*,
global_db_path: str | None,
rules: list[Any],
rules: list[RuleTokens],
cli_chats_path: str | None = None,
) -> dict[str, Any]:
"""Build a fingerprint dict for cache invalidation."""
Expand Down
4 changes: 2 additions & 2 deletions services/workspace_composer_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from typing import Any

from models import Bubble, Composer, ParseWarningCollector, SchemaError
from utils.exclusion_rules import build_searchable_text, is_excluded_by_rules
from utils.exclusion_rules import RuleTokens, build_searchable_text, is_excluded_by_rules
from services.workspace_resolver import determine_project_for_conversation

_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -81,7 +81,7 @@ def composer_chat_title(composer: Composer) -> str:


def is_composer_excluded(
rules: list[Any],
rules: list[RuleTokens],
*,
project_name: str,
composer: Composer,
Expand Down
8 changes: 5 additions & 3 deletions services/workspace_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from dataclasses import dataclass, replace
from typing import Any

from utils.exclusion_rules import RuleTokens

from models import Bubble
from services.workspace_db import (
COMPOSER_ROWS_WITH_HEADERS_SQL,
Expand Down Expand Up @@ -86,7 +88,7 @@ def resolve_workspace_context(

def resolve_workspace_context_cached(
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
*,
workspace_entries: list[dict[str, Any]] | None = None,
nocache: bool = False,
Expand Down Expand Up @@ -147,7 +149,7 @@ def resolve_invalid_workspace_aliases_cached(
ctx: WorkspaceContext,
global_db: sqlite3.Connection,
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
*,
nocache: bool = False,
project_layouts_map: dict[str, list[str]] | None = None,
Expand Down Expand Up @@ -223,7 +225,7 @@ def with_invalid_workspace_aliases(
ctx: WorkspaceContext,
global_db: sqlite3.Connection,
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
*,
nocache: bool = False,
project_layouts_map: dict[str, list[str]] | None = None,
Expand Down
4 changes: 3 additions & 1 deletion services/workspace_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from pathlib import Path
from typing import Any, cast

from utils.exclusion_rules import RuleTokens

_logger = logging.getLogger(__name__)

from models import Bubble, ParseWarningCollector, SchemaError
Expand Down Expand Up @@ -428,7 +430,7 @@ def build_composer_id_to_workspace_id(
def build_composer_id_to_workspace_id_cached(
workspace_path: str,
workspace_entries: list[dict[str, Any]],
rules: list[Any],
rules: list[RuleTokens],
*,
nocache: bool = False,
) -> dict[str, str]:
Expand Down
6 changes: 3 additions & 3 deletions services/workspace_listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
_logger = logging.getLogger(__name__)

from utils.cli_chat_reader import list_cli_projects
from utils.exclusion_rules import build_searchable_text, is_excluded_by_rules
from utils.exclusion_rules import RuleTokens, build_searchable_text, is_excluded_by_rules
from utils.path_helpers import (
get_workspace_folder_paths,
normalize_file_path,
Expand Down Expand Up @@ -49,7 +49,7 @@

def list_workspace_projects(
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
*,
nocache: bool = False,
) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
Expand Down Expand Up @@ -102,7 +102,7 @@ def list_workspace_projects(

def _build_workspace_projects_uncached(
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
orch: WorkspaceOrchestration,
*,
nocache: bool = False,
Expand Down
12 changes: 6 additions & 6 deletions services/workspace_tabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
to_epoch_ms,
warn_workspace_json_read,
)
from utils.exclusion_rules import build_searchable_text, is_excluded_by_rules
from utils.exclusion_rules import RuleTokens, build_searchable_text, is_excluded_by_rules
from utils.display_bubble import (
bubble_display_timestamp_ms,
build_storage_bubble_metadata,
Expand Down Expand Up @@ -130,7 +130,7 @@ def _assemble_tab_from_composer_data(
contexts: list[dict[str, Any]],
code_block_diffs: list[dict[str, Any]],
workspace_display_name: str,
rules: list[Any],
rules: list[RuleTokens],
parse_warnings: ParseWarningCollector,
) -> dict[str, Any] | None:
"""Assemble a single tab dict from a validated :class:`Composer`.
Expand Down Expand Up @@ -378,7 +378,7 @@ def _build_matching_ws_ids(
def list_workspace_tab_summaries(
workspace_id: str,
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
*,
nocache: bool = False,
) -> tuple[dict[str, Any], int]:
Expand Down Expand Up @@ -425,7 +425,7 @@ def list_workspace_tab_summaries(
def _build_workspace_tab_summaries_uncached(
workspace_id: str,
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
workspace_entries: list[dict[str, Any]],
*,
nocache: bool,
Expand Down Expand Up @@ -531,7 +531,7 @@ def assemble_single_tab(
workspace_id: str,
composer_id: str,
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
*,
nocache: bool = False,
) -> tuple[dict[str, Any], int]:
Expand Down Expand Up @@ -638,7 +638,7 @@ def assemble_single_tab(
def assemble_workspace_tabs(
workspace_id: str,
workspace_path: str,
rules: list[Any],
rules: list[RuleTokens],
*,
nocache: bool = False,
) -> tuple[dict[str, Any], int]:
Expand Down
Loading