@lvce-editor/shared-process 0.89.2 → 0.90.1

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.
@@ -35,12 +35,10 @@
35
35
 
36
36
  "sessionReplay.enabled": false,
37
37
 
38
- "serviceWorker.enabled": false,
39
-
40
38
  "simpleBrowser.suggestions": false,
41
39
 
42
40
  "terminal.backend": "real",
43
- "terminal.renderer": "termterm",
41
+ "terminal.renderer": "xterm",
44
42
  "terminal.separateConnection": false,
45
43
 
46
44
  "window.titleBarStyle": "custom",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/shared-process",
3
- "version": "0.89.2",
3
+ "version": "0.90.1",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -18,28 +18,29 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@lvce-editor/assert": "1.7.0",
21
- "@lvce-editor/auth-process": "1.8.0",
22
- "@lvce-editor/extension-host-helper-process": "0.89.2",
21
+ "@lvce-editor/auth-process": "1.9.0",
22
+ "@lvce-editor/extension-host-helper-process": "0.90.1",
23
23
  "@lvce-editor/ipc": "16.3.0",
24
24
  "@lvce-editor/json-rpc": "8.2.0",
25
25
  "@lvce-editor/jsonc-parser": "1.5.0",
26
26
  "@lvce-editor/pretty-error": "2.0.0",
27
27
  "@lvce-editor/process-explorer": "3.10.0",
28
- "@lvce-editor/rpc-registry": "9.33.0",
28
+ "@lvce-editor/rpc-registry": "9.35.0",
29
29
  "@lvce-editor/verror": "1.7.0",
30
30
  "is-object": "^1.0.2",
31
+ "markdown-it": "^14.3.0",
31
32
  "xdg-basedir": "^5.1.0"
32
33
  },
