Direct, mapped language features

The parent supplies a pure captured disk-and-buffer snapshot, never generation. Only trusted local folders and globally inspected executable settings may start a server. A session owns one folder and canonical language; JavaScript/TypeScript siblings are synchronized together so imports can see the captured project.

Keep authority outside the project

Executable configuration never uses a merged getter. The resource-scoped automaticCompletion boolean is separate and defaults to true. Invalid entries receive a fixed diagnostic; aliases normalize fence labels, not configuration keys. Omitted arguments mean an empty array. Executables run without a shell through the existing client. Output never includes configuration values, source, protocol errors or stderr.

import * as vscode from 'vscode';
import * as path from 'node:path';
import { hasErrors, parseProject, parseFragmentHeader, scanFragmentTags, SourceDocument } from './engine';
import { LanguageClient } from './language-client';
import { LanguageDiagnostics } from './language-diagnostics';
import { mapLanguageCodeActions } from './language-actions';
import { mapLanguageLocations } from './language-navigation';
import { mapGeneratedRange, mapSourcePosition, projectLanguageSources, SourceProjectionPosition } from './language-projection';

type ObjectValue = Record<string, unknown>;
const object = (value: unknown): value is ObjectValue => value !== null && typeof value === 'object' && !Array.isArray(value);
const aliases: Record<string, string> = { ts: 'typescript', js: 'javascript', tsx: 'typescriptreact', jsx: 'javascriptreact',
    py: 'python', rb: 'ruby', sh: 'shellscript', bash: 'shellscript', yml: 'yaml', cs: 'csharp', 'c++': 'cpp', rs: 'rust' };
const language = (value: string): string => Object.prototype.hasOwnProperty.call(aliases, value.toLowerCase())
    ? aliases[value.toLowerCase()] : value.toLowerCase();
const family = (value: string): boolean => ['typescript', 'javascript', 'typescriptreact', 'javascriptreact'].includes(value);
interface Server { command: string; args: string[]; initializationOptions?: ObjectValue; configuration?: ObjectValue; }
interface RequestView { document: vscode.TextDocument; position: vscode.Position; hit: SourceProjectionPosition; }
export interface LanguageSnapshot { documents: SourceDocument[]; templates: Record<string, string>; }
function servers(invalid: () => void = () => undefined): Record<string, Server> {
    const raw = vscode.workspace.getConfiguration('literate').inspect<unknown>('languageServers')?.globalValue;
    const result: Record<string, Server> = Object.create(null);
    if (!object(raw)) { if (raw !== undefined) { invalid(); } return result; }
    for (const [id, entry] of Object.entries(raw)) {
        if (!/^[a-z][a-z0-9+-]*$/.test(id) || language(id) !== id || !object(entry)
            || typeof entry.command !== 'string' || !path.isAbsolute(entry.command) || entry.command.includes('\0')
            || (entry.args !== undefined && (!Array.isArray(entry.args)
                || !entry.args.every(arg => typeof arg === 'string' && !arg.includes('\0'))))
            || (entry.initializationOptions !== undefined && !object(entry.initializationOptions))
            || (entry.configuration !== undefined && !object(entry.configuration))) { invalid(); continue; }
        result[id] = { command: entry.command, args: entry.args === undefined ? [] : [...entry.args as string[]],
            initializationOptions: entry.initializationOptions as ObjectValue | undefined,
            configuration: entry.configuration as ObjectValue | undefined };
    }
    return result;
}
function local(folder: vscode.WorkspaceFolder, document: vscode.TextDocument): boolean {
    return vscode.workspace.isTrusted && !vscode.env.remoteName && folder.uri.scheme === 'file' && !folder.uri.authority
        && document.uri.scheme === 'file' && !document.uri.authority && !document.isClosed
        && document.languageId === 'markdown' && document.uri.fsPath.endsWith('.literate')
        && !!vscode.workspace.workspaceFolders?.includes(folder)
        && vscode.workspace.getWorkspaceFolder(document.uri) === folder;
}

A single-buffer parse scopes Escape immediately, without disk capture or graph expansion. Token maps and the shared header parser exclude prose and fence lines; reference spans and unfinished markers are excluded too. This proves only a local body, never a generated mapping: requests still require full snapshot projection.

function localBody(document: vscode.TextDocument, cursor: vscode.Position): boolean {
    try {
        const text = document.getText(), lines = text.split(/\r\n|\r|\n/);
        const parsed = parseProject([{ path: 'input.literate', text }]);
        const token = parsed.documents[0]?.tokens.find(value => value.type === 'fence' && value.map
            && cursor.line > value.map[0] && cursor.line < value.map[1]);
        if (!token?.map) { return false; }
        const header = parseFragmentHeader(token.info);
        if (!header || (header.language && !servers()[language(header.language)])) { return false; }
        const bodyLines = token.content.split('\n'), index = cursor.line - token.map[0] - 1;
        if (index >= bodyLines.length - (token.content.endsWith('\n') ? 1 : 0)) { return false; }
        const body = bodyLines[index], column = cursor.character - (lines[cursor.line].length - body.length);
        if (column <= 0 || column > body.length) { return false; }
        const before = body.slice(0, column - 1) + body.slice(column);
        if (before.trim().startsWith(token.markup)) { return false; }
        if (scanFragmentTags(body).some(tag => column >= tag.start && column <= tag.end +
            (tag.annotation === 'rail' ? '[rail]'.length : 0) + (tag.modifier?.length ?? 0))) {
            return false;
        }
        const prefix = body.slice(0, column);
        return prefix.lastIndexOf('<<') <= prefix.lastIndexOf('>>');
    } catch { return false; }
}

Treat replies as untrusted data

Positions use UTF-16 indexes and reject out-of-line coordinates rather than clamping them. Every edit must stay in the original occurrence, on the cursor's line, and contain the cursor. Unsupported completion defaults reject the list; commands and auxiliary edits reject the item. Snippets use the standard VS Code SnippetString interpreter, including its normal variables; no shell is involved.

