Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-mcp

Model Context Protocol server for Pudu language documentation and compiler tools

0.1.1Apache-2.01

InstallClose

Conversation.md

Markdown89 lines3.0 KB

GitHub ↗

LSP conversation


type: module path: "@root/src/PuduLangMcp/Domain/Lsp/Conversation.pudu" fidelity: Active grammar: "[[grammar/pudu]]" seam: "[[seams/Toolchain]]" depth_score: 0.6 depth_status: DEEP coupling: 2 interface_stability: 0.8 tags: [module, deep] aliases: [Lsp Conversation]


Purpose

Write one complete language-server conversation for one question, and read the answer and the published diagnostics back out of everything the server wrote ([[decisions/ADR-0003-toolchain-subprocess]]).

Interface

Signatures

export type Question = { method: Str, line: Int, character: Int, newName: Str, query: Str }   // 1-based
export type Answer = { result: Option[Json.Json], diagnostics: Array[Json.Json], error: Option[Str] }

export fn conversation(rootUri: Str, uri: Str, source: Str, question: &Question) -> Str
export fn answerIn(transcript: Str) -> Answer
export fn frame(message: &Json.Json) -> Str
export fn params(uri: Str, question: &Question) -> Json.Json

Linkage

  • Requires: Std.Json, [[src/PuduLangMcp/Utils/JsonAccess]].
  • Consumed by: [[src/PuduLangMcp/Services/Lsp]].

Algorithm

conversation frames, in order: initialize (id 1, rootUri, empty capabilities), initialized, textDocument/didOpen (skipped when source is empty and the method is workspace/symbol), the question (id 2), shutdown (id 3), and exit. Each message is Content-Length: <UTF-8 bytes> then a blank line then the JSON body.

params converts the 1-based position to 0-based and adds what each method needs:

MethodExtra parameters
textDocument/hover, definition, signatureHelp, prepareRenameposition
textDocument/referencesposition, context.includeDeclaration: true
textDocument/completionposition, context.triggerKind: 1
textDocument/renameposition, newName
textDocument/codeActiona zero-width range at the position, context.diagnostics: []
textDocument/documentSymbolnone
workspace/symbolquery only, no document

answerIn cuts the transcript at each Content-Length: header; in each piece that has a blank line (Text.find), the body after it is decoded. The body with id 2 gives result (JSON null is Some(Null)) or, when it carries error, the error's message. Every textDocument/publishDiagnostics notification's diagnostics are collected, the last publication for the document winning.

Negative Logic (Prohibited Paths)

  • No body is trusted to be well formed: an undecodable piece is skipped.
  • The server is never asked two questions in one conversation.

Edge Cases

  • A transcript with no id-2 reply answers result: None, error: None (the server was stopped or never answered); the caller reports it.
  • Positions below 1 convert to 0 (Math.max(position - 1, 0)).

Depth

DEPTH 0.6 (DEEP).

Grill Log

  • Q: Cut on headers or count bytes? A: Cut on headers. JSON bodies cannot contain a raw line break, so a header never occurs inside a body, and cutting avoids byte arithmetic on text.

Referenced by

[[src/PuduLangMcp/Domain/Lsp/_MOC]]