22
33from __future__ import annotations
44
5+ import os
56import sqlite3
6- from dataclasses import dataclass , replace
7+ from dataclasses import dataclass , field , replace
78from typing import Any
89
910from models import Bubble
1011from services .workspace_db import (
12+ COMPOSER_ROWS_WITH_HEADERS_SQL ,
1113 build_composer_id_to_workspace_id ,
1214 build_composer_id_to_workspace_id_cached ,
1315 collect_invalid_workspace_ids ,
1416 collect_workspace_entries ,
17+ global_storage_db_path ,
1518 load_bubble_map ,
1619 load_project_layouts_map ,
20+ safe_fetchall ,
1721)
1822from services .workspace_resolver import (
1923 create_project_name_to_workspace_id_map ,
2024 create_workspace_path_to_id_map ,
25+ infer_invalid_workspace_aliases ,
2126)
2227
2328
@@ -32,6 +37,7 @@ class WorkspaceContext:
3237 workspace_path_to_id : dict [str , str ]
3338 project_layouts_map : dict [str , list [str ]]
3439 bubble_map : dict [str , Bubble ]
40+ invalid_workspace_aliases : dict [str , str ] = field (default_factory = dict )
3541
3642
3743def _entries (
@@ -135,3 +141,100 @@ def enrich_workspace_context_from_global_db(
135141 if not updates :
136142 return ctx
137143 return replace (ctx , ** updates )
144+
145+
146+ def resolve_invalid_workspace_aliases_cached (
147+ ctx : WorkspaceContext ,
148+ global_db : sqlite3 .Connection ,
149+ workspace_path : str ,
150+ rules : list [Any ],
151+ * ,
152+ nocache : bool = False ,
153+ project_layouts_map : dict [str , list [str ]] | None = None ,
154+ ) -> dict [str , str ]:
155+ """Return invalid-workspace alias map, using the summary-cache fingerprint.
156+
157+ Computes ``infer_invalid_workspace_aliases`` at most once per storage
158+ fingerprint (same mtime key as composer-map / tab-summary caches). When
159+ *ctx* already carries a populated ``invalid_workspace_aliases`` field,
160+ that value is returned without touching disk or the global DB roster.
161+
162+ Args:
163+ ctx: Workspace maps from :func:`resolve_workspace_context_cached`.
164+ global_db: Open global ``state.vscdb`` connection.
165+ workspace_path: Cursor ``workspaceStorage`` root.
166+ rules: Exclusion rule token lists (fingerprint input).
167+ nocache: When ``True``, bypass disk cache reads and writes.
168+ project_layouts_map: Pre-loaded layouts; loaded from *global_db* when
169+ ``None``.
170+
171+ Returns:
172+ ``{invalid_id: replacement_id}``, or ``{}`` when every workspace is valid.
173+ """
174+ if not ctx .invalid_workspace_ids :
175+ return {}
176+
177+ from services .summary_cache import (
178+ fingerprint_workspace_storage ,
179+ get_cached_invalid_workspace_aliases ,
180+ nocache_enabled ,
181+ set_cached_invalid_workspace_aliases ,
182+ )
183+ from utils .workspace_path import get_cli_chats_path
184+
185+ gdb = global_storage_db_path (workspace_path )
186+ cli_path = get_cli_chats_path ()
187+ fingerprint = fingerprint_workspace_storage (
188+ workspace_path ,
189+ ctx .workspace_entries ,
190+ global_db_path = gdb if os .path .isfile (gdb ) else None ,
191+ rules = rules ,
192+ cli_chats_path = cli_path if os .path .isdir (cli_path ) else None ,
193+ )
194+ if not nocache_enabled (request_nocache = nocache ):
195+ cached = get_cached_invalid_workspace_aliases (fingerprint )
196+ if cached is not None :
197+ return cached
198+
199+ layouts = (
200+ project_layouts_map
201+ if project_layouts_map is not None
202+ else load_project_layouts_map (global_db )
203+ )
204+ composer_rows = safe_fetchall (global_db , COMPOSER_ROWS_WITH_HEADERS_SQL )
205+ aliases = infer_invalid_workspace_aliases (
206+ composer_rows = composer_rows ,
207+ project_layouts_map = layouts ,
208+ project_name_map = ctx .project_name_to_workspace_id ,
209+ workspace_path_map = ctx .workspace_path_to_id ,
210+ workspace_entries = ctx .workspace_entries ,
211+ bubble_map = {},
212+ composer_id_to_ws = ctx .composer_id_to_workspace_id ,
213+ invalid_workspace_ids = ctx .invalid_workspace_ids ,
214+ )
215+ if not nocache_enabled (request_nocache = nocache ):
216+ set_cached_invalid_workspace_aliases (fingerprint , aliases )
217+ return aliases
218+
219+
220+ def with_invalid_workspace_aliases (
221+ ctx : WorkspaceContext ,
222+ global_db : sqlite3 .Connection ,
223+ workspace_path : str ,
224+ rules : list [Any ],
225+ * ,
226+ nocache : bool = False ,
227+ project_layouts_map : dict [str , list [str ]] | None = None ,
228+ ) -> WorkspaceContext :
229+ """Return *ctx* with ``invalid_workspace_aliases`` populated from cache."""
230+ aliases = resolve_invalid_workspace_aliases_cached (
231+ ctx ,
232+ global_db ,
233+ workspace_path ,
234+ rules ,
235+ nocache = nocache ,
236+ project_layouts_map = project_layouts_map ,
237+ )
238+ if aliases is ctx .invalid_workspace_aliases :
239+ return ctx
240+ return replace (ctx , invalid_workspace_aliases = aliases )
0 commit comments