Skip to content

Commit 14ddb43

Browse files
committed
fix: reviewer's comments
1 parent 3430976 commit 14ddb43

5 files changed

Lines changed: 167 additions & 124 deletions

File tree

api/export_api.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@
2222
from utils.text_extract import extract_text_from_bubble, slug
2323
from utils.exclusion_rules import build_searchable_text, is_excluded_by_rules
2424
from utils.cursor_md_exporter import cursor_ide_chat_to_markdown
25-
from services.workspace_context import (
26-
enrich_workspace_context_from_global_db,
27-
resolve_workspace_context,
28-
)
25+
from services.workspace_context import resolve_workspace_context_minimal
2926
from services.workspace_db import (
27+
load_bubble_map,
3028
load_code_block_diff_map,
3129
open_global_db,
3230
)
@@ -100,11 +98,7 @@ def export_chats():
10098
last_export_ms = to_epoch_ms(ts_str)
10199

102100
# ── Workspace scanning via service layer ──────────────────────────────
103-
ctx = resolve_workspace_context(
104-
workspace_path,
105-
include_invalid_workspace_ids=False,
106-
include_workspace_path_map=False,
107-
)
101+
ctx = resolve_workspace_context_minimal(workspace_path)
108102
workspace_entries = ctx.workspace_entries
109103
composer_id_to_ws = ctx.composer_id_to_workspace_id
110104

@@ -126,10 +120,7 @@ def export_chats():
126120
if global_db is None:
127121
return jsonify({"error": "Cursor global storage not found"}), 404
128122

129-
ctx = enrich_workspace_context_from_global_db(
130-
ctx, global_db, populate_bubble_map=True,
131-
)
132-
bubble_map = ctx.bubble_map
123+
bubble_map = load_bubble_map(global_db)
133124
code_block_diff_map = load_code_block_diff_map(global_db)
134125

135126
try:

services/workspace_context.py

Lines changed: 66 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
from __future__ import annotations
44

5+
import sqlite3
56
from dataclasses import dataclass, replace
6-
from typing import TYPE_CHECKING
77

88
from services.workspace_db import (
99
build_composer_id_to_workspace_id,
@@ -18,15 +18,11 @@
1818
create_workspace_path_to_id_map,
1919
)
2020

21-
if TYPE_CHECKING:
22-
import sqlite3
23-
2421

2522
@dataclass(frozen=True)
2623
class WorkspaceContext:
2724
"""Precomputed workspace-resolution maps for conversation assignment."""
2825

29-
workspace_path: str
3026
workspace_entries: list[dict]
3127
invalid_workspace_ids: set[str]
3228
composer_id_to_workspace_id: dict[str, str]
@@ -36,82 +32,79 @@ class WorkspaceContext:
3632
bubble_map: dict[str, dict]
3733

3834

