@askdkc/dsh-lsp-server 0.1.11 → 0.1.13
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/README.md +37 -0
- package/docs/usage.md +2 -0
- package/lib/code-intelligence-DvhxPnpu.js +890 -0
- package/lib/code-intelligence-DvhxPnpu.js.map +1 -0
- package/lib/code-intelligence-contracts-CWXTofdI.js +8 -0
- package/lib/code-intelligence-contracts-CWXTofdI.js.map +1 -0
- package/lib/code-intelligence-contracts.js +3 -0
- package/lib/code-intelligence.js +5 -0
- package/lib/errors-DtyWAUi0.js.map +1 -1
- package/lib/extra-tool.js +136 -8
- package/lib/extra-tool.js.map +1 -1
- package/lib/launch-ByUvgkVv.js.map +1 -1
- package/lib/provider.js +653 -40
- package/lib/provider.js.map +1 -1
- package/lib/structure/grammars/manifest.json +40 -0
- package/lib/structure/grammars/tree-sitter-javascript.wasm +0 -0
- package/lib/structure/grammars/tree-sitter-tsx.wasm +0 -0
- package/lib/structure/grammars/tree-sitter-typescript.wasm +0 -0
- package/lib/structure/parser-worker.mjs +200 -0
- package/lib/types/code-intelligence-contracts.d.ts +113 -0
- package/lib/types/code-intelligence.d.ts +5 -0
- package/lib/types/errors.d.ts +1 -1
- package/lib/types/extra-tool.d.ts +2 -1
- package/lib/types/provider.d.ts +4 -0
- package/lib/types/routing/classifier.d.ts +2 -0
- package/lib/types/runtime/webstack-runtime.d.ts +13 -1
- package/lib/types/service.d.ts +23 -0
- package/lib/types/structure/code-intelligence.d.ts +23 -0
- package/lib/types/structure/coordinates.d.ts +14 -0
- package/lib/types/structure/engine.d.ts +49 -0
- package/lib/types/structure/protocol.d.ts +19 -0
- package/lib/types/structure/queries.d.ts +4 -0
- package/lib/types/structure/snapshots.d.ts +37 -0
- package/lib/types/structure/types.d.ts +147 -0
- package/lib/types/structure/worker-pool.d.ts +66 -0
- package/package.json +17 -4
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { Language, Parser, Query } from 'web-tree-sitter'
|
|
2
|
+
|
|
3
|
+
const port = (await import('node:worker_threads')).parentPort
|
|
4
|
+
if (!port) throw new Error('structure worker requires a parent port')
|
|
5
|
+
|
|
6
|
+
const assets = {
|
|
7
|
+
javascript: 'tree-sitter-javascript.wasm',
|
|
8
|
+
typescript: 'tree-sitter-typescript.wasm',
|
|
9
|
+
tsx: 'tree-sitter-tsx.wasm',
|
|
10
|
+
}
|
|
11
|
+
const MAX_CACHE_ENTRIES = 16
|
|
12
|
+
const MAX_CACHE_BYTES = 16 * 1024 * 1024
|
|
13
|
+
let init
|
|
14
|
+
const languages = new Map()
|
|
15
|
+
const trees = new Map()
|
|
16
|
+
let cachedBytes = 0
|
|
17
|
+
|
|
18
|
+
async function loadLanguage(language) {
|
|
19
|
+
if (!assets[language]) throw new Error('unsupported grammar')
|
|
20
|
+
init ??= Parser.init()
|
|
21
|
+
await init
|
|
22
|
+
if (!languages.has(language)) {
|
|
23
|
+
const url = new URL(`./grammars/${assets[language]}`, import.meta.url)
|
|
24
|
+
languages.set(language, await Language.load(url))
|
|
25
|
+
}
|
|
26
|
+
return languages.get(language)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function summarizeErrors(root, limit = 100) {
|
|
30
|
+
const stack = [root]
|
|
31
|
+
let errorNodes = 0, missingNodes = 0, visited = 0
|
|
32
|
+
while (stack.length && visited < 200_000) {
|
|
33
|
+
const node = stack.pop()
|
|
34
|
+
visited++
|
|
35
|
+
if (node.type === 'ERROR') errorNodes++
|
|
36
|
+
if (node.isMissing) missingNodes++
|
|
37
|
+
if (errorNodes + missingNodes >= limit) break
|
|
38
|
+
for (const child of node.children) stack.push(child)
|
|
39
|
+
}
|
|
40
|
+
return { hasError: root.hasError, errorNodes: Math.min(errorNodes, limit), missingNodes: Math.min(missingNodes, limit), truncated: stack.length > 0 }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function nodeSummary(node) {
|
|
44
|
+
const name = node.childForFieldName('name')
|
|
45
|
+
return {
|
|
46
|
+
kind: node.type,
|
|
47
|
+
startIndex: node.startIndex,
|
|
48
|
+
endIndex: node.endIndex,
|
|
49
|
+
startPosition: node.startPosition,
|
|
50
|
+
endPosition: node.endPosition,
|
|
51
|
+
...(name ? { nameStartIndex: name.startIndex, nameEndIndex: name.endIndex } : {}),
|
|
52
|
+
childCount: node.namedChildCount,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function run(request) {
|
|
57
|
+
const language = await loadLanguage(request.language)
|
|
58
|
+
let cached = request.snapshotHandle ? trees.get(request.snapshotHandle) : undefined
|
|
59
|
+
let incremental = false
|
|
60
|
+
if (cached && (cached.languageName !== request.language || cached.text !== request.text)) {
|
|
61
|
+
cached.tree.delete()
|
|
62
|
+
cachedBytes -= cached.bytes
|
|
63
|
+
trees.delete(request.snapshotHandle)
|
|
64
|
+
cached = undefined
|
|
65
|
+
}
|
|
66
|
+
let previous = !cached && request.previousSnapshotHandle ? trees.get(request.previousSnapshotHandle) : undefined
|
|
67
|
+
if (previous && previous.languageName !== request.language) previous = undefined
|
|
68
|
+
let tree = cached?.tree
|
|
69
|
+
let parser
|
|
70
|
+
try {
|
|
71
|
+
if (tree) {
|
|
72
|
+
trees.delete(request.snapshotHandle)
|
|
73
|
+
trees.set(request.snapshotHandle, cached)
|
|
74
|
+
} else if (previous && previous.text === request.text) {
|
|
75
|
+
trees.delete(request.previousSnapshotHandle)
|
|
76
|
+
tree = previous.tree
|
|
77
|
+
if (request.snapshotHandle) trees.set(request.snapshotHandle, previous)
|
|
78
|
+
else { cachedBytes -= previous.bytes; tree.delete() }
|
|
79
|
+
} else {
|
|
80
|
+
parser = new Parser()
|
|
81
|
+
parser.setLanguage(language)
|
|
82
|
+
if (previous) {
|
|
83
|
+
try {
|
|
84
|
+
const edit = changedRange(previous.text, request.text)
|
|
85
|
+
previous.tree.edit(edit)
|
|
86
|
+
tree = parser.parse(request.text, previous.tree)
|
|
87
|
+
incremental = Boolean(tree)
|
|
88
|
+
} catch {
|
|
89
|
+
tree = undefined
|
|
90
|
+
} finally {
|
|
91
|
+
trees.delete(request.previousSnapshotHandle)
|
|
92
|
+
cachedBytes -= previous.bytes
|
|
93
|
+
previous.tree.delete()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
tree ??= parser.parse(request.text)
|
|
97
|
+
if (!tree) throw new Error('parser returned no tree')
|
|
98
|
+
if (request.snapshotHandle && Buffer.byteLength(request.text, 'utf8') <= MAX_CACHE_BYTES) {
|
|
99
|
+
const bytes = Buffer.byteLength(request.text, 'utf8')
|
|
100
|
+
trees.set(request.snapshotHandle, { tree, text: request.text, languageName: request.language, bytes })
|
|
101
|
+
cachedBytes += bytes
|
|
102
|
+
while (trees.size > MAX_CACHE_ENTRIES || cachedBytes > MAX_CACHE_BYTES) {
|
|
103
|
+
const [oldestKey, oldest] = trees.entries().next().value
|
|
104
|
+
trees.delete(oldestKey)
|
|
105
|
+
cachedBytes -= oldest.bytes
|
|
106
|
+
oldest.tree.delete()
|
|
107
|
+
if (oldestKey === request.snapshotHandle) {
|
|
108
|
+
tree = undefined
|
|
109
|
+
break
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const root = tree.rootNode
|
|
115
|
+
const errors = summarizeErrors(root)
|
|
116
|
+
if (request.operation === 'inspect') return { status: errors.hasError ? 'partial' : 'ok', errors, abiVersion: language.abiVersion, reusedTree: Boolean(cached), incremental }
|
|
117
|
+
if (request.operation === 'enclosing') {
|
|
118
|
+
const leaf = root.namedDescendantForIndex(request.index, request.index) ?? root
|
|
119
|
+
const allowed = request.kinds?.length ? new Set(request.kinds) : undefined
|
|
120
|
+
const nodes = []
|
|
121
|
+
for (let node = leaf; node && nodes.length < 16; node = node.parent) {
|
|
122
|
+
if (!allowed || allowed.has(node.type)) nodes.push(nodeSummary(node))
|
|
123
|
+
}
|
|
124
|
+
return { status: errors.hasError ? 'partial' : 'ok', nodes, errors, reusedTree: Boolean(cached), incremental }
|
|
125
|
+
}
|
|
126
|
+
const query = new Query(language, request.querySource)
|
|
127
|
+
try {
|
|
128
|
+
const options = {
|
|
129
|
+
matchLimit: Math.max(1, Math.min(2048, request.limit + 1)),
|
|
130
|
+
...(request.startIndex === undefined ? {} : { startIndex: request.startIndex }),
|
|
131
|
+
...(request.endIndex === undefined ? {} : { endIndex: request.endIndex }),
|
|
132
|
+
}
|
|
133
|
+
const matches = query.matches(root, options)
|
|
134
|
+
const result = matches.slice(0, request.limit + 1).map(match => ({
|
|
135
|
+
captures: match.captures.map(capture => ({ name: capture.name, ...nodeSummary(capture.node) })),
|
|
136
|
+
}))
|
|
137
|
+
return { status: errors.hasError ? 'partial' : 'ok', matches: result, truncated: matches.length > request.limit, errors, reusedTree: Boolean(cached), incremental }
|
|
138
|
+
} finally { query.delete() }
|
|
139
|
+
} finally {
|
|
140
|
+
if (tree && (!request.snapshotHandle || trees.get(request.snapshotHandle)?.tree !== tree)) tree.delete()
|
|
141
|
+
parser?.delete()
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function changedRange(oldText, newText) {
|
|
146
|
+
let prefix = 0
|
|
147
|
+
const sharedLength = Math.min(oldText.length, newText.length)
|
|
148
|
+
while (prefix < sharedLength && oldText.charCodeAt(prefix) === newText.charCodeAt(prefix)) prefix++
|
|
149
|
+
while (prefix > 0 && (splitsSurrogate(oldText, prefix) || splitsSurrogate(newText, prefix))) prefix--
|
|
150
|
+
|
|
151
|
+
let suffix = 0
|
|
152
|
+
while (suffix < oldText.length - prefix && suffix < newText.length - prefix &&
|
|
153
|
+
oldText.charCodeAt(oldText.length - suffix - 1) === newText.charCodeAt(newText.length - suffix - 1)) suffix++
|
|
154
|
+
while (suffix > 0 && (splitsSurrogate(oldText, oldText.length - suffix) || splitsSurrogate(newText, newText.length - suffix))) suffix--
|
|
155
|
+
|
|
156
|
+
const oldEndIndex = oldText.length - suffix
|
|
157
|
+
const newEndIndex = newText.length - suffix
|
|
158
|
+
return {
|
|
159
|
+
startIndex: prefix,
|
|
160
|
+
oldEndIndex,
|
|
161
|
+
newEndIndex,
|
|
162
|
+
startPosition: pointAt(oldText, prefix),
|
|
163
|
+
oldEndPosition: pointAt(oldText, oldEndIndex),
|
|
164
|
+
newEndPosition: pointAt(newText, newEndIndex),
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function pointAt(text, index) {
|
|
169
|
+
let row = 0
|
|
170
|
+
let lineStart = 0
|
|
171
|
+
for (let cursor = 0; cursor < index; cursor++) {
|
|
172
|
+
if (text.charCodeAt(cursor) === 10) { row++; lineStart = cursor + 1 }
|
|
173
|
+
}
|
|
174
|
+
return { row, column: index - lineStart }
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function splitsSurrogate(text, index) {
|
|
178
|
+
if (index <= 0 || index >= text.length) return false
|
|
179
|
+
const before = text.charCodeAt(index - 1)
|
|
180
|
+
const after = text.charCodeAt(index)
|
|
181
|
+
return before >= 0xd800 && before <= 0xdbff && after >= 0xdc00 && after <= 0xdfff
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
port.on('message', async request => {
|
|
185
|
+
if (typeof request.releaseSnapshotHandle === 'string') {
|
|
186
|
+
const cached = trees.get(request.releaseSnapshotHandle)
|
|
187
|
+
if (cached) {
|
|
188
|
+
trees.delete(request.releaseSnapshotHandle)
|
|
189
|
+
cachedBytes -= cached.bytes
|
|
190
|
+
cached.tree.delete()
|
|
191
|
+
}
|
|
192
|
+
return
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const value = await run(request)
|
|
196
|
+
port.postMessage({ id: request.id, ok: true, value })
|
|
197
|
+
} catch (error) {
|
|
198
|
+
port.postMessage({ id: request.id, ok: false, error: error instanceof Error ? error.message.slice(0, 500) : 'structure parse failed' })
|
|
199
|
+
}
|
|
200
|
+
})
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/** Side-effect-free V1 protocol shared with protected Lisp adapters. */
|
|
2
|
+
export declare const CODE_INTELLIGENCE_SERVICE: "codeIntelligence";
|
|
3
|
+
export declare const CODE_INTELLIGENCE_VERSION: 1;
|
|
4
|
+
export type CodeStatus = 'ok' | 'partial' | 'unsupported' | 'unavailable' | 'stale' | 'cancelled' | 'timeout' | 'limit_exceeded';
|
|
5
|
+
export interface CodePosition {
|
|
6
|
+
line: number;
|
|
7
|
+
character: number;
|
|
8
|
+
}
|
|
9
|
+
export interface CodeRange {
|
|
10
|
+
start: CodePosition;
|
|
11
|
+
end: CodePosition;
|
|
12
|
+
}
|
|
13
|
+
export type CodeSemanticKind = 'definition' | 'references' | 'implementation' | 'hover' | 'diagnostics' | 'completion';
|
|
14
|
+
export type CodeQueryId = 'declarations' | 'calls' | 'imports';
|
|
15
|
+
export type CodeRequestV1 = {
|
|
16
|
+
method: 'capabilities';
|
|
17
|
+
} | {
|
|
18
|
+
method: 'snapshot.open';
|
|
19
|
+
path: string;
|
|
20
|
+
} | {
|
|
21
|
+
method: 'snapshot.release';
|
|
22
|
+
handle: string;
|
|
23
|
+
} | {
|
|
24
|
+
method: 'structure.outline';
|
|
25
|
+
handle: string;
|
|
26
|
+
range?: CodeRange;
|
|
27
|
+
limit?: number;
|
|
28
|
+
} | {
|
|
29
|
+
method: 'structure.enclosing';
|
|
30
|
+
handle: string;
|
|
31
|
+
position: CodePosition;
|
|
32
|
+
kinds?: string[];
|
|
33
|
+
} | {
|
|
34
|
+
method: 'structure.query';
|
|
35
|
+
handle: string;
|
|
36
|
+
queryId: CodeQueryId;
|
|
37
|
+
range?: CodeRange;
|
|
38
|
+
limit?: number;
|
|
39
|
+
} | {
|
|
40
|
+
method: 'structure.span';
|
|
41
|
+
nodeHandle: string;
|
|
42
|
+
maxChars?: number;
|
|
43
|
+
} | {
|
|
44
|
+
method: 'semantic.query';
|
|
45
|
+
handle: string;
|
|
46
|
+
kind: CodeSemanticKind;
|
|
47
|
+
position?: CodePosition;
|
|
48
|
+
limit?: number;
|
|
49
|
+
};
|
|
50
|
+
export interface CodeCapabilitiesV1 {
|
|
51
|
+
version: 1;
|
|
52
|
+
capabilities: Array<'snapshots' | 'structure' | 'semantic'>;
|
|
53
|
+
languages: string[];
|
|
54
|
+
queryIds: CodeQueryId[];
|
|
55
|
+
semanticReady: boolean;
|
|
56
|
+
sourceKinds: ['disk'];
|
|
57
|
+
languageCapabilities: Array<{
|
|
58
|
+
language: string;
|
|
59
|
+
structure: boolean;
|
|
60
|
+
semantic: CodeSemanticKind[];
|
|
61
|
+
semanticReady: boolean;
|
|
62
|
+
reason?: string;
|
|
63
|
+
}>;
|
|
64
|
+
limits: {
|
|
65
|
+
documentBytes: number;
|
|
66
|
+
captureItems: number;
|
|
67
|
+
outlineItems: number;
|
|
68
|
+
spanChars: number;
|
|
69
|
+
responseBytes: number;
|
|
70
|
+
files: number;
|
|
71
|
+
inputBytes: number;
|
|
72
|
+
outputBytes: number;
|
|
73
|
+
calls: number;
|
|
74
|
+
batchMs: number;
|
|
75
|
+
structureMs: number;
|
|
76
|
+
semanticMs: number;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export interface CodeResponseV1 {
|
|
80
|
+
protocol: 'code-intelligence/v1';
|
|
81
|
+
status: CodeStatus;
|
|
82
|
+
reason?: string;
|
|
83
|
+
sourceKind: 'disk';
|
|
84
|
+
freshness: 'pinned' | 'current' | 'unknown' | 'stale';
|
|
85
|
+
snapshotVersion?: string;
|
|
86
|
+
truncated: boolean;
|
|
87
|
+
omitted: number;
|
|
88
|
+
inputBytes?: number;
|
|
89
|
+
data?: unknown;
|
|
90
|
+
}
|
|
91
|
+
/** Authority comes from the host binding, never from code primitive arguments. */
|
|
92
|
+
export interface CodeHostBindingV1 {
|
|
93
|
+
owner: {
|
|
94
|
+
agentId: string;
|
|
95
|
+
sessionId: string;
|
|
96
|
+
};
|
|
97
|
+
workspaceRoot: string;
|
|
98
|
+
scope: object;
|
|
99
|
+
context: {
|
|
100
|
+
get(name: string, strict?: boolean): unknown;
|
|
101
|
+
};
|
|
102
|
+
assertCurrent(): void | Promise<void>;
|
|
103
|
+
}
|
|
104
|
+
export interface CodeLeaseV1 {
|
|
105
|
+
request(input: CodeRequestV1, signal: AbortSignal): Promise<CodeResponseV1>;
|
|
106
|
+
dispose(): Promise<void>;
|
|
107
|
+
}
|
|
108
|
+
export interface CodeIntelligenceServiceV1 {
|
|
109
|
+
version: 1;
|
|
110
|
+
capabilities: readonly ('snapshots' | 'structure' | 'semantic')[];
|
|
111
|
+
bind(binding: CodeHostBindingV1, signal: AbortSignal): Promise<CodeLeaseV1>;
|
|
112
|
+
dispose?(): Promise<void>;
|
|
113
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { CODE_INTELLIGENCE_SERVICE, CODE_INTELLIGENCE_VERSION } from './code-intelligence-contracts.js';
|
|
2
|
+
export type { CodeCapabilitiesV1, CodeHostBindingV1, CodeIntelligenceServiceV1, CodeLeaseV1, CodePosition, CodeQueryId, CodeRange, CodeRequestV1, CodeResponseV1, CodeSemanticKind, CodeStatus } from './code-intelligence-contracts.js';
|
|
3
|
+
export type { CodeIntelligenceCapabilities, CodeIntelligenceStatus, SemanticOperation, SemanticQuery, SemanticResult, SnapshotDescriptor, SnapshotOpenResult, SnapshotReleaseResult, SnapshotScope, SourceKind, StructureCapture, StructureEnclosingResult, StructureErrorSummary, StructureLanguage, StructureNode, StructureOutlineResult, StructureQueryResult, StructureSpanResult } from './structure/types.js';
|
|
4
|
+
export { createCodeIntelligenceToolServiceV1 } from './structure/code-intelligence.js';
|
|
5
|
+
export type { CodeIntelligenceToolServiceV1 } from './structure/types.js';
|
package/lib/types/errors.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LspError } from '@deepseek-ai/dsh-lsp';
|
|
2
|
-
export type WebstackErrorCode = 'LSP_UNAVAILABLE' | 'LSP_UNSUPPORTED_OPERATION' | 'LSP_DISPOSED' | 'LSP_MALFORMED_RESPONSE' | 'LSP_CONFLICT' | 'LSP_WORKSPACE_REQUIRED' | 'LSP_WEBSTACK_CONFIG_INVALID';
|
|
2
|
+
export type WebstackErrorCode = 'LSP_UNAVAILABLE' | 'LSP_UNSUPPORTED_OPERATION' | 'LSP_DISPOSED' | 'LSP_MALFORMED_RESPONSE' | 'LSP_CONFLICT' | 'LSP_WORKSPACE_REQUIRED' | 'LSP_WEBSTACK_CONFIG_INVALID' | 'LSP_STALE_SNAPSHOT' | 'LSP_SNAPSHOT_LIMIT' | 'LSP_STRUCTURE_BUSY' | 'LSP_STRUCTURE_TIMEOUT' | 'LSP_STRUCTURE_LIMIT' | 'LSP_STRUCTURE_UNAVAILABLE' | 'LSP_STRUCTURE_UNSUPPORTED' | 'LSP_CODE_INTELLIGENCE_UNAVAILABLE';
|
|
3
3
|
export declare class WebstackLspError extends LspError {
|
|
4
4
|
readonly code: WebstackErrorCode;
|
|
5
5
|
constructor(code: WebstackErrorCode, message: string, options?: ErrorOptions);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
2
2
|
import type { ToolDefinition } from '@deepseek-ai/dsh-tools';
|
|
3
3
|
import type { WebstackLspService } from './service.js';
|
|
4
|
+
import type { CodeIntelligenceToolServiceV1 } from './structure/types.js';
|
|
4
5
|
export declare const name = "lsp_extra";
|
|
5
6
|
export declare const inject: string[];
|
|
6
7
|
export interface Config {
|
|
@@ -9,5 +10,5 @@ export interface Config {
|
|
|
9
10
|
maxResultChars?: number;
|
|
10
11
|
timeoutMs?: number;
|
|
11
12
|
}
|
|
12
|
-
export declare function createExtraTool(service: WebstackLspService, config?: Config): ToolDefinition;
|
|
13
|
+
export declare function createExtraTool(service: WebstackLspService, codeIntelligence?: CodeIntelligenceToolServiceV1, config?: Config): ToolDefinition;
|
|
13
14
|
export declare function apply(ctx: Context, config?: Config): void;
|
package/lib/types/provider.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { Context } from '@deepseek-ai/cordis';
|
|
|
2
2
|
import type { LspProvider, LspProviderQuery, LspQueryResult } from '@deepseek-ai/dsh-lsp';
|
|
3
3
|
import type { Config as PluginConfig, ResolvedConfig } from './config.js';
|
|
4
4
|
import type { WebstackLspService } from './service.js';
|
|
5
|
+
import type { CodeIntelligenceServiceV1 } from './code-intelligence-contracts.js';
|
|
6
|
+
import type { CodeIntelligenceToolServiceV1 } from './structure/types.js';
|
|
5
7
|
export type { LspProvider, LspProviderQuery, LspQueryResult };
|
|
6
8
|
export type Config = PluginConfig;
|
|
7
9
|
export declare const name = "lsp-webstack-provider";
|
|
@@ -9,6 +11,8 @@ export declare const inject: string[];
|
|
|
9
11
|
declare module '@deepseek-ai/cordis' {
|
|
10
12
|
interface Context {
|
|
11
13
|
webstackLsp: WebstackLspService;
|
|
14
|
+
codeIntelligence: CodeIntelligenceServiceV1;
|
|
15
|
+
codeIntelligenceRuntime: CodeIntelligenceToolServiceV1;
|
|
12
16
|
}
|
|
13
17
|
}
|
|
14
18
|
export declare const OUTER_EXTENSION_MAP: {
|
|
@@ -6,3 +6,5 @@ export interface ClassifiedFile {
|
|
|
6
6
|
kind: FileKind;
|
|
7
7
|
}
|
|
8
8
|
export declare function classifyFile(filePath: string, bladeSuffixes?: string[]): ClassifiedFile | undefined;
|
|
9
|
+
/** Return the supported suffixes, including configured Blade suffixes. */
|
|
10
|
+
export declare function supportedFileSuffixes(bladeSuffixes?: string[]): string[];
|
|
@@ -3,12 +3,18 @@ import type { SubprocessRuntime } from '@deepseek-ai/dsh-subprocess';
|
|
|
3
3
|
import type { ResolvedConfig } from '../config.js';
|
|
4
4
|
import { type HostFileSystem } from '../host/dsh.js';
|
|
5
5
|
import type { CompletionRequest, CompletionResult, DiagnosticsRequest, DiagnosticsResult, WebstackLspStatus } from '../service.js';
|
|
6
|
+
import type { CodeIntelligenceServiceV1 } from '../code-intelligence-contracts.js';
|
|
7
|
+
import type { CodeIntelligenceToolServiceV1 } from '../structure/types.js';
|
|
6
8
|
export type HostSubprocess = Pick<SubprocessRuntime, 'spawn' | 'resolveExecutable'>;
|
|
7
9
|
export declare class WebstackLspRuntime {
|
|
8
10
|
private readonly config;
|
|
9
11
|
private readonly fs;
|
|
10
12
|
private readonly subprocess;
|
|
11
13
|
private readonly pool;
|
|
14
|
+
private readonly snapshots;
|
|
15
|
+
readonly codeIntelligence: CodeIntelligenceServiceV1;
|
|
16
|
+
readonly codeIntelligenceRuntime: CodeIntelligenceToolServiceV1;
|
|
17
|
+
private readonly semanticOperations;
|
|
12
18
|
private readonly workspaces;
|
|
13
19
|
private readonly lifetime;
|
|
14
20
|
private readonly live;
|
|
@@ -16,12 +22,18 @@ export declare class WebstackLspRuntime {
|
|
|
16
22
|
private readonly restarts;
|
|
17
23
|
constructor(config: ResolvedConfig, fs: HostFileSystem, subprocess: HostSubprocess);
|
|
18
24
|
navigation(request: LspProviderQuery, signal?: AbortSignal): Promise<LspQueryResult>;
|
|
25
|
+
private navigationFromSource;
|
|
19
26
|
completion(request: CompletionRequest, signal?: AbortSignal): Promise<CompletionResult>;
|
|
27
|
+
private completionFromSource;
|
|
20
28
|
diagnostics(request: DiagnosticsRequest, signal?: AbortSignal): Promise<DiagnosticsResult>;
|
|
21
|
-
|
|
29
|
+
private diagnosticsFromSource;
|
|
30
|
+
private semanticFromSnapshot;
|
|
31
|
+
status(signal?: AbortSignal): Promise<WebstackLspStatus>;
|
|
32
|
+
private codeCapabilities;
|
|
22
33
|
dispose(): Promise<void>;
|
|
23
34
|
private signal;
|
|
24
35
|
private prepare;
|
|
36
|
+
private rememberWorkspace;
|
|
25
37
|
private validatePosition;
|
|
26
38
|
private useTailwind;
|
|
27
39
|
private document;
|
package/lib/types/service.d.ts
CHANGED
|
@@ -43,7 +43,28 @@ export interface NormalizedCompletionItem {
|
|
|
43
43
|
insertTextFormat?: number;
|
|
44
44
|
deprecated?: boolean;
|
|
45
45
|
}
|
|
46
|
+
export type NavigationResult = {
|
|
47
|
+
kind: 'locations';
|
|
48
|
+
locations: ReadonlyArray<{
|
|
49
|
+
uri: string;
|
|
50
|
+
range: LspRange;
|
|
51
|
+
}>;
|
|
52
|
+
resolvedWorkspaceUri: string;
|
|
53
|
+
truncated?: boolean;
|
|
54
|
+
omitted?: number;
|
|
55
|
+
} | {
|
|
56
|
+
kind: 'hover';
|
|
57
|
+
hover: {
|
|
58
|
+
contents: string;
|
|
59
|
+
range?: LspRange;
|
|
60
|
+
} | null;
|
|
61
|
+
};
|
|
62
|
+
/** A skipped diagnostic query is unverified; an empty diagnostics array alone is not evidence of a clean file. */
|
|
46
63
|
export interface DiagnosticsResult {
|
|
64
|
+
skipped?: {
|
|
65
|
+
reason: 'unsupported_file_type';
|
|
66
|
+
filePath: string;
|
|
67
|
+
};
|
|
47
68
|
diagnostics: NormalizedDiagnostic[];
|
|
48
69
|
omittedServers?: string[];
|
|
49
70
|
truncated?: {
|
|
@@ -60,6 +81,8 @@ export interface CompletionResult {
|
|
|
60
81
|
}
|
|
61
82
|
export interface WebstackLspStatus {
|
|
62
83
|
providerId: string;
|
|
84
|
+
/** Routing suffixes; enabled/available servers are reported separately. */
|
|
85
|
+
supportedFileSuffixes?: string[];
|
|
63
86
|
servers: Array<{
|
|
64
87
|
id: import('./config.js').ServerId;
|
|
65
88
|
enabled: boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DocumentSnapshotStore } from './snapshots.js';
|
|
2
|
+
import type { SnapshotRecord } from './snapshots.js';
|
|
3
|
+
import type { CodeIntelligenceCapabilities, CodeIntelligenceToolServiceV1, SemanticQuery, SnapshotScope } from './types.js';
|
|
4
|
+
import type { CompletionResult, DiagnosticsResult, NavigationResult } from '../service.js';
|
|
5
|
+
export interface CodeIntelligenceServiceOptions {
|
|
6
|
+
snapshots: DocumentSnapshotStore;
|
|
7
|
+
semanticQuery(scope: SnapshotScope, snapshot: SnapshotRecord, request: SemanticQuery, signal: AbortSignal): Promise<CompletionResult | DiagnosticsResult | NavigationResult>;
|
|
8
|
+
}
|
|
9
|
+
export declare class CodeIntelligenceRuntime implements CodeIntelligenceToolServiceV1 {
|
|
10
|
+
readonly version: 1;
|
|
11
|
+
readonly snapshot: CodeIntelligenceToolServiceV1['snapshot'];
|
|
12
|
+
readonly structure: CodeIntelligenceToolServiceV1['structure'];
|
|
13
|
+
readonly semantic: CodeIntelligenceToolServiceV1['semantic'];
|
|
14
|
+
private readonly store;
|
|
15
|
+
private readonly engine;
|
|
16
|
+
constructor(options: CodeIntelligenceServiceOptions);
|
|
17
|
+
capabilities(): CodeIntelligenceCapabilities;
|
|
18
|
+
releaseOwner(scope: SnapshotScope): Promise<number>;
|
|
19
|
+
dispose(): Promise<void>;
|
|
20
|
+
private span;
|
|
21
|
+
private withSnapshot;
|
|
22
|
+
}
|
|
23
|
+
export declare function createCodeIntelligenceToolServiceV1(options: CodeIntelligenceServiceOptions): CodeIntelligenceToolServiceV1;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { LspPosition, LspRange } from '../service.js';
|
|
2
|
+
/** web-tree-sitter 0.27.1 exposes JS-string indices as UTF-16 code-unit offsets. */
|
|
3
|
+
export declare class Utf16Coordinates {
|
|
4
|
+
private readonly text;
|
|
5
|
+
private readonly lines;
|
|
6
|
+
constructor(text: string);
|
|
7
|
+
positionToIndex(position: LspPosition): number;
|
|
8
|
+
indexToPosition(index: number): LspPosition;
|
|
9
|
+
rangeToIndices(range: LspRange): {
|
|
10
|
+
startIndex: number;
|
|
11
|
+
endIndex: number;
|
|
12
|
+
};
|
|
13
|
+
indicesToRange(startIndex: number, endIndex: number): LspRange;
|
|
14
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type SnapshotRecord } from './snapshots.js';
|
|
2
|
+
import { StructureWorkerPool } from './worker-pool.js';
|
|
3
|
+
import type { SnapshotScope, StructureEnclosingResult, StructureLanguage, StructureNode, StructureOutlineResult, StructureQueryResult, StructureSpanResult } from './types.js';
|
|
4
|
+
export declare const MAX_CAPTURES = 200;
|
|
5
|
+
export declare const MAX_OUTLINE = 100;
|
|
6
|
+
export declare const MAX_SPAN_CHARS = 8000;
|
|
7
|
+
export declare const MAX_STRUCTURE_RESPONSE_BYTES: number;
|
|
8
|
+
export declare class StructureEngine {
|
|
9
|
+
private readonly workers;
|
|
10
|
+
private readonly nodeHandles;
|
|
11
|
+
private readonly snapshotOwners;
|
|
12
|
+
private readonly parserFailures;
|
|
13
|
+
constructor(workers?: StructureWorkerPool);
|
|
14
|
+
inspect(record: SnapshotRecord, signal?: AbortSignal): Promise<{
|
|
15
|
+
available: boolean;
|
|
16
|
+
parseErrors: boolean;
|
|
17
|
+
reason?: string;
|
|
18
|
+
}>;
|
|
19
|
+
outline(record: SnapshotRecord, scope: SnapshotScope, options?: {
|
|
20
|
+
range?: StructureNode['range'];
|
|
21
|
+
limit?: number;
|
|
22
|
+
}, signal?: AbortSignal): Promise<StructureOutlineResult>;
|
|
23
|
+
enclosing(record: SnapshotRecord, scope: SnapshotScope, position: {
|
|
24
|
+
line: number;
|
|
25
|
+
character: number;
|
|
26
|
+
}, kinds?: string[], signal?: AbortSignal): Promise<StructureEnclosingResult>;
|
|
27
|
+
query(record: SnapshotRecord, scope: SnapshotScope, queryId: string, options?: {
|
|
28
|
+
range?: StructureNode['range'];
|
|
29
|
+
limit?: number;
|
|
30
|
+
}, signal?: AbortSignal): Promise<StructureQueryResult>;
|
|
31
|
+
span(record: SnapshotRecord, scope: SnapshotScope, nodeHandle: string, maxChars?: number): Promise<StructureSpanResult>;
|
|
32
|
+
releaseSnapshot(handle: string): void;
|
|
33
|
+
releaseSnapshotForOwner(scope: SnapshotScope, handle: string): void;
|
|
34
|
+
snapshotForNode(scope: SnapshotScope, nodeHandle: string): string;
|
|
35
|
+
releaseOwner(scope: SnapshotScope): void;
|
|
36
|
+
capabilities(): Array<{
|
|
37
|
+
language: StructureLanguage;
|
|
38
|
+
extensions: string[];
|
|
39
|
+
available: boolean;
|
|
40
|
+
abiVersion: number | null;
|
|
41
|
+
lastError?: string;
|
|
42
|
+
}>;
|
|
43
|
+
dispose(): Promise<void>;
|
|
44
|
+
private runMatches;
|
|
45
|
+
private capability;
|
|
46
|
+
private runWorker;
|
|
47
|
+
private outlineResult;
|
|
48
|
+
private node;
|
|
49
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CodeCapabilitiesV1, CodeHostBindingV1, CodeIntelligenceServiceV1, CodeLeaseV1 } from '../code-intelligence-contracts.js';
|
|
2
|
+
import type { CodeIntelligenceToolServiceV1 } from './types.js';
|
|
3
|
+
export interface CodeIntelligenceProtocolOptions {
|
|
4
|
+
backend: CodeIntelligenceToolServiceV1;
|
|
5
|
+
fs: unknown;
|
|
6
|
+
subprocess: unknown;
|
|
7
|
+
capabilities(signal: AbortSignal): Promise<CodeCapabilitiesV1>;
|
|
8
|
+
}
|
|
9
|
+
/** Host-bound V1 facade. Each lease owns its handles and cumulative evaluation budget. */
|
|
10
|
+
export declare class CodeIntelligenceProtocolService implements CodeIntelligenceServiceV1 {
|
|
11
|
+
private readonly options;
|
|
12
|
+
readonly version: 1;
|
|
13
|
+
readonly capabilities: readonly ["snapshots", "structure", "semantic"];
|
|
14
|
+
private readonly leases;
|
|
15
|
+
private closed;
|
|
16
|
+
constructor(options: CodeIntelligenceProtocolOptions);
|
|
17
|
+
bind(binding: CodeHostBindingV1, signal: AbortSignal): Promise<CodeLeaseV1>;
|
|
18
|
+
dispose(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { StructureLanguage } from './types.js';
|
|
2
|
+
export type RegisteredQueryId = 'declarations' | 'calls' | 'imports';
|
|
3
|
+
export declare function getRegisteredQuery(language: StructureLanguage, queryId: string): string | undefined;
|
|
4
|
+
export declare function isRegisteredQueryId(value: string): value is RegisteredQueryId;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { HostSource } from '../host/dsh.js';
|
|
2
|
+
import type { SnapshotDescriptor, SnapshotScope, StructureLanguage } from './types.js';
|
|
3
|
+
export declare const SNAPSHOT_TTL_MS: number;
|
|
4
|
+
export declare const SNAPSHOT_MAX_DOCUMENTS = 32;
|
|
5
|
+
export declare const SNAPSHOT_MAX_BYTES: number;
|
|
6
|
+
export declare const STRUCTURE_MAX_DOCUMENT_BYTES: number;
|
|
7
|
+
export interface SnapshotRecord {
|
|
8
|
+
readonly descriptor: SnapshotDescriptor;
|
|
9
|
+
readonly scopeKey: string;
|
|
10
|
+
readonly source: HostSource;
|
|
11
|
+
readonly previousSnapshotHandle?: string;
|
|
12
|
+
readonly openedAt: number;
|
|
13
|
+
lastUsedAt: number;
|
|
14
|
+
}
|
|
15
|
+
export type SnapshotReader = (workspaceRoot: string, filePath: string, maxBytes: number, signal?: AbortSignal) => Promise<HostSource>;
|
|
16
|
+
export declare class DocumentSnapshotStore {
|
|
17
|
+
private readonly readSource;
|
|
18
|
+
private readonly maxDocumentBytes;
|
|
19
|
+
private readonly records;
|
|
20
|
+
private readonly versions;
|
|
21
|
+
constructor(readSource: SnapshotReader, maxDocumentBytes: number);
|
|
22
|
+
open(scope: SnapshotScope, filePath: string, signal?: AbortSignal): Promise<SnapshotRecord>;
|
|
23
|
+
current(scope: SnapshotScope, handle: string, signal?: AbortSignal): Promise<SnapshotRecord>;
|
|
24
|
+
readFresh(scope: SnapshotScope, filePath: string, signal?: AbortSignal): Promise<HostSource>;
|
|
25
|
+
release(scope: SnapshotScope, handle: string): boolean;
|
|
26
|
+
releaseOwner(scope: SnapshotScope): number;
|
|
27
|
+
clear(): void;
|
|
28
|
+
get size(): number;
|
|
29
|
+
get documentByteLimit(): number;
|
|
30
|
+
private totalBytes;
|
|
31
|
+
private rememberVersion;
|
|
32
|
+
private evictExpired;
|
|
33
|
+
}
|
|
34
|
+
export declare function languageForPath(filePath: string): StructureLanguage | null;
|
|
35
|
+
export declare function validateScope(scope: SnapshotScope): void;
|
|
36
|
+
export declare function normalizeRelativePath(filePath: string): string;
|
|
37
|
+
export declare function scopeIdentity(scope: SnapshotScope): string;
|