function errorCategory(error: unknown): string {
    const code = object(error) ? error.code : undefined;
    if (code === 'ENOENT') { return 'ENOENT (executable, working directory or input file not found)'; }
    if (code === 'EACCES' || code === 'EPERM') { return 'permission denied (check executable and input permissions)'; }
    if (code === 'EPIPE' || code === 'ECONNRESET') { return 'server transport closed'; }
    const message = error instanceof Error ? error.message : '';
    if (code === 'ETIMEDOUT' || /^LSP request timed out:/.test(message)) { return 'request timeout (server did not respond)'; }
    if (/^Language server (exited|stdout closed)/.test(message)) { return 'server exited or closed stdout'; }
    if (/^Language server (document synchronization unsupported|open\/close synchronization required)/.test(message)) {
        return 'server lacks required document synchronization';
    }
    if (message === 'Language server must use UTF-16 positions') { return 'unsupported position encoding (UTF-16 required)'; }
    if (/^Invalid (LSP|JSON-RPC|initialize result)/.test(message)) { return 'invalid server protocol response'; }
    if (/^LSP .*limit exceeded/.test(message)) { return 'protocol resource limit exceeded'; }
    if (typeof code === 'number') { return 'server returned a protocol error'; }
    return 'unclassified failure (raw error omitted for privacy)';
}
function projectionReason(message: string): string {
    if (message.startsWith('Missing template:')) { return 'missing template; check template paths and captured template inputs.'; }
    if (message.startsWith('Missing fragment:') || message.startsWith('Cannot append to missing fragment:')) {
        return 'missing fragment; define the referenced fragment or correct its name.';
    }
    if (message.startsWith('Fragment cycle:')) { return 'fragment cycle; remove recursive references.'; }
    if (message.startsWith('Duplicate fragment:')) { return 'duplicate fragment; use append syntax for additional definitions.'; }
    if (/^Invalid (fragment header|fragment setting|template path)/.test(message)) {
        return 'invalid fragment header, setting or template path; check fence syntax and relative template paths.';
    }
    if (message.includes('limit exceeded')) { return 'expansion limit exceeded; reduce repeated fragment/template expansion.'; }
    return 'invalid project graph or inputs; check fragment definitions, references and output paths.';
}
function offset(text: string, value: unknown): number | undefined {
    if (!object(value) || !Number.isSafeInteger(value.line) || !Number.isSafeInteger(value.character)
        || (value.line as number) < 0 || (value.character as number) < 0) { return undefined; }
    const lines = text.split(/\r\n|\r|\n/);
    const line = value.line as number, character = value.character as number;
    if (line >= lines.length || character > lines[line].length) { return undefined; }
    let start = 0, index = 0;
    for (const match of text.matchAll(/\r\n|\r|\n/g)) {
        if (index++ === line) { break; }
        start = match.index! + match[0].length;
    }
    return start + character;
}
function position(text: string, at: number): { line: number; character: number } {
    const lines = text.slice(0, at).split(/\r\n|\r|\n/);
    return { line: lines.length - 1, character: lines[lines.length - 1].length };
}
function mappedRange(view: RequestView, value: unknown): vscode.Range | undefined {
    if (!object(value)) { return undefined; }
    const { file, mapping } = view.hit;
    const start = offset(file.content, value.start), end = offset(file.content, value.end);
    if (start === undefined || end === undefined) { return undefined; }
    const mapped = mapGeneratedRange(file, start, end, mapping);
    if (!mapped) { return undefined; }
    const range = new vscode.Range(view.document.positionAt(mapped.start), view.document.positionAt(mapped.end));
    return range.start.line === range.end.line && range.start.line === view.position.line && range.contains(view.position)
        ? range : undefined;
}

A default edit uses the source word, not the whole prefix preceding the cursor. The explicit identifier expression excludes dots even under Markdown word rules. An absent or unsafe word becomes a zero-width insertion inside the active mapping.

function actionRange(document: vscode.TextDocument, hit: SourceProjectionPosition, range: vscode.Range): ObjectValue | undefined {
    const start = document.offsetAt(range.start), end = document.offsetAt(range.end), mapping = hit.mapping;
    if (start < mapping.sourceStart || end < start || end > mapping.sourceEnd) { return; }
    return { start: position(hit.file.content, mapping.generatedStart + start - mapping.sourceStart),
        end: position(hit.file.content, mapping.generatedStart + end - mapping.sourceStart) };
}
function actionContext(document: vscode.TextDocument, hit: SourceProjectionPosition, range: vscode.Range,
    context: vscode.CodeActionContext): ObjectValue | undefined {
    const mapped = actionRange(document, hit, range);
    if (!mapped) { return; }
    const diagnostics = context.diagnostics.slice(0, 100).flatMap(value => {
        const target = actionRange(document, hit, value.range);
        if (!target || typeof value.message !== 'string') { return []; }
        const code = typeof value.code === 'object' ? value.code.value : value.code;
        return [{ range: target, message: value.message.slice(0, 8192), severity: value.severity + 1,
            ...(typeof code === 'string' || typeof code === 'number' ? { code } : {}),
            ...(typeof value.source === 'string' ? { source: value.source.slice(0, 256) } : {}),
            ...(value.tags?.every(tag => tag === 1 || tag === 2) ? { tags: [...value.tags] } : {}) }];
    });
    const only = context.only?.value;
    if (only !== undefined && !/^[\w.-]{1,256}$/.test(only)) { return; }
    return { range: mapped, context: { diagnostics, ...(only === undefined ? {} : { only: [only] }), triggerKind: 1 } };
}

Code actions are explicit VS Code invocations only. Request diagnostics are bounded, reduced to portable LSP fields, and retained only when their complete range belongs to the selected projection occurrence. context.only is sent as the LSP string array. Server replies are delegated to the edit-only helper; commands and resolution are not exposed.

function wordRange(view: RequestView): vscode.Range {
    const { document, position: cursor, hit } = view;
    const word = document.getWordRangeAtPosition(cursor, /[\p{L}\p{N}_$]+/u);
    if (word && word.start.line === cursor.line && word.end.line === cursor.line && word.contains(cursor)
        && document.offsetAt(word.start) >= hit.mapping.sourceStart
        && document.offsetAt(word.end) <= hit.mapping.sourceEnd) { return word; }
    return new vscode.Range(cursor, cursor);
}
type CompletionResult = vscode.CompletionItem[] | vscode.CompletionList;
const completionItems = (result: CompletionResult): vscode.CompletionItem[] => Array.isArray(result) ? result : result.items;
function completions(view: RequestView, reply: unknown,
    retain: (item: vscode.CompletionItem, raw: ObjectValue) => void): CompletionResult | undefined {
    if (object(reply) && 'editDefaults' in reply) { return undefined; }
    const defaults = object(reply) && 'itemDefaults' in reply ? reply.itemDefaults : undefined;
    if (defaults !== undefined && !completionDefaults(view, defaults)) { return undefined; }
    const items = Array.isArray(reply) ? reply : object(reply) && Array.isArray(reply.items) ? reply.items : undefined;
    if (!items) { return undefined; }
    const converted = items.slice(0, 1000).flatMap(raw => {
        const value = inheritCompletion(raw, defaults as ObjectValue | undefined);
        const item = completion(view, value);
        if (item) { retain(item, value as ObjectValue); }
        return item ? [item] : [];
    });
    return object(reply) ? new vscode.CompletionList(converted, reply.isIncomplete === true) : converted;
}

Only explicitly supported defaults are accepted; unknown fields cannot silently change insertion semantics. Default ranges pass the same fragment, line and cursor checks as item edits, including insert/replace containment. Item fields override defaults. Expanded items retain inherited data for metadata-only resolution.