35+
def _entries(
36+
workspace_path: str,
37+
workspace_entries: list[dict] | None,
38+
) -> list[dict]:
39+
if workspace_entries is not None:
40+
return workspace_entries
41+
return collect_workspace_entries(workspace_path)
42+
43+
44+
def _assemble_context(
45+
entries: list[dict],
46+
*,
47+
invalid_workspace_ids: set[str],
48+
workspace_path_to_id: dict[str, str],
49+
composer_id_to_workspace_id: dict[str, str],
50+
) -> WorkspaceContext:
51+
return WorkspaceContext(
52+
workspace_entries=entries,
53+
invalid_workspace_ids=invalid_workspace_ids,
54+
composer_id_to_workspace_id=composer_id_to_workspace_id,
55+
project_name_to_workspace_id=create_project_name_to_workspace_id_map(entries),
56+
workspace_path_to_id=workspace_path_to_id,
57+
project_layouts_map={},
58+
bubble_map={},
59+
)
60+
61+
3962
def resolve_workspace_context(
4063
workspace_path: str,
4164
*,
4265
workspace_entries: list[dict] | None = None,
43-
rules: list | None = None,
44-
nocache: bool = False,
45-
use_composer_cache: bool = False,
46-
include_invalid_workspace_ids: bool = True,
47-
include_workspace_path_map: bool = True,
48-
global_db: sqlite3.Connection | None = None,
49-
populate_project_layouts: bool = False,
50-
populate_bubble_map: bool = False,
5166
) -> WorkspaceContext:
52-
"""Run the workspace-determination ceremony and return a typed context.
53-
54-
Always resolves ``workspace_entries`` (when not supplied), composer and
55-
project-name maps. Optional pieces are controlled by flags so lightweight
56-
consumers (e.g. HTTP export) can omit unused maps.
57-
58-
Args:
59-
workspace_path: Cursor ``workspaceStorage`` root.
60-
workspace_entries: Pre-collected entries; when ``None``, scanned from disk.
61-
rules: Exclusion rules; required when ``use_composer_cache`` is ``True``.
62-
nocache: Skip the mtime-keyed composer-map disk cache.
63-
use_composer_cache: Use :func:`build_composer_id_to_workspace_id_cached`.
64-
include_invalid_workspace_ids: When ``False``, ``invalid_workspace_ids`` is empty.
65-
include_workspace_path_map: When ``False``, ``workspace_path_to_id`` is empty.
66-
global_db: Open global ``state.vscdb`` connection for optional KV loads.
67-
populate_project_layouts: Populate ``project_layouts_map`` from *global_db*.
68-
populate_bubble_map: Populate ``bubble_map`` from *global_db*.
69-
70-
Returns:
71-
:class:`WorkspaceContext` with all requested maps populated.
72-
"""
73-
entries = (
74-
workspace_entries
75-
if workspace_entries is not None
76-
else collect_workspace_entries(workspace_path)
67+
"""Full workspace maps with an uncached composer→workspace scan (CLI export)."""
68+
entries = _entries(workspace_path, workspace_entries)
69+
return _assemble_context(
70+
entries,
71+
invalid_workspace_ids=collect_invalid_workspace_ids(entries),
72+
workspace_path_to_id=create_workspace_path_to_id_map(entries),
73+
composer_id_to_workspace_id=build_composer_id_to_workspace_id(
74+
workspace_path, entries,
75+
),
7776
)
78-
invalid_ids = (
79-
collect_invalid_workspace_ids(entries)
80-
if include_invalid_workspace_ids
81-
else set()
82-
)
83-
project_name_map = create_project_name_to_workspace_id_map(entries)
84-
workspace_path_map = (
85-
create_workspace_path_to_id_map(entries)
86-
if include_workspace_path_map
87-
else {}
88-
)
89-
if use_composer_cache:
90-
if rules is None:
91-
raise ValueError("rules is required when use_composer_cache=True")
92-
composer_id_to_ws = build_composer_id_to_workspace_id_cached(
77+
78+
79+
def resolve_workspace_context_cached(
80+
workspace_path: str,
81+
rules: list,
82+
*,
83+
workspace_entries: list[dict] | None = None,
84+
nocache: bool = False,
85+
) -> WorkspaceContext:
86+
"""Full workspace maps with a mtime-keyed composer map (listing / tabs)."""
87+
entries = _entries(workspace_path, workspace_entries)
88+
return _assemble_context(
89+
entries,
90+
invalid_workspace_ids=collect_invalid_workspace_ids(entries),
91+
workspace_path_to_id=create_workspace_path_to_id_map(entries),
92+
composer_id_to_workspace_id=build_composer_id_to_workspace_id_cached(
9393
workspace_path, entries, rules, nocache=nocache,
94-
)
95-
else:
96-
composer_id_to_ws = build_composer_id_to_workspace_id(workspace_path, entries)
97-
98-
project_layouts: dict[str, list] = {}
99-
bubble_map: dict[str, dict] = {}
100-
if global_db is not None:
101-
if populate_project_layouts:
102-
project_layouts = load_project_layouts_map(global_db)
103-
if populate_bubble_map:
104-
bubble_map = load_bubble_map(global_db)
94+
),
95+
)
10596

106-
return WorkspaceContext(
107-
workspace_path=workspace_path,
108-
workspace_entries=entries,
109-
invalid_workspace_ids=invalid_ids,
110-
composer_id_to_workspace_id=composer_id_to_ws,
111-
project_name_to_workspace_id=project_name_map,
112-
workspace_path_to_id=workspace_path_map,
113-
project_layouts_map=project_layouts,
114-
bubble_map=bubble_map,
97+
98+
def resolve_workspace_context_minimal(workspace_path: str) -> WorkspaceContext:
99+
"""Entries, project-name, and composer maps only (HTTP export)."""
100+
entries = collect_workspace_entries(workspace_path)
101+
return _assemble_context(
102+
entries,
103+
invalid_workspace_ids=set(),
104+
workspace_path_to_id={},
105+
composer_id_to_workspace_id=build_composer_id_to_workspace_id(
106+
workspace_path, entries,
107+
),
115108
)
116109

117110

services/workspace_listing.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
nocache_enabled,
2525
set_cached_projects,
2626
)
27-
from services.workspace_context import resolve_workspace_context
27+
from services.workspace_context import resolve_workspace_context_cached
2828
from services.workspace_db import (
2929
COMPOSER_ROWS_WITH_HEADERS_SQL,
3030
collect_workspace_entries,
@@ -122,12 +122,11 @@ def _build_workspace_projects_uncached(
122122
nocache: bool,
123123
) -> tuple[list[dict], list[dict]]:
124124
parse_warnings = ParseWarningCollector()
125-
ctx = resolve_workspace_context(
125+
ctx = resolve_workspace_context_cached(
126126
workspace_path,
127+
rules,
127128
workspace_entries=workspace_entries,
128-
rules=rules,
129129
nocache=nocache,
130-
use_composer_cache=True,
131130
)
132131
invalid_workspace_ids = ctx.invalid_workspace_ids
133132
project_name_map = ctx.project_name_to_workspace_id

services/workspace_tabs.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
nocache_enabled,
2828
set_cached_tab_summaries,
2929
)
30-
from services.workspace_context import resolve_workspace_context
30+
from services.workspace_context import resolve_workspace_context_cached
3131
from services.workspace_db import (
3232
COMPOSER_ROWS_WITH_HEADERS_SQL,
3333
collect_workspace_entries,
@@ -486,12 +486,11 @@ def _build_workspace_tab_summaries_uncached(
486486
parse_warnings = ParseWarningCollector()
487487
response: dict = {"tabs": []}
488488

489-
ctx = resolve_workspace_context(
489+
ctx = resolve_workspace_context_cached(
490490
workspace_path,
491+
rules,
491492
workspace_entries=workspace_entries,
492-
rules=rules,
493493
nocache=nocache,
494-
use_composer_cache=True,
495494
)
496495
invalid_workspace_ids = ctx.invalid_workspace_ids
497496
project_name_map = ctx.project_name_to_workspace_id
@@ -637,11 +636,7 @@ def assemble_single_tab(
637636
"""
638637
parse_warnings = ParseWarningCollector()
639638

640-
ctx = resolve_workspace_context(
641-
workspace_path,
642-
rules=rules,
643-
use_composer_cache=True,
644-
)
639+
ctx = resolve_workspace_context_cached(workspace_path, rules)
645640
workspace_entries = ctx.workspace_entries
646641
invalid_workspace_ids = ctx.invalid_workspace_ids
647642
project_name_map = ctx.project_name_to_workspace_id
@@ -773,11 +768,7 @@ def assemble_workspace_tabs(
773768
parse_warnings = ParseWarningCollector()
774769
response: dict = {"tabs": []}
775770

776-
ctx = resolve_workspace_context(
777-
workspace_path,
778-
rules=rules,
779-
use_composer_cache=True,
780-
)
771+
ctx = resolve_workspace_context_cached(workspace_path, rules)
781772
workspace_entries = ctx.workspace_entries
782773
invalid_workspace_ids = ctx.invalid_workspace_ids
783774
project_name_map = ctx.project_name_to_workspace_id

0 commit comments

Comments
 (0)