1use crate::diagnostics_scheduler::{
2 RustDiagnosticsSchedulerBoundaryV0, rust_diagnostics_scheduler_contract,
3};
4use crate::disk_cache::{DiskDiagnosticsCacheBoundaryV0, disk_diagnostics_cache_contract};
5use crate::query_reuse::{RustQueryReuseBoundaryV0, rust_query_reuse_contract};
6use crate::workspace_runtime_registry::{
7 WorkspaceRuntimeRegistryBoundaryV0, workspace_runtime_registry_contract,
8};
9use crate::{
10 CANCEL_REQUEST_METHOD, CASCADE_AT_POSITION_REQUEST, CLEAR_CACHES_REQUEST,
11 EXPLAIN_HOVER_TRACE_REQUEST, EXPLAIN_REQUEST, NODE_TEXT_DOCUMENT_SYNC_KIND,
12 STYLE_CONTEXT_INDEX_REQUEST,
13};
14use omena_tsgo_client::{OmenaTsgoClientBoundarySummaryV0, summarize_omena_tsgo_client_boundary};
15use serde::Serialize;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
18#[serde(rename_all = "camelCase")]
19#[non_exhaustive]
20pub enum CacheStorageRungV0 {
21 InitializationOptions,
22 Environment,
23 Platform,
24 Workspace,
25 Disabled,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
29#[serde(rename_all = "camelCase")]
30#[non_exhaustive]
31pub enum CacheWriteSurfaceKindV0 {
32 LspWorkspaceCache,
33 BridgeExternalSifCache,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
37#[serde(rename_all = "camelCase")]
38pub struct CacheWriteSurfaceV0 {
39 pub root_kind: CacheWriteSurfaceKindV0,
40 pub resolved_rung: CacheStorageRungV0,
41 pub root_shape: &'static str,
42 pub cache_directories: Vec<&'static str>,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
46#[serde(rename_all = "camelCase")]
47pub struct OmenaLspServerBoundarySummaryV0 {
48 pub schema_version: &'static str,
49 pub product: &'static str,
50 pub server_name: &'static str,
51 pub migration_status: &'static str,
52 pub transport_contract: &'static str,
53 pub trust_boundary: LspTrustBoundaryV0,
54 pub capabilities: OmenaLspServerCapabilitiesV0,
55 pub handler_surfaces: Vec<LspHandlerSurfaceV0>,
56 pub migration_phases: Vec<LspMigrationPhaseV0>,
57 pub blocking_work_policy: Vec<&'static str>,
58 pub tsgo_client_boundary: OmenaTsgoClientBoundarySummaryV0,
59 pub source_provider_adapter: SourceProviderDirectRustAdapterV0,
60 pub workspace_runtime_registry: WorkspaceRuntimeRegistryBoundaryV0,
61 pub diagnostics_scheduler: RustDiagnosticsSchedulerBoundaryV0,
62 pub query_reuse: RustQueryReuseBoundaryV0,
63 pub disk_diagnostics_cache: DiskDiagnosticsCacheBoundaryV0,
64 pub thin_client_endpoint: ThinClientEndpointV0,
65 pub multi_editor_distribution: MultiEditorDistributionV0,
66 pub node_parity_contracts: Vec<&'static str>,
67 pub next_decoupling_targets: Vec<&'static str>,
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
71#[serde(rename_all = "camelCase")]
72pub struct LspTrustBoundaryV0 {
73 pub product: &'static str,
74 pub network_access: &'static str,
75 pub verification_owner: &'static str,
76 pub request_path_policy: Vec<&'static str>,
77 pub forbidden_runtime_capabilities: Vec<&'static str>,
78 pub disk_write_surfaces: Vec<CacheWriteSurfaceV0>,
83}
84
85#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
86#[serde(rename_all = "camelCase")]
87pub struct OmenaLspServerCapabilitiesV0 {
88 pub text_document_sync: u8,
89 pub definition_provider: bool,
90 pub hover_provider: bool,
91 pub color_provider: bool,
92 pub completion_provider: CompletionProviderCapabilityV0,
93 pub code_action_provider: CodeActionProviderCapabilityV0,
94 pub references_provider: bool,
95 pub code_lens_provider: ResolveProviderCapabilityV0,
96 pub document_link_provider: ResolveProviderCapabilityV0,
97 pub workspace_symbol_provider: bool,
98 pub rename_provider: RenameProviderCapabilityV0,
99 pub workspace: WorkspaceCapabilityV0,
100}
101
102#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
103#[serde(rename_all = "camelCase")]
104pub struct CompletionProviderCapabilityV0 {
105 pub trigger_characters: Vec<&'static str>,
106 pub resolve_provider: bool,
107}
108
109#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
110#[serde(rename_all = "camelCase")]
111pub struct CodeActionProviderCapabilityV0 {
112 pub code_action_kinds: Vec<&'static str>,
113 pub resolve_provider: bool,
114}
115
116#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
117#[serde(rename_all = "camelCase")]
118pub struct ResolveProviderCapabilityV0 {
119 pub resolve_provider: bool,
120}
121
122#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
123#[serde(rename_all = "camelCase")]
124pub struct RenameProviderCapabilityV0 {
125 pub prepare_provider: bool,
126}
127
128#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
129#[serde(rename_all = "camelCase")]
130pub struct WorkspaceCapabilityV0 {
131 pub workspace_folders: WorkspaceFoldersCapabilityV0,
132}
133
134#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
135#[serde(rename_all = "camelCase")]
136pub struct WorkspaceFoldersCapabilityV0 {
137 pub supported: bool,
138 pub change_notifications: bool,
139}
140
141#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
142#[serde(rename_all = "camelCase")]
143pub struct LspHandlerSurfaceV0 {
144 pub method: &'static str,
145 pub node_owner: &'static str,
146 pub rust_owner_target: &'static str,
147 pub migration_state: &'static str,
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
151#[serde(rename_all = "camelCase")]
152pub struct LspMigrationPhaseV0 {
153 pub phase: &'static str,
154 pub goal: &'static str,
155 pub exit_gate: &'static str,
156}
157
158#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
159#[serde(rename_all = "camelCase")]
160pub struct ThinClientEndpointV0 {
161 pub product: &'static str,
162 pub endpoint_name: &'static str,
163 pub transport_contract: &'static str,
164 pub command_owner: &'static str,
165 pub standalone_package: &'static str,
166 pub split_repository: &'static str,
167 pub cargo_install_command: &'static str,
168 pub node_fallback_allowed: bool,
169 pub file_watcher_globs: Vec<&'static str>,
170 pub host_responsibilities: Vec<&'static str>,
171 pub rust_responsibilities: Vec<&'static str>,
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
175#[serde(rename_all = "camelCase")]
176pub struct MultiEditorDistributionV0 {
177 pub product: &'static str,
178 pub owner: &'static str,
179 pub distribution_model: &'static str,
180 pub supported_editors: Vec<&'static str>,
181 pub install_surfaces: Vec<&'static str>,
182 pub documentation: Vec<&'static str>,
183 pub endpoint_policy: Vec<&'static str>,
184}
185
186#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
187#[serde(rename_all = "camelCase")]
188pub struct SourceProviderDirectRustAdapterV0 {
189 pub product: &'static str,
190 pub candidate_owner: &'static str,
191 pub style_definition_owner: &'static str,
192 pub type_fact_owner: &'static str,
193 pub request_path_policy: Vec<&'static str>,
194 pub provider_surfaces: Vec<&'static str>,
195}
196
197pub fn summarize_omena_lsp_server_boundary() -> OmenaLspServerBoundarySummaryV0 {
198 OmenaLspServerBoundarySummaryV0 {
199 schema_version: "0",
200 product: "omena-lsp-server.boundary",
201 server_name: "omena-css",
202 migration_status: "rustStable",
203 transport_contract: "LSP stdio or IPC JSON-RPC",
204 trust_boundary: lsp_trust_boundary_contract(),
205 capabilities: current_node_lsp_capability_contract(),
206 handler_surfaces: lsp_handler_surfaces(),
207 migration_phases: lsp_migration_phases(),
208 blocking_work_policy: vec![
209 "noFullWorkspaceProgramOnRequestPath",
210 "queuedRequestCancellationBeforeProviderWork",
211 "dispatchedRequestCancellationAtCompletionBoundary",
212 "noMidComputationCancellationClaim",
213 "workerQueriesUseSnapshotReadView",
214 "tsgoProviderCancellationTokenBoundary",
215 "backgroundIndexAndTypeFactWarmup",
216 "staleOrUnresolvableFastReturn",
217 ],
218 tsgo_client_boundary: summarize_omena_tsgo_client_boundary(),
219 source_provider_adapter: source_provider_direct_rust_adapter_contract(),
220 workspace_runtime_registry: workspace_runtime_registry_contract(),
221 diagnostics_scheduler: rust_diagnostics_scheduler_contract(),
222 query_reuse: rust_query_reuse_contract(),
223 disk_diagnostics_cache: disk_diagnostics_cache_contract(),
224 thin_client_endpoint: thin_client_endpoint_contract(),
225 multi_editor_distribution: multi_editor_distribution_contract(),
226 node_parity_contracts: vec![
227 "initializeCapabilities",
228 "textDocumentSync",
229 "workspaceFolders",
230 "dynamicFileWatchers",
231 "diagnosticsPush",
232 "codeLensRefresh",
233 ],
234 next_decoupling_targets: vec![],
235 }
236}
237
238pub fn lsp_trust_boundary_contract() -> LspTrustBoundaryV0 {
239 let lsp_rung = current_cache_storage_rung();
240 let bridge_rung = current_bridge_cache_storage_rung();
241 LspTrustBoundaryV0 {
242 product: "omena-lsp-server.trust-boundary",
243 network_access: "neverFetch",
244 verification_owner: "omena-cli.lock-provenance",
245 request_path_policy: vec![
246 "analysisTimeUsesLocalWorkspaceOnly",
247 "recordedSifEvidenceReadFromDiskWithoutWorkspaceLockAuthority",
248 "attestationVerificationOwnedByCli",
249 "recordedShardVerdictsVerifiedOfflineWithoutNetworkAuthority",
253 "noRegistryFetchOnLspRequestPath",
254 "noTransparencyLogLookupOnLspRequestPath",
255 "cacheWritesConfinedToDeclaredOwnedRootsNeverNetwork",
259 ],
260 forbidden_runtime_capabilities: vec![
261 "registryHttpClient",
262 "sigstoreBundleVerifier",
263 "transparencyLogClient",
264 "socketNetworkIo",
265 ],
266 disk_write_surfaces: declared_cache_write_surfaces_for_rungs(lsp_rung, bridge_rung),
267 }
268}
269
270pub(crate) fn current_cache_storage_rung() -> CacheStorageRungV0 {
271 let config = crate::cache_root::LspCacheStorageConfigV0::standalone(None);
272 crate::cache_root::process_cache_roots(
273 &config,
274 "<workspaceIdentity>",
275 std::path::Path::new("<workspaceFolder>"),
276 )
277 .source
278 .into()
279}
280
281fn current_bridge_cache_storage_rung() -> CacheStorageRungV0 {
282 let has_environment_override = [
283 crate::cache_root::OMENA_CACHE_DIR_ENV,
284 crate::cache_root::OMENA_GLOBAL_CACHE_DIR_ENV,
285 ]
286 .into_iter()
287 .any(|name| std::env::var_os(name).is_some_and(|value| !value.is_empty()));
288 if has_environment_override {
289 CacheStorageRungV0::Environment
290 } else {
291 CacheStorageRungV0::Platform
292 }
293}
294
295pub(crate) fn declared_cache_write_surfaces_for_rungs(
296 lsp_rung: CacheStorageRungV0,
297 bridge_rung: CacheStorageRungV0,
298) -> Vec<CacheWriteSurfaceV0> {
299 let mut surfaces = Vec::new();
300 if let Some(root_shape) = cache_root_shape(CacheWriteSurfaceKindV0::LspWorkspaceCache, lsp_rung)
301 {
302 surfaces.push(CacheWriteSurfaceV0 {
303 root_kind: CacheWriteSurfaceKindV0::LspWorkspaceCache,
304 resolved_rung: lsp_rung,
305 root_shape,
306 cache_directories: vec![
307 "diagnostics-cache-v1",
308 "source-document-index-v1",
309 "source-type-fact-cache-v1",
310 "workspace-occurrence-shards-v2",
311 ],
312 });
313 }
314 if let Some(root_shape) =
315 cache_root_shape(CacheWriteSurfaceKindV0::BridgeExternalSifCache, bridge_rung)
316 {
317 surfaces.push(CacheWriteSurfaceV0 {
318 root_kind: CacheWriteSurfaceKindV0::BridgeExternalSifCache,
319 resolved_rung: bridge_rung,
320 root_shape,
321 cache_directories: vec!["external-sif-v0"],
322 });
323 }
324 surfaces
325}
326
327fn cache_root_shape(
328 kind: CacheWriteSurfaceKindV0,
329 rung: CacheStorageRungV0,
330) -> Option<&'static str> {
331 match (kind, rung) {
332 (CacheWriteSurfaceKindV0::LspWorkspaceCache, CacheStorageRungV0::InitializationOptions) => {
333 Some("<initializationWorkspaceStorage>/omena/workspaces/<workspaceIdentityHash>/**")
334 }
335 (CacheWriteSurfaceKindV0::LspWorkspaceCache, CacheStorageRungV0::Environment) => {
336 Some("<environmentCacheDir>/omena/workspaces/<workspaceIdentityHash>/**")
337 }
338 (CacheWriteSurfaceKindV0::LspWorkspaceCache, CacheStorageRungV0::Platform) => {
339 Some("<platformCacheHome>/omena/workspaces/<workspaceIdentityHash>/**")
340 }
341 (CacheWriteSurfaceKindV0::LspWorkspaceCache, CacheStorageRungV0::Workspace) => {
342 Some("<workspaceFolder>/.cache/omena/**")
343 }
344 (
345 CacheWriteSurfaceKindV0::BridgeExternalSifCache,
346 CacheStorageRungV0::InitializationOptions,
347 ) => {
348 Some("<initializationGlobalStorage>/omena/workspaces/<bridgeWorkspaceIdentityHash>/**")
349 }
350 (CacheWriteSurfaceKindV0::BridgeExternalSifCache, CacheStorageRungV0::Environment) => {
351 Some("<environmentCacheDir>/omena/workspaces/<bridgeWorkspaceIdentityHash>/**")
352 }
353 (CacheWriteSurfaceKindV0::BridgeExternalSifCache, CacheStorageRungV0::Platform) => {
354 Some("<platformCacheHome>/omena/workspaces/<bridgeWorkspaceIdentityHash>/**")
355 }
356 (CacheWriteSurfaceKindV0::BridgeExternalSifCache, CacheStorageRungV0::Workspace) => {
357 Some("<bridgeWorkspaceRoot>/.cache/omena/**")
358 }
359 (_, CacheStorageRungV0::Disabled) => None,
360 }
361}
362
363pub(crate) fn declared_disk_diagnostics_storage_locations() -> Vec<CacheWriteSurfaceV0> {
364 declared_cache_write_surfaces_for_rungs(
365 current_cache_storage_rung(),
366 CacheStorageRungV0::Disabled,
367 )
368 .into_iter()
369 .filter(|surface| surface.root_kind == CacheWriteSurfaceKindV0::LspWorkspaceCache)
370 .map(|mut surface| {
371 surface.cache_directories = vec!["diagnostics-cache-v1"];
372 surface
373 })
374 .collect()
375}
376
377impl From<crate::cache_root::CacheRootSourceV0> for CacheStorageRungV0 {
378 fn from(source: crate::cache_root::CacheRootSourceV0) -> Self {
379 match source {
380 crate::cache_root::CacheRootSourceV0::InitializationOptions => {
381 Self::InitializationOptions
382 }
383 crate::cache_root::CacheRootSourceV0::Environment => Self::Environment,
384 crate::cache_root::CacheRootSourceV0::Platform => Self::Platform,
385 crate::cache_root::CacheRootSourceV0::Workspace => Self::Workspace,
386 crate::cache_root::CacheRootSourceV0::Disabled => Self::Disabled,
387 }
388 }
389}
390
391pub fn source_provider_direct_rust_adapter_contract() -> SourceProviderDirectRustAdapterV0 {
392 SourceProviderDirectRustAdapterV0 {
393 product: "omena-lsp-server.source-provider-direct-rust-adapter",
394 candidate_owner: "omena-query/sourceSyntaxIndex",
395 style_definition_owner: "omena-query/styleHoverCandidates",
396 type_fact_owner: "omena-tsgo-client",
397 request_path_policy: vec![
398 "noNodeWorkspaceTypeResolverOnSourceProviderPath",
399 "buildQuerySourceSyntaxIndexOnDocumentChange",
400 "dedupeTargetAwareSourceCandidates",
401 "consumeQueryStyleHoverCandidates",
402 "consumeQuerySassModuleSources",
403 "consumeConfiguredPackageManifestPaths",
404 "consumeTsgoTypeFactsForTypedCxProjection",
405 "consumeSassPartialEvaluatorGeneratedSelectors",
406 "useOpenedDocumentIndexesBeforeWorkspaceFallback",
407 "unresolvedCandidatesRemainFastDiagnostics",
408 ],
409 provider_surfaces: vec![
410 "textDocument/hover",
411 "textDocument/definition",
412 "textDocument/references",
413 "textDocument/completion",
414 "textDocument/publishDiagnostics",
415 CASCADE_AT_POSITION_REQUEST,
416 STYLE_CONTEXT_INDEX_REQUEST,
417 EXPLAIN_HOVER_TRACE_REQUEST,
418 EXPLAIN_REQUEST,
419 ],
420 }
421}
422
423pub fn thin_client_endpoint_contract() -> ThinClientEndpointV0 {
424 ThinClientEndpointV0 {
425 product: "omena-lsp-server.thin-client-endpoint",
426 endpoint_name: "omena-css.thin-client-runtime-endpoint",
427 transport_contract: "LSP stdio JSON-RPC",
428 command_owner: "dist/bin/<platform>-<arch>/omena-lsp-server",
429 standalone_package: "omena-lsp-server",
430 split_repository: env!("CARGO_PKG_REPOSITORY"),
431 cargo_install_command: concat!(
432 "cargo install omena-lsp-server --version ",
433 env!("CARGO_PKG_VERSION")
434 ),
435 node_fallback_allowed: false,
436 file_watcher_globs: vec![
437 "**/*.module.{scss,css,less}",
438 "**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs,d.ts,vue,html,svelte,astro,md,mdx,liquid,twig,njk,nunjucks,hbs,handlebars,erb,ejs,html.eex,heex}",
439 "**/tsconfig*.json",
440 "**/jsconfig*.json",
441 "**/package.json",
442 "**/vite.config.{ts,mts,cts,js,mjs,cjs}",
443 "**/webpack.config.{ts,mts,cts,js,mjs,cjs}",
444 ],
445 host_responsibilities: vec![
446 "resolvePackagedRustBinary",
447 "resolveStandaloneRustCommand",
448 "buildThinClientServerOptions",
449 "prepareEditorStorageRoots",
450 "passStorageInitializationOptions",
451 "declareStaticDocumentSelector",
452 "startLanguageClient",
453 "registerStaticFileWatchers",
454 "requestServerOwnedCacheClear",
455 "translateShowReferencesArguments",
456 "renderHoverTracePanel",
457 "surfaceStartupErrors",
458 ],
459 rust_responsibilities: vec![
460 "ownLspLifecycle",
461 "ownWorkspaceState",
462 "ownDiagnosticsScheduling",
463 "ownProviderExecution",
464 "ownTsgoClientLifecycle",
465 "resolveAndClearDeclaredOwnedCachePaths",
466 ],
467 }
468}
469
470pub fn multi_editor_distribution_contract() -> MultiEditorDistributionV0 {
471 MultiEditorDistributionV0 {
472 product: "omena-lsp-server.multi-editor-distribution",
473 owner: "omena-lsp-server/distribution",
474 distribution_model: "standaloneRustLspServerWithThinEditorHosts",
475 supported_editors: vec!["vscode", "neovim", "zed"],
476 install_surfaces: vec![
477 "vsixBundledDistBinary",
478 "cargoInstallOmenaLspServer",
479 "repoLocalDistBin",
480 ],
481 documentation: vec![
482 "client/src/extension.ts",
483 "docs/clients/neovim.md",
484 "docs/clients/zed.md",
485 ],
486 endpoint_policy: vec![
487 "standaloneRustServerIsPrimaryMultiEditorEndpoint",
488 "nodeLspServerIsNotPrimaryEndpoint",
489 "editorClientsDoNotImplementProviderSemantics",
490 "editorsMayRunBesideNativeTypeScriptServer",
491 ],
492 }
493}
494
495pub fn current_node_lsp_capability_contract() -> OmenaLspServerCapabilitiesV0 {
496 OmenaLspServerCapabilitiesV0 {
497 text_document_sync: NODE_TEXT_DOCUMENT_SYNC_KIND,
498 definition_provider: true,
499 hover_provider: true,
500 color_provider: true,
501 completion_provider: CompletionProviderCapabilityV0 {
502 trigger_characters: vec!["'", "\"", "`", ",", ".", "$", "@", "-"],
503 resolve_provider: false,
504 },
505 code_action_provider: CodeActionProviderCapabilityV0 {
506 code_action_kinds: vec!["quickfix", "refactor.extract", "refactor.inline"],
507 resolve_provider: false,
508 },
509 references_provider: true,
510 code_lens_provider: ResolveProviderCapabilityV0 {
511 resolve_provider: false,
512 },
513 document_link_provider: ResolveProviderCapabilityV0 {
514 resolve_provider: false,
515 },
516 workspace_symbol_provider: true,
517 rename_provider: RenameProviderCapabilityV0 {
518 prepare_provider: true,
519 },
520 workspace: WorkspaceCapabilityV0 {
521 workspace_folders: WorkspaceFoldersCapabilityV0 {
522 supported: true,
523 change_notifications: true,
524 },
525 },
526 }
527}
528
529pub fn lsp_handler_surfaces() -> Vec<LspHandlerSurfaceV0> {
530 vec![
531 style_provider_handler("textDocument/definition"),
532 style_provider_handler("textDocument/hover"),
533 style_provider_handler("textDocument/completion"),
534 style_provider_handler("textDocument/codeAction"),
535 style_provider_handler("textDocument/references"),
536 style_provider_handler("textDocument/codeLens"),
537 style_provider_handler("textDocument/documentColor"),
538 style_provider_handler("textDocument/colorPresentation"),
539 style_provider_handler("textDocument/documentLink"),
540 style_provider_handler("workspace/symbol"),
541 style_provider_handler("textDocument/prepareRename"),
542 style_provider_handler("textDocument/rename"),
543 runtime_handler("initialized"),
544 runtime_handler("textDocument/didOpen"),
545 runtime_handler("textDocument/didChange"),
546 runtime_handler("textDocument/didClose"),
547 runtime_handler("workspace/didChangeWatchedFiles"),
548 runtime_handler("workspace/didChangeConfiguration"),
549 runtime_handler("workspace/didChangeWorkspaceFolders"),
550 diagnostics_handler("textDocument/publishDiagnostics"),
551 query_inspection_handler(CASCADE_AT_POSITION_REQUEST),
552 query_inspection_handler(STYLE_CONTEXT_INDEX_REQUEST),
553 query_inspection_handler(EXPLAIN_HOVER_TRACE_REQUEST),
554 query_inspection_handler(EXPLAIN_REQUEST),
555 runtime_handler(CLEAR_CACHES_REQUEST),
556 runtime_handler(CANCEL_REQUEST_METHOD),
557 ]
558}
559
560fn style_provider_handler(method: &'static str) -> LspHandlerSurfaceV0 {
561 LspHandlerSurfaceV0 {
562 method,
563 node_owner: "server/lsp-server/src/providers",
564 rust_owner_target: "omena-lsp-server/providers/style-source",
565 migration_state: "providerParity",
566 }
567}
568
569fn runtime_handler(method: &'static str) -> LspHandlerSurfaceV0 {
570 LspHandlerSurfaceV0 {
571 method,
572 node_owner: "server/lsp-server/src/handler-registration.ts",
573 rust_owner_target: "omena-lsp-server/runtime",
574 migration_state: "implemented",
575 }
576}
577
578fn diagnostics_handler(method: &'static str) -> LspHandlerSurfaceV0 {
579 LspHandlerSurfaceV0 {
580 method,
581 node_owner: "server/lsp-server/src/diagnostics-scheduler.ts",
582 rust_owner_target: "omena-lsp-server/diagnostics",
583 migration_state: "implemented",
584 }
585}
586
587fn query_inspection_handler(method: &'static str) -> LspHandlerSurfaceV0 {
588 LspHandlerSurfaceV0 {
589 method,
590 node_owner: "server/lsp-server/src/query-inspection",
591 rust_owner_target: "omena-lsp-server/query-inspection",
592 migration_state: "implemented",
593 }
594}
595
596pub fn lsp_migration_phases() -> Vec<LspMigrationPhaseV0> {
597 vec![
598 LspMigrationPhaseV0 {
599 phase: "phase-0-boundary",
600 goal: "declare Rust LSP capability and handler parity with the Node server",
601 exit_gate: "rust/omena-lsp-server/boundary",
602 },
603 LspMigrationPhaseV0 {
604 phase: "phase-1-shell",
605 goal: "own initialize, shutdown, text sync, workspace folders, and watcher state in Rust",
606 exit_gate: "rust/omena-lsp-server/runtime-loop",
607 },
608 LspMigrationPhaseV0 {
609 phase: "phase-2-style-providers",
610 goal: "serve style-side hover, definition, references, diagnostics, and code lens from Rust",
611 exit_gate: "rust/omena-lsp-server/provider-parity",
612 },
613 LspMigrationPhaseV0 {
614 phase: "phase-3-source-providers",
615 goal: "replace Node WorkspaceTypeResolver hot path with a long-lived tsgo client and Rust query runtime",
616 exit_gate: "rust/omena-tsgo-client/boundary",
617 },
618 LspMigrationPhaseV0 {
619 phase: "phase-4-thin-client",
620 goal: "shrink the VS Code extension to UI commands and Rust LSP process orchestration",
621 exit_gate: "rust/omena-lsp-server/thin-client-boundary",
622 },
623 ]
624}
625
626#[cfg(test)]
627mod cache_storage_boundary_tests {
628 use super::*;
629
630 #[test]
631 fn declared_cache_surface_table_is_typed_and_exhaustive_by_rung() {
632 let rows = [
633 (
634 CacheStorageRungV0::InitializationOptions,
635 "<initializationWorkspaceStorage>/omena/workspaces/<workspaceIdentityHash>/**",
636 "<initializationGlobalStorage>/omena/workspaces/<bridgeWorkspaceIdentityHash>/**",
637 ),
638 (
639 CacheStorageRungV0::Environment,
640 "<environmentCacheDir>/omena/workspaces/<workspaceIdentityHash>/**",
641 "<environmentCacheDir>/omena/workspaces/<bridgeWorkspaceIdentityHash>/**",
642 ),
643 (
644 CacheStorageRungV0::Platform,
645 "<platformCacheHome>/omena/workspaces/<workspaceIdentityHash>/**",
646 "<platformCacheHome>/omena/workspaces/<bridgeWorkspaceIdentityHash>/**",
647 ),
648 (
649 CacheStorageRungV0::Workspace,
650 "<workspaceFolder>/.cache/omena/**",
651 "<bridgeWorkspaceRoot>/.cache/omena/**",
652 ),
653 ];
654
655 for (rung, expected_lsp_root, expected_bridge_root) in rows {
656 let surfaces = declared_cache_write_surfaces_for_rungs(rung, rung);
657 assert_eq!(surfaces.len(), 2, "rung={rung:?}");
658 assert_eq!(
659 surfaces[0],
660 CacheWriteSurfaceV0 {
661 root_kind: CacheWriteSurfaceKindV0::LspWorkspaceCache,
662 resolved_rung: rung,
663 root_shape: expected_lsp_root,
664 cache_directories: vec![
665 "diagnostics-cache-v1",
666 "source-document-index-v1",
667 "source-type-fact-cache-v1",
668 "workspace-occurrence-shards-v2",
669 ],
670 }
671 );
672 assert_eq!(
673 surfaces[1],
674 CacheWriteSurfaceV0 {
675 root_kind: CacheWriteSurfaceKindV0::BridgeExternalSifCache,
676 resolved_rung: rung,
677 root_shape: expected_bridge_root,
678 cache_directories: vec!["external-sif-v0"],
679 }
680 );
681 }
682
683 assert!(
684 declared_cache_write_surfaces_for_rungs(
685 CacheStorageRungV0::Disabled,
686 CacheStorageRungV0::Disabled,
687 )
688 .is_empty(),
689 "disabled resolution must declare no writable cache surface"
690 );
691
692 let split = declared_cache_write_surfaces_for_rungs(
693 CacheStorageRungV0::Platform,
694 CacheStorageRungV0::Workspace,
695 );
696 assert_eq!(split[0].resolved_rung, CacheStorageRungV0::Platform);
697 assert_eq!(split[1].resolved_rung, CacheStorageRungV0::Workspace);
698 }
699}