@nogataka/smart-edit 0.0.14

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.
Files changed (186) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +244 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +7 -0
  5. package/dist/devtools/generate_prompt_factory.d.ts +5 -0
  6. package/dist/devtools/generate_prompt_factory.js +114 -0
  7. package/dist/index.d.ts +34 -0
  8. package/dist/index.js +34 -0
  9. package/dist/interprompt/index.d.ts +2 -0
  10. package/dist/interprompt/index.js +1 -0
  11. package/dist/interprompt/jinja_template.d.ts +10 -0
  12. package/dist/interprompt/jinja_template.js +174 -0
  13. package/dist/interprompt/multilang_prompt.d.ts +54 -0
  14. package/dist/interprompt/multilang_prompt.js +302 -0
  15. package/dist/interprompt/prompt_factory.d.ts +16 -0
  16. package/dist/interprompt/prompt_factory.js +189 -0
  17. package/dist/interprompt/util/class_decorators.d.ts +1 -0
  18. package/dist/interprompt/util/class_decorators.js +1 -0
  19. package/dist/interprompt/util/index.d.ts +1 -0
  20. package/dist/interprompt/util/index.js +1 -0
  21. package/dist/serena/agent.d.ts +118 -0
  22. package/dist/serena/agent.js +675 -0
  23. package/dist/serena/agno.d.ts +111 -0
  24. package/dist/serena/agno.js +278 -0
  25. package/dist/serena/analytics.d.ts +24 -0
  26. package/dist/serena/analytics.js +119 -0
  27. package/dist/serena/cli.d.ts +9 -0
  28. package/dist/serena/cli.js +731 -0
  29. package/dist/serena/code_editor.d.ts +42 -0
  30. package/dist/serena/code_editor.js +239 -0
  31. package/dist/serena/config/context_mode.d.ts +41 -0
  32. package/dist/serena/config/context_mode.js +239 -0
  33. package/dist/serena/config/serena_config.d.ts +134 -0
  34. package/dist/serena/config/serena_config.js +718 -0
  35. package/dist/serena/constants.d.ts +18 -0
  36. package/dist/serena/constants.js +27 -0
  37. package/dist/serena/dashboard.d.ts +55 -0
  38. package/dist/serena/dashboard.js +472 -0
  39. package/dist/serena/generated/generated_prompt_factory.d.ts +27 -0
  40. package/dist/serena/generated/generated_prompt_factory.js +42 -0
  41. package/dist/serena/gui_log_viewer.d.ts +41 -0
  42. package/dist/serena/gui_log_viewer.js +436 -0
  43. package/dist/serena/mcp.d.ts +118 -0
  44. package/dist/serena/mcp.js +904 -0
  45. package/dist/serena/project.d.ts +62 -0
  46. package/dist/serena/project.js +321 -0
  47. package/dist/serena/prompt_factory.d.ts +20 -0
  48. package/dist/serena/prompt_factory.js +42 -0
  49. package/dist/serena/resources/config/contexts/agent.yml +8 -0
  50. package/dist/serena/resources/config/contexts/chatgpt.yml +28 -0
  51. package/dist/serena/resources/config/contexts/codex.yml +27 -0
  52. package/dist/serena/resources/config/contexts/context.template.yml +11 -0
  53. package/dist/serena/resources/config/contexts/desktop-app.yml +17 -0
  54. package/dist/serena/resources/config/contexts/ide-assistant.yml +26 -0
  55. package/dist/serena/resources/config/contexts/oaicompat-agent.yml +8 -0
  56. package/dist/serena/resources/config/internal_modes/jetbrains.yml +15 -0
  57. package/dist/serena/resources/config/modes/editing.yml +112 -0
  58. package/dist/serena/resources/config/modes/interactive.yml +11 -0
  59. package/dist/serena/resources/config/modes/mode.template.yml +7 -0
  60. package/dist/serena/resources/config/modes/no-onboarding.yml +8 -0
  61. package/dist/serena/resources/config/modes/onboarding.yml +16 -0
  62. package/dist/serena/resources/config/modes/one-shot.yml +15 -0
  63. package/dist/serena/resources/config/modes/planning.yml +15 -0
  64. package/dist/serena/resources/config/prompt_templates/simple_tool_outputs.yml +75 -0
  65. package/dist/serena/resources/config/prompt_templates/system_prompt.yml +66 -0
  66. package/dist/serena/resources/dashboard/dashboard.js +815 -0
  67. package/dist/serena/resources/dashboard/index.html +314 -0
  68. package/dist/serena/resources/dashboard/jquery.min.js +3 -0
  69. package/dist/serena/resources/dashboard/serena-icon-16.png +0 -0
  70. package/dist/serena/resources/dashboard/serena-icon-32.png +0 -0
  71. package/dist/serena/resources/dashboard/serena-icon-48.png +0 -0
  72. package/dist/serena/resources/dashboard/serena-logs-dark-mode.png +0 -0
  73. package/dist/serena/resources/dashboard/serena-logs.png +0 -0
  74. package/dist/serena/resources/project.template.yml +67 -0
  75. package/dist/serena/resources/serena_config.template.yml +85 -0
  76. package/dist/serena/symbol.d.ts +199 -0
  77. package/dist/serena/symbol.js +616 -0
  78. package/dist/serena/text_utils.d.ts +51 -0
  79. package/dist/serena/text_utils.js +267 -0
  80. package/dist/serena/tools/cmd_tools.d.ts +31 -0
  81. package/dist/serena/tools/cmd_tools.js +48 -0
  82. package/dist/serena/tools/config_tools.d.ts +53 -0
  83. package/dist/serena/tools/config_tools.js +176 -0
  84. package/dist/serena/tools/file_tools.d.ts +231 -0
  85. package/dist/serena/tools/file_tools.js +511 -0
  86. package/dist/serena/tools/index.d.ts +7 -0
  87. package/dist/serena/tools/index.js +7 -0
  88. package/dist/serena/tools/memory_tools.d.ts +60 -0
  89. package/dist/serena/tools/memory_tools.js +135 -0
  90. package/dist/serena/tools/symbol_tools.d.ts +165 -0
  91. package/dist/serena/tools/symbol_tools.js +362 -0
  92. package/dist/serena/tools/tools_base.d.ts +162 -0
  93. package/dist/serena/tools/tools_base.js +378 -0
  94. package/dist/serena/tools/workflow_tools.d.ts +35 -0
  95. package/dist/serena/tools/workflow_tools.js +161 -0
  96. package/dist/serena/util/class_decorators.d.ts +7 -0
  97. package/dist/serena/util/class_decorators.js +37 -0
  98. package/dist/serena/util/exception.d.ts +8 -0
  99. package/dist/serena/util/exception.js +53 -0
  100. package/dist/serena/util/file_system.d.ts +30 -0
  101. package/dist/serena/util/file_system.js +352 -0
  102. package/dist/serena/util/general.d.ts +11 -0
  103. package/dist/serena/util/general.js +42 -0
  104. package/dist/serena/util/git.d.ts +11 -0
  105. package/dist/serena/util/git.js +37 -0
  106. package/dist/serena/util/inspection.d.ts +45 -0
  107. package/dist/serena/util/inspection.js +221 -0
  108. package/dist/serena/util/logging.d.ts +46 -0
  109. package/dist/serena/util/logging.js +205 -0
  110. package/dist/serena/util/shell.d.ts +21 -0
  111. package/dist/serena/util/shell.js +95 -0
  112. package/dist/serena/util/thread.d.ts +23 -0
  113. package/dist/serena/util/thread.js +88 -0
  114. package/dist/serena/version.d.ts +1 -0
  115. package/dist/serena/version.js +23 -0
  116. package/dist/solidlsp/language_servers/autoload.d.ts +23 -0
  117. package/dist/solidlsp/language_servers/autoload.js +25 -0
  118. package/dist/solidlsp/language_servers/bash_language_server.d.ts +10 -0
  119. package/dist/solidlsp/language_servers/bash_language_server.js +64 -0
  120. package/dist/solidlsp/language_servers/clangd_language_server.d.ts +13 -0
  121. package/dist/solidlsp/language_servers/clangd_language_server.js +110 -0
  122. package/dist/solidlsp/language_servers/clojure_lsp.d.ts +13 -0
  123. package/dist/solidlsp/language_servers/clojure_lsp.js +137 -0
  124. package/dist/solidlsp/language_servers/common.d.ts +41 -0
  125. package/dist/solidlsp/language_servers/common.js +365 -0
  126. package/dist/solidlsp/language_servers/csharp_language_server.d.ts +21 -0
  127. package/dist/solidlsp/language_servers/csharp_language_server.js +694 -0
  128. package/dist/solidlsp/language_servers/dart_language_server.d.ts +10 -0
  129. package/dist/solidlsp/language_servers/dart_language_server.js +122 -0
  130. package/dist/solidlsp/language_servers/eclipse_jdtls.d.ts +24 -0
  131. package/dist/solidlsp/language_servers/eclipse_jdtls.js +671 -0
  132. package/dist/solidlsp/language_servers/erlang_language_server.d.ts +22 -0
  133. package/dist/solidlsp/language_servers/erlang_language_server.js +327 -0
  134. package/dist/solidlsp/language_servers/gopls.d.ts +12 -0
  135. package/dist/solidlsp/language_servers/gopls.js +59 -0
  136. package/dist/solidlsp/language_servers/intelephense.d.ts +13 -0
  137. package/dist/solidlsp/language_servers/intelephense.js +121 -0
  138. package/dist/solidlsp/language_servers/jedi_server.d.ts +18 -0
  139. package/dist/solidlsp/language_servers/jedi_server.js +234 -0
  140. package/dist/solidlsp/language_servers/kotlin_language_server.d.ts +19 -0
  141. package/dist/solidlsp/language_servers/kotlin_language_server.js +474 -0
  142. package/dist/solidlsp/language_servers/lua_ls.d.ts +18 -0
  143. package/dist/solidlsp/language_servers/lua_ls.js +319 -0
  144. package/dist/solidlsp/language_servers/nixd_language_server.d.ts +17 -0
  145. package/dist/solidlsp/language_servers/nixd_language_server.js +341 -0
  146. package/dist/solidlsp/language_servers/pyright_server.d.ts +19 -0
  147. package/dist/solidlsp/language_servers/pyright_server.js +180 -0
  148. package/dist/solidlsp/language_servers/r_language_server.d.ts +19 -0
  149. package/dist/solidlsp/language_servers/r_language_server.js +184 -0
  150. package/dist/solidlsp/language_servers/ruby_common.d.ts +10 -0
  151. package/dist/solidlsp/language_servers/ruby_common.js +136 -0
  152. package/dist/solidlsp/language_servers/ruby_lsp.d.ts +18 -0
  153. package/dist/solidlsp/language_servers/ruby_lsp.js +230 -0
  154. package/dist/solidlsp/language_servers/rust_analyzer.d.ts +13 -0
  155. package/dist/solidlsp/language_servers/rust_analyzer.js +96 -0
  156. package/dist/solidlsp/language_servers/solargraph.d.ts +18 -0
  157. package/dist/solidlsp/language_servers/solargraph.js +208 -0
  158. package/dist/solidlsp/language_servers/sourcekit_lsp.d.ts +24 -0
  159. package/dist/solidlsp/language_servers/sourcekit_lsp.js +449 -0
  160. package/dist/solidlsp/language_servers/terraform_ls.d.ts +13 -0
  161. package/dist/solidlsp/language_servers/terraform_ls.js +139 -0
  162. package/dist/solidlsp/language_servers/typescript_language_server.d.ts +20 -0
  163. package/dist/solidlsp/language_servers/typescript_language_server.js +237 -0
  164. package/dist/solidlsp/language_servers/vts_language_server.d.ts +13 -0
  165. package/dist/solidlsp/language_servers/vts_language_server.js +121 -0
  166. package/dist/solidlsp/language_servers/zls.d.ts +20 -0
  167. package/dist/solidlsp/language_servers/zls.js +254 -0
  168. package/dist/solidlsp/ls.d.ts +197 -0
  169. package/dist/solidlsp/ls.js +507 -0
  170. package/dist/solidlsp/ls_config.d.ts +43 -0
  171. package/dist/solidlsp/ls_config.js +157 -0
  172. package/dist/solidlsp/ls_exceptions.d.ts +5 -0
  173. package/dist/solidlsp/ls_exceptions.js +14 -0
  174. package/dist/solidlsp/ls_handler.d.ts +54 -0
  175. package/dist/solidlsp/ls_handler.js +406 -0
  176. package/dist/solidlsp/ls_request.d.ts +31 -0
  177. package/dist/solidlsp/ls_request.js +42 -0
  178. package/dist/solidlsp/ls_types.d.ts +7 -0
  179. package/dist/solidlsp/ls_types.js +8 -0
  180. package/dist/solidlsp/lsp_protocol_handler/server.d.ts +61 -0
  181. package/dist/solidlsp/lsp_protocol_handler/server.js +68 -0
  182. package/dist/solidlsp/util/subprocess_util.d.ts +6 -0
  183. package/dist/solidlsp/util/subprocess_util.js +11 -0
  184. package/dist/solidlsp/util/zip.d.ts +25 -0
  185. package/dist/solidlsp/util/zip.js +188 -0
  186. package/package.json +65 -0