function completionDefaults(view: RequestView, value: unknown): value is ObjectValue {
    if (!object(value) || Object.keys(value).some(key => !['editRange', 'insertTextFormat', 'insertTextMode', 'data'].includes(key))
        || (value.insertTextFormat !== undefined && value.insertTextFormat !== 1 && value.insertTextFormat !== 2)
        || (value.insertTextMode !== undefined && value.insertTextMode !== 1)) { return false; }
    if (value.editRange === undefined) { return true; }
    const range = value.editRange;
    if (!object(range)) { return false; }
    if ('start' in range || 'end' in range) {
        return !('insert' in range || 'replace' in range) && !!mappedRange(view, range);
    }
    const inserting = mappedRange(view, range.insert), replacing = mappedRange(view, range.replace);
    return !!inserting && !!replacing && inserting.start.isEqual(replacing.start) && replacing.contains(inserting);
}
function inheritCompletion(raw: unknown, defaults: ObjectValue | undefined): unknown {
    if (!object(raw) || !defaults) { return raw; }
    const value = { ...raw };
    for (const key of ['insertTextFormat', 'insertTextMode', 'data']) {
        if (value[key] === undefined && defaults[key] !== undefined) { value[key] = defaults[key]; }
    }
    if (defaults.editRange !== undefined) {
        if (value.textEditText !== undefined && typeof value.textEditText !== 'string') { return undefined; }
        if (value.textEdit === undefined) {
            const range = defaults.editRange as ObjectValue;
            const newText = value.textEditText ?? value.insertText ?? value.label;
            value.textEdit = 'start' in range ? { range, newText } : { insert: range.insert, replace: range.replace, newText };
        }
        delete value.textEditText;
    }
    return value;
}
function completion(view: RequestView, value: unknown): vscode.CompletionItem | undefined {
    if (!object(value) || typeof value.label !== 'string' || !value.label.length || value.label.length > 4096
        || 'command' in value || 'editDefaults' in value || 'textEditText' in value
        || (value.insertTextFormat !== undefined && value.insertTextFormat !== 1 && value.insertTextFormat !== 2)
        || (value.insertTextMode !== undefined && value.insertTextMode !== 1)
        || (value.additionalTextEdits !== undefined && (!Array.isArray(value.additionalTextEdits) || value.additionalTextEdits.length))
        || (value.insertText !== undefined && typeof value.insertText !== 'string')) { return undefined; }
    const item = new vscode.CompletionItem(value.label);
    let text = typeof value.insertText === 'string' ? value.insertText : value.label;
    item.range = wordRange(view);
    if (value.textEdit !== undefined) {
        const edit = value.textEdit;
        if (!object(edit) || typeof edit.newText !== 'string') { return undefined; }
        text = edit.newText;
        if ('range' in edit) {
            if ('insert' in edit || 'replace' in edit) { return undefined; }
            const range = mappedRange(view, edit.range);
            if (!range) { return undefined; }
            item.range = range;
        } else {
            const inserting = mappedRange(view, edit.insert), replacing = mappedRange(view, edit.replace);
            if (!inserting || !replacing || !inserting.start.isEqual(replacing.start)
                || !replacing.contains(inserting)) { return undefined; }
            item.range = { inserting, replacing };
        }
    }
    if (text.length > 65536) { return undefined; }
    item.insertText = value.insertTextFormat === 2 ? new vscode.SnippetString(text) : text;
    item.documentation = hoverText(value.documentation);
    for (const key of ['sortText', 'filterText', 'detail'] as const) {
        const text = value[key];
        if (typeof text === 'string') { item[key] = text.slice(0, 4096); }
    }
    const kinds = [vscode.CompletionItemKind.Text, vscode.CompletionItemKind.Method, vscode.CompletionItemKind.Function,
        vscode.CompletionItemKind.Constructor, vscode.CompletionItemKind.Field, vscode.CompletionItemKind.Variable,
        vscode.CompletionItemKind.Class, vscode.CompletionItemKind.Interface, vscode.CompletionItemKind.Module,
        vscode.CompletionItemKind.Property, vscode.CompletionItemKind.Unit, vscode.CompletionItemKind.Value,
        vscode.CompletionItemKind.Enum, vscode.CompletionItemKind.Keyword, vscode.CompletionItemKind.Snippet,
        vscode.CompletionItemKind.Color, vscode.CompletionItemKind.File, vscode.CompletionItemKind.Reference,
        vscode.CompletionItemKind.Folder, vscode.CompletionItemKind.EnumMember, vscode.CompletionItemKind.Constant,
        vscode.CompletionItemKind.Struct, vscode.CompletionItemKind.Event, vscode.CompletionItemKind.Operator,
        vscode.CompletionItemKind.TypeParameter];
    if (Number.isInteger(value.kind) && (value.kind as number) >= 1 && (value.kind as number) <= kinds.length) {
        item.kind = kinds[(value.kind as number) - 1];
    }
    return item;
}

Hover text is bounded and explicitly untrusted, including legacy marked strings. Explicit unsafe hover ranges discard the hover. Completion resolution shares this Markdown boundary and copies only documentation/detail, never replacement edits or commands. Signature labels and parameter offsets are validated separately.

