@telorun/editor-protocol 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ # SUSTAINABLE USE LICENSE (Fair-code)
2
+
3
+ Copyright (c) 2026 CodeNet Sp. z o.o.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to use, copy, modify, and distribute the Software for any purpose—including commercial purposes—subject to the following conditions:
6
+
7
+ 1. ANTI-COMPETITION RESTRICTION: The Software may not be provided to third parties as a managed service, commercial SaaS (Software-as-a-Service), PaaS (Platform-as-a-Service), BaaS (Backend-as-a-Service), or similar offering where the primary value provided to the user is the functionality of the Software itself, without a separate commercial license from the copyright holder.
8
+
9
+ 2. PERMITTED COMMERCIAL USE: You are free to use the Software to build, host, and monetize your own commercial applications, products, and services, provided such use does not violate Clause 1.
10
+
11
+ 3. ATTRIBUTION: This copyright notice and license must be included in all copies or substantial portions of the Software.
12
+
13
+ 4. CONTRIBUTIONS: Contributions to the Software are welcome and encouraged. By contributing, you agree that your contributions may be incorporated into the Software and distributed under this license.
14
+
15
+ 5. DISCLAIMER: The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software.
16
+
17
+ For commercial licensing, managed hosting exemptions, or enterprise inquiries, please contact <contact@codenet.pl>.
package/README.md ADDED
@@ -0,0 +1,197 @@
1
+ # @telorun/editor-protocol
2
+
3
+ The contract between an **editor host** (VS Code, telo studio, any LSP client)
4
+ and a **telo language-server engine** — the part of the conversation LSP itself
5
+ does not define. An editor edits a module against one chosen telo version; that
6
+ version's engine produces every diagnostic and language feature, and the host
7
+ supplies everything the engine cannot do itself: files, imports, the hub.
8
+
9
+ This README is the specification. The TypeScript types in `src/index.ts` and
10
+ [`editor-protocol-schema.json`](./editor-protocol-schema.json) (for hosts written
11
+ in other languages) are its projections; the package has no dependencies.
12
+
13
+ ## The engine
14
+
15
+ Telo `X` publishes its engine as `@telorun/language-server@X`: one
16
+ self-contained ES module, `dist/language-server.mjs`, with no imports. Its
17
+ `package.json` declares `teloEditorProtocol`, the protocol generation the engine
18
+ speaks — a host offers only versions whose generation it speaks.
19
+
20
+ The module exports one entry:
21
+
22
+ ```ts
23
+ serve(port: { postMessage(message): void; addEventListener("message", (event) => void): void }): void
24
+ ```
25
+
26
+ `port` carries **LSP JSON-RPC message objects** (not framed text) in both
27
+ directions; the engine reads each message from `event.data`. A Web Worker scope,
28
+ a `MessagePort` and a Node `parentPort` adapted to `addEventListener` all fit.
29
+ The host loads the module into a worker, calls `serve(self)` there, and speaks
30
+ LSP to the worker.
31
+
32
+ **The engine performs no I/O of its own** — no `fetch`, no filesystem. Every
33
+ byte it reads arrives through the `telo/*` requests below, which is what lets one
34
+ build run in a browser, a desktop app and an extension host alike, and what
35
+ leaves transports, credentials, caches and integrity checks with the host.
36
+
37
+ ## Handshake
38
+
39
+ The host sends a standard `initialize`. The engine answers:
40
+
41
+ - `serverInfo: { name: "telo", version: "<identity>" }` — the engine's
42
+ **identity**. For a release build it is `X`, the telo version the engine
43
+ implements (the surface generation `requires: telo:` ranges are written
44
+ against) and exactly the version of the `@telorun/language-server` package it
45
+ was published as. A build made while that release is still pending — a
46
+ development checkout, a main-branch deployment — reports `X+unreleased`: it
47
+ implements `X` but is not the `X` that will be published, so it never shares
48
+ an identity with a published engine. A host orders identities and tests them
49
+ against `requires: telo:` intervals by semver precedence (build metadata
50
+ ignored), and tells engines apart by the whole string.
51
+ - `capabilities.experimental.telo.protocol: 1` — the generation it speaks.
52
+ - The standard capabilities it serves: full text sync, completion, hover,
53
+ definition, rename with `prepareRename`, signature help, `semanticTokens/full`
54
+ (the legend is in the capabilities), `codeAction` (quick fixes),
55
+ `codeLens`, and `workspace/executeCommand` for the commands below.
56
+
57
+ A host verifies every handshake: `serverInfo.name` is `telo`, the protocol is a
58
+ generation the host speaks, and an engine the host downloaded as version `X`
59
+ reports exactly `X`. An engine failing any of these is refused, not run.
60
+
61
+ The engine reads the client's `workspace.codeLens.refreshSupport`,
62
+ `workspace.semanticTokens.refreshSupport` and
63
+ `workspace.didChangeWatchedFiles.dynamicRegistration` capabilities; with the
64
+ last it registers a watcher for `**/*.yaml` and re-analyses what a changed file
65
+ feeds.
66
+
67
+ ## URIs
68
+
69
+ Documents are `file:` URIs; a remote module is named by its import source as
70
+ written (`oci://host/repo@1.2.0`, `https://…`). One `file:` location has many
71
+ spellings, so the protocol fixes **one canonical form** and identity is
72
+ equality of canonical forms:
73
+
74
+ - there is no query and no fragment;
75
+ - a local file has an empty authority (`file:///…`; `file://localhost/…` is the
76
+ same location), and a file on a UNC share has the share's host as its
77
+ authority, ASCII-lowercased and percent-encoded like a path segment —
78
+ `\\ServerA\share\x` is `file://servera/share/x`, and the four-slash
79
+ spelling `file:////ServerA/share/x` folds to that same form;
80
+ - the path is its UTF-8 bytes, each percent-encoded except the unreserved
81
+ characters `A–Z a–z 0–9 - . _ ~` and `/`, with uppercase hex digits —
82
+ `My Project (copy)` is `My%20Project%20%28copy%29`;
83
+ - a local Windows drive is written `/<lowercase letter>%3A/` — `C:\Users\u` is
84
+ `file:///c%3A/Users/u`; the drive rule does not apply under a UNC host.
85
+
86
+ An engine emits every `file:` URI in canonical form. A host compares URIs only
87
+ by their canonical forms — a document the editor opened under another spelling
88
+ of the same location is the same document — and does not rewrite the URIs in
89
+ the messages it passes along.
90
+
91
+ ## Host-served requests (engine → host)
92
+
93
+ A relative path is resolved against the **directory of the file** its `base`
94
+ names.
95
+
96
+ | Method | Params | Result |
97
+ | --- | --- | --- |
98
+ | `telo/read` | `{ uri }` | `{ uri, text }` — the text and the **canonical** location it was read from: a directory resolves to its `telo.yaml` (`TELO_MODULE_FILENAME`), an `oci://` tag to the reference the host resolved — or `null` when nothing exists at `uri`. |
99
+ | `telo/exists` | `{ base, relative }` | `boolean` — whether a file or directory exists there. |
100
+ | `telo/listDirectory` | `{ uri }` | `[{ name, kind }]`, or `null` when `uri` names nothing or a file. `kind` is `file`, `directory`, `symlink` or `other`, read without following links — a symbolic link is `symlink` whatever it points at. |
101
+ | `telo/hub/searchRefs` | `{ query }` | `[{ ref, latestVersion, description? }]` — refs the configured hub matches `query` against. |
102
+ | `telo/hub/listVersions` | `{ ref }` | `[{ version, integrity? }]`, newest first; `[]` for a ref the hub does not track. |
103
+
104
+ Any other failure — an unreachable registry, a hub that did not answer, a
105
+ permission error — is a **JSON-RPC error** carrying its reason, never a silent
106
+ `null`: the engine reports it (a load failure becomes a diagnostic; a failed hub
107
+ lookup is logged through `window/logMessage` and, where a user asked for it,
108
+ shown). Hub lookups feed completion and upgrade lenses only.
109
+
110
+ The engine expands `include:` globs itself, by walking `telo/listDirectory`
111
+ from the including file's directory — collecting `file` entries and descending
112
+ into `directory` ones, never through a link, as the kernel does — so a host
113
+ serves directories, never patterns, and every host matches a glob exactly as the
114
+ kernel does. `telo/read` and `telo/exists` do follow links.
115
+
116
+ Remote modules are read through `telo/read` like any document: the host owns
117
+ the transport (`oci://`, `https://`, a manifest cache) and any integrity check.
118
+ A candidate version an import upgrade considers is read as its versioned ref
119
+ (`oci://host/repo@1.3.0`).
120
+
121
+ ## `telo/requirements` (engine → host notification)
122
+
123
+ Sent after each analysis of an **owner module** — a `telo.yaml`, or a manifest
124
+ analysed standalone:
125
+
126
+ ```json
127
+ {
128
+ "owner": "file:///ws/app/telo.yaml",
129
+ "documents": ["file:///ws/app/telo.yaml", "file:///ws/app/routes.yaml"],
130
+ "ranges": [
131
+ { "module": "file:///ws/app/telo.yaml", "text": ">=0.100.0",
132
+ "interval": { "min": { "version": "0.100.0", "inclusive": true } } },
133
+ { "module": "oci://ghcr.io/telorun/sql@0.25.0", "text": ">=0.90.0 <0.120.0",
134
+ "interval": { "min": { "version": "0.90.0", "inclusive": true },
135
+ "max": { "version": "0.120.0", "inclusive": false } } }
136
+ ]
137
+ }
138
+ ```
139
+
140
+ - `owner` — the owner module's URI.
141
+ - `documents` — the owner and every partial it includes. A host routes these
142
+ documents to the engine it chose for `owner`.
143
+ - `ranges` — every `requires: telo:` range in the owner's import closure, one
144
+ per declaring module. The owner declares one exactly when an entry's `module`
145
+ equals `owner`. `interval` is the range reduced to its edges by the engine,
146
+ through the analyzer's own range reader; an absent edge is open. A host only
147
+ compares plain versions against it — it never parses a range.
148
+
149
+ A range the analyzer refuses as malformed is reported as a diagnostic and does
150
+ not appear here.
151
+
152
+ ## `Diagnostic.data`
153
+
154
+ Every diagnostic the engine publishes may carry:
155
+
156
+ ```ts
157
+ { fix?: { replacement: string; tag?: "ref" | "cel" | "module-path" },
158
+ resource?: { kind: string; name: string },
159
+ path?: string }
160
+ ```
161
+
162
+ `fix` is a mechanically applicable repair — the whole corrected value at the
163
+ diagnostic's range, written behind the YAML tag `tag` when present. A host
164
+ returns the diagnostic unchanged in a `textDocument/codeAction` request's
165
+ context, and the engine answers with the quick fix that applies it. `resource`
166
+ and `path` locate the offending value inside a manifest (a host may use them to
167
+ place a diagnostic on a form field). `Diagnostic.tags` carries LSP's
168
+ `Deprecated` / `Unnecessary`.
169
+
170
+ ## Commands
171
+
172
+ | Command | Arguments | Effect |
173
+ | --- | --- | --- |
174
+ | `telo.upgradeImport` | `[{ uri, aliases }]` | Recomputes the document's import upgrades and applies those of `aliases` through `workspace/applyEdit`. |
175
+ | `telo.upgradeAllImports` | `[{ uri, aliases }]` | Same, for every alias the summary lens named. |
176
+ | `telo.refreshImportUpgrades` | — | Drops cached version lists and verdicts, then `workspace/codeLens/refresh`. |
177
+
178
+ The engine's code lenses over an `imports:` block name the first two.
179
+
180
+ ## Generations
181
+
182
+ `TELO_EDITOR_PROTOCOL` is the generation this package describes (`1`).
183
+ **Additions within a generation are negotiated by capability**: a new request, a
184
+ new optional field or a new command is advertised by the side that has it and
185
+ used only when advertised, so an older host and a newer engine (or the reverse)
186
+ keep working. **An incompatible change bumps the generation**: a host speaking
187
+ generation `N` offers only engines whose `teloEditorProtocol` is `N`, and an
188
+ engine refuses nothing — it simply is not selected.
189
+
190
+ **A receiver must ignore what it does not know**, so that an addition within a
191
+ generation never breaks the other side: a member it does not know is ignored,
192
+ and an enumeration value it does not know is read as that enumeration's
193
+ least-capable value — a `telo/listDirectory` entry `kind` as `other` (neither
194
+ read as a file nor descended into), a `Diagnostic.data.fix.tag` as no fix
195
+ offered. `editor-protocol-schema.json` is written the same way: its objects are
196
+ open and its enumerations admit any string, so a message carrying a later
197
+ addition still validates.
@@ -0,0 +1,159 @@
1
+ /** The protocol generation this package describes. Additions within a
2
+ * generation are negotiated by capability; an incompatible change bumps it. */
3
+ export declare const TELO_EDITOR_PROTOCOL = 1;
4
+ /** What an engine advertises under `ServerCapabilities.experimental`. */
5
+ export interface TeloExperimentalCapabilities {
6
+ telo: TeloProtocolCapability;
7
+ }
8
+ export interface TeloProtocolCapability {
9
+ /** The generation the engine speaks. */
10
+ protocol: number;
11
+ }
12
+ /** The file a module directory is read as: `telo/read` of a directory answers
13
+ * with this file inside it. */
14
+ export declare const TELO_MODULE_FILENAME = "telo.yaml";
15
+ /** `initialize`'s `serverInfo.name` for every telo engine. Its
16
+ * `serverInfo.version` is the engine's identity: the telo version `X` for a
17
+ * release build, `X+unreleased` for a build made while that release is still
18
+ * pending. */
19
+ export declare const TELO_SERVER_NAME = "telo";
20
+ /** Method names of the requests an engine sends and a host serves, and of the
21
+ * notification an engine sends. */
22
+ export declare const TeloMethod: {
23
+ readonly read: "telo/read";
24
+ readonly exists: "telo/exists";
25
+ readonly listDirectory: "telo/listDirectory";
26
+ readonly hubSearchRefs: "telo/hub/searchRefs";
27
+ readonly hubListVersions: "telo/hub/listVersions";
28
+ readonly requirements: "telo/requirements";
29
+ };
30
+ export type TeloMethod = (typeof TeloMethod)[keyof typeof TeloMethod];
31
+ /** `telo/read`: the text at `uri`. `uri` is a document URI (`file:///…`) or an
32
+ * import source (`oci://host/repo@1.2.0`, `https://…`); the host reads it
33
+ * through whatever transport it owns. */
34
+ export interface ReadParams {
35
+ uri: string;
36
+ }
37
+ /** The text read, with the CANONICAL location it was read from — a directory
38
+ * resolves to its {@link TELO_MODULE_FILENAME}, an `oci://` tag to the reference the host
39
+ * resolved. `null` when nothing exists at `uri`; any other failure is a
40
+ * JSON-RPC error carrying its reason. */
41
+ export type ReadResult = {
42
+ uri: string;
43
+ text: string;
44
+ } | null;
45
+ /** `telo/exists`: whether a file or directory exists at `relative`, resolved
46
+ * against the DIRECTORY of the file `base` names. */
47
+ export interface ExistsParams {
48
+ base: string;
49
+ relative: string;
50
+ }
51
+ export type ExistsResult = boolean;
52
+ /** `telo/listDirectory`: the entries of the directory at `uri`. */
53
+ export interface ListDirectoryParams {
54
+ uri: string;
55
+ }
56
+ /** What a directory entry is, read WITHOUT following a link: a symbolic link
57
+ * is `symlink` whatever it points at. A receiver reads a kind it does not know
58
+ * as `other`. */
59
+ export type DirectoryEntryKind = "file" | "directory" | "symlink" | "other";
60
+ export interface DirectoryEntry {
61
+ name: string;
62
+ kind: DirectoryEntryKind;
63
+ }
64
+ /** `null` when `uri` names nothing or names a file. */
65
+ export type ListDirectoryResult = DirectoryEntry[] | null;
66
+ /** `telo/hub/searchRefs`: module refs the configured telo hub matches `query`
67
+ * against (a substring over every registered ref). */
68
+ export interface SearchRefsParams {
69
+ query: string;
70
+ }
71
+ export interface HubRef {
72
+ ref: string;
73
+ latestVersion: string;
74
+ description?: string;
75
+ }
76
+ export type SearchRefsResult = HubRef[];
77
+ /** `telo/hub/listVersions`: every version the hub tracks for a location ref,
78
+ * newest first, each with its import pin when the hub has one. `[]` for a ref
79
+ * the hub does not track; an unreachable hub is a JSON-RPC error. */
80
+ export interface ListVersionsParams {
81
+ ref: string;
82
+ }
83
+ export interface ModuleVersion {
84
+ version: string;
85
+ /** Canonical `sha256-<base64url>` pin. */
86
+ integrity?: string;
87
+ }
88
+ export type ListVersionsResult = ModuleVersion[];
89
+ /** Params and result of every host-served request, by method. */
90
+ export interface TeloHostRequests {
91
+ "telo/read": [ReadParams, ReadResult];
92
+ "telo/exists": [ExistsParams, ExistsResult];
93
+ "telo/listDirectory": [ListDirectoryParams, ListDirectoryResult];
94
+ "telo/hub/searchRefs": [SearchRefsParams, SearchRefsResult];
95
+ "telo/hub/listVersions": [ListVersionsParams, ListVersionsResult];
96
+ }
97
+ /** One edge of a version interval. */
98
+ export interface VersionBound {
99
+ version: string;
100
+ inclusive: boolean;
101
+ }
102
+ /** A `requires: telo:` range reduced to its edges; an absent edge is open. */
103
+ export interface VersionInterval {
104
+ min?: VersionBound;
105
+ max?: VersionBound;
106
+ }
107
+ export interface RequirementsRange {
108
+ /** URI of the module document declaring the range. */
109
+ module: string;
110
+ /** The range as written. */
111
+ text: string;
112
+ interval: VersionInterval;
113
+ }
114
+ /** `telo/requirements`: sent after each analysis of an owner module. */
115
+ export interface RequirementsParams {
116
+ /** URI of the owner module's `telo.yaml` (or standalone manifest). */
117
+ owner: string;
118
+ /** URIs of the owner's member documents — the owner and every partial it
119
+ * includes. A host routes these documents to the engine chosen for `owner`. */
120
+ documents: string[];
121
+ /** Every `requires: telo:` range in the owner's import closure. The owner
122
+ * itself declares one exactly when an entry's `module` equals `owner`. */
123
+ ranges: RequirementsRange[];
124
+ }
125
+ /** The YAML tags a repair may write. A receiver that does not know a tag
126
+ * offers no fix for it. */
127
+ export type DiagnosticFixTag = "ref" | "cel" | "module-path";
128
+ /** A mechanically applicable repair: the whole corrected value at the
129
+ * diagnostic's range, written behind `tag` when one is present. */
130
+ export interface DiagnosticFix {
131
+ replacement: string;
132
+ tag?: DiagnosticFixTag;
133
+ }
134
+ /** What an engine puts in `Diagnostic.data`. A host hands the diagnostic back
135
+ * unchanged in `codeAction`'s context, which is how a fix round-trips. */
136
+ export interface TeloDiagnosticData {
137
+ fix?: DiagnosticFix;
138
+ /** The resource the diagnostic is pinned to. */
139
+ resource?: {
140
+ kind: string;
141
+ name: string;
142
+ };
143
+ /** Dotted path of the offending value within that resource. */
144
+ path?: string;
145
+ }
146
+ /** `workspace/executeCommand` commands an engine serves. The two upgrade
147
+ * commands take `[{ uri, aliases }]` and apply through `workspace/applyEdit`;
148
+ * refresh takes no argument. */
149
+ export declare const TeloCommand: {
150
+ readonly upgradeImport: "telo.upgradeImport";
151
+ readonly upgradeAllImports: "telo.upgradeAllImports";
152
+ readonly refreshImportUpgrades: "telo.refreshImportUpgrades";
153
+ };
154
+ export type TeloCommand = (typeof TeloCommand)[keyof typeof TeloCommand];
155
+ export interface UpgradeImportsArguments {
156
+ uri: string;
157
+ aliases: string[];
158
+ }
159
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,34 @@
1
+ // The Telo editor protocol: what an editor host and a telo language-server
2
+ // engine say to each other beyond LSP itself. Zero dependencies and no runtime
3
+ // beyond constants, so a host of any telo version — and a host in any language,
4
+ // through `editor-protocol-schema.json` — can speak it. `README.md` is the spec.
5
+ /** The protocol generation this package describes. Additions within a
6
+ * generation are negotiated by capability; an incompatible change bumps it. */
7
+ export const TELO_EDITOR_PROTOCOL = 1;
8
+ /** The file a module directory is read as: `telo/read` of a directory answers
9
+ * with this file inside it. */
10
+ export const TELO_MODULE_FILENAME = "telo.yaml";
11
+ /** `initialize`'s `serverInfo.name` for every telo engine. Its
12
+ * `serverInfo.version` is the engine's identity: the telo version `X` for a
13
+ * release build, `X+unreleased` for a build made while that release is still
14
+ * pending. */
15
+ export const TELO_SERVER_NAME = "telo";
16
+ /** Method names of the requests an engine sends and a host serves, and of the
17
+ * notification an engine sends. */
18
+ export const TeloMethod = {
19
+ read: "telo/read",
20
+ exists: "telo/exists",
21
+ listDirectory: "telo/listDirectory",
22
+ hubSearchRefs: "telo/hub/searchRefs",
23
+ hubListVersions: "telo/hub/listVersions",
24
+ requirements: "telo/requirements",
25
+ };
26
+ // --- Commands --------------------------------------------------------------
27
+ /** `workspace/executeCommand` commands an engine serves. The two upgrade
28
+ * commands take `[{ uri, aliases }]` and apply through `workspace/applyEdit`;
29
+ * refresh takes no argument. */
30
+ export const TeloCommand = {
31
+ upgradeImport: "telo.upgradeImport",
32
+ upgradeAllImports: "telo.upgradeAllImports",
33
+ refreshImportUpgrades: "telo.refreshImportUpgrades",
34
+ };
@@ -0,0 +1,373 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://telo.run/schemas/editor-protocol.json",
4
+ "title": "Telo editor protocol, generation 1",
5
+ "description": "The messages an editor host and a telo language-server engine exchange beyond LSP itself. Each host-served request (engine to host) has a `<Name>Params` and a `<Name>Result` definition; `RequirementsParams` is the engine-to-host `telo/requirements` notification; `TeloDiagnosticData` is what an engine puts in `Diagnostic.data`; `ExperimentalCapabilities` is what an engine advertises under `ServerCapabilities.experimental`. `x-telo-methods` maps each method name to its definitions. Objects are open and enumerations list the values known to this generation: a receiver ignores a member it does not know and reads an unknown enumeration value as its least-capable value (README.md, Generations). See README.md for the handshake and the generation rule.",
6
+ "x-telo-methods": {
7
+ "telo/read": {
8
+ "params": "#/$defs/ReadParams",
9
+ "result": "#/$defs/ReadResult"
10
+ },
11
+ "telo/exists": {
12
+ "params": "#/$defs/ExistsParams",
13
+ "result": "#/$defs/ExistsResult"
14
+ },
15
+ "telo/listDirectory": {
16
+ "params": "#/$defs/ListDirectoryParams",
17
+ "result": "#/$defs/ListDirectoryResult"
18
+ },
19
+ "telo/hub/searchRefs": {
20
+ "params": "#/$defs/SearchRefsParams",
21
+ "result": "#/$defs/SearchRefsResult"
22
+ },
23
+ "telo/hub/listVersions": {
24
+ "params": "#/$defs/ListVersionsParams",
25
+ "result": "#/$defs/ListVersionsResult"
26
+ },
27
+ "telo/requirements": {
28
+ "params": "#/$defs/RequirementsParams"
29
+ }
30
+ },
31
+ "$defs": {
32
+ "ExperimentalCapabilities": {
33
+ "type": "object",
34
+ "required": [
35
+ "telo"
36
+ ],
37
+ "properties": {
38
+ "telo": {
39
+ "type": "object",
40
+ "required": [
41
+ "protocol"
42
+ ],
43
+ "properties": {
44
+ "protocol": {
45
+ "type": "integer",
46
+ "minimum": 1,
47
+ "description": "The protocol generation the engine speaks."
48
+ }
49
+ }
50
+ }
51
+ }
52
+ },
53
+ "ReadParams": {
54
+ "type": "object",
55
+ "required": [
56
+ "uri"
57
+ ],
58
+ "properties": {
59
+ "uri": {
60
+ "type": "string",
61
+ "description": "A document URI (`file:///…`) or an import source (`oci://…`, `https://…`)."
62
+ }
63
+ }
64
+ },
65
+ "ReadResult": {
66
+ "description": "The text and the canonical location it was read from (a directory resolves to its `telo.yaml`), or null when nothing exists at the URI.",
67
+ "oneOf": [
68
+ {
69
+ "type": "object",
70
+ "required": [
71
+ "uri",
72
+ "text"
73
+ ],
74
+ "properties": {
75
+ "uri": {
76
+ "type": "string"
77
+ },
78
+ "text": {
79
+ "type": "string"
80
+ }
81
+ }
82
+ },
83
+ {
84
+ "type": "null"
85
+ }
86
+ ]
87
+ },
88
+ "ExistsParams": {
89
+ "type": "object",
90
+ "required": [
91
+ "base",
92
+ "relative"
93
+ ],
94
+ "properties": {
95
+ "base": {
96
+ "type": "string",
97
+ "description": "URI of a file; `relative` resolves against its directory."
98
+ },
99
+ "relative": {
100
+ "type": "string"
101
+ }
102
+ }
103
+ },
104
+ "ExistsResult": {
105
+ "type": "boolean"
106
+ },
107
+ "ListDirectoryParams": {
108
+ "type": "object",
109
+ "required": [
110
+ "uri"
111
+ ],
112
+ "properties": {
113
+ "uri": {
114
+ "type": "string"
115
+ }
116
+ }
117
+ },
118
+ "DirectoryEntry": {
119
+ "type": "object",
120
+ "required": [
121
+ "name",
122
+ "kind"
123
+ ],
124
+ "properties": {
125
+ "name": {
126
+ "type": "string"
127
+ },
128
+ "kind": {
129
+ "description": "What the entry is, read without following a link: a symbolic link is `symlink` whatever it points at. A receiver reads a kind it does not know as `other`.",
130
+ "anyOf": [
131
+ {
132
+ "enum": [
133
+ "file",
134
+ "directory",
135
+ "symlink",
136
+ "other"
137
+ ]
138
+ },
139
+ {
140
+ "type": "string"
141
+ }
142
+ ]
143
+ }
144
+ }
145
+ },
146
+ "ListDirectoryResult": {
147
+ "description": "The entries, or null when the URI names nothing or names a file.",
148
+ "oneOf": [
149
+ {
150
+ "type": "array",
151
+ "items": {
152
+ "$ref": "#/$defs/DirectoryEntry"
153
+ }
154
+ },
155
+ {
156
+ "type": "null"
157
+ }
158
+ ]
159
+ },
160
+ "SearchRefsParams": {
161
+ "type": "object",
162
+ "required": [
163
+ "query"
164
+ ],
165
+ "properties": {
166
+ "query": {
167
+ "type": "string"
168
+ }
169
+ }
170
+ },
171
+ "HubRef": {
172
+ "type": "object",
173
+ "required": [
174
+ "ref",
175
+ "latestVersion"
176
+ ],
177
+ "properties": {
178
+ "ref": {
179
+ "type": "string"
180
+ },
181
+ "latestVersion": {
182
+ "type": "string"
183
+ },
184
+ "description": {
185
+ "type": "string"
186
+ }
187
+ }
188
+ },
189
+ "SearchRefsResult": {
190
+ "type": "array",
191
+ "items": {
192
+ "$ref": "#/$defs/HubRef"
193
+ }
194
+ },
195
+ "ListVersionsParams": {
196
+ "type": "object",
197
+ "required": [
198
+ "ref"
199
+ ],
200
+ "properties": {
201
+ "ref": {
202
+ "type": "string"
203
+ }
204
+ }
205
+ },
206
+ "ModuleVersion": {
207
+ "type": "object",
208
+ "required": [
209
+ "version"
210
+ ],
211
+ "properties": {
212
+ "version": {
213
+ "type": "string"
214
+ },
215
+ "integrity": {
216
+ "type": "string",
217
+ "pattern": "^sha256-[A-Za-z0-9_-]{43}$",
218
+ "description": "Canonical import pin: `sha256-` and 43 base64url characters."
219
+ }
220
+ }
221
+ },
222
+ "ListVersionsResult": {
223
+ "description": "Newest first; empty for a ref the hub does not track.",
224
+ "type": "array",
225
+ "items": {
226
+ "$ref": "#/$defs/ModuleVersion"
227
+ }
228
+ },
229
+ "VersionBound": {
230
+ "type": "object",
231
+ "required": [
232
+ "version",
233
+ "inclusive"
234
+ ],
235
+ "properties": {
236
+ "version": {
237
+ "type": "string"
238
+ },
239
+ "inclusive": {
240
+ "type": "boolean"
241
+ }
242
+ }
243
+ },
244
+ "VersionInterval": {
245
+ "description": "A `requires: telo:` range reduced to its edges; an absent edge is open.",
246
+ "type": "object",
247
+ "properties": {
248
+ "min": {
249
+ "$ref": "#/$defs/VersionBound"
250
+ },
251
+ "max": {
252
+ "$ref": "#/$defs/VersionBound"
253
+ }
254
+ }
255
+ },
256
+ "RequirementsRange": {
257
+ "type": "object",
258
+ "required": [
259
+ "module",
260
+ "text",
261
+ "interval"
262
+ ],
263
+ "properties": {
264
+ "module": {
265
+ "type": "string",
266
+ "description": "URI of the module document declaring the range."
267
+ },
268
+ "text": {
269
+ "type": "string",
270
+ "description": "The range as written."
271
+ },
272
+ "interval": {
273
+ "$ref": "#/$defs/VersionInterval"
274
+ }
275
+ }
276
+ },
277
+ "RequirementsParams": {
278
+ "type": "object",
279
+ "required": [
280
+ "owner",
281
+ "documents",
282
+ "ranges"
283
+ ],
284
+ "properties": {
285
+ "owner": {
286
+ "type": "string"
287
+ },
288
+ "documents": {
289
+ "type": "array",
290
+ "items": {
291
+ "type": "string"
292
+ }
293
+ },
294
+ "ranges": {
295
+ "type": "array",
296
+ "items": {
297
+ "$ref": "#/$defs/RequirementsRange"
298
+ }
299
+ }
300
+ }
301
+ },
302
+ "DiagnosticFix": {
303
+ "type": "object",
304
+ "required": [
305
+ "replacement"
306
+ ],
307
+ "properties": {
308
+ "replacement": {
309
+ "type": "string"
310
+ },
311
+ "tag": {
312
+ "description": "The YAML tag the replacement is written behind. A receiver that does not know a tag offers no fix for it.",
313
+ "anyOf": [
314
+ {
315
+ "enum": [
316
+ "ref",
317
+ "cel",
318
+ "module-path"
319
+ ]
320
+ },
321
+ {
322
+ "type": "string"
323
+ }
324
+ ]
325
+ }
326
+ }
327
+ },
328
+ "TeloDiagnosticData": {
329
+ "type": "object",
330
+ "properties": {
331
+ "fix": {
332
+ "$ref": "#/$defs/DiagnosticFix"
333
+ },
334
+ "resource": {
335
+ "type": "object",
336
+ "required": [
337
+ "kind",
338
+ "name"
339
+ ],
340
+ "properties": {
341
+ "kind": {
342
+ "type": "string"
343
+ },
344
+ "name": {
345
+ "type": "string"
346
+ }
347
+ }
348
+ },
349
+ "path": {
350
+ "type": "string"
351
+ }
352
+ }
353
+ },
354
+ "UpgradeImportsArguments": {
355
+ "type": "object",
356
+ "required": [
357
+ "uri",
358
+ "aliases"
359
+ ],
360
+ "properties": {
361
+ "uri": {
362
+ "type": "string"
363
+ },
364
+ "aliases": {
365
+ "type": "array",
366
+ "items": {
367
+ "type": "string"
368
+ }
369
+ }
370
+ }
371
+ }
372
+ }
373
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@telorun/editor-protocol",
3
+ "version": "0.1.0",
4
+ "description": "The Telo editor protocol: the contract between an editor host and a telo language-server engine — the telo/* requests, the telo/requirements notification and the protocol generation.",
5
+ "keywords": [
6
+ "telo",
7
+ "lsp",
8
+ "language-server",
9
+ "editor",
10
+ "protocol"
11
+ ],
12
+ "author": "Bartosz Pasiński <bartosz.pasinski@codenet.pl>",
13
+ "license": "SEE LICENSE IN LICENSE",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/telorun/telo.git",
17
+ "directory": "packages/editor-protocol"
18
+ },
19
+ "homepage": "https://github.com/telorun/telo#readme",
20
+ "bugs": {
21
+ "url": "https://github.com/telorun/telo/issues"
22
+ },
23
+ "type": "module",
24
+ "main": "./dist/index.js",
25
+ "exports": {
26
+ ".": {
27
+ "source": "./src/index.ts",
28
+ "types": "./dist/index.d.ts",
29
+ "bun": "./src/index.ts",
30
+ "import": "./dist/index.js",
31
+ "default": "./dist/index.js"
32
+ },
33
+ "./editor-protocol-schema.json": "./editor-protocol-schema.json",
34
+ "./package.json": "./package.json"
35
+ },
36
+ "files": [
37
+ "dist/**",
38
+ "src/**",
39
+ "editor-protocol-schema.json"
40
+ ],
41
+ "devDependencies": {
42
+ "ajv": "^8.17.1",
43
+ "typescript": "^5.0.0",
44
+ "vitest": "^2.1.8"
45
+ },
46
+ "scripts": {
47
+ "build": "tsc -p tsconfig.lib.json",
48
+ "test": "vitest run"
49
+ }
50
+ }
package/src/index.ts ADDED
@@ -0,0 +1,186 @@
1
+ // The Telo editor protocol: what an editor host and a telo language-server
2
+ // engine say to each other beyond LSP itself. Zero dependencies and no runtime
3
+ // beyond constants, so a host of any telo version — and a host in any language,
4
+ // through `editor-protocol-schema.json` — can speak it. `README.md` is the spec.
5
+
6
+ /** The protocol generation this package describes. Additions within a
7
+ * generation are negotiated by capability; an incompatible change bumps it. */
8
+ export const TELO_EDITOR_PROTOCOL = 1;
9
+
10
+ /** What an engine advertises under `ServerCapabilities.experimental`. */
11
+ export interface TeloExperimentalCapabilities {
12
+ telo: TeloProtocolCapability;
13
+ }
14
+
15
+ export interface TeloProtocolCapability {
16
+ /** The generation the engine speaks. */
17
+ protocol: number;
18
+ }
19
+
20
+ /** The file a module directory is read as: `telo/read` of a directory answers
21
+ * with this file inside it. */
22
+ export const TELO_MODULE_FILENAME = "telo.yaml";
23
+
24
+ /** `initialize`'s `serverInfo.name` for every telo engine. Its
25
+ * `serverInfo.version` is the engine's identity: the telo version `X` for a
26
+ * release build, `X+unreleased` for a build made while that release is still
27
+ * pending. */
28
+ export const TELO_SERVER_NAME = "telo";
29
+
30
+ /** Method names of the requests an engine sends and a host serves, and of the
31
+ * notification an engine sends. */
32
+ export const TeloMethod = {
33
+ read: "telo/read",
34
+ exists: "telo/exists",
35
+ listDirectory: "telo/listDirectory",
36
+ hubSearchRefs: "telo/hub/searchRefs",
37
+ hubListVersions: "telo/hub/listVersions",
38
+ requirements: "telo/requirements",
39
+ } as const;
40
+ export type TeloMethod = (typeof TeloMethod)[keyof typeof TeloMethod];
41
+
42
+ // --- Host-served requests (engine → host) ---------------------------------
43
+
44
+ /** `telo/read`: the text at `uri`. `uri` is a document URI (`file:///…`) or an
45
+ * import source (`oci://host/repo@1.2.0`, `https://…`); the host reads it
46
+ * through whatever transport it owns. */
47
+ export interface ReadParams {
48
+ uri: string;
49
+ }
50
+
51
+ /** The text read, with the CANONICAL location it was read from — a directory
52
+ * resolves to its {@link TELO_MODULE_FILENAME}, an `oci://` tag to the reference the host
53
+ * resolved. `null` when nothing exists at `uri`; any other failure is a
54
+ * JSON-RPC error carrying its reason. */
55
+ export type ReadResult = { uri: string; text: string } | null;
56
+
57
+ /** `telo/exists`: whether a file or directory exists at `relative`, resolved
58
+ * against the DIRECTORY of the file `base` names. */
59
+ export interface ExistsParams {
60
+ base: string;
61
+ relative: string;
62
+ }
63
+ export type ExistsResult = boolean;
64
+
65
+ /** `telo/listDirectory`: the entries of the directory at `uri`. */
66
+ export interface ListDirectoryParams {
67
+ uri: string;
68
+ }
69
+ /** What a directory entry is, read WITHOUT following a link: a symbolic link
70
+ * is `symlink` whatever it points at. A receiver reads a kind it does not know
71
+ * as `other`. */
72
+ export type DirectoryEntryKind = "file" | "directory" | "symlink" | "other";
73
+ export interface DirectoryEntry {
74
+ name: string;
75
+ kind: DirectoryEntryKind;
76
+ }
77
+ /** `null` when `uri` names nothing or names a file. */
78
+ export type ListDirectoryResult = DirectoryEntry[] | null;
79
+
80
+ /** `telo/hub/searchRefs`: module refs the configured telo hub matches `query`
81
+ * against (a substring over every registered ref). */
82
+ export interface SearchRefsParams {
83
+ query: string;
84
+ }
85
+ export interface HubRef {
86
+ ref: string;
87
+ latestVersion: string;
88
+ description?: string;
89
+ }
90
+ export type SearchRefsResult = HubRef[];
91
+
92
+ /** `telo/hub/listVersions`: every version the hub tracks for a location ref,
93
+ * newest first, each with its import pin when the hub has one. `[]` for a ref
94
+ * the hub does not track; an unreachable hub is a JSON-RPC error. */
95
+ export interface ListVersionsParams {
96
+ ref: string;
97
+ }
98
+ export interface ModuleVersion {
99
+ version: string;
100
+ /** Canonical `sha256-<base64url>` pin. */
101
+ integrity?: string;
102
+ }
103
+ export type ListVersionsResult = ModuleVersion[];
104
+
105
+ /** Params and result of every host-served request, by method. */
106
+ export interface TeloHostRequests {
107
+ "telo/read": [ReadParams, ReadResult];
108
+ "telo/exists": [ExistsParams, ExistsResult];
109
+ "telo/listDirectory": [ListDirectoryParams, ListDirectoryResult];
110
+ "telo/hub/searchRefs": [SearchRefsParams, SearchRefsResult];
111
+ "telo/hub/listVersions": [ListVersionsParams, ListVersionsResult];
112
+ }
113
+
114
+ // --- Engine → host notification -------------------------------------------
115
+
116
+ /** One edge of a version interval. */
117
+ export interface VersionBound {
118
+ version: string;
119
+ inclusive: boolean;
120
+ }
121
+
122
+ /** A `requires: telo:` range reduced to its edges; an absent edge is open. */
123
+ export interface VersionInterval {
124
+ min?: VersionBound;
125
+ max?: VersionBound;
126
+ }
127
+
128
+ export interface RequirementsRange {
129
+ /** URI of the module document declaring the range. */
130
+ module: string;
131
+ /** The range as written. */
132
+ text: string;
133
+ interval: VersionInterval;
134
+ }
135
+
136
+ /** `telo/requirements`: sent after each analysis of an owner module. */
137
+ export interface RequirementsParams {
138
+ /** URI of the owner module's `telo.yaml` (or standalone manifest). */
139
+ owner: string;
140
+ /** URIs of the owner's member documents — the owner and every partial it
141
+ * includes. A host routes these documents to the engine chosen for `owner`. */
142
+ documents: string[];
143
+ /** Every `requires: telo:` range in the owner's import closure. The owner
144
+ * itself declares one exactly when an entry's `module` equals `owner`. */
145
+ ranges: RequirementsRange[];
146
+ }
147
+
148
+ // --- Diagnostic.data -------------------------------------------------------
149
+
150
+ /** The YAML tags a repair may write. A receiver that does not know a tag
151
+ * offers no fix for it. */
152
+ export type DiagnosticFixTag = "ref" | "cel" | "module-path";
153
+
154
+ /** A mechanically applicable repair: the whole corrected value at the
155
+ * diagnostic's range, written behind `tag` when one is present. */
156
+ export interface DiagnosticFix {
157
+ replacement: string;
158
+ tag?: DiagnosticFixTag;
159
+ }
160
+
161
+ /** What an engine puts in `Diagnostic.data`. A host hands the diagnostic back
162
+ * unchanged in `codeAction`'s context, which is how a fix round-trips. */
163
+ export interface TeloDiagnosticData {
164
+ fix?: DiagnosticFix;
165
+ /** The resource the diagnostic is pinned to. */
166
+ resource?: { kind: string; name: string };
167
+ /** Dotted path of the offending value within that resource. */
168
+ path?: string;
169
+ }
170
+
171
+ // --- Commands --------------------------------------------------------------
172
+
173
+ /** `workspace/executeCommand` commands an engine serves. The two upgrade
174
+ * commands take `[{ uri, aliases }]` and apply through `workspace/applyEdit`;
175
+ * refresh takes no argument. */
176
+ export const TeloCommand = {
177
+ upgradeImport: "telo.upgradeImport",
178
+ upgradeAllImports: "telo.upgradeAllImports",
179
+ refreshImportUpgrades: "telo.refreshImportUpgrades",
180
+ } as const;
181
+ export type TeloCommand = (typeof TeloCommand)[keyof typeof TeloCommand];
182
+
183
+ export interface UpgradeImportsArguments {
184
+ uri: string;
185
+ aliases: string[];
186
+ }