33
34
  "optionalDependencies": {
34
35
  "@lvce-editor/embeds-process": "4.9.1",
35
- "@lvce-editor/file-system-process": "5.3.0",
36
- "@lvce-editor/file-watcher-process": "4.2.0",
36
+ "@lvce-editor/file-system-process": "5.4.0",
37
+ "@lvce-editor/file-watcher-process": "4.4.0",
37
38
  "@lvce-editor/network-process": "5.2.0",
38
39
  "@lvce-editor/preload": "1.5.0",
39
40
  "@lvce-editor/preview-process": "11.0.0",
40
- "@lvce-editor/pty-host": "8.2.0",
41
+ "@lvce-editor/pty-host": "8.3.0",
41
42
  "@lvce-editor/search-process": "15.1.0",
42
- "@lvce-editor/typescript-compile-process": "5.2.0",
43
+ "@lvce-editor/typescript-compile-process": "5.3.0",
43
44
  "open": "^11.0.0",
44
45
  "tail": "^2.2.6",
45
46
  "tmp-promise": "^3.0.3",
@@ -3,6 +3,6 @@ import { fileURLToPath } from 'url'
3
3
 
4
4
  export const getBuiltinExtensionsPath = () => {
5
5
  const staticServerPath = fileURLToPath(import.meta.resolve('@lvce-editor/static-server'))
6
- const builtinExtensionsPath = join(staticServerPath, '..', '..', 'static', '331d398', 'extensions')
6
+ const builtinExtensionsPath = join(staticServerPath, '..', '..', 'static', 'd347596', 'extensions')
7
7
  return builtinExtensionsPath
8
8
  }
@@ -3,6 +3,9 @@ import * as ElectronProcess from './ElectronProcess.js'
3
3
  export const name = 'ElectronProcess'
4
4
 
5
5
  export const Commands = {
6
+ getArgv: ElectronProcess.getArgv,
6
7
  getChromeVersion: ElectronProcess.getChromeVersion,
7
8
  getElectronVersion: ElectronProcess.getElectronVersion,
9
+ writeStderr: ElectronProcess.writeStderr,
10
+ writeStdout: ElectronProcess.writeStdout,
8
11
  }
@@ -1,5 +1,9 @@
1
1
  import * as ParentIpc from '../MainProcess/MainProcess.js'
2
2
 
3
+ export const getArgv = () => {
4
+ return ParentIpc.invoke('Process.getArgv')
5
+ }
6
+
3
7
  export const getElectronVersion = () => {
4
8
  return ParentIpc.invoke('Process.getElectronVersion')
5
9
  }
@@ -7,3 +11,11 @@ export const getElectronVersion = () => {
7
11
  export const getChromeVersion = () => {
8
12
  return ParentIpc.invoke('Process.getChromeVersion')
9
13
  }
14
+
15
+ export const writeStderr = (value) => {
16
+ return ParentIpc.invoke('Process.writeStderr', value)
17
+ }
18
+
19
+ export const writeStdout = (value) => {
20
+ return ParentIpc.invoke('Process.writeStdout', value)
21
+ }
@@ -1,5 +1,8 @@
1
1
  import * as ParentIpc from '../MainProcess/MainProcess.js'
2
2
 
3
- export const exit = () => {
4
- return ParentIpc.invoke('Exit.exit')
3
+ export const exit = (code) => {
4
+ if (code === undefined) {
5
+ return ParentIpc.invoke('Exit.exit')
6
+ }
7
+ return ParentIpc.invoke('Exit.exit', code)
5
8
  }
@@ -0,0 +1,6 @@
1
+ const promptFlag = '--prompt'
2
+ const promptWithValuePrefix = `${promptFlag}=`
3
+
4
+ export const isPromptMode = (argv) => {
5
+ return argv.some((argument) => argument === promptFlag || argument.startsWith(promptWithValuePrefix))
6
+ }
@@ -0,0 +1,7 @@
1
+ import * as LanguageServer from './LanguageServer.js'
2
+
3
+ export const name = 'LanguageServer'
4
+
5
+ export const Commands = {
6
+ complete: LanguageServer.complete,
7
+ }
@@ -0,0 +1,78 @@
1
+ import { dirname } from 'node:path'
2
+ import { pathToFileURL } from 'node:url'
3
+ import { LanguageServerConnection } from '../LanguageServerConnection/LanguageServerConnection.js'
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+ const connections = new Map ()
26
+
27
+ const normalizeDocumentUri = (uri) => {
28
+ if (uri.startsWith('/')) {
29
+ return pathToFileURL(uri).href
30
+ }
31
+ return uri
32
+ }
33
+
34
+ const getRootUri = (documentUri) => {
35
+ if (documentUri.startsWith('file:')) {
36
+ return new URL('.', documentUri).href
37
+ }
38
+ if (documentUri.startsWith('/')) {
39
+ return pathToFileURL(dirname(documentUri)).href
40
+ }
41
+ return new URL('.', documentUri).href
42
+ }
43
+
44
+ const hasSameOptions = (state, uri, argv) => {
45
+ return state.uri === uri && state.argv.length === argv.length && state.argv.every((argument, index) => argument === argv[index])
46
+ }
47
+
48
+ const getConnection = (id, uri, argv, rootUri) => {
49
+ const existing = connections.get(id)
50
+ if (existing && existing.connection.isRunning() && hasSameOptions(existing, uri, argv)) {
51
+ return existing.connection
52
+ }
53
+ existing?.connection.dispose()
54
+ const connection = new LanguageServerConnection({ argv, rootUri, uri })
55
+ connections.set(id, {
56
+ argv: [...argv],
57
+ connection,
58
+ uri,
59
+ })
60
+ return connection
61
+ }
62
+
63
+ export const complete = async ({ argv, id, offset, textDocument, uri } ) => {
64
+ const normalizedDocument = {
65
+ ...textDocument,
66
+ uri: normalizeDocumentUri(textDocument.uri),
67
+ }
68
+ const rootUri = getRootUri(normalizedDocument.uri)
69
+ const connection = getConnection(`${id}:${rootUri}`, uri, argv, rootUri)
70
+ return connection.complete(normalizedDocument, offset)
71
+ }
72
+
73
+ export const disposeAll = () => {
74
+ for (const state of connections.values()) {
75
+ state.connection.dispose()
76
+ }
77
+ connections.clear()
78
+ }
@@ -0,0 +1,354 @@
1
+ import { spawn, } from 'node:child_process'
2
+ import { basename } from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+ import { LanguageServerMessageParser } from '../LanguageServerMessageParser/LanguageServerMessageParser.js'
5
+ import {
6
+ executeMarkdownLanguageServerRequest,
7
+ isMarkdownLanguageServerRequest,
8
+ } from '../MarkdownLanguageServerRequest/MarkdownLanguageServerRequest.js'
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+ const getPosition = (text, offset) => {
45
+ const safeOffset = Math.max(0, Math.min(offset, text.length))
46
+ const before = text.slice(0, safeOffset)
47
+ const lastLineBreak = before.lastIndexOf('\n')
48
+ return {
49
+ character: lastLineBreak === -1 ? safeOffset : safeOffset - lastLineBreak - 1,
50
+ line: before.split('\n').length - 1,
51
+ }
52
+ }
53
+
54
+ const getWorkspaceName = (rootUri) => {
55
+ try {
56
+ return basename(fileURLToPath(rootUri)) || 'workspace'
57
+ } catch {
58
+ return 'workspace'
59
+ }
60
+ }
61
+
62
+ export class LanguageServerConnection {
63
+ child
64
+ documents = new Map ()
65
+ parser = new LanguageServerMessageParser()
66
+ pendingRequests = new Map ()
67
+ ready
68
+ rootUri
69
+ markdownConfigured = false
70
+ nextRequestId = 1
71
+ running = true
72
+ stderr = ''
73
+
74
+ constructor({ argv, rootUri, uri } ) {
75
+ this.rootUri = rootUri
76
+ this.child = spawn(fileURLToPath(uri), [...argv], {
77
+ stdio: ['pipe', 'pipe', 'pipe'],
78
+ })
79
+ this.child.stdout.on('data', (chunk) => {
80
+ this.handleData(chunk)
81
+ })
82
+ this.child.stderr.on('data', (chunk) => {
83
+ this.stderr += chunk.toString()
84
+ })
85
+ this.child.on('error', (error) => {
86
+ this.handleExit(error)
87
+ })
88
+ this.child.on('exit', (code, signal) => {
89
+ const detail = this.stderr.trim()
90
+ const suffix = detail ? `: ${detail}` : ''
91
+ this.handleExit(new Error(`Language server exited with code ${code} and signal ${signal}${suffix}`))
92
+ })
93
+ this.ready = this.initialize()
94
+ }
95
+
96
+ isRunning() {
97
+ return this.running
98
+ }
99
+
100
+ dispose() {
101
+ if (!this.running) {
102
+ return
103
+ }
104
+ this.running = false
105
+ this.child.kill()
106
+ this.rejectPendingRequests(new Error('Language server was disposed'))
107
+ }
108
+
109
+ async complete(textDocument, offset) {
110
+ await this.ready
111
+ this.configureMarkdown(textDocument.languageId)
112
+ this.syncDocument(textDocument)
113
+ const result = await this.sendRequest('textDocument/completion', {
114
+ context: {
115
+ triggerKind: 1,
116
+ },
117
+ position: getPosition(textDocument.text, offset),
118
+ textDocument: {
119
+ uri: textDocument.uri,
120
+ },
121
+ })
122
+ if (Array.isArray(result)) {
123
+ return result
124
+ }
125
+ if (result && typeof result === 'object' && Array.isArray((result).items)) {
126
+ return (result).items
127
+ }
128
+ return []
129
+ }
130
+
131
+ configureMarkdown(languageId) {
132
+ if (languageId !== 'markdown' || this.markdownConfigured) {
133
+ return
134
+ }
135
+ this.markdownConfigured = true
136
+ this.sendNotification('workspace/didChangeConfiguration', {
137
+ settings: {
138
+ markdown: {
139
+ occurrencesHighlight: {
140
+ enabled: true,
141
+ },
142
+ preferredMdPathExtensionStyle: 'auto',
143
+ server: {
144
+ log: 'off',
145
+ },
146
+ suggest: {
147
+ paths: {
148
+ enabled: true,
149
+ includeWorkspaceHeaderCompletions: 'never',
150
+ },
151
+ },
152
+ validate: {
153
+ enabled: false,
154
+ },
155
+ },
156
+ },
157
+ })
158
+ }
159
+
160
+ async initialize() {
161
+ await this.sendRequest('initialize', {
162
+ capabilities: {
163
+ textDocument: {
164
+ completion: {
165
+ completionItem: {
166
+ snippetSupport: true,
167
+ },
168
+ },
169
+ synchronization: {
170
+ didSave: true,
171
+ dynamicRegistration: false,
172
+ },
173
+ },
174
+ workspace: {
175
+ configuration: true,
176
+ workspaceFolders: true,
177
+ },
178
+ },
179
+ clientInfo: {
180
+ name: 'Lvce Editor',
181
+ },
182
+ processId: process.pid,
183
+ rootUri: this.rootUri,
184
+ workspaceFolders: [
185
+ {
186
+ name: getWorkspaceName(this.rootUri),
187
+ uri: this.rootUri,
188
+ },
189
+ ],
190
+ })
191
+ this.sendNotification('initialized', {})
192
+ }
193
+
194
+ syncDocument(textDocument) {
195
+ const previous = this.documents.get(textDocument.uri)
196
+ if (!previous || previous.languageId !== textDocument.languageId) {
197
+ if (previous) {
198
+ this.sendNotification('textDocument/didClose', {
199
+ textDocument: {
200
+ uri: textDocument.uri,
201
+ },
202
+ })
203
+ }
204
+ const next = {
205
+ languageId: textDocument.languageId,
206
+ text: textDocument.text,
207
+ version: 1,
208
+ }
209
+ this.documents.set(textDocument.uri, next)
210
+ this.sendNotification('textDocument/didOpen', {
211
+ textDocument: {
212
+ languageId: next.languageId,
213
+ text: next.text,
214
+ uri: textDocument.uri,
215
+ version: next.version,
216
+ },
217
+ })
218
+ return
219
+ }
220
+ if (previous.text === textDocument.text) {
221
+ return
222
+ }
223
+ const next = {
224
+ ...previous,
225
+ text: textDocument.text,
226
+ version: previous.version + 1,
227
+ }
228
+ this.documents.set(textDocument.uri, next)
229
+ this.sendNotification('textDocument/didChange', {
230
+ contentChanges: [
231
+ {
232
+ text: next.text,
233
+ },
234
+ ],
235
+ textDocument: {
236
+ uri: textDocument.uri,
237
+ version: next.version,
238
+ },
239
+ })
240
+ }
241
+
242
+ handleData(chunk) {
243
+ try {
244
+ const messages = this.parser.push(chunk)
245
+ for (const message of messages) {
246
+ this.handleMessage(message)
247
+ }
248
+ } catch (error) {
249
+ this.handleExit(error instanceof Error ? error : new Error(String(error)))
250
+ }
251
+ }
252
+
253
+ handleMessage(message) {
254
+ if (message.method && message.id !== undefined && message.id !== null) {
255
+ void this.handleServerRequest(message)
256
+ return
257
+ }
258
+ if (message.id === undefined || message.id === null) {
259
+ return
260
+ }
261
+ const pending = this.pendingRequests.get(message.id)
262
+ if (!pending) {
263
+ return
264
+ }
265
+ this.pendingRequests.delete(message.id)
266
+ if (message.error) {
267
+ pending.reject(new Error(message.error.message || `Language server request failed with code ${message.error.code}`))
268
+ return
269
+ }
270
+ pending.resolve(message.result)
271
+ }
272
+
273
+ async handleServerRequest(message) {
274
+ try {
275
+ let result = null
276
+ if (message.method === 'workspace/configuration') {
277
+ const itemCount = Array.isArray(message.params?.items) ? message.params.items.length : 0
278
+ result = Array.from({ length: itemCount }).fill(null)
279
+ } else if (message.method === 'workspace/workspaceFolders') {
280
+ result = [
281
+ {
282
+ name: getWorkspaceName(this.rootUri),
283
+ uri: this.rootUri,
284
+ },
285
+ ]
286
+ } else if (isMarkdownLanguageServerRequest(message.method || '')) {
287
+ result = await executeMarkdownLanguageServerRequest(message.method || '', message.params || {}, {
288
+ documents: this.documents,
289
+ rootUri: this.rootUri,
290
+ })
291
+ }
292
+ this.sendMessage({
293
+ id: message.id,
294
+ jsonrpc: '2.0',
295
+ result,
296
+ })
297
+ } catch (error) {
298
+ this.sendMessage({
299
+ error: {
300
+ code: -32_603,
301
+ message: error instanceof Error ? error.message : String(error),
302
+ },
303
+ id: message.id,
304
+ jsonrpc: '2.0',
305
+ })
306
+ }
307
+ }
308
+
309
+ handleExit(error) {
310
+ if (!this.running) {
311
+ return
312
+ }
313
+ this.running = false
314
+ this.rejectPendingRequests(error)
315
+ }
316
+
317
+ rejectPendingRequests(error) {
318
+ for (const pending of this.pendingRequests.values()) {
319
+ pending.reject(error)
320
+ }
321
+ this.pendingRequests.clear()
322
+ }
323
+
324
+ sendNotification(method, params) {
325
+ this.sendMessage({
326
+ jsonrpc: '2.0',
327
+ method,
328
+ params,
329
+ })
330
+ }
331
+
332
+ sendRequest(method, params) {
333
+ if (!this.running) {
334
+ return Promise.reject(new Error('Language server is not running'))
335
+ }
336
+ const id = this.nextRequestId++
337
+ const promise = new Promise ((resolve, reject) => {
338
+ this.pendingRequests.set(id, { reject, resolve })
339
+ })
340
+ this.sendMessage({
341
+ id,
342
+ jsonrpc: '2.0',
343
+ method,
344
+ params,
345
+ })
346
+ return promise
347
+ }
348
+
349
+ sendMessage(message) {
350
+ const content = JSON.stringify(message)
351
+ const header = `Content-Length: ${Buffer.byteLength(content)}\r\n\r\n`
352
+ this.child.stdin.write(header + content)
353
+ }
354
+ }
@@ -0,0 +1,32 @@
1
+ const headerSeparator = Buffer.from('\r\n\r\n')
2
+ const contentLengthRegex = /(?:^|\r\n)Content-Length:\s*(\d+)/i
3
+
4
+ export class LanguageServerMessageParser {
5
+ buffer = Buffer.alloc(0)
6
+
7
+ push(chunk) {
8
+ this.buffer = Buffer.concat([this.buffer, chunk])
9
+ const messages = []
10
+ while (true) {
11
+ const headerEnd = this.buffer.indexOf(headerSeparator)
12
+ if (headerEnd === -1) {
13
+ break
14
+ }
15
+ const header = this.buffer.subarray(0, headerEnd).toString('ascii')
16
+ const match = contentLengthRegex.exec(header)
17
+ if (!match) {
18
+ throw new Error('Language server message is missing Content-Length')
19
+ }
20
+ const contentLength = Number(match[1])
21
+ const contentStart = headerEnd + headerSeparator.length
22
+ const contentEnd = contentStart + contentLength
23
+ if (this.buffer.length < contentEnd) {
24
+ break
25
+ }
26
+ const content = this.buffer.subarray(contentStart, contentEnd).toString('utf8')
27
+ this.buffer = this.buffer.subarray(contentEnd)
28
+ messages.push(JSON.parse(content))
29
+ }
30
+ return messages
31
+ }
32
+ }
@@ -0,0 +1,116 @@
1
+ import MarkdownIt from 'markdown-it'
2
+ import { readFile, readdir, stat } from 'node:fs/promises'
3
+ import { isAbsolute, relative, resolve, sep } from 'node:path'
4
+ import { fileURLToPath, pathToFileURL } from 'node:url'
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+ const markdownFileExtensions = new Set(['.markdown', '.md', '.mdown', '.mdtext', '.mdtxt', '.mdwn', '.mkd', '.mkdn'])
21
+ const ignoredDirectories = new Set(['.git', 'node_modules'])
22
+ const markdownIt = new MarkdownIt({ html: true })
23
+
24
+ export const isMarkdownLanguageServerRequest = (method) => {
25
+ return (
26
+ method === 'markdown/parse' ||
27
+ method === 'markdown/fs/readFile' ||
28
+ method === 'markdown/fs/readDirectory' ||
29
+ method === 'markdown/fs/stat' ||
30
+ method === 'markdown/findMarkdownFilesInWorkspace'
31
+ )
32
+ }
33
+
34
+ const getWorkspacePath = (uri, rootUri) => {
35
+ const rootPath = resolve(fileURLToPath(rootUri))
36
+ const targetPath = resolve(fileURLToPath(uri))
37
+ const relativePath = relative(rootPath, targetPath)
38
+ if (relativePath === '..' || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath)) {
39
+ throw new Error(`Language server file request is outside the workspace`)
40
+ }
41
+ return targetPath
42
+ }
43
+
44
+ const getMarkdownText = async (params, context) => {
45
+ if (typeof params.text === 'string') {
46
+ return params.text
47
+ }
48
+ if (!params.uri) {
49
+ throw new Error(`Markdown parse request is missing a uri`)
50
+ }
51
+ const document = context.documents.get(params.uri)
52
+ if (document) {
53
+ return document.text
54
+ }
55
+ const path = getWorkspacePath(params.uri, context.rootUri)
56
+ return readFile(path, 'utf8')
57
+ }
58
+
59
+ const findMarkdownFiles = async (rootPath) => {
60
+ const result = []
61
+ const visit = async (directory) => {
62
+ const entries = await readdir(directory, { withFileTypes: true })
63
+ await Promise.all(
64
+ entries.map(async (entry) => {
65
+ const path = resolve(directory, entry.name)
66
+ if (entry.isDirectory()) {
67
+ if (ignoredDirectories.has(entry.name)) {
68
+ return
69
+ }
70
+ await visit(path)
71
+ return
72
+ }
73
+ const extensionIndex = entry.name.lastIndexOf('.')
74
+ const extension = extensionIndex === -1 ? '' : entry.name.slice(extensionIndex).toLowerCase()
75
+ if (markdownFileExtensions.has(extension)) {
76
+ result.push(pathToFileURL(path).href)
77
+ }
78
+ }),
79
+ )
80
+ }
81
+ await visit(rootPath)
82
+ return result.sort()
83
+ }
84
+
85
+ export const executeMarkdownLanguageServerRequest = async (
86
+ method,
87
+ params,
88
+ context,
89
+ ) => {
90
+ if (method === 'markdown/parse') {
91
+ return markdownIt.parse(await getMarkdownText(params, context), {})
92
+ }
93
+ if (method === 'markdown/findMarkdownFilesInWorkspace') {
94
+ return findMarkdownFiles(getWorkspacePath(context.rootUri, context.rootUri))
95
+ }
96
+ if (!params.uri) {
97
+ throw new Error(`Markdown file request is missing a uri`)
98
+ }
99
+ const path = getWorkspacePath(params.uri, context.rootUri)
100
+ if (method === 'markdown/fs/readFile') {
101
+ return [...(await readFile(path))]
102
+ }
103
+ if (method === 'markdown/fs/readDirectory') {
104
+ const entries = await readdir(path, { withFileTypes: true })
105
+ return entries.map((entry) => [entry.name, { isDirectory: entry.isDirectory() }])
106
+ }
107
+ if (method === 'markdown/fs/stat') {
108
+ try {
109
+ const fileStat = await stat(path)
110
+ return { isDirectory: fileStat.isDirectory() }
111
+ } catch {
112
+ return undefined
113
+ }
114
+ }
115
+ throw new Error(`Unsupported Markdown language server request: ${method}`)
116
+ }
@@ -110,6 +110,8 @@ export const load = (moduleId) => {
110
110
  return import('../InstallExtension/InstallExtension.ipc.js')
111
111
  case ModuleId.IsAutoUpdateSupported:
112
112
  return import('../IsAutoUpdateSupported/IsAutoUpdateSupported.ipc.js')
113
+ case ModuleId.LanguageServer:
114
+ return import('../LanguageServer/LanguageServer.ipc.js')
113
115
  case ModuleId.OpenExternal:
114
116
  return import('../OpenExternal/OpenExternal.ipc.js')
115
117
  case ModuleId.OpenNativeFolder:
@@ -78,3 +78,4 @@ export const HandleMessagePortForClipBoardProcess = 82
78
78
  export const Exec = 83
79
79
  export const PlatformPaths = 84
80
80
  export const HandleMessagePortForAuthProcess = 86
81
+ export const LanguageServer = 87
@@ -67,8 +67,11 @@ export const getModuleId = (commandId) => {
67
67
  case 'ElectronPowerSaveBlocker.start':
68
68
  case 'ElectronPowerSaveBlocker.stop':
69
69
  return ModuleId.ElectronPowerSaveBlocker
70
+ case 'ElectronProcess.getArgv':
70
71
  case 'ElectronProcess.getChromeVersion':
71
72
  case 'ElectronProcess.getElectronVersion':
73
+ case 'ElectronProcess.writeStderr':
74
+ case 'ElectronProcess.writeStdout':
72
75
  return ModuleId.ElectronProcess
73
76
  case 'ElectronSafeStorage.decryptString':
74
77
  case 'ElectronSafeStorage.encryptString':
@@ -244,6 +247,8 @@ export const getModuleId = (commandId) => {
244
247
  return ModuleId.InstallExtension
245
248
  case 'IsAutoUpdateSupported.isAutoUpdateSupported':
246
249
  return ModuleId.IsAutoUpdateSupported
250
+ case 'LanguageServer.complete':
251
+ return ModuleId.LanguageServer
247
252
  case 'ListProcessesWithMemoryUsage.listProcessesWithMemoryUsage':
248
253
  return ModuleId.ListProcessesWithMemoryUsage
249
254
  case 'Native.openFolder':
@@ -61,11 +61,11 @@ export const getSetupName = () => {
61
61
  return 'Lvce-Setup'
62
62
  }
63
63
 
64
- export const version = '0.89.2'
64
+ export const version = '0.90.1'
65
65
 
66
- export const commit = '331d398'
66
+ export const commit = 'd347596'
67
67
 
68
- export const date = '2026-07-14T10:36:39.000Z'
68
+ export const date = '2026-07-14T15:50:53.000Z'
69
69
 
70
70
  export const getVersion = () => {
71
71
  return version
@@ -2,5 +2,5 @@ import { join } from 'node:path'
2
2
  import * as Root from '../Root/Root.js'
3
3
 
4
4
  export const getPreloadUrl = () => {
5
- return join(Root.root, 'static', '331d398', 'packages', 'preload', 'dist', 'index.js')
5
+ return join(Root.root, 'static', 'd347596', 'packages', 'preload', 'dist', 'index.js')
6
6
  }
@@ -5,6 +5,7 @@ import * as Env from '../Env/Env.js'
5
5
  import * as GetWorkspaceId from '../GetWorkspaceId/GetWorkspaceId.js'
6
6
  import * as IsAbsolutePath from '../IsAbsolutePath/IsAbsolutePath.js'
7
7
  import * as IsElectron from '../IsElectron/IsElectron.js'
8
+ import * as IsPromptMode from '../IsPromptMode/IsPromptMode.js'
8
9
  import * as ParentIpc from '../MainProcess/MainProcess.js'
9
10
  import * as Platform from '../Platform/Platform.js'
10
11
  import * as PlatformPaths from '../PlatformPaths/PlatformPaths.js'
@@ -33,7 +34,7 @@ export const resolveRoot = async () => {
33
34
  const argv = await ParentIpc.invoke('Process.getArgv')
34
35
  const relevantArgv = argv.slice(1)
35
36
  const last = relevantArgv.at(-1)
36
- if (last && last === '.') {
37
+ if (IsPromptMode.isPromptMode(relevantArgv) || (last && last === '.')) {
37
38
  const actual = process.cwd()
38
39
  return {
39
40
  homeDir: PlatformPaths.getHomeDir(),