function hoverText(value: unknown): vscode.MarkdownString | undefined {
    const markdown = new vscode.MarkdownString();
    markdown.isTrusted = false;
    markdown.supportHtml = false;
    if (typeof value === 'string') { markdown.appendMarkdown(value.slice(0, 8192)); }
    else if (object(value) && typeof value.value === 'string') {
        const text = value.value.slice(0, 8192);
        if (value.kind === 'plaintext') { markdown.appendText(text); }
        else if (value.kind === 'markdown') { markdown.appendMarkdown(text); }
        else if (typeof value.language === 'string' && /^[\w+-]{1,40}$/.test(value.language)) {
            markdown.appendCodeblock(text, value.language);
        } else { return undefined; }
    } else { return undefined; }
    return markdown.value ? markdown : undefined;
}
function hover(view: RequestView, reply: unknown): vscode.Hover | undefined {
    if (!object(reply)) { return undefined; }
    const values = Array.isArray(reply.contents) ? reply.contents.slice(0, 8) : [reply.contents];
    const contents = values.map(hoverText).filter((value): value is vscode.MarkdownString => !!value);
    if (!contents.length) { return undefined; }
    const range = reply.range === undefined ? wordRange(view) : mappedRange(view, reply.range);
    if (!range) { return undefined; }
    return new vscode.Hover(contents, range);
}
function signature(reply: unknown): vscode.SignatureHelp | undefined {
    if (!object(reply) || !Array.isArray(reply.signatures) || !reply.signatures.length || reply.signatures.length > 100) { return; }
    const result = new vscode.SignatureHelp();
    for (const raw of reply.signatures) {
        if (!object(raw) || typeof raw.label !== 'string' || raw.label.length > 8192) { return; }
        const info = new vscode.SignatureInformation(raw.label, hoverText(raw.documentation));
        if (raw.parameters !== undefined && (!Array.isArray(raw.parameters) || raw.parameters.length > 100)) { return; }
        for (const parameter of (raw.parameters || []) as unknown[]) {
            if (!object(parameter)) { return; }
            const label = parameter.label;
            if (typeof label === 'string') {
                if (!raw.label.includes(label)) { return; }
            } else if (!Array.isArray(label) || label.length !== 2 || !label.every(Number.isSafeInteger)
                || label[0] < 0 || label[1] < label[0] || label[1] > raw.label.length) { return; }
            info.parameters.push(new vscode.ParameterInformation(label as string | [number, number], hoverText(parameter.documentation)));
        }
        if (raw.activeParameter !== undefined) { info.activeParameter = boundedIndex(raw.activeParameter, info.parameters.length); }
        result.signatures.push(info);
    }
    result.activeSignature = boundedIndex(reply.activeSignature, result.signatures.length);
    result.activeParameter = result.signatures[result.activeSignature].activeParameter
        ?? boundedIndex(reply.activeParameter, result.signatures[result.activeSignature].parameters.length);
    return result;
}
function boundedIndex(value: unknown, length: number): number {
    return Number.isSafeInteger(value) && (value as number) >= 0 && (value as number) < length ? value as number : 0;
}
type Method = 'hover' | 'completion' | 'signatureHelp' | 'definition' | 'typeDefinition' | 'implementation' | 'references' | 'codeAction';
type Result = vscode.Hover | CompletionResult | vscode.SignatureHelp | vscode.Location[] | vscode.CodeAction[] | undefined;

One operation with bounded foreground waiting

At most 32 foreground requests wait for the serialization gate. Cancellation and freshness are checked before acquisition; foreground work precedes background work. The operation owns initialization, full synchronization and its reply as one unit. Every asynchronous boundary checks document version, the global revision epoch, folder membership, trust, configuration and cancellation. Disk events invalidate literate inputs and captured template paths. Paths changing during capture are bounded and checked against the completed template input set. Non-input changes, including publication outputs and transaction files, do not cancel cold startup. New source files always invalidate; missing templates cannot yield suggestions.