@@ -0,0 +1,237 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { createSerenaLogger } from '../../serena/util/logging.js';
6
+ import { Language } from '../ls_config.js';
7
+ import { ensureDefaultSubprocessOptions } from '../util/subprocess_util.js';
8
+ import { SolidLanguageServer, SolidLspSettings, registerLanguageServer } from '../ls.js';
9
+ import { NodeLanguageServerHandler } from '../ls_handler.js';
10
+ import { Platform, RuntimeDependencyCollection, quoteWindowsPath } from './common.js';
11
+ const TYPESCRIPT_IGNORED_PATTERNS = ['**/node_modules', '**/dist', '**/build', '**/coverage'];
12
+ export class TypeScriptLanguageServer extends SolidLanguageServer {
13
+ nodeHandler;
14
+ initialized = false;
15
+ serverReady = false;
16
+ initializeCommandRegistered = false;
17
+ constructor(config, loggerLike, repositoryRootPath, options = {}) {
18
+ const augmentedConfig = {
19
+ ...config,
20
+ ignoredPaths: mergeIgnoredPaths(config.ignoredPaths, TYPESCRIPT_IGNORED_PATTERNS)
21
+ };
22
+ const solidSettings = new SolidLspSettings(options?.solidlspSettings);
23
+ const launchInfo = determineLaunchInfo(solidSettings);
24
+ const handler = new NodeLanguageServerHandler({
25
+ ...launchInfo,
26
+ cwd: repositoryRootPath
27
+ });
28
+ super(augmentedConfig, loggerLike, repositoryRootPath, {
29
+ ...options,
30
+ handler,
31
+ solidlspSettings: options?.solidlspSettings
32
+ });
33
+ this.nodeHandler = handler;
34
+ this.registerHandlers();
35
+ }
36
+ start() {
37
+ const shouldInitialize = !this.initialized;
38
+ super.start();
39
+ if (shouldInitialize) {
40
+ this.serverReady = false;
41
+ this.initializeCommandRegistered = false;
42
+ this.initializeLanguageServer();
43
+ this.initialized = true;
44
+ }
45
+ return this;
46
+ }
47
+ stop(shutdownTimeout = 2.0) {
48
+ super.stop(shutdownTimeout);
49
+ this.initialized = false;
50
+ this.serverReady = false;
51
+ this.initializeCommandRegistered = false;
52
+ }
53
+ registerHandlers() {
54
+ this.nodeHandler.onRequest('client/registerCapability', (params) => {
55
+ const registrations = params?.registrations;
56
+ if (!Array.isArray(registrations)) {
57
+ return null;
58
+ }
59
+ for (const registration of registrations) {
60
+ if (registration?.method === 'workspace/executeCommand') {
61
+ this.initializeCommandRegistered = true;
62
+ }
63
+ }
64
+ return null;
65
+ });
66
+ this.nodeHandler.onRequest('workspace/executeClientCommand', () => []);
67
+ const noop = () => undefined;
68
+ this.nodeHandler.onNotification('$/progress', noop);
69
+ this.nodeHandler.onNotification('textDocument/publishDiagnostics', noop);
70
+ this.nodeHandler.onNotification('window/logMessage', (payload) => {
71
+ const message = extractMessage(payload);
72
+ if (message) {
73
+ this.logger.info(`TypeScript LS: ${message}`);
74
+ }
75
+ });
76
+ this.nodeHandler.onNotification('experimental/serverStatus', (payload) => {
77
+ const params = payload;
78
+ if (params?.quiescent) {
79
+ this.serverReady = true;
80
+ }
81
+ });
82
+ }
83
+ initializeLanguageServer() {
84
+ const params = this.buildInitializeParams();
85
+ const response = this.nodeHandler.sendRequest('initialize', params);
86
+ if (!response || typeof response !== 'object') {
87
+ throw new Error('TypeScript language server returned an invalid initialize response.');
88
+ }
89
+ this.verifyCapabilities(response.capabilities ?? null);
90
+ this.nodeHandler.notify.initialized({});
91
+ if (!this.serverReady) {
92
+ this.logger.debug('TypeScript language server did not report readiness before timeout; continuing.');
93
+ }
94
+ if (!this.initializeCommandRegistered) {
95
+ this.logger.debug('TypeScript language server did not register workspace/executeCommand capability during initialization.');
96
+ }
97
+ }
98
+ buildInitializeParams() {
99
+ const rootUri = pathToFileURL(this.repositoryRootPath).href;
100
+ return {
101
+ locale: 'en',
102
+ capabilities: {
103
+ textDocument: {
104
+ synchronization: { didSave: true, dynamicRegistration: true },
105
+ completion: {
106
+ dynamicRegistration: true,
107
+ completionItem: { snippetSupport: true }
108
+ },
109
+ definition: { dynamicRegistration: true },
110
+ references: { dynamicRegistration: true },
111
+ documentSymbol: {
112
+ dynamicRegistration: true,
113
+ hierarchicalDocumentSymbolSupport: true,
114
+ symbolKind: { valueSet: rangeArray(1, 27) }
115
+ },
116
+ hover: {
117
+ dynamicRegistration: true,
118
+ contentFormat: ['markdown', 'plaintext']
119
+ },
120
+ signatureHelp: { dynamicRegistration: true },
121
+ codeAction: { dynamicRegistration: true }
122
+ },
123
+ workspace: {
124
+ workspaceFolders: true,
125
+ didChangeConfiguration: { dynamicRegistration: true },
126
+ symbol: { dynamicRegistration: true }
127
+ }
128
+ },
129
+ processId: process.pid,
130
+ rootPath: this.repositoryRootPath,
131
+ rootUri,
132
+ workspaceFolders: [
133
+ {
134
+ uri: rootUri,
135
+ name: path.basename(this.repositoryRootPath)
136
+ }
137
+ ]
138
+ };
139
+ }
140
+ verifyCapabilities(capabilities) {
141
+ if (!capabilities) {
142
+ throw new Error('TypeScript initialization response is missing capabilities.');
143
+ }
144
+ const textDocumentSync = capabilities.textDocumentSync;
145
+ const completionProvider = capabilities.completionProvider;
146
+ if (textDocumentSync !== 2) {
147
+ throw new Error('TypeScript language server must provide incremental textDocumentSync (value 2).');
148
+ }
149
+ if (!completionProvider || typeof completionProvider !== 'object') {
150
+ throw new Error('TypeScript language server does not expose completionProvider capability.');
151
+ }
152
+ }
153
+ }
154
+ function determineLaunchInfo(settings) {
155
+ const { logger } = createSerenaLogger({
156
+ name: 'solidlsp.language_servers.typescript',
157
+ emitToConsole: false
158
+ });
159
+ const runtimeDir = resolveRuntimeDirectory(settings);
160
+ let localBinary = null;
161
+ if (process.env.SERENA_SKIP_RUNTIME_INSTALL !== '1') {
162
+ assertBinaryAvailable('node');
163
+ assertBinaryAvailable('npm');
164
+ const dependencies = new RuntimeDependencyCollection([
165
+ {
166
+ id: 'typescript',
167
+ description: 'typescript npm package',
168
+ command: ['npm', 'install', '--prefix', './', 'typescript@5.5.4'],
169
+ platformId: 'any'
170
+ },
171
+ {
172
+ id: 'typescript-language-server',
173
+ description: 'typescript-language-server npm package',
174
+ command: ['npm', 'install', '--prefix', './', 'typescript-language-server@4.3.3'],
175
+ platformId: 'any'
176
+ }
177
+ ]);
178
+ try {
179
+ dependencies.install(logger, runtimeDir);
180
+ }
181
+ catch (error) {
182
+ logger.warn(`Failed to install TypeScript language server dependencies: ${String(error)}`);
183
+ }
184
+ }
185
+ const binName = Platform.isWindows() ? 'typescript-language-server.cmd' : 'typescript-language-server';
186
+ localBinary = locateLocalBinary(runtimeDir, binName);
187
+ if (localBinary) {
188
+ return { cmd: `${quoteWindowsPath(localBinary)} --stdio` };
189
+ }
190
+ if (process.env.SERENA_SKIP_RUNTIME_INSTALL === '1') {
191
+ return { cmd: 'typescript-language-server --stdio' };
192
+ }
193
+ throw new Error(`typescript-language-server executable not found in ${runtimeDir}.`);
194
+ }
195
+ function locateLocalBinary(runtimeDir, binaryName) {
196
+ const candidate = path.join(runtimeDir, 'node_modules', '.bin', binaryName);
197
+ if (fs.existsSync(candidate)) {
198
+ return candidate;
199
+ }
200
+ return null;
201
+ }
202
+ function resolveRuntimeDirectory(settings) {
203
+ const dir = path.join(settings.languageServersStaticDir, 'TypeScriptLanguageServer');
204
+ fs.mkdirSync(dir, { recursive: true });
205
+ return dir;
206
+ }
207
+ function assertBinaryAvailable(command) {
208
+ const locator = process.platform === 'win32' ? 'where' : 'which';
209
+ const result = spawnSync(locator, [command], ensureDefaultSubprocessOptions({
210
+ stdio: 'ignore'
211
+ }));
212
+ if (result.status !== 0) {
213
+ throw new Error(`${command} is not installed or not available in PATH.`);
214
+ }
215
+ }
216
+ function mergeIgnoredPaths(existing, additions) {
217
+ const merged = new Set(existing ?? []);
218
+ for (const entry of additions) {
219
+ merged.add(entry);
220
+ }
221
+ return Array.from(merged);
222
+ }
223
+ function extractMessage(payload) {
224
+ if (!payload || typeof payload !== 'object') {
225
+ return null;
226
+ }
227
+ const message = payload.message;
228
+ return typeof message === 'string' ? message : null;
229
+ }
230
+ function rangeArray(start, endExclusive) {
231
+ const values = [];
232
+ for (let value = start; value < endExclusive; value += 1) {
233
+ values.push(value);
234
+ }
235
+ return values;
236
+ }
237
+ registerLanguageServer(Language.TYPESCRIPT, TypeScriptLanguageServer);
@@ -0,0 +1,13 @@
1
+ import { type LogLevel } from '../../serena/util/logging.js';
2
+ import { SolidLanguageServer, type LanguageServerConfigLike, type SolidLspSettingsInit } from '../ls.js';
3
+ import { NodeLanguageServerHandler } from '../ls_handler.js';
4
+ export declare class VtsLanguageServer extends SolidLanguageServer {
5
+ protected readonly handler: NodeLanguageServerHandler;
6
+ constructor(config: LanguageServerConfigLike, loggerLike: {
7
+ level?: number | LogLevel;
8
+ } | null, repositoryRootPath: string, options?: {
9
+ timeout?: number | null;
10
+ solidlspSettings?: SolidLspSettingsInit;
11
+ });
12
+ private registerHandlers;
13
+ }
@@ -0,0 +1,121 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { createSerenaLogger } from '../../serena/util/logging.js';
5
+ import { Language } from '../ls_config.js';
6
+ import { ensureDefaultSubprocessOptions } from '../util/subprocess_util.js';
7
+ import { SolidLanguageServer, SolidLspSettings, registerLanguageServer, coerceLogLevel } from '../ls.js';
8
+ import { NodeLanguageServerHandler } from '../ls_handler.js';
9
+ import { RuntimeDependencyCollection, quoteWindowsPath } from './common.js';
10
+ const VTS_DEPENDENCIES = [
11
+ {
12
+ id: 'vtsls',
13
+ command: 'npm install --prefix ./ @vtsls/language-server@0.2.9',
14
+ platformId: 'any'
15
+ }
16
+ ];
17
+ function commandExists(command) {
18
+ const locator = process.platform === 'win32' ? 'where' : 'which';
19
+ return spawnSync(locator, [command], ensureDefaultSubprocessOptions({ stdio: 'ignore' })).status === 0;
20
+ }
21
+ function ensureNodeTooling() {
22
+ if (process.env.SERENA_ASSUME_VTSLS === '1') {
23
+ return;
24
+ }
25
+ if (!commandExists('node')) {
26
+ throw new Error('Node.js is not installed or not in PATH. Install it from https://nodejs.org/ and retry.');
27
+ }
28
+ if (!commandExists('npm')) {
29
+ throw new Error('npm is not installed or not in PATH. Install npm (bundled with Node.js) and retry.');
30
+ }
31
+ }
32
+ function resolveRuntimeDirectory(settings) {
33
+ const dir = path.join(settings.languageServersStaticDir, 'vts-lsp');
34
+ fs.mkdirSync(dir, { recursive: true });
35
+ return dir;
36
+ }
37
+ function resolveBinaryPath(runtimeDir) {
38
+ const base = path.join(runtimeDir, 'node_modules', '.bin');
39
+ if (process.platform === 'win32') {
40
+ const cmdPath = path.join(base, 'vtsls.cmd');
41
+ if (fs.existsSync(cmdPath)) {
42
+ return cmdPath;
43
+ }
44
+ const ps1Path = path.join(base, 'vtsls.ps1');
45
+ if (fs.existsSync(ps1Path)) {
46
+ return ps1Path;
47
+ }
48
+ }
49
+ return path.join(base, 'vtsls');
50
+ }
51
+ function ensureVtslsBinary(runtimeDir, dependencies, loggerLevel) {
52
+ const { logger } = createSerenaLogger({
53
+ name: 'solidlsp.language_servers.vtsls',
54
+ emitToConsole: false,
55
+ level: loggerLevel === undefined ? undefined : coerceLogLevel(loggerLevel)
56
+ });
57
+ const binaryPath = resolveBinaryPath(runtimeDir);
58
+ if (fs.existsSync(binaryPath)) {
59
+ return binaryPath;
60
+ }
61
+ if (process.env.SERENA_SKIP_RUNTIME_INSTALL === '1') {
62
+ throw new Error(`vtsls executable not found at ${binaryPath}. Allow downloads or install @vtsls/language-server manually.`);
63
+ }
64
+ ensureNodeTooling();
65
+ logger.info('Installing @vtsls/language-server via npm');
66
+ dependencies.install(logger, runtimeDir);
67
+ if (!fs.existsSync(binaryPath)) {
68
+ throw new Error(`@vtsls/language-server installation completed but executable missing at ${binaryPath}. Verify npm installation succeeded.`);
69
+ }
70
+ if (process.platform !== 'win32') {
71
+ try {
72
+ fs.chmodSync(binaryPath, 0o755);
73
+ }
74
+ catch {
75
+ // ignore chmod failures
76
+ }
77
+ }
78
+ return binaryPath;
79
+ }
80
+ function mergeIgnoredPaths(existing) {
81
+ const merged = new Set(existing ?? []);
82
+ ['node_modules', 'dist', 'build', 'coverage'].forEach((entry) => merged.add(entry));
83
+ return Array.from(merged);
84
+ }
85
+ export class VtsLanguageServer extends SolidLanguageServer {
86
+ handler;
87
+ constructor(config, loggerLike, repositoryRootPath, options = {}) {
88
+ const augmentedConfig = {
89
+ ...config,
90
+ ignoredPaths: mergeIgnoredPaths(config.ignoredPaths)
91
+ };
92
+ const solidSettings = new SolidLspSettings(options?.solidlspSettings);
93
+ const runtimeDir = resolveRuntimeDirectory(solidSettings);
94
+ const dependencies = new RuntimeDependencyCollection(VTS_DEPENDENCIES);
95
+ const binaryPath = ensureVtslsBinary(runtimeDir, dependencies, loggerLike?.level);
96
+ const handler = new NodeLanguageServerHandler({
97
+ cmd: `${quoteWindowsPath(binaryPath)} --stdio`,
98
+ cwd: repositoryRootPath
99
+ });
100
+ super(augmentedConfig, loggerLike, repositoryRootPath, {
101
+ ...options,
102
+ handler,
103
+ solidlspSettings: options?.solidlspSettings
104
+ });
105
+ this.handler = handler;
106
+ this.registerHandlers();
107
+ }
108
+ registerHandlers() {
109
+ const noop = () => undefined;
110
+ this.handler.onNotification('window/logMessage', (payload) => {
111
+ if (payload && typeof payload === 'object' && 'message' in payload) {
112
+ this.logger.info(`vtsls: ${payload.message ?? ''}`);
113
+ }
114
+ });
115
+ this.handler.onNotification('$/progress', noop);
116
+ this.handler.onNotification('textDocument/publishDiagnostics', noop);
117
+ this.handler.onRequest('client/registerCapability', noop);
118
+ this.handler.onRequest('workspace/executeClientCommand', () => []);
119
+ }
120
+ }
121
+ registerLanguageServer(Language.TYPESCRIPT_VTS, VtsLanguageServer);
@@ -0,0 +1,20 @@
1
+ import type { LogLevel } from '../../serena/util/logging.js';
2
+ import { SolidLanguageServer, type LanguageServerConfigLike, type SolidLspSettingsInit } from '../ls.js';
3
+ import { NodeLanguageServerHandler } from '../ls_handler.js';
4
+ export declare class ZigLanguageServer extends SolidLanguageServer {
5
+ protected readonly handler: NodeLanguageServerHandler;
6
+ private initialized;
7
+ constructor(config: LanguageServerConfigLike, loggerLike: {
8
+ level?: number | LogLevel;
9
+ } | null, repositoryRootPath: string, options?: {
10
+ timeout?: number | null;
11
+ solidlspSettings?: SolidLspSettingsInit;
12
+ });
13
+ start(): this;
14
+ stop(shutdownTimeout?: number): void;
15
+ private registerHandlers;
16
+ private initializeLanguageServer;
17
+ private buildInitializeParams;
18
+ private verifyCapabilities;
19
+ private openBuildFileIfPresent;
20
+ }
@@ -0,0 +1,254 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { ensureDefaultSubprocessOptions } from '../util/subprocess_util.js';
6
+ import { Language } from '../ls_config.js';
7
+ import { SolidLanguageServer, registerLanguageServer } from '../ls.js';
8
+ import { NodeLanguageServerHandler } from '../ls_handler.js';
9
+ import { quoteWindowsPath } from './common.js';
10
+ const ZLS_ASSUME_ENV = 'SERENA_ASSUME_ZLS';
11
+ const ZLS_PATH_ENV = 'SERENA_ZLS_PATH';
12
+ const ZIG_PATH_ENV = 'SERENA_ZIG_PATH';
13
+ const WINDOWS_UNSUPPORTED_MESSAGE = 'Windows is not supported by the Zig Language Server integration. Cross-file references are unreliable on Windows.';
14
+ const ZIG_IGNORED_DIRECTORIES = ['zig-cache', '.zig-cache', 'zig-out', 'node_modules', 'build', 'dist'];
15
+ export class ZigLanguageServer extends SolidLanguageServer {
16
+ handler;
17
+ initialized = false;
18
+ constructor(config, loggerLike, repositoryRootPath, options = {}) {
19
+ const augmentedConfig = {
20
+ ...config,
21
+ ignoredPaths: mergeIgnoredPaths(config.ignoredPaths, ZIG_IGNORED_DIRECTORIES)
22
+ };
23
+ const binaryPath = ensureZlsRuntime();
24
+ const handler = new NodeLanguageServerHandler({
25
+ cmd: [quoteWindowsPath(binaryPath)],
26
+ cwd: repositoryRootPath
27
+ });
28
+ super(augmentedConfig, loggerLike, repositoryRootPath, {
29
+ ...options,
30
+ handler,
31
+ solidlspSettings: options?.solidlspSettings
32
+ });
33
+ this.handler = handler;
34
+ this.registerHandlers();
35
+ }
36
+ start() {
37
+ const shouldInitialize = !this.initialized;
38
+ super.start();
39
+ if (shouldInitialize) {
40
+ this.initializeLanguageServer();
41
+ this.initialized = true;
42
+ }
43
+ return this;
44
+ }
45
+ stop(shutdownTimeout = 2.0) {
46
+ super.stop(shutdownTimeout);
47
+ this.initialized = false;
48
+ }
49
+ registerHandlers() {
50
+ const noop = () => undefined;
51
+ this.handler.onRequest('client/registerCapability', noop);
52
+ this.handler.onNotification('window/logMessage', (payload) => {
53
+ const message = extractWindowMessage(payload);
54
+ if (message) {
55
+ this.logger.info(`zls: ${message}`);
56
+ }
57
+ });
58
+ this.handler.onNotification('$/progress', noop);
59
+ this.handler.onNotification('textDocument/publishDiagnostics', noop);
60
+ }
61
+ initializeLanguageServer() {
62
+ const params = this.buildInitializeParams();
63
+ const response = this.handler.sendRequest('initialize', params);
64
+ this.verifyCapabilities(response?.capabilities ?? null);
65
+ this.handler.notify.initialized({});
66
+ this.openBuildFileIfPresent();
67
+ }
68
+ buildInitializeParams() {
69
+ const rootUri = pathToFileURL(this.repositoryRootPath).href;
70
+ return {
71
+ processId: process.pid,
72
+ locale: 'en',
73
+ rootPath: this.repositoryRootPath,
74
+ rootUri,
75
+ capabilities: buildClientCapabilities(),
76
+ workspaceFolders: [
77
+ {
78
+ uri: rootUri,
79
+ name: path.basename(this.repositoryRootPath)
80
+ }
81
+ ],
82
+ initializationOptions: buildInitializationOptions()
83
+ };
84
+ }
85
+ verifyCapabilities(capabilities) {
86
+ if (!capabilities) {
87
+ throw new Error('Zig language server initialize response is missing capabilities.');
88
+ }
89
+ const subset = capabilities;
90
+ for (const key of ['textDocumentSync', 'definitionProvider', 'documentSymbolProvider', 'referencesProvider']) {
91
+ if (!(key in subset)) {
92
+ throw new Error(`Zig language server did not advertise required capability '${key}'.`);
93
+ }
94
+ }
95
+ }
96
+ openBuildFileIfPresent() {
97
+ const buildFilePath = path.join(this.repositoryRootPath, 'build.zig');
98
+ if (!fs.existsSync(buildFilePath)) {
99
+ return;
100
+ }
101
+ try {
102
+ const contents = fs.readFileSync(buildFilePath, { encoding: 'utf-8' });
103
+ const uri = pathToFileURL(buildFilePath).href;
104
+ this.handler.notify.didOpenTextDocument({
105
+ textDocument: {
106
+ uri,
107
+ languageId: 'zig',
108
+ version: 1,
109
+ text: contents
110
+ }
111
+ });
112
+ this.logger.info('Opened build.zig to seed Zig language server project context.');
113
+ }
114
+ catch (error) {
115
+ this.logger.warn(`Failed to open build.zig: ${error.message}`);
116
+ }
117
+ }
118
+ }
119
+ registerLanguageServer(Language.ZIG, ZigLanguageServer);
120
+ function mergeIgnoredPaths(existing, additions) {
121
+ const merged = new Set(existing ?? []);
122
+ for (const entry of additions) {
123
+ merged.add(entry);
124
+ }
125
+ return Array.from(merged);
126
+ }
127
+ function ensureZlsRuntime() {
128
+ if (process.env[ZLS_ASSUME_ENV] === '1') {
129
+ const override = process.env[ZLS_PATH_ENV];
130
+ if (override && override.length > 0) {
131
+ return override;
132
+ }
133
+ return process.platform === 'win32' ? 'zls.exe' : 'zls';
134
+ }
135
+ if (process.platform === 'win32') {
136
+ throw new Error(WINDOWS_UNSUPPORTED_MESSAGE);
137
+ }
138
+ const zigPath = resolveZigExecutable();
139
+ if (!zigPath || !detectZigVersion(zigPath)) {
140
+ throw new Error('Zig is not installed. Install Zig from https://ziglang.org/download/ and ensure it is available in PATH.');
141
+ }
142
+ const zlsExecutable = resolveZlsExecutable();
143
+ if (!zlsExecutable) {
144
+ throw new Error('Found Zig but ZLS (Zig Language Server) is not installed. Install it via package managers or from https://github.com/zigtools/zls and ensure `zls` is on PATH.');
145
+ }
146
+ return zlsExecutable;
147
+ }
148
+ function resolveZigExecutable() {
149
+ const override = process.env[ZIG_PATH_ENV];
150
+ if (override && fs.existsSync(override)) {
151
+ return override;
152
+ }
153
+ const binaryName = process.platform === 'win32' ? 'zig.exe' : 'zig';
154
+ const located = which(binaryName);
155
+ if (located && fs.existsSync(located)) {
156
+ return located;
157
+ }
158
+ return null;
159
+ }
160
+ function detectZigVersion(executable) {
161
+ const result = spawnSync(executable, ['version'], ensureDefaultSubprocessOptions({ encoding: 'utf-8' }));
162
+ if (result.status === 0 && typeof result.stdout === 'string') {
163
+ const trimmed = result.stdout.trim();
164
+ return trimmed.length > 0 ? trimmed : null;
165
+ }
166
+ return null;
167
+ }
168
+ function resolveZlsExecutable() {
169
+ const override = process.env[ZLS_PATH_ENV];
170
+ if (override && fs.existsSync(override)) {
171
+ return override;
172
+ }
173
+ const binaryName = process.platform === 'win32' ? 'zls.exe' : 'zls';
174
+ const located = which(binaryName);
175
+ if (located && fs.existsSync(located)) {
176
+ return located;
177
+ }
178
+ return null;
179
+ }
180
+ function which(command) {
181
+ const locator = process.platform === 'win32' ? 'where' : 'which';
182
+ const result = spawnSync(locator, [command], ensureDefaultSubprocessOptions({ encoding: 'utf-8' }));
183
+ if (result.status !== 0 || typeof result.stdout !== 'string') {
184
+ return null;
185
+ }
186
+ const lines = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
187
+ return lines[0] ?? null;
188
+ }
189
+ function extractWindowMessage(payload) {
190
+ if (!payload || typeof payload !== 'object') {
191
+ return null;
192
+ }
193
+ const message = payload.message;
194
+ return typeof message === 'string' ? message : null;
195
+ }
196
+ function buildClientCapabilities() {
197
+ const symbolKinds = Array.from({ length: 26 }, (_, index) => index + 1);
198
+ return {
199
+ textDocument: {
200
+ synchronization: { didSave: true, dynamicRegistration: true },
201
+ definition: { dynamicRegistration: true },
202
+ references: { dynamicRegistration: true },
203
+ documentSymbol: {
204
+ dynamicRegistration: true,
205
+ hierarchicalDocumentSymbolSupport: true,
206
+ symbolKind: { valueSet: symbolKinds }
207
+ },
208
+ completion: {
209
+ dynamicRegistration: true,
210
+ completionItem: {
211
+ snippetSupport: true,
212
+ commitCharactersSupport: true,
213
+ documentationFormat: ['markdown', 'plaintext'],
214
+ deprecatedSupport: true,
215
+ preselectSupport: true
216
+ }
217
+ },
218
+ hover: {
219
+ dynamicRegistration: true,
220
+ contentFormat: ['markdown', 'plaintext']
221
+ }
222
+ },
223
+ workspace: {
224
+ workspaceFolders: true,
225
+ didChangeConfiguration: { dynamicRegistration: true },
226
+ configuration: true
227
+ }
228
+ };
229
+ }
230
+ function buildInitializationOptions() {
231
+ return {
232
+ zig_exe_path: resolveZigExecutable(),
233
+ zig_lib_path: null,
234
+ build_runner_path: null,
235
+ global_cache_path: null,
236
+ enable_build_on_save: true,
237
+ build_on_save_args: ['build'],
238
+ enable_snippets: true,
239
+ enable_argument_placeholders: true,
240
+ semantic_tokens: 'full',
241
+ warn_style: false,
242
+ highlight_global_var_declarations: false,
243
+ skip_std_references: false,
244
+ prefer_ast_check_as_child_process: true,
245
+ completion_label_details: true,
246
+ inlay_hints_show_variable_type_hints: true,
247
+ inlay_hints_show_struct_literal_field_type: true,
248
+ inlay_hints_show_parameter_name: true,
249
+ inlay_hints_show_builtin: true,
250
+ inlay_hints_exclude_single_argument: true,
251
+ inlay_hints_hide_redundant_param_names: false,
252
+ inlay_hints_hide_redundant_param_names_last_token: false
253
+ };
254
+ }