@deepseek-ai/dsh-lsp-stdio 0.0.1-rc.5

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.
@@ -0,0 +1,23 @@
1
+ //#region lib/types/invariant.js
2
+ /**
3
+ * Package-owned invariant companion for `@deepseek-ai/dsh-lsp-stdio`.
4
+ * @module @deepseek-ai/dsh-lsp-stdio/invariant
5
+ */
6
+ const PACKAGE_NAME = "@deepseek-ai/dsh-lsp-stdio";
7
+ /** Cordis companion plugin name. */
8
+ const name = "lsp-stdio-invariant";
9
+ /** Service required before the companion can reserve package ownership. */
10
+ const inject = ["invariants"];
11
+ /**
12
+ * No runtime invariant: process pools and per-workspace queues are private implementation state,
13
+ * and this provider publishes no independent lifecycle event stream or enumerable snapshot.
14
+ */
15
+ const install = () => {};
16
+ /**
17
+ * Register this package's invariant companion.
18
+ * @param ctx - Cordis context carrying the invariant service.
19
+ * @returns the installed registration's disposer after setup succeeds.
20
+ */
21
+ const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
22
+ //#endregion
23
+ export { apply, inject, name };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Shared cancellation helpers for the local LSP provider's host-I/O, queue, and protocol phases.
3
+ * @module @deepseek-ai/dsh-lsp-stdio/abort
4
+ */
5
+ /**
6
+ * Build an abort Error carrying the signal's reason and preserving timeout classification.
7
+ * @param signal - the aborted signal whose reason to surface.
8
+ * @returns the timeout reason if present, else the Error reason, else a generic aborted Error.
9
+ */
10
+ export declare function abortError(signal: AbortSignal): Error;
11
+ /**
12
+ * Throw the signal's classified abort error when it has already fired.
13
+ * @param signal - the optional query cancellation signal.
14
+ */
15
+ export declare function throwIfAborted(signal?: AbortSignal): void;
16
+ /**
17
+ * Await work while allowing a query signal to abandon its wait; the underlying work keeps its own
18
+ * handlers and continues to its owner-defined quiescence boundary.
19
+ * @param work - the owned asynchronous work.
20
+ * @param signal - optional query cancellation.
21
+ * @returns the work result, or a rejection carrying the classified abort reason.
22
+ */
23
+ export declare function abortable<T>(work: Promise<T>, signal?: AbortSignal): Promise<T>;
24
+ //# sourceMappingURL=abort.d.ts.map
@@ -0,0 +1,119 @@
1
+ /**
2
+ * A JSON-RPC endpoint over one language server spawned through the subprocess
3
+ * capability. Owns id correlation, outbound requests/notifications, and inbound
4
+ * server→client requests: it answers `workspace/configuration` from static
5
+ * config, and rejects `workspace/applyEdit` (this host never applies edits or
6
+ * runs commands). It caps stderr, surfaces framing/decoder failures as a
7
+ * fatal close, and exposes tree-scoped termination through the handle so the
8
+ * instance owns teardown; group/tree mechanics live in the subprocess
9
+ * Service provider.
10
+ * @module @deepseek-ai/dsh-lsp-stdio/connection
11
+ */
12
+ import type { Writable } from 'node:stream';
13
+ import type { SubprocessHandle, SubprocessSpawnSpec } from '@deepseek-ai/dsh-subprocess';
14
+ /** How to launch the server and answer its config requests. */
15
+ export interface ConnectionSpec {
16
+ /** The resolved absolute executable path (no shell). */
17
+ readonly command: string;
18
+ /** Arguments passed to the executable. */
19
+ readonly args: readonly string[];
20
+ /** The child's working directory (the canonical workspace). */
21
+ readonly cwd: string;
22
+ /** Explicit child environment overrides; the subprocess provider owns its ambient scrub. */
23
+ readonly env: Record<string, string>;
24
+ /** Largest single framed message accepted from the server. */
25
+ readonly maxMessageBytes: number;
26
+ /** Largest stderr tail retained for diagnostics. */
27
+ readonly maxStderrBytes: number;
28
+ /**
29
+ * The subprocess spec's `graceMs`: the SIGTERM→SIGKILL window of
30
+ * {@link LspConnection.terminate}'s escalation, and the bound for draining
31
+ * pipes a surviving helper still holds after the server exits.
32
+ */
33
+ readonly killGraceMs: number;
34
+ /** Static answer to every `workspace/configuration` item. */
35
+ readonly configuration: unknown;
36
+ }
37
+ /**
38
+ * Write one JSON-RPC message to the child stdin.
39
+ * @param stdin - the spawned server stdin.
40
+ * @param message - the unencoded JSON-RPC message.
41
+ * @param done - callback that reports asynchronous stream settlement.
42
+ */
43
+ export type ConnectionWriter = (stdin: Writable, message: unknown, done: (error?: Error | null) => void) => void;
44
+ /** Spawn one subprocess for this connection (the provider passes `ctx.subprocess.spawn`). */
45
+ export type ConnectionSpawner = (spec: SubprocessSpawnSpec) => SubprocessHandle;
46
+ /** A live JSON-RPC endpoint bound to one child process. */
47
+ export declare class LspConnection {
48
+ private readonly onServerRequest;
49
+ private readonly writer;
50
+ private readonly handle;
51
+ private readonly stdin;
52
+ private readonly decoder;
53
+ private readonly pending;
54
+ private nextId;
55
+ private closeReason;
56
+ /** Set once the process has fully exited; the instance awaits it during teardown. */
57
+ readonly closed: Promise<void>;
58
+ /**
59
+ * @param spec - how to launch the server and answer its config requests.
60
+ * @param spawner - the subprocess seam's spawn (the provider passes `ctx.subprocess.spawn`).
61
+ * @param onServerRequest - answers a server→client request; rejects to send an error response.
62
+ * @param writer - message writer; tests inject callback failures without relying on OS pipe races.
63
+ */
64
+ constructor(spec: ConnectionSpec, spawner: ConnectionSpawner, onServerRequest: (method: string, params: unknown) => Promise<unknown>, writer?: ConnectionWriter);
65
+ /** The child's pid, or `-1` when the spawn produced no pid (so signalling is a no-op). */
66
+ get pid(): number;
67
+ /** The retained stderr tail, for diagnostics on a failed server. */
68
+ get stderrTail(): string;
69
+ /** Whether the transport has failed even if the child close event has not arrived yet. */
70
+ get failed(): boolean;
71
+ /**
72
+ * Test whether a caught error is this connection's retained fatal transport cause.
73
+ * @param error - error caught by the instance or provider.
74
+ * @returns `true` only when this connection produced that exact failure.
75
+ */
76
+ failedWith(error: unknown): boolean;
77
+ /**
78
+ * Send a request and await its result.
79
+ * @param method - the JSON-RPC method.
80
+ * @param params - the request params.
81
+ * @returns the response result; rejects on an error response, write failure, or close.
82
+ */
83
+ request(method: string, params: unknown): Promise<unknown>;
84
+ /**
85
+ * Send a notification (no id, no response).
86
+ * @param method - the JSON-RPC method.
87
+ * @param params - the notification params.
88
+ * @returns a promise that settles when the framed notification has been written.
89
+ */
90
+ notify(method: string, params: unknown): Promise<void>;
91
+ /**
92
+ * Send a `$/cancelRequest` for an in-flight request id (best-effort; ignores write failure).
93
+ * @param requestId - the numeric id of the request to cancel.
94
+ */
95
+ cancel(requestId: number): void;
96
+ /**
97
+ * The id the NEXT `request()` will use, so the instance can pre-arm a cancel.
98
+ * @returns the numeric id the next request will be assigned.
99
+ */
100
+ peekNextId(): number;
101
+ /** Terminate the server's process tree (the seam's SIGTERM→grace→SIGKILL escalation; idempotent). */
102
+ terminate(): void;
103
+ /**
104
+ * Wait until the owned process tree has exited.
105
+ * @param signal - optional bound for the wait.
106
+ * @returns `true` when the tree exited, or `false` when the signal aborted first.
107
+ */
108
+ waitForProcessTreeExit(signal?: AbortSignal): Promise<boolean>;
109
+ private onStdout;
110
+ private dispatch;
111
+ private handleServerRequest;
112
+ private handleResponse;
113
+ private write;
114
+ /** The exit-close error message, appending the retained stderr tail when the server wrote any. */
115
+ private exitMessage;
116
+ private fail;
117
+ private failAll;
118
+ }
119
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1,35 @@
1
+ /**
2
+ * LSP base-protocol framing: `Content-Length`-delimited JSON-RPC over a byte stream. The encoder
3
+ * produces one framed buffer; the decoder buffers incoming bytes and yields complete message bodies,
4
+ * bounding the header and total message size so a hostile or broken server cannot exhaust memory.
5
+ * @module @deepseek-ai/dsh-lsp-stdio/framing
6
+ */
7
+ /**
8
+ * Encode one JSON-RPC message as a framed LSP buffer (`Content-Length: N\r\n\r\n<utf-8 json>`).
9
+ * @param message - the JSON-RPC message object to serialize.
10
+ * @returns the framed bytes ready to write to the server's stdin.
11
+ */
12
+ export declare function encodeMessage(message: unknown): Buffer;
13
+ /**
14
+ * A streaming decoder for `Content-Length`-framed JSON-RPC. Feed it stdout chunks; it returns any
15
+ * whole message bodies that completed. It parses only the `Content-Length` header and ignores other
16
+ * headers (e.g. `Content-Type`), matching the base protocol.
17
+ */
18
+ export declare class MessageDecoder {
19
+ private buffer;
20
+ private readonly maxMessageBytes;
21
+ /**
22
+ * @param maxMessageBytes - reject any single framed body larger than this (guards memory).
23
+ */
24
+ constructor(maxMessageBytes: number);
25
+ /**
26
+ * Append a chunk and return every message body that is now complete.
27
+ * @param chunk - raw bytes from the server's stdout.
28
+ * @returns the parsed JSON bodies, in arrival order (possibly empty).
29
+ * @throws Error when a header is malformed or a body exceeds `maxMessageBytes`.
30
+ */
31
+ push(chunk: Buffer): unknown[];
32
+ /** Parse and consume the next complete message, or report that more bytes are needed. */
33
+ private next;
34
+ }
35
+ //# sourceMappingURL=framing.d.ts.map
@@ -0,0 +1,39 @@
1
+ /** Filesystem-seam source access for the generic stdio LSP provider. */
2
+ import type { FileSystem, FsTarget } from '@deepseek-ai/dsh-fs';
3
+ /** A canonical workspace in the filesystem/subprocess execution world. */
4
+ export interface HostWorkspace {
5
+ /** Stable filesystem identity used for provider pooling. */
6
+ readonly target: FsTarget;
7
+ /** Canonical absolute path accepted as a subprocess cwd. */
8
+ readonly canonicalPath: string;
9
+ /** Canonical file URI sent during LSP initialization. */
10
+ readonly fileUrl: string;
11
+ }
12
+ /** A validated source and the exact URI sent to the language server. */
13
+ export interface HostSource {
14
+ /** Canonical file URI in the execution world's platform syntax. */
15
+ readonly fileUrl: string;
16
+ /** Current complete UTF-8 text. */
17
+ readonly text: string;
18
+ }
19
+ /**
20
+ * Resolve and validate one workspace through `ctx.fs`.
21
+ * @param fs - filesystem provider sharing the language server's execution world.
22
+ * @param workspaceRoot - caller-supplied workspace path.
23
+ * @param signal - optional cancellation around provider operations.
24
+ * @returns stable identity plus process path and file URI.
25
+ */
26
+ export declare function canonicalizeWorkspace(fs: FileSystem, workspaceRoot: string, signal?: AbortSignal): Promise<HostWorkspace>;
27
+ /**
28
+ * Resolve, contain, and read one byte-bounded query source through `ctx.fs`.
29
+ * This layer owns the LSP-specific complete-document cap while the filesystem
30
+ * provider owns streaming, regular-file checks, and UTF-8 validation.
31
+ * @param fs - filesystem provider sharing the server's execution world.
32
+ * @param filePath - absolute source path or path relative to `workspace`.
33
+ * @param workspace - already-canonical workspace.
34
+ * @param maxDocumentBytes - largest complete source accepted by this host.
35
+ * @param signal - optional cancellation.
36
+ * @returns canonical file URI and current text.
37
+ */
38
+ export declare function readHostSource(fs: FileSystem, filePath: string, workspace: HostWorkspace, maxDocumentBytes: number, signal?: AbortSignal): Promise<HostSource>;
39
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Generic stdio language-server backend for `ctx.lsp`. One plugin instance configures a named table
3
+ * of server commands and registers one isolated provider for each entry. Every provider lazily
4
+ * single-flights one server process per canonical workspace target, serves transient-open queries
5
+ * through it, and replaces a selected transport that fails before or during the next read-only
6
+ * query. Providers read sources through `ctx.fs` and launch servers through
7
+ * `ctx.subprocess`, so both local and remote implementations share one host.
8
+ *
9
+ * Namespace plugin (named exports, no default export). Lifecycle is effect-scoped: disposal
10
+ * unregisters from `ctx.lsp` and tears down every live server.
11
+ * @module @deepseek-ai/dsh-lsp-stdio
12
+ */
13
+ import type { Context } from '@deepseek-ai/cordis';
14
+ import z from '@deepseek-ai/schemastery';
15
+ export { canonicalizeWorkspace, readHostSource } from './host.ts';
16
+ export { encodeMessage, MessageDecoder } from './framing.ts';
17
+ export { negotiatePositionEncoding, normalizeHover, normalizeLocations, requestMethod, supportsOperation, supportsTransientOpen, } from './translate.ts';
18
+ export { LspInstance } from './instance.ts';
19
+ export { LspConnection } from './connection.ts';
20
+ /** Cordis plugin name for loader diagnostics. */
21
+ export declare const name = "lsp-stdio";
22
+ /** Services required by this plugin. */
23
+ export declare const inject: string[];
24
+ /** One configured local language server and its host bounds. */
25
+ export interface LspLocalServerConfig {
26
+ /** Executable to spawn (absolute, or resolved on PATH at load). */
27
+ command: string;
28
+ /** Lowercase leading-dot extension → LSP language id (e.g. `{ '.ts': 'typescript' }`). */
29
+ extensionToLanguage: Record<string, string>;
30
+ /** Arguments passed to the executable (no shell). Default `[]`. */
31
+ args?: string[];
32
+ /** Extra env vars merged on top of the scrubbed ambient env. Default `{}`. */
33
+ env?: Record<string, string>;
34
+ /** Static `initialize` options forwarded to the server. Default `null`. */
35
+ initializationOptions?: unknown;
36
+ /** Static answer to every `workspace/configuration` item. Default `null`. */
37
+ configuration?: unknown;
38
+ /** Largest single framed message accepted from the server (bytes). Default 16000000. */
39
+ maxMessageBytes?: number;
40
+ /** Largest stderr tail retained for diagnostics (bytes). Default 1000000. */
41
+ maxStderrBytes?: number;
42
+ /** Largest source file this host will open (bytes). Default 4000000. */
43
+ maxDocumentBytes?: number;
44
+ /** Graceful `shutdown`/`exit` budget before escalation (ms). Default 5000. */
45
+ shutdownTimeoutMs?: number;
46
+ /** Request-cancel and SIGTERM→SIGKILL grace (ms). Default 2000. */
47
+ killGraceMs?: number;
48
+ }
49
+ /** Plugin configuration: provider id → local language-server configuration. */
50
+ export interface Config {
51
+ /** Non-empty table of stable provider ids to independent local server configurations. */
52
+ servers: Record<string, LspLocalServerConfig>;
53
+ }
54
+ export declare const Config: z<Config>;
55
+ /**
56
+ * Register the configured stdio LSP providers. Resolves every executable at load (after credential
57
+ * scrubbing) before publishing any provider; each process launches lazily on its first matching
58
+ * query.
59
+ * @param ctx - the plugin context carrying `fs`, `lsp`, and `subprocess`.
60
+ * @param config - the resolved plugin configuration (schemastery has filled every default).
61
+ */
62
+ export declare function apply(ctx: Context, config: Config): Promise<void>;
63
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,89 @@
1
+ /**
2
+ * One language-server instance: a connection plus the initialize handshake, the serialized abortable
3
+ * query queue, the transient `didOpen`→request→`didClose` lifecycle, and bounded teardown. One
4
+ * instance owns one `(provider id, canonical workspace)` process. Queries serialize through a single
5
+ * queue so a cancellation that fails to stop the server can terminate it without killing unrelated
6
+ * work; distinct instances run in parallel.
7
+ * @module @deepseek-ai/dsh-lsp-stdio/instance
8
+ */
9
+ import type { LspProviderQuery, LspQueryResult } from '@deepseek-ai/dsh-lsp';
10
+ import type { ConnectionSpawner, ConnectionSpec, ConnectionWriter } from './connection.ts';
11
+ import type { HostSource } from './host.ts';
12
+ /** Everything an instance needs beyond the connection spec. */
13
+ export interface InstanceSpec extends ConnectionSpec {
14
+ /** Canonical workspace file URI supplied by the filesystem provider. */
15
+ readonly workspaceUri: string;
16
+ /** Static `initialize` options forwarded to the server. */
17
+ readonly initializationOptions: unknown;
18
+ /** Graceful `shutdown`/`exit` budget before escalation (ms). */
19
+ readonly shutdownTimeoutMs: number;
20
+ }
21
+ /**
22
+ * A single initialized server process. Not exported as a provider — the provider single-flights and
23
+ * pools these. `query()` serializes; `dispose()` rejects queued work and tears the process down.
24
+ */
25
+ export declare class LspInstance {
26
+ private readonly spec;
27
+ private readonly connection;
28
+ private capabilities;
29
+ /** The serialization tail: each query awaits the prior one, so lifecycles never interleave. */
30
+ private queue;
31
+ private disposed;
32
+ /** The one teardown transaction shared by abort, failure, and explicit disposal. */
33
+ private teardownPromise;
34
+ /** Set once the process closes, so the pool can synchronously skip a dead instance. */
35
+ private processClosed;
36
+ /** Populated once `initialize` succeeds; a failed handshake rejects every query. */
37
+ private readonly ready;
38
+ /**
39
+ * @param spec - the launch, initialize, and teardown parameters.
40
+ * @param spawner - the subprocess seam's spawn function.
41
+ * @param writer - optional connection writer used by transport conformance tests.
42
+ */
43
+ constructor(spec: InstanceSpec, spawner: ConnectionSpawner, writer?: ConnectionWriter);
44
+ /** Synchronous liveness check: true once the process has closed or the instance was disposed. */
45
+ get dead(): boolean;
46
+ /**
47
+ * Test whether a caught query error came from this instance's transport.
48
+ * @param error - error caught by the provider.
49
+ * @returns `true` only for the connection's retained fatal transport cause.
50
+ */
51
+ isTransportFailure(error: unknown): boolean;
52
+ /**
53
+ * Run one query through the serialized queue.
54
+ * @param request - the resolved provider query.
55
+ * @param source - the pre-validated, already-read host source (the provider reads before spawning).
56
+ * @param signal - optional cancellation for this query's full lifecycle.
57
+ * @returns the normalized result.
58
+ */
59
+ query(request: LspProviderQuery, source: HostSource, signal?: AbortSignal): Promise<LspQueryResult>;
60
+ private initialize;
61
+ private runQuery;
62
+ private sendRequest;
63
+ /**
64
+ * Race a pending request against abort. On abort, send `$/cancelRequest` and give the server a
65
+ * bounded grace to acknowledge; if it does not settle in time, invalidate and tear down the
66
+ * instance so the still-active request cannot overlap the next queued query's document lifecycle.
67
+ */
68
+ private raceAbort;
69
+ private normalize;
70
+ private answerServerRequest;
71
+ /**
72
+ * Reject queued work, attempt graceful `shutdown`/`exit`, then escalate SIGTERM→SIGKILL, awaiting
73
+ * process close so nothing outlives disposal.
74
+ */
75
+ dispose(): Promise<void>;
76
+ /** Publish disposal once and make every caller await the same quiescence boundary. */
77
+ private startTeardown;
78
+ private tearDown;
79
+ /** Best-effort LSP `shutdown`/`exit`, including process close, bounded by `signal`. */
80
+ private gracefulShutdown;
81
+ /**
82
+ * Terminate the tree (the seam escalates SIGTERM→`killGraceMs`→SIGKILL),
83
+ * then await leader and helper exit. The awaits are unbounded on purpose:
84
+ * the seam's escalation already committed to SIGKILL, so quiescence — not
85
+ * another timer — is the postcondition disposal owes its callers.
86
+ */
87
+ private forceTerminate;
88
+ }
89
+ //# sourceMappingURL=instance.d.ts.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Package-owned invariant companion for `@deepseek-ai/dsh-lsp-stdio`.
3
+ * @module @deepseek-ai/dsh-lsp-stdio/invariant
4
+ */
5
+ import type { Context } from '@deepseek-ai/cordis';
6
+ /** Cordis companion plugin name. */
7
+ export declare const name = "lsp-stdio-invariant";
8
+ /** Service required before the companion can reserve package ownership. */
9
+ export declare const inject: string[];
10
+ /**
11
+ * Register this package's invariant companion.
12
+ * @param ctx - Cordis context carrying the invariant service.
13
+ * @returns the installed registration's disposer after setup succeeds.
14
+ */
15
+ export declare const apply: (ctx: Context) => Promise<() => void>;
16
+ //# sourceMappingURL=invariant.d.ts.map
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The subset of LSP wire types this generic host reads and writes: initialize capabilities, the four
3
+ * request results (`Location`, `LocationLink`, `Hover`), and the `textDocumentSync` shapes used to
4
+ * decide transient-open support. Types only. Fields absent from a real server payload stay optional;
5
+ * the translation layer normalizes them into the seam's closed unions.
6
+ * @module @deepseek-ai/dsh-lsp-stdio/protocol
7
+ */
8
+ /** A zero-based UTF-16 position on the wire (the protocol's `Position`). */
9
+ export interface WirePosition {
10
+ readonly line: number;
11
+ readonly character: number;
12
+ }
13
+ /** A wire range (`Range`). */
14
+ export interface WireRange {
15
+ readonly start: WirePosition;
16
+ readonly end: WirePosition;
17
+ }
18
+ /** A `Location`: a document URI plus a range. */
19
+ export interface WireLocation {
20
+ readonly uri: string;
21
+ readonly range: WireRange;
22
+ }
23
+ /** A `LocationLink`: the target uri plus the selection range to focus. */
24
+ export interface WireLocationLink {
25
+ readonly targetUri: string;
26
+ readonly targetSelectionRange: WireRange;
27
+ readonly targetRange?: WireRange;
28
+ }
29
+ /** A `MarkupContent` hover body (`markdown` or `plaintext`). */
30
+ export interface WireMarkupContent {
31
+ readonly kind: 'markdown' | 'plaintext';
32
+ readonly value: string;
33
+ }
34
+ /** A `MarkedString` object form (`{ language, value }`); the string form is a bare `string`. */
35
+ export interface WireMarkedStringObject {
36
+ readonly language: string;
37
+ readonly value: string;
38
+ }
39
+ /** One `MarkedString`: a raw string or a language-tagged code block. */
40
+ export type WireMarkedString = string | WireMarkedStringObject;
41
+ /** A `Hover`: contents in any of the protocol's three encodings, plus an optional range. */
42
+ export interface WireHover {
43
+ readonly contents: WireMarkupContent | WireMarkedString | readonly WireMarkedString[];
44
+ readonly range?: WireRange;
45
+ }
46
+ /** The legacy enum form of `textDocumentSync` (`0` None, `1` Full, `2` Incremental). */
47
+ export type WireTextDocumentSyncKind = 0 | 1 | 2;
48
+ /** The options form of `textDocumentSync` (`{ openClose, change }`). */
49
+ export interface WireTextDocumentSyncOptions {
50
+ readonly openClose?: boolean;
51
+ readonly change?: WireTextDocumentSyncKind;
52
+ }
53
+ /** A `ServerCapabilities.provider` slot: a boolean or an options object (both mean "supported"). */
54
+ export type WireProviderCapability = boolean | Record<string, unknown> | undefined;
55
+ /** The `ServerCapabilities` fields this host inspects. */
56
+ export interface WireServerCapabilities {
57
+ readonly positionEncoding?: string;
58
+ readonly textDocumentSync?: WireTextDocumentSyncKind | WireTextDocumentSyncOptions;
59
+ readonly definitionProvider?: WireProviderCapability;
60
+ readonly referencesProvider?: WireProviderCapability;
61
+ readonly implementationProvider?: WireProviderCapability;
62
+ readonly hoverProvider?: WireProviderCapability;
63
+ }
64
+ /** The `initialize` result envelope. */
65
+ export interface WireInitializeResult {
66
+ readonly capabilities: WireServerCapabilities;
67
+ }
68
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Pure protocol translation for the local host: what the server's capabilities allow, and how its
3
+ * `Location`/`LocationLink`/`Hover` payloads normalize into the seam's closed result unions. No I/O
4
+ * or process state — every function here is a pure transform, which the fake-stdio tests pin exactly.
5
+ * @module @deepseek-ai/dsh-lsp-stdio/translate
6
+ */
7
+ import type { LspHover, LspLocation, LspOperation } from '@deepseek-ai/dsh-lsp';
8
+ import type { WireServerCapabilities } from './protocol.ts';
9
+ /**
10
+ * The `textDocument/*` request method for each LSP operation.
11
+ * @param operation - the LSP operation to map.
12
+ * @returns the LSP request method name.
13
+ */
14
+ export declare function requestMethod(operation: LspOperation): string;
15
+ /**
16
+ * Whether the server advertises the requested operation.
17
+ * @param capabilities - the server's `initialize` capabilities.
18
+ * @param operation - the LSP operation to check.
19
+ * @returns true when the corresponding provider capability is present.
20
+ */
21
+ export declare function supportsOperation(capabilities: WireServerCapabilities, operation: LspOperation): boolean;
22
+ /**
23
+ * Whether a `textDocumentSync` value permits the transient `didOpen`/`didClose` this host relies on.
24
+ * The legacy enum form implies open/close for `Full`/`Incremental`; the options form requires an
25
+ * explicit `openClose: true`, because the protocol defaults an omitted `openClose` to false.
26
+ * @param sync - the server's advertised `textDocumentSync` capability.
27
+ * @returns true when transient open/close is supported.
28
+ */
29
+ export declare function supportsTransientOpen(sync: WireServerCapabilities['textDocumentSync']): boolean;
30
+ /**
31
+ * Normalize the negotiated position encoding. An omitted encoding defaults to `utf-16`; any value
32
+ * other than `utf-16` is a protocol error this host does not support.
33
+ * @param encoding - the server's advertised `positionEncoding`, if any.
34
+ * @returns the string `'utf-16'`.
35
+ * @throws Error for any non-`utf-16` encoding.
36
+ */
37
+ export declare function negotiatePositionEncoding(encoding: string | undefined): 'utf-16';
38
+ /**
39
+ * Normalize a navigation result (`Location`, `Location[]`, `LocationLink[]`, or `null`) to the seam's
40
+ * locations. `Location` maps directly; `LocationLink` maps `targetUri` + `targetSelectionRange`.
41
+ * @param payload - the raw `textDocument/definition|references|implementation` result.
42
+ * @returns the normalized locations (empty for `null`/`[]`).
43
+ * @throws Error when an element is neither a `Location` nor a `LocationLink`.
44
+ */
45
+ export declare function normalizeLocations(payload: unknown): LspLocation[];
46
+ /**
47
+ * Normalize a `Hover` (or `null`) to the seam's hover. `MarkupContent` uses its `value`; a string
48
+ * `MarkedString` is verbatim; a language-tagged `MarkedString` becomes a fenced code block; an array
49
+ * joins its rendered parts with one blank line. The model-facing tool owns the complete result cap.
50
+ * @param payload - the raw `textDocument/hover` result.
51
+ * @returns the normalized hover, or `null` when there is no content.
52
+ * @throws Error when the payload is a non-null, non-object, or structurally invalid hover.
53
+ */
54
+ export declare function normalizeHover(payload: unknown): LspHover | null;
55
+ //# sourceMappingURL=translate.d.ts.map
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@deepseek-ai/dsh-lsp-stdio",
3
+ "description": "Generic stdio language-server provider for the DeepSeek Harness LSP capability seam (ctx.lsp) — spawns configured servers, translates JSON-RPC, and serves transient-open goToDefinition/findReferences/goToImplementation/hover queries in the host filesystem namespace",
4
+ "version": "0.0.1-rc.5",
5
+ "publishConfig": {
6
+ "access": "restricted"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
11
+ "directory": "packages/lsp/lsp-stdio"
12
+ },
13
+ "type": "module",
14
+ "main": "lib/index.js",
15
+ "types": "lib/types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/types/index.d.ts",
19
+ "default": "./lib/index.js"
20
+ },
21
+ "./invariant": {
22
+ "types": "./lib/types/invariant.d.ts",
23
+ "default": "./lib/invariant.js"
24
+ },
25
+ "./src/*": "./src/*",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "files": [
29
+ "lib/index.js",
30
+ "lib/invariant.js",
31
+ "lib/types/**/*.d.ts"
32
+ ],
33
+ "license": "BSD-3-Clause",
34
+ "peerDependencies": {
35
+ "@deepseek-ai/dsh-brand": "^0.0.1-rc.5",
36
+ "@deepseek-ai/dsh-fs": "^0.0.1-rc.5",
37
+ "@deepseek-ai/dsh-invariants": "^0.0.1-rc.5",
38
+ "@deepseek-ai/dsh-llm": "^0.0.1-rc.5",
39
+ "@deepseek-ai/dsh-timeout": "^0.0.1-rc.5",
40
+ "@deepseek-ai/cordis": "^4.0.1-rc.4",
41
+ "@deepseek-ai/dsh-subprocess": "^0.0.1-rc.5",
42
+ "@deepseek-ai/dsh-lsp": "^0.0.1-rc.5"
43
+ },
44
+ "dependencies": {
45
+ "@deepseek-ai/schemastery": "^3.18.1-rc.4"
46
+ },
47
+ "devDependencies": {
48
+ "typescript": "^6.0.3",
49
+ "typescript-language-server": "^5.0.0",
50
+ "@deepseek-ai/dsh-brand": "^0.0.1-rc.5",
51
+ "@deepseek-ai/dsh-fs": "^0.0.1-rc.5",
52
+ "@deepseek-ai/dsh-fs-local": "^0.0.1-rc.5",
53
+ "@deepseek-ai/dsh-llm": "^0.0.1-rc.5",
54
+ "@deepseek-ai/dsh-lsp": "^0.0.1-rc.5",
55
+ "@deepseek-ai/dsh-invariants": "^0.0.1-rc.5",
56
+ "@deepseek-ai/dsh-subprocess": "^0.0.1-rc.5",
57
+ "@deepseek-ai/dsh-timeout": "^0.0.1-rc.5",
58
+ "@deepseek-ai/cordis": "^4.0.1-rc.4",
59
+ "@deepseek-ai/dsh-subprocess-local": "^0.0.1-rc.5"
60
+ }
61
+ }