export function registerLanguageFeatures(context: vscode.ExtensionContext,
    snapshot: (folder: vscode.WorkspaceFolder) => Promise<LanguageSnapshot>): void {
    type Session = { client: LanguageClient; failed: boolean; started?: boolean; stop?: () => void };
    const sessions = new Map<string, Session>();
    const snapshots = new Map<string, string>();
    let epoch = 0, busy = false, disposed = false;
    let active: AbortController | undefined;
    const invalidate = (): void => { epoch++; active?.abort(); cancelAutomatic(); wakeWaiters(); };
    const close = (client: LanguageClient): void => { void client.dispose().catch(() => undefined); };
    let invalidReported = false, capturing = false;
    const captureChanges = new Set<string>();
    const templatePaths = new Map<string, Set<string>>(), reported = new Set<string>();
    const reset = (): void => {
        invalidate(); invalidateInputs(); sessions.forEach(session => { session.stop?.(); if (!session.failed) { close(session.client); } });
        sessions.clear(); snapshots.clear(); templatePaths.clear(); reported.clear(); invalidReported = false;
    };
    context.subscriptions.push({ dispose() { disposed = true; reset(); } });
    const waiters = new Set<() => void>();
    function wakeWaiters(): void { for (const wake of [...waiters]) { wake(); } }
    async function acquire(signal: AbortSignal, fresh: () => boolean): Promise<boolean> {
        if (waiters.size >= 32) { return false; }
        while (busy && fresh()) {
            await new Promise<void>(resolve => {
                const wake = (): void => { waiters.delete(wake); signal.removeEventListener('abort', wake); resolve(); };
                waiters.add(wake); signal.addEventListener('abort', wake, { once: true });
                if (signal.aborted) { wake(); }
            });
        }
        if (!fresh()) { return false; }
        busy = true; return true;
    }
    function release(): void {
        active = undefined; busy = false; capturing = false; captureChanges.clear();
        wakeWaiters();
        queueMicrotask(() => { void drain(); void drainBackground(); });
    }

A failed capture clears only the affected folder's diagnostics. Buffer mismatches are source evidence; focus and selection changes alone are not.

    function invalidateFolder(folder: vscode.WorkspaceFolder): void {
        for (const key of sessions.keys()) {
            if (JSON.parse(key)[0] === folder.uri.toString()) { diagnostics.invalidate(key); }
        }
    }
    function acceptSnapshot(folder: vscode.WorkspaceFolder, documents: SourceDocument[], templates: Record<string, string>): void {
        const key = folder.uri.toString(), identity = JSON.stringify([documents, templates]);
        if (snapshots.get(key) !== identity) { invalidateFolder(folder); snapshots.set(key, identity); }
    }
    function matchesBuffers(folder: vscode.WorkspaceFolder, documents: SourceDocument[]): boolean {
        return vscode.workspace.textDocuments.filter(document => local(folder, document)).every(document => {
            const name = path.relative(folder.uri.fsPath, document.uri.fsPath).split(path.sep).join('/');
            return documents.some(source => source.path.replace(/^\.\//, '') === name && source.text === document.getText());
        });
    }

Failure disables that session until configuration changes or the user invokes literate.restartLanguageServers. Cancellation is not failure. Restart invalidates old work without releasing the serialization gate until it settles. Diagnostics in the output channel are fixed, actionable messages, once per failed session or invalid configuration revision, with at most 100 retained lines. No automatic restart loop is possible.

    const output = vscode.window.createOutputChannel('Literate Language Servers');
    let lines = 0;
    let sourceRevision = 0;
    const diagnostics = new LanguageDiagnostics(context, message => report(message));
    let backgroundTimer: ReturnType<typeof setTimeout> | undefined;
    const background = new Map<string, vscode.TextDocument>();
    function diagnosticEnabled(document: vscode.TextDocument): boolean {
        return vscode.workspace.getConfiguration('literate', document.uri).get<boolean>('languageDiagnostics', true);
    }
    function inputUri(uri: vscode.Uri): boolean {
        return uri.fsPath.endsWith('.literate') || [...templatePaths.values()].some(paths => paths.has(path.resolve(uri.fsPath)));
    }
    function invalidateInputs(): void {
        sourceRevision++; diagnostics.invalidate();
        if (backgroundTimer) { clearTimeout(backgroundTimer); backgroundTimer = undefined; }
        background.clear();
        if (!disposed) { for (const document of vscode.workspace.textDocuments) { scheduleBackground(document); } }
    }
    function scheduleBackground(document: vscode.TextDocument): void {
        const folder = vscode.workspace.getWorkspaceFolder(document.uri);
        if (disposed || !folder || !local(folder, document) || !diagnosticEnabled(document) || !Object.keys(servers()).length) { return; }
        background.set(folder.uri.toString(), document);
        if (backgroundTimer) { clearTimeout(backgroundTimer); }
        backgroundTimer = setTimeout(() => { backgroundTimer = undefined; void drainBackground(); }, 400);
    }
    const report = (message: string): void => {
        if (disposed) { return; }
        if (lines >= 100) { output.clear(); lines = 0; }
        output.appendLine(message); lines++;
    };
    const reportOnce = (message: string): void => {
        if (!reported.has(message)) { reported.add(message); report(message); }
    };
    const invalid = (): void => {
        if (invalidReported) { return; }
        invalidReported = true;
        report('Invalid global literate.languageServers: use canonical language IDs, an absolute executable command, '
            + 'optional string-array args and object initializationOptions/configuration. Workspace overrides are ignored.');
    };
    context.subscriptions.push(output, vscode.commands.registerCommand('literate.restartLanguageServers', () => {
        if (!disposed) { reset(); }
    }));

Debounce only the latest focused insertion

One candidate survives a busy initialization or hover, without a request queue. Its version, cursor, editor and epoch must still agree after every asynchronous boundary. The insertion's own keyboard selection event is acknowledged once; other selection events cancel. The parent owns the default-true resource boolean and an Escape binding for literate.cancelAutomaticCompletion, guarded exactly by editorTextFocus && literate.automaticCompletionPending && !suggestWidgetVisible && !findWidgetVisible && !renameInputVisible && !inSnippetMode. The command only cancels pending work; normal widget Escape remains untouched. The context starts synchronously after local body verification, before debounce, and clears before showing results. Every eligible edit rechecks local Markdown; selection moves cancel. The asynchronous setContext delivery has no added wait. No public event observes raw Escape. Text change events do not identify the originating command: a one-character paste is indistinguishable from typing. Multi-character paste, replacements, undo/redo and multi-cursor edits are rejected.

    type Edit = { editor: vscode.TextEditor; document: vscode.TextDocument; cursor: vscode.Position;
        version: number; revision: number; character: string; selectionSeen: boolean; body: boolean };
    let candidate: Edit | undefined, pending: Edit | undefined;
    let timer: ReturnType<typeof setTimeout> | undefined;
    let cached: { edit: Edit; items: CompletionResult } | undefined;
    let signatureCache: { edit: Edit; value: vscode.SignatureHelp } | undefined;
    const signatureTriggers = new Set(['(', ',']);
    let signatureRegistration: vscode.Disposable | undefined;
    const retained = new WeakMap<vscode.CompletionItem, { raw: ObjectValue; client: LanguageClient; fresh: () => boolean }>();
    function cancelAutomatic(keepContext = false): void {
        if (timer) { clearTimeout(timer); timer = undefined; }
        candidate = pending = undefined; cached = undefined; signatureCache = undefined;
        if (!keepContext) { setPending(false); }
    }
    function enabled(document: vscode.TextDocument): boolean {
        const folder = vscode.workspace.getWorkspaceFolder(document.uri);
        return !!folder && local(folder, document)
            && vscode.workspace.getConfiguration('literate', document.uri).get<boolean>('automaticCompletion', true);
    }

Context writes are issued in transition order, without awaiting or installing state-changing promise callbacks. An old drain may only clear its own candidate; its completion cannot clear the latest candidate's context or debounce timer.

    let pendingContext: boolean | undefined;
    function setPending(value: boolean): void {
        if (pendingContext === value) { return; }
        pendingContext = value;
        void vscode.commands.executeCommand('setContext', 'literate.automaticCompletionPending', value)
            .then(undefined, () => undefined);
    }
    setPending(false);

Automatic-completion freshness is presented in Coordinating language features in the editor.

Prefetch uses the normal projection and payload validators. Only nonempty valid items open suggestions, and the provider consumes exactly one matching cache, discarding its candidate immediately. Widget-token cancellation then has no stale candidate to retain and must not cancel a newer edit. Arrays deliberately make no incomplete-result claim. No Markdown settings or Markdown-wide trigger registrations are needed.

    async function drain(): Promise<void> {
        if (busy || timer || !pending) { return; }
        const edit = pending; pending = undefined;
        if (!current(edit)) { if (candidate === edit) { cancelAutomatic(); } return; }
        const cancellation = new vscode.CancellationTokenSource();
        try {
            const method = signatureTriggers.has(edit.character) ? 'signatureHelp' : 'completion';
            const result = await request(edit.document, edit.cursor, cancellation.token, method, edit);
            if (!result || !current(edit)) { return; }
            if (result instanceof vscode.SignatureHelp) {
                signatureCache = { edit, value: result as vscode.SignatureHelp }; setPending(false);
                await vscode.commands.executeCommand('editor.action.triggerParameterHints');
            } else {
                if (!completionItems(result as CompletionResult).length) { return; }
                cached = { edit, items: result as CompletionResult }; setPending(false);
                await vscode.commands.executeCommand('editor.action.triggerSuggest');
            }
        } catch { if (candidate === edit) { cancelAutomatic(); } }
        finally {
            cancellation.dispose();
            if (candidate === edit) {
                setPending(false);
                if (cached?.edit !== edit && signatureCache?.edit !== edit) { cancelAutomatic(); }
            }
        }
    }
    function changed(event: vscode.TextDocumentChangeEvent): void {
        if (event.contentChanges.length === 0) { return; }
        if (!inputUri(event.document.uri)) { diskChanged(event.document.uri); return; }
        invalidateInputs();
        epoch++; active?.abort(); cancelAutomatic(true); wakeWaiters();
        try {
            const editor = vscode.window.activeTextEditor;
            if (!editor || !vscode.window.state.focused || event.document !== editor.document
                || event.reason !== undefined || event.contentChanges.length !== 1
                || editor.selections.length !== 1 || !editor.selection.isEmpty || !enabled(event.document)
                || !Object.keys(servers()).length) { return; }
            const change = event.contentChanges[0];
            if (change.rangeLength !== 0 || change.text.length !== 1 || /[\r\n]/.test(change.text)) { return; }
            const cursor = event.document.positionAt(change.rangeOffset + 1), before = change.range.start;
            if (!editor.selection.active.isEqual(before) && !editor.selection.active.isEqual(cursor)) { return; }
            candidate = pending = { editor, document: event.document, cursor, version: event.document.version,
                revision: epoch, character: change.text, selectionSeen: false, body: localBody(event.document, cursor) };
            timer = setTimeout(() => { timer = undefined; void drain(); }, 200);
        } finally { setPending(candidate?.body ?? false); }
    }
    context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(invalidate),
        vscode.window.onDidChangeWindowState(invalidate), vscode.workspace.onDidGrantWorkspaceTrust(reset),
        vscode.window.onDidChangeTextEditorSelection(event => {
            if (!candidate) { invalidate(); return; }
            if (event.textEditor === candidate.editor && !candidate.selectionSeen
                && event.kind === vscode.TextEditorSelectionChangeKind.Keyboard && current(candidate)) {
                candidate.selectionSeen = true; return;
            }
            invalidate();
        }), vscode.commands.registerCommand('literate.cancelAutomaticCompletion', () => {
            invalidate();
        }));
    context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(event => {
        if (event.affectsConfiguration('literate.languageServers')) { reset(); }
        else { invalidate(); invalidateInputs(); }
    }), vscode.workspace.onDidChangeWorkspaceFolders(() => reset()),
    vscode.workspace.onDidChangeTextDocument(changed), vscode.workspace.onDidOpenTextDocument(document => {
        diskChanged(document.uri); scheduleBackground(document);
    }), vscode.workspace.onDidCloseTextDocument(document => diskChanged(document.uri)));
    const watcher = vscode.workspace.createFileSystemWatcher('**/*');
    const diskChanged = (uri: vscode.Uri): void => {
        const changedPath = path.resolve(uri.fsPath);
        if (inputUri(uri)) {
            invalidate(); invalidateInputs();
        } else if (capturing) {
            if (captureChanges.size >= 1000) { invalidate(); invalidateInputs(); }
            else { captureChanges.add(changedPath); }
        }
    };
    context.subscriptions.push(watcher, watcher.onDidChange(diskChanged), watcher.onDidCreate(diskChanged), watcher.onDidDelete(diskChanged));
    async function request(document: vscode.TextDocument, cursor: vscode.Position, token: vscode.CancellationToken,
        method: Method, edit?: Edit, requestContext?: ObjectValue): Promise<Result> {
        const folder = vscode.workspace.getWorkspaceFolder(document.uri);
        if (disposed || token.isCancellationRequested || !folder || !local(folder, document)) { return undefined; }
        const configured = servers(invalid), fingerprint = JSON.stringify(configured);
        if (!Object.keys(configured).length) { return undefined; }
        const revision = epoch, version = document.version, inputs = sourceRevision;
        const controller = new AbortController();
        const cancellation = token.onCancellationRequested(() => controller.abort());
        let session: Session | undefined, sessionKey = '', phase = 'snapshot';
        const fresh = (): boolean => !disposed && !controller.signal.aborted && !token.isCancellationRequested
            && epoch === revision && sourceRevision === inputs && document.version === version && local(folder, document)
            && JSON.stringify(servers()) === fingerprint && (!edit || current(edit));
        if (!await acquire(controller.signal, fresh)) { cancellation.dispose(); return undefined; }
        active = controller;
        try {
            if (!fresh()) { return undefined; }
            captureChanges.clear(); capturing = true;
            const { documents, templates } = await snapshot(folder);
            capturing = false;
            if (!fresh()) { return undefined; }
            templatePaths.set(folder.uri.toString(), new Set(Object.keys(templates).map(name => path.resolve(folder.uri.fsPath, name))));
            acceptSnapshot(folder, documents, templates);
            const sourcePath = path.relative(folder.uri.fsPath, document.uri.fsPath).split(path.sep).join('/');
            if (!matchesBuffers(folder, documents)) {
                invalidateFolder(folder); return undefined;
            }
            phase = 'projection';
            const projected = projectLanguageSources(documents, templates);
            if (hasErrors(projected.diagnostics)) {
                invalidateFolder(folder);
                for (const diagnostic of projected.diagnostics) {
                    reportOnce('Language projection unavailable: ' + projectionReason(diagnostic.message));
                }
                return undefined;
            }
            if ([...captureChanges].some(name => templatePaths.get(folder.uri.toString())!.has(name))) {
                invalidate(); invalidateInputs(); return undefined;
            }
            const hit = mapSourcePosition(projected.files, sourcePath, document.offsetAt(cursor));
            if (!hit) { return undefined; }
            const action = method === 'codeAction' && requestContext
                ? actionContext(document, hit, requestContext.range as vscode.Range, requestContext.context as vscode.CodeActionContext)
                : undefined;
            if (method === 'codeAction' && !action) { return undefined; }
            const id = language(hit.file.language), config = configured[id];
            if (!config) { return undefined; }
            sessionKey = JSON.stringify([folder.uri.toString(), id]);
            session = sessions.get(sessionKey);
            if (session?.failed) { return undefined; }
            if (edit) { setPending(true); }
            phase = 'initialization';
            if (!session) {
                session = { client: new LanguageClient({ ...config, cwd: folder.uri.fsPath, rootUri: folder.uri.toString() }), failed: false };
                sessions.set(sessionKey, session); observeSession(sessionKey, session);
            }
            const client = session.client;
            const uri = (name: string): string => vscode.Uri.file(path.resolve(folder.uri.fsPath, name)).toString();
            phase = 'initialization';
            await client.initialize();
            if (!fresh()) { return undefined; }
            if (!session.started) {
                session.started = true;
                report('Language server ready: ' + id.slice(0, 80) + '; projected output ' + JSON.stringify(hit.file.path.slice(0, 200)) + '.');
            }
            updateSignatureTriggers(client);
            if (edit) { method = signatureTrigger(client, edit.character) ? 'signatureHelp' : 'completion'; }
            if (method === 'signatureHelp' && requestContext?.triggerKind === 2
                && !signatureTrigger(client, requestContext.triggerCharacter, requestContext.isRetrigger === true)) { return; }
            const capability = client.capabilities[method + 'Provider'];
            if (method === 'codeAction' ? !client.supportsCodeActions()
                : !(object(capability) || (!['completion', 'signatureHelp'].includes(method) && capability === true))) { return undefined; }
            const triggered = edit && object(capability) && Array.isArray(capability.triggerCharacters)
                && capability.triggerCharacters.includes(edit.character);
            if (edit && method === 'completion' && !triggered && !/[\p{L}\p{N}_$]/u.test(edit.character)) { return undefined; }

Advertised characters take precedence over identifier invocation, including on an initial punctuation edit. Mapping is established before startup or UI work.

            phase = 'synchronization';
            const wire = projected.files.filter(file => language(file.language) === id || (family(id) && family(language(file.language))))
                .map(file => ({ uri: uri(file.path), languageId: language(file.language), text: file.content }));
            const diagnosticFresh = (): boolean => !disposed && sourceRevision === inputs && local(folder, document)
                && diagnosticEnabled(document) && document.version === version && JSON.stringify(servers()) === fingerprint;
            if (diagnosticEnabled(document)) {
                await diagnostics.synchronize(sessionKey, client, { root: folder.uri, files: projected.files, documents }, wire, diagnosticFresh);
            } else { diagnostics.invalidate(sessionKey); await client.sync(wire); }
            if (!fresh()) { return undefined; }
            phase = 'request';
            const reply = await client.request('textDocument/' + method, method === 'codeAction' ? {
                textDocument: { uri: uri(hit.file.path) }, ...action
            } : {
                textDocument: { uri: uri(hit.file.path) }, position: position(hit.file.content, hit.offset),
                ...(method === 'completion' ? { context: requestContext || (triggered
                    ? { triggerKind: 2, triggerCharacter: edit!.character } : { triggerKind: 1 }) } : {}),
                ...(method === 'references' ? { context: { includeDeclaration: requestContext?.includeDeclaration === true } } : {}),
                ...(method === 'signatureHelp' ? { context: requestContext || {
                    triggerKind: edit ? 2 : 1, ...(edit ? { triggerCharacter: edit.character } : {}), isRetrigger: false } } : {})
            }, controller.signal);
            if (!fresh()) { return undefined; }
            const view = { document, position: cursor, hit };
            if (method === 'hover') { return hover(view, reply); }
            if (method === 'signatureHelp') { return signature(reply); }
            if (method === 'codeAction') { return mapLanguageCodeActions(reply, { document, sourcePath,
                generatedUri: vscode.Uri.file(path.resolve(folder.uri.fsPath, hit.file.path)), file: hit.file,
                mapping: hit.mapping, requestVersion: version, triggerKind: vscode.CodeActionTriggerKind.Invoke }); }
            if (method !== 'completion') { return mapLanguageLocations(reply, { root: folder.uri, files: projected.files, documents }); }
            return completions(view, reply, (item, raw) => retained.set(item, { raw, client,
                fresh: () => !disposed && epoch === revision && sourceRevision === inputs && document.version === version
                    && local(folder, document) && sessions.get(sessionKey) === session && !session?.failed
                    && JSON.stringify(servers()) === fingerprint }));

Failures preserve the gate until cleanup finishes.

        } catch (error) {
            if (!session && sourceRevision === inputs) { invalidateFolder(folder); }
            if (!session && fresh()) {
                reportOnce('Language ' + phase + ' failed: ' + errorCategory(error)
                    + '. Check source/template inputs and global literate.languageServers settings, then retry.');
            }
            if (session && sessions.get(sessionKey) === session && !session.failed
                && !(phase === 'request' && controller.signal.aborted)) {
                session.failed = true; diagnostics.invalidate(sessionKey); close(session.client);
                report('Language server ' + phase + ' failed: ' + errorCategory(error)
                    + '. Check the executable and global literate.languageServers settings, then run literate.restartLanguageServers to retry.');
            }
            return undefined;
        } finally {
            cancellation.dispose(); release();
        }
    }

Resolution copies only advertised metadata, never replacing an already validated edit. Even malicious replacement edits remain inert. Optional metadata failure is nonfatal.

    async function resolveCompletion(item: vscode.CompletionItem, token: vscode.CancellationToken): Promise<vscode.CompletionItem> {
        const saved = retained.get(item);
        if (!saved || busy || !saved.fresh() || token.isCancellationRequested
            || !object(saved.client.capabilities.completionProvider)
            || saved.client.capabilities.completionProvider.resolveProvider !== true) { return item; }
        const controller = new AbortController(), cancellation = token.onCancellationRequested(() => controller.abort());
        busy = true; active = controller;
        try {
            const reply = await saved.client.request('completionItem/resolve', saved.raw, controller.signal);
            if (saved.fresh() && !controller.signal.aborted && !token.isCancellationRequested && object(reply)) {

                if (typeof reply.detail === 'string') { item.detail = reply.detail.slice(0, 4096); }
                const documentation = hoverText(reply.documentation);
                if (documentation) { item.documentation = documentation; }
            }
        } catch {  }
        finally { cancellation.dispose(); release(); }
        return item;
    }

Keep only the latest document per folder and yield to foreground typing.

    async function drainBackground(): Promise<void> {
        if (disposed || busy || pending || timer || backgroundTimer || !background.size) { return; }
        const [key, document] = background.entries().next().value as [string, vscode.TextDocument];
        background.delete(key);
        const folder = vscode.workspace.getWorkspaceFolder(document.uri);
        if (!folder || !local(folder, document) || !diagnosticEnabled(document)) { return; }
        const inputs = sourceRevision, configured = servers(invalid), fingerprint = JSON.stringify(configured);
        const fresh = (): boolean => !disposed && sourceRevision === inputs && local(folder, document)
            && diagnosticEnabled(document) && JSON.stringify(servers()) === fingerprint;
        busy = true;

Capture template inputs under an input revision, not an editor-focus epoch.

        try {
            captureChanges.clear(); capturing = true;
            const { documents, templates } = await snapshot(folder); capturing = false;
            if (!fresh()) { return; }
            acceptSnapshot(folder, documents, templates);
            const paths = new Set(Object.keys(templates).map(name => path.resolve(folder.uri.fsPath, name)));
            templatePaths.set(key, paths);
            if ([...captureChanges].some(name => paths.has(name))) { invalidateInputs(); return; }
            const projected = projectLanguageSources(documents, templates);
            if (!matchesBuffers(folder, documents) || hasErrors(projected.diagnostics)) { invalidateFolder(folder); return; }

Only configured output languages may start shared sessions.

            for (const id of new Set(projected.files.map(file => language(file.language)))) {
                if (!fresh()) { break; }
                if (!configured[id]) { continue; }
                const sessionKey = JSON.stringify([key, id]);
                let session = sessions.get(sessionKey);
                if (session?.failed) { continue; }
                if (!session) {
                    session = { client: new LanguageClient({ ...configured[id], cwd: folder.uri.fsPath, rootUri: key }), failed: false };
                    sessions.set(sessionKey, session); observeSession(sessionKey, session);
                }

The diagnostics controller owns sync and asynchronous pull. Stale work cannot disable a replacement session.

                try {
                    await session.client.initialize();
                    if (!fresh()) { break; }
                    updateSignatureTriggers(session.client);
                    const wire = projected.files.filter(file => language(file.language) === id || (family(id) && family(language(file.language))))
                        .map(file => ({ uri: vscode.Uri.file(path.resolve(folder.uri.fsPath, file.path)).toString(),
                            languageId: language(file.language), text: file.content }));
                    await diagnostics.synchronize(sessionKey, session.client,
                        { root: folder.uri, files: projected.files, documents }, wire, fresh);
                } catch (error) {
                    if (sessions.get(sessionKey) === session && fresh()) {
                        session.failed = true; diagnostics.invalidate(sessionKey); close(session.client);
                        report('Language background synchronization failed: ' + errorCategory(error) + '. Restart language servers to retry.');
                    }
                }
                if (pending || waiters.size) { background.set(key, document); break; }
            }
        } catch (error) {
            if (sourceRevision === inputs) { invalidateFolder(folder); }
            if (fresh()) { reportOnce('Language background snapshot failed: ' + errorCategory(error)); }
        } finally { release(); }
    }

A stopped transport clears its diagnostics and remains disabled until restart.

    function observeSession(key: string, session: Session): void {
        session.stop = session.client.onDidStop(() => {
            if (sessions.get(key) === session && !session.failed) {
                session.failed = true; diagnostics.invalidate(key);
                report('Language server stopped. Check global literate.languageServers and run literate.restartLanguageServers to retry.');
            }
        });
    }

Learn bounded trigger and retrigger characters after initialization.

    function updateSignatureTriggers(client: LanguageClient): void {
        const provider = client.capabilities.signatureHelpProvider;
        if (!object(provider)) { return; }
        let changed = false;
        for (const values of [provider.triggerCharacters, provider.retriggerCharacters]) {
            if (!Array.isArray(values)) { continue; }
            for (const value of values.slice(0, 64)) {
                if (typeof value === 'string' && value.length === 1 && !/[\r\n]/.test(value) && !signatureTriggers.has(value)) {
                    signatureTriggers.add(value); changed = true;
                }
            }
        }
        if (changed) { registerSignature(); }
    }

The registration union is not routing authority: only the selected server's triggers may start help, and retrigger-only characters require an existing session. Native automatic callbacks also respect the resource opt-out and local body guard.

    function signatureTrigger(client: LanguageClient, character: unknown, retrigger = false): boolean {
        const provider = client.capabilities.signatureHelpProvider;
        if (!object(provider) || typeof character !== 'string') { return false; }
        const triggers = Array.isArray(provider.triggerCharacters) ? provider.triggerCharacters : ['(', ','];
        return triggers.includes(character) || (retrigger && Array.isArray(provider.retriggerCharacters)
            && provider.retriggerCharacters.includes(character));
    }

Consume prefetched signature help once; manual help shares the request gate.

    function registerSignature(): void {
        signatureRegistration?.dispose();
        signatureRegistration = vscode.languages.registerSignatureHelpProvider(selector, {
            provideSignatureHelp(document, cursor, token, signatureContext) {
                if (token.isCancellationRequested) { return; }
                if (signatureContext.triggerKind !== 1 && (!enabled(document) || !vscode.window.state.focused
                    || !localBody(document, cursor))) { return; }
                if (signatureCache && signatureCache.edit.document === document && signatureCache.edit.cursor.isEqual(cursor)
                    && current(signatureCache.edit)) { const value = signatureCache.value; cancelAutomatic(); return value; }
                return request(document, cursor, token, 'signatureHelp', undefined, {
                    triggerKind: signatureContext.triggerKind, isRetrigger: signatureContext.isRetrigger,
                    ...(signatureContext.triggerCharacter ? { triggerCharacter: signatureContext.triggerCharacter } : {})
                }) as Promise<vscode.SignatureHelp | undefined>;
            }
        }, ...signatureTriggers);
    }

Completion registration advertises no punctuation triggers; the scoped typing controller handles them. Signature registration learns server triggers at runtime. The parent retains its separate fragment provider and restricts that provider to reference-marker contexts. Snapshot paths must be workspace-relative; active buffer text must match exactly. The parent also owns the machine/restricted manifest schema and activation wiring.

    const selector: vscode.DocumentSelector = { scheme: 'file', language: 'markdown', pattern: '**/*.literate' };
    registerSignature();
    context.subscriptions.push({ dispose: () => signatureRegistration?.dispose() });
    context.subscriptions.push(vscode.languages.registerCodeActionsProvider(selector, {
        provideCodeActions(document, range, codeContext, token) {
            if (token.isCancellationRequested || codeContext.triggerKind !== vscode.CodeActionTriggerKind.Invoke) { return; }
            return request(document, range.start, token, 'codeAction', undefined,
                { range, context: codeContext }) as Promise<vscode.CodeAction[] | undefined>;
        }
    }));
    context.subscriptions.push(vscode.languages.registerDefinitionProvider(selector, {
        provideDefinition: (d, p, t) => request(d, p, t, 'definition') as Promise<vscode.Location[] | undefined>
    }), vscode.languages.registerTypeDefinitionProvider(selector, {
        provideTypeDefinition: (d, p, t) => request(d, p, t, 'typeDefinition') as Promise<vscode.Location[] | undefined>
    }), vscode.languages.registerImplementationProvider(selector, {
        provideImplementation: (d, p, t) => request(d, p, t, 'implementation') as Promise<vscode.Location[] | undefined>
    }), vscode.languages.registerReferenceProvider(selector, {
        provideReferences: (d, p, c, t) => request(d, p, t, 'references', undefined,
            { includeDeclaration: c.includeDeclaration }) as Promise<vscode.Location[] | undefined>
    }));
    for (const document of vscode.workspace.textDocuments) { scheduleBackground(document); }
    context.subscriptions.push(vscode.languages.registerHoverProvider(selector, {
        provideHover: (document, cursor, token) => request(document, cursor, token, 'hover') as Promise<vscode.Hover | undefined>
    }));
    context.subscriptions.push(vscode.languages.registerCompletionItemProvider(selector, {
        provideCompletionItems: (document, cursor, token, completionContext) => {
            if (token.isCancellationRequested) {
                if (cached?.edit.document === document && cached.edit.cursor.isEqual(cursor)) { cancelAutomatic(); }
                return undefined;
            }
            if (cached && cached.edit.document === document && cached.edit.cursor.isEqual(cursor) && current(cached.edit)) {
                const items = cached.items; cancelAutomatic(); return items;
            }
            if (completionContext.triggerKind !== vscode.CompletionTriggerKind.Invoke
                && completionContext.triggerKind !== vscode.CompletionTriggerKind.TriggerForIncompleteCompletions) { return undefined; }
            return request(document, cursor, token, 'completion', undefined, {
                triggerKind: completionContext.triggerKind === vscode.CompletionTriggerKind.TriggerForIncompleteCompletions ? 3 : 1
            }) as Promise<CompletionResult | undefined>;
        },
        resolveCompletionItem: resolveCompletion
    }));
}

Shared providers and independent diagnostics

Navigation uses the complete captured projection and safe location mapper. Signature labels and UTF-16 parameter offsets are bounded before conversion. Resolve retains raw completion data privately and copies only untrusted documentation and detail.

Background diagnostics debounce source inputs independently of editor focus. They share transport sessions and the serialization gate, yielding to queued typing. The diagnostics controller owns push versions, asynchronous pull cancellation and unversioned-report policy. Resource opt-out clears problems without disabling sync for interactive features. No generation, file writes or workspace edits occur.