From b799945374cf5933a9730bd3c5ca8cfe5d5aba3d Mon Sep 17 00:00:00 2001 From: oscharko-dev Date: Thu, 25 Jun 2026 23:02:30 +0200 Subject: [PATCH] docs(editor): document capability registry exhaustiveness and editor mode map (#1379) Update the deterministic editor language-service doc to reflect the #1379 additions (ADR-0067): the canonical editor language mode map in keiko-contracts (authoritative file-extension matching + syntax support), the exhaustive capabilities response (every known language returns a structured provider state; synthetic unavailable descriptor for known-but-unprovided languages), the safe plain-text degrade boundary, and the content-free languageCapability field on the agent session snapshot. Notes code actions are reserved for the staged-LSP work (ADR-0045). Refs #1379 Co-Authored-By: Claude Opus 4.8 --- docs/editor-language-service.md | 56 ++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/docs/editor-language-service.md b/docs/editor-language-service.md index 1ecbdc69..5a11b612 100644 --- a/docs/editor-language-service.md +++ b/docs/editor-language-service.md @@ -20,7 +20,7 @@ The module exposes one BFF route family: | Method + path | Purpose | | --------------------------------------- | ------------------------------------------------------------------------------------------- | | `POST /api/editor/language` | Run one operation (`diagnostics`, `completion`, `hover`, `symbols`) over an editor overlay. | -| `GET /api/editor/language/capabilities` | Advertise the registered providers and the operations each serves. | +| `GET /api/editor/language/capabilities` | Advertise a structured provider state for every known language (exhaustive — see below). | The wire contracts live in `@oscharko-dev/keiko-contracts` (`language-service.ts`) and are imported type-only by the browser tier. They are kept disjoint from the editor-session namespace @@ -100,3 +100,57 @@ The LSP bridge architecture (server-side, not browser-side), the provider-regist per-language security model, and the dependency-decision record are detailed in [ADR-0045](adr/ADR-0045-staged-multi-language-lsp-expansion.md) and the companion [architecture blueprint](planning/keiko-editor-multi-language-expansion.md). + +## Capability registry and editor mode map (#1379) + +Issue [#1379](https://github.com/oscharko-dev/Keiko/issues/1379) · Parent epic +[#1491](https://github.com/oscharko-dev/Keiko/issues/1491) · Decision record +[ADR-0067](adr/ADR-0067-language-capability-registry-and-editor-mode-map.md). + +So that the UI and future agents stay provider-agnostic, the capability registry is the **single +authoritative source** for what each language supports — modelled at the contract boundary the way +LSP and VS Code model language features as capabilities. + +### Canonical editor language mode map + +The known **source-language** universe is a single frozen const table in `@oscharko-dev/keiko-contracts` +(`editor-language-mode-map.ts`, `EDITOR_LANGUAGE_MODE_MAP`). Each entry carries the canonical +`languageId`, its `fileExtensions` (the authoritative file-extension matching), and a +`syntaxHighlighting` flag (syntax support). It is a strict leaf — pure const tables and pure functions, +no other `keiko-*` imports. The browser editor's Monaco language inference +(`keiko-editor/src/monaco/language-inference.ts`) **derives** its extension map and id set from this +table (plus the editor-only `plaintext` render fallback), so the browser and the server agree on the +known-language universe by construction rather than through two divergent maps. + +### Exhaustive capabilities — every known language returns a structured provider state + +`GET /api/editor/language/capabilities` is **exhaustive** over the mode map. The server registry first +contributes the real providers (TypeScript/JavaScript, JSON, builtin-text) and the unavailable external +LSP descriptors (Python/Java/Go/Rust/shell/SQL); then, for every known mode-map language that no +descriptor already covers, `describeLanguageCapabilities()` synthesises a structured +`{ id: "none", operations: [], availability: "unavailable", unavailableReason }` descriptor. As a +result a consumer resolving a known `languageId` always receives a structured provider state, never a +missing entry. The UI gates each language action (completion, diagnostics, hover, symbols, formatting) +on the resolved descriptor's `availability` and advertised `operations` — never on a hard-coded +TypeScript/JavaScript check. + +### Unsupported languages degrade safely + +`plaintext` and any unknown extension are deliberately **not** registry languages: they are the +editor's plain-text render fallback. Monaco still tokenises/colours the buffer locally, every governed +operation is disabled (no provider resolves), and `runLanguageOperation()` returns +`UNSUPPORTED_LANGUAGE` without throwing. "Known" (a mode-map id) and "unsupported" (everything else) +are disjoint by design. + +### Provider availability in agent snapshots + +`EditorAgentSessionSnapshot` (`editor-agent.ts`) carries an additive, optional, **content-free** +`languageCapability` field — `{ languageId, providerId, available, unavailableReason? }` (ids, a +boolean, and a short reason string only; never buffer text) — so a future agent can read the active +file's provider availability from the snapshot without calling the capabilities route itself. The +field is additive and the agent-snapshot schema version is unchanged. + +Code-action capabilities are **not** modelled as an executable operation yet: no provider implements +them, so adding one would be speculative surface. They are reserved for the staged-LSP work +([ADR-0045](adr/ADR-0045-staged-multi-language-lsp-expansion.md)), to be added additively alongside a +real implementor.