Parser drift.
Contracts and edge cases
Platform spec article
Contracts and edge cases
Spec standingStandard
-
LSP graph
Context
Decision
Graph via LSP executeCommand.
Consequences
Thin wrappers.
Verification anchors
beskid_lsp handlers.
-
Focus without restart
Context
UX on focus.
Decision
didChangeConfiguration for focus; no LSP restart.
Consequences
Fast focus switch.
Verification anchors
Session invalidation.
- Contracts and edge cases focusedProjectUri, LSP executeCommand JSON schemas, and explorer edge-case rules.
- Decisions record (legacy index) Migration index for workspace and project explorer ADRs.
- Design model Tree item model, focus state, icons, and multi-root labeling for workspace and project explorers.
- Examples Corelib workspace and single-application explorer scenarios.
- Flow and algorithm Activation, LSP init, tree refresh, auto-select, and reveal flows for workspace and project explorers.
0 revisions (git unavailable at build; counts may be empty)
No commits recorded for this path.
| Section id | Required | Found |
|---|---|---|
what-this-feature-specifies | yes | yes |
implementation-anchors | yes | yes |
Full tree: run pnpm verify:platform-spec-layout (writes src/generated/platform-spec-layout-report.json).
Purpose and scope
Section titled “Purpose and scope”Normative LSP workspace/executeCommand payloads and focusedProjectUri configuration. All URIs must be file:// URIs normalized per LSP URI rules.
focusedProjectUri
Section titled “focusedProjectUri”| Rule ID | Rule |
|---|---|
| F-01 | On language client start, extension must send initializationOptions.focusedProjectUri when a project is focused. |
| F-02 | LSP must accept deprecated initializationOptions.selectedProjectUri as an alias when focusedProjectUri is absent. |
| F-03 | On focus change without client restart, extension must notify via workspace/didChangeConfiguration with settings object { "beskid": { "focusedProjectUri": "<uri>" } } or the beskid.project configuration section equivalent documented in extension settings. |
| F-04 | When focusedProjectUri is set, LSP should prefer that manifest for workspace scan ordering and cached_compilation_context selection; when unset, behavior must match pre-explorer semantics (all roots). |
| F-05 | Extension must not restart the language client solely because focusedProjectUri changed. |
Command transport
Section titled “Command transport”All commands below use LSP method workspace/executeCommand with:
command: string identifierarguments: JSON array; first element must be the args object when args are required
Errors must use LSP error codes; clients must surface message in a notification.
beskid.refreshWorkspace
Section titled “beskid.refreshWorkspace”| Field | Value |
|---|---|
| Purpose | Trigger workspace rescan and diagnostic refresh (existing contract). |
| Arguments | [] (empty) |
| Result | null |
Extension must invoke after manifest/lock watcher debounce and from command beskid.refreshWorkspace.
beskid.listWorkspaces
Section titled “beskid.listWorkspaces”Discover every Workspace.proj under current LSP workspace roots (respecting scan skip dirs).
Arguments (optional object):
{ "roots": ["file:///path/to/folder"]}When roots is omitted, LSP must use initialized workspace folders.
Result:
{ "workspaces": [ { "uri": "file:///…/Workspace.proj", "name": "corelib", "members": [ { "id": "collections", "uri": "file:///…/packages/collections/Project.proj", "name": "collections" } ] } ]}| Field | Required | Type | Meaning |
|---|---|---|---|
workspaces | yes | array | One entry per discovered workspace manifest |
workspaces[].uri | yes | string | Workspace.proj file URI |
workspaces[].name | yes | string | Workspace name from manifest |
workspaces[].members | yes | array | Parsed workspace members |
members[].id | yes | string | Member id from Workspace.proj |
members[].uri | yes | string | Member Project.proj URI |
members[].name | no | string | Display name; defaults to id when omitted |
beskid.getWorkspaceSummary
Section titled “beskid.getWorkspaceSummary”Arguments:
{ "workspaceUri": "file:///…/Workspace.proj"}Result:
{ "workspaceUri": "file:///…/Workspace.proj", "name": "corelib", "members": [ { "id": "collections", "uri": "file:///…/Project.proj", "name": "collections", "projectName": "collections" } ], "registries": [ { "alias": "default", "url": "https://registry.example/" } ]}| Field | Required | Meaning |
|---|---|---|
registries | yes | Effective registry URLs from workspace resolution rules (see compiler workspace contracts); used by package panel for default registry base |
members[].projectName | no | Parsed project.name when available |
beskid.getProjectGraph
Section titled “beskid.getProjectGraph”Arguments:
{ "projectUri": "file:///…/Project.proj"}Result:
{ "projectUri": "file:///…/Project.proj", "nodes": [ { "id": "dep:corelib", "kind": "dependency", "label": "corelib", "manifestUri": "file:///…/Project.proj", "materializedRoot": "file:///…/.beskid/packages/corelib/1.0.0" } ], "edges": [ { "from": "project", "to": "dep:corelib" } ], "unresolved": [ { "dependencyName": "missing-pkg", "source": "registry", "descriptor": "missing-pkg@1.0.0" } ]}nodes[].kind | Meaning |
|---|---|
project | Root project node (exactly one per result) |
target | Build target |
dependency | Resolved or declared dependency project |
sourceRoot | Source directory |
unresolved[] must mirror analysis UnresolvedDependencyNote (dependencyName, source, descriptor).
beskid.getProjectDependencies
Section titled “beskid.getProjectDependencies”Merged view of manifest declarations and lock lines for one project.
Arguments:
{ "projectUri": "file:///…/Project.proj"}Result:
{ "projectUri": "file:///…/Project.proj", "declared": [ { "name": "corelib", "version": null, "source": "registry", "registry": "default", "descriptor": "corelib" } ], "locked": [ { "name": "corelib", "resolvedVersion": "1.2.0", "registry": "default", "checksum": "sha256:…", "materializedRoot": "file:///…/.beskid/packages/corelib/1.2.0" } ], "unresolved": []}| Array | Meaning |
|---|---|
declared | Entries from Project.proj dependency tables |
locked | Entries from Project.lock when present; empty when lock missing |
unresolved | Declared deps that could not be resolved or locked |
locked[].resolvedVersion must match lockfile semantics in workspace and lock contracts.
Explorer-specific rules
Section titled “Explorer-specific rules”| ID | Rule |
|---|---|
| E-W01 | beskid.listWorkspaces must complete in O(roots × files) with scan skip dirs; must not build full compile graphs. |
| E-W02 | beskid.getProjectGraph may use build_project_graph_with_options from analysis; cycles must be represented as edges without infinite expansion in the tree UI. |
| E-W03 | When projectUri is outside workspace roots, LSP must return error InvalidParams with a clear message. |
| E-W04 | Extension command beskid.focusProject must set focusedProjectUri; beskid.clearFocus must clear it and notify LSP. |
Related topics
Section titled “Related topics”- Extension surface contracts — view IDs and cross-feature settings
- Snapshot and refresh — interaction with
beskid.refreshWorkspace