micro-models-agent 0.58.2 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/CHANGELOG.md +578 -556
  2. package/README.md +358 -358
  3. package/dist/certification/certifications.json +493 -493
  4. package/dist/i18n/en.json +732 -716
  5. package/dist/i18n/ru.json +732 -716
  6. package/dist/main.js +1243 -448
  7. package/dist/modules/browser/bridge-server.mjs +219 -219
  8. package/dist/skills/builtin/git.md +36 -36
  9. package/dist/skills/builtin/typescript.md +35 -35
  10. package/package.json +51 -51
  11. package/dist/cli/commands.js +0 -447
  12. package/dist/cli/completer.js +0 -167
  13. package/dist/cli/index.js +0 -2
  14. package/dist/cli/main.js +0 -153
  15. package/dist/cli/plugin-commands.js +0 -36
  16. package/dist/cli/repl-commands.js +0 -761
  17. package/dist/cli/repl.js +0 -702
  18. package/dist/cli/run-result.js +0 -33
  19. package/dist/cli/security-commands.js +0 -164
  20. package/dist/cli/setup.js +0 -237
  21. package/dist/config/config.js +0 -276
  22. package/dist/config/defaults.js +0 -141
  23. package/dist/config/domains.js +0 -179
  24. package/dist/config/experts.js +0 -15
  25. package/dist/config/index.js +0 -4
  26. package/dist/config/security.js +0 -213
  27. package/dist/config/types.js +0 -1
  28. package/dist/core/agent-moe.js +0 -102
  29. package/dist/core/agent.js +0 -1018
  30. package/dist/core/bootstrap.js +0 -481
  31. package/dist/core/crash-handler.js +0 -51
  32. package/dist/core/environment.js +0 -199
  33. package/dist/core/index.js +0 -2
  34. package/dist/core/prompt-builder.js +0 -76
  35. package/dist/core/session-logger.js +0 -251
  36. package/dist/core/types.js +0 -1
  37. package/dist/core/version.js +0 -26
  38. package/dist/core/workspace.js +0 -76
  39. package/dist/i18n/index.js +0 -46
  40. package/dist/index.js +0 -22
  41. package/dist/llm/image-utils.js +0 -143
  42. package/dist/llm/index.js +0 -4
  43. package/dist/llm/model-loader.js +0 -78
  44. package/dist/llm/openai-compat.js +0 -497
  45. package/dist/llm/orchestrator.js +0 -200
  46. package/dist/llm/provider.js +0 -10
  47. package/dist/llm/response.js +0 -39
  48. package/dist/llm/token-counter.js +0 -39
  49. package/dist/llm/types.js +0 -1
  50. package/dist/logger/app-logger.js +0 -189
  51. package/dist/logger/file-log.js +0 -151
  52. package/dist/logger/index.js +0 -1
  53. package/dist/migration/backup.js +0 -45
  54. package/dist/migration/detect.js +0 -50
  55. package/dist/migration/index.js +0 -2
  56. package/dist/modules/artifacts/store.js +0 -61
  57. package/dist/modules/browser/actions.js +0 -76
  58. package/dist/modules/browser/bridge-client.js +0 -199
  59. package/dist/modules/browser/bridge-path.js +0 -10
  60. package/dist/modules/browser/cookie-store.js +0 -24
  61. package/dist/modules/browser/driver.js +0 -136
  62. package/dist/modules/browser/index.js +0 -7
  63. package/dist/modules/browser/module.js +0 -29
  64. package/dist/modules/browser/session.js +0 -342
  65. package/dist/modules/browser/snapshot.js +0 -148
  66. package/dist/modules/browser/types.js +0 -12
  67. package/dist/modules/certification/cli.js +0 -213
  68. package/dist/modules/certification/fact-checker.js +0 -82
  69. package/dist/modules/certification/loader.js +0 -106
  70. package/dist/modules/certification/manifest.js +0 -58
  71. package/dist/modules/certification/runner.js +0 -245
  72. package/dist/modules/certification/scenarios.js +0 -407
  73. package/dist/modules/certification/types.js +0 -1
  74. package/dist/modules/context/chunk-query.js +0 -100
  75. package/dist/modules/context/fact-extractor.js +0 -168
  76. package/dist/modules/context/history.js +0 -15
  77. package/dist/modules/context/index.js +0 -1
  78. package/dist/modules/context/manager.js +0 -440
  79. package/dist/modules/execution/audit-runners.js +0 -206
  80. package/dist/modules/execution/auditor.js +0 -218
  81. package/dist/modules/execution/execution-plugin.js +0 -431
  82. package/dist/modules/execution/index.js +0 -8
  83. package/dist/modules/execution/module.js +0 -625
  84. package/dist/modules/execution/moe-executor.js +0 -304
  85. package/dist/modules/execution/plan-coverage.js +0 -68
  86. package/dist/modules/execution/plan-persister.js +0 -46
  87. package/dist/modules/execution/plan-store.js +0 -196
  88. package/dist/modules/execution/plan-tool.js +0 -677
  89. package/dist/modules/execution/plan-validator.js +0 -153
  90. package/dist/modules/execution/planner.js +0 -94
  91. package/dist/modules/execution/stuck-detector.js +0 -746
  92. package/dist/modules/execution/tracker.js +0 -69
  93. package/dist/modules/execution/types.js +0 -1
  94. package/dist/modules/execution/verifier.js +0 -235
  95. package/dist/modules/execution/windows-commands.js +0 -41
  96. package/dist/modules/hallucination/confidence.js +0 -66
  97. package/dist/modules/hallucination/consistency.js +0 -26
  98. package/dist/modules/hallucination/detector.js +0 -47
  99. package/dist/modules/hallucination/factual.js +0 -169
  100. package/dist/modules/hallucination/index.js +0 -5
  101. package/dist/modules/hallucination/js-identifiers.js +0 -262
  102. package/dist/modules/hallucination/llm-judge.js +0 -101
  103. package/dist/modules/index.js +0 -5
  104. package/dist/modules/indexer/cache.js +0 -40
  105. package/dist/modules/indexer/index.js +0 -3
  106. package/dist/modules/indexer/module.js +0 -246
  107. package/dist/modules/indexer/project-profile.js +0 -183
  108. package/dist/modules/indexer/walker.js +0 -101
  109. package/dist/modules/lsp/check-tool.js +0 -58
  110. package/dist/modules/lsp/client.js +0 -389
  111. package/dist/modules/lsp/command.js +0 -60
  112. package/dist/modules/lsp/config.js +0 -135
  113. package/dist/modules/lsp/index.js +0 -3
  114. package/dist/modules/lsp/module.js +0 -260
  115. package/dist/modules/lsp/probe.js +0 -86
  116. package/dist/modules/lsp/project-root.js +0 -32
  117. package/dist/modules/lsp/startup-check.js +0 -144
  118. package/dist/modules/lsp/types.js +0 -1
  119. package/dist/modules/mcp/client.js +0 -399
  120. package/dist/modules/mcp/index.js +0 -3
  121. package/dist/modules/mcp/module.js +0 -142
  122. package/dist/modules/mcp/registry.js +0 -15
  123. package/dist/modules/memory/index.js +0 -1
  124. package/dist/modules/memory/module.js +0 -96
  125. package/dist/modules/memory/search.js +0 -42
  126. package/dist/modules/memory/store.js +0 -69
  127. package/dist/modules/pipelines/engine.js +0 -60
  128. package/dist/modules/pipelines/index.js +0 -3
  129. package/dist/modules/pipelines/parser.js +0 -56
  130. package/dist/modules/pipelines/template.js +0 -14
  131. package/dist/modules/plugins/builtin/lint-on-write.js +0 -334
  132. package/dist/modules/plugins/builtin/notify.js +0 -9
  133. package/dist/modules/plugins/index.js +0 -1
  134. package/dist/modules/plugins/loader.js +0 -70
  135. package/dist/modules/plugins/manager.js +0 -261
  136. package/dist/modules/plugins/types.js +0 -1
  137. package/dist/modules/pricing/index.js +0 -61
  138. package/dist/modules/pricing/prices.js +0 -129
  139. package/dist/modules/processes/detect.js +0 -34
  140. package/dist/modules/processes/index.js +0 -2
  141. package/dist/modules/processes/registry.js +0 -327
  142. package/dist/modules/processes/runner.js +0 -23
  143. package/dist/modules/providers/create.js +0 -22
  144. package/dist/modules/providers/fallback.js +0 -79
  145. package/dist/modules/providers/health.js +0 -46
  146. package/dist/modules/providers/index.js +0 -5
  147. package/dist/modules/providers/manager.js +0 -161
  148. package/dist/modules/providers/presets.js +0 -128
  149. package/dist/modules/providers/registry.js +0 -22
  150. package/dist/modules/providers/types.js +0 -1
  151. package/dist/modules/registry.js +0 -48
  152. package/dist/modules/security/audit-log.js +0 -136
  153. package/dist/modules/security/audit-notifier.js +0 -292
  154. package/dist/modules/security/command-validator.js +0 -219
  155. package/dist/modules/security/content-scanner.js +0 -53
  156. package/dist/modules/security/data-sanitizer.js +0 -89
  157. package/dist/modules/security/encryption.js +0 -242
  158. package/dist/modules/security/index.js +0 -14
  159. package/dist/modules/security/network-validator.js +0 -88
  160. package/dist/modules/security/path-validator.js +0 -203
  161. package/dist/modules/security/rate-limiter.js +0 -119
  162. package/dist/modules/security/security-policies.js +0 -531
  163. package/dist/modules/security/session-encryption.js +0 -210
  164. package/dist/modules/security/session-isolation.js +0 -95
  165. package/dist/modules/session/index.js +0 -3
  166. package/dist/modules/session/manager.js +0 -172
  167. package/dist/modules/session/module.js +0 -24
  168. package/dist/modules/session/store.js +0 -222
  169. package/dist/modules/session/types.js +0 -1
  170. package/dist/modules/skills/index.js +0 -2
  171. package/dist/modules/skills/loader.js +0 -72
  172. package/dist/modules/skills/matcher.js +0 -27
  173. package/dist/modules/skills/module.js +0 -129
  174. package/dist/modules/types.js +0 -1
  175. package/dist/modules/updater/checker.js +0 -96
  176. package/dist/modules/updater/index.js +0 -2
  177. package/dist/modules/updater/module.js +0 -116
  178. package/dist/modules/user-profile/compressor.js +0 -16
  179. package/dist/modules/user-profile/index.js +0 -1
  180. package/dist/modules/user-profile/profile.js +0 -68
  181. package/dist/tools/approve.js +0 -33
  182. package/dist/tools/attach-image.js +0 -101
  183. package/dist/tools/bash.js +0 -519
  184. package/dist/tools/browser.js +0 -115
  185. package/dist/tools/chunk-query.js +0 -100
  186. package/dist/tools/create-dir.js +0 -56
  187. package/dist/tools/delete-file.js +0 -63
  188. package/dist/tools/download-file.js +0 -117
  189. package/dist/tools/edit-file.js +0 -80
  190. package/dist/tools/enable-tools.js +0 -59
  191. package/dist/tools/executor.js +0 -154
  192. package/dist/tools/file-info.js +0 -47
  193. package/dist/tools/filter-tools.js +0 -17
  194. package/dist/tools/glob-tool.js +0 -27
  195. package/dist/tools/grep-tool.js +0 -125
  196. package/dist/tools/hidden-tools-block.js +0 -37
  197. package/dist/tools/index.js +0 -78
  198. package/dist/tools/list-dir.js +0 -49
  199. package/dist/tools/load-skill.js +0 -43
  200. package/dist/tools/mcp-call.js +0 -69
  201. package/dist/tools/move-file.js +0 -86
  202. package/dist/tools/path-utils.js +0 -101
  203. package/dist/tools/pipeline-run.js +0 -145
  204. package/dist/tools/preview.js +0 -2
  205. package/dist/tools/process-kill.js +0 -40
  206. package/dist/tools/process-list.js +0 -37
  207. package/dist/tools/process-log.js +0 -54
  208. package/dist/tools/question.js +0 -141
  209. package/dist/tools/read-file.js +0 -179
  210. package/dist/tools/recall.js +0 -118
  211. package/dist/tools/registry.js +0 -47
  212. package/dist/tools/remember.js +0 -68
  213. package/dist/tools/scope-check.js +0 -32
  214. package/dist/tools/search-history.js +0 -85
  215. package/dist/tools/subagent.js +0 -196
  216. package/dist/tools/types.js +0 -1
  217. package/dist/tools/user-input.js +0 -123
  218. package/dist/tools/web-browse.js +0 -87
  219. package/dist/tools/web-fetch.js +0 -119
  220. package/dist/tools/web-search.js +0 -105
  221. package/dist/tools/write-file.js +0 -82
  222. package/dist/ui/box.js +0 -77
  223. package/dist/ui/colors.js +0 -4
  224. package/dist/ui/diff.js +0 -178
  225. package/dist/ui/index.js +0 -6
  226. package/dist/ui/line-editor.js +0 -822
  227. package/dist/ui/line-math.js +0 -73
  228. package/dist/ui/md-formatter.js +0 -212
  229. package/dist/ui/output.js +0 -13
  230. package/dist/ui/plan-view.js +0 -103
  231. package/dist/ui/renderer.js +0 -259
  232. package/dist/ui/spinner.js +0 -70
  233. package/dist/ui/table.js +0 -144
@@ -1,389 +0,0 @@
1
- import { spawn, execSync } from "child_process";
2
- import { resolve } from "path";
3
- import { platform } from "os";
4
- import { resolveSpawnCommand, buildWinCommandLine } from "./command";
5
- import { killTree } from "../processes/registry";
6
- /**
7
- * Logger adapter that writes LSP diagnostics to app.jsonl only — never to
8
- * console/terminal. LSP warnings are noisy (timeout on first run, npx
9
- * install) and should be diagnosable from session files without polluting
10
- * the user's chat.
11
- */
12
- export class FileOnlyLogger {
13
- logger;
14
- constructor(logger) {
15
- this.logger = logger;
16
- }
17
- debug(msg, meta) {
18
- this.logger.logSilent("debug", msg, meta);
19
- }
20
- info(msg, meta) {
21
- this.logger.logSilent("info", msg, meta);
22
- }
23
- warn(msg, meta) {
24
- this.logger.logSilent("warn", msg, meta);
25
- }
26
- error(msg, meta) {
27
- this.logger.logSilent("error", msg, meta);
28
- }
29
- }
30
- const DEFAULT_TIMEOUT = 15000;
31
- export class LspClient {
32
- logger = null;
33
- setLogger(logger) {
34
- this.logger = logger;
35
- }
36
- process = null;
37
- requestId = 0;
38
- pending = new Map();
39
- buffer = "";
40
- contentLength = -1;
41
- diagnostics = [];
42
- diagnosticsResolve = null;
43
- diagnosticsTimer = null;
44
- initialized = false;
45
- async checkFile(filePath, baseDir, config, projectRoot = baseDir) {
46
- const timeout = config.timeout ?? DEFAULT_TIMEOUT;
47
- try {
48
- await this.initialize(config, projectRoot, timeout);
49
- this.sendNotification("initialized", {});
50
- const uri = this.pathToUri(resolve(filePath));
51
- const fs = await import("fs");
52
- const content = fs.readFileSync(filePath, "utf-8");
53
- const diagPromise = new Promise((resolve) => {
54
- this.diagnosticsResolve = resolve;
55
- this.diagnostics = [];
56
- this.diagnosticsTimer = setTimeout(() => {
57
- this.diagnosticsResolve?.([]);
58
- this.diagnosticsResolve = null;
59
- }, timeout);
60
- });
61
- this.sendNotification("textDocument/didOpen", {
62
- textDocument: {
63
- uri,
64
- languageId: this.languageFromPath(filePath),
65
- version: 1,
66
- text: content,
67
- },
68
- });
69
- return await diagPromise;
70
- }
71
- catch (e) {
72
- // Re-throw so the LspModule can surface failures instead of hiding them.
73
- throw e instanceof Error ? e : new Error(String(e));
74
- }
75
- finally {
76
- await this.shutdown();
77
- }
78
- }
79
- /**
80
- * Lightweight "does the server actually start" probe: spawn + initialize +
81
- * shutdown. Used by the REPL banner to surface a dead server (npx
82
- * auto-install failure, wrong package name, missing binary) up front instead
83
- * of the first write_file timing out.
84
- */
85
- async probe(config, projectRoot, timeout) {
86
- try {
87
- await this.initialize(config, projectRoot, timeout);
88
- }
89
- finally {
90
- await this.shutdown();
91
- }
92
- }
93
- async initialize(config, projectRoot, timeout) {
94
- await this.startServer(config, projectRoot);
95
- const rootUri = this.pathToUri(projectRoot);
96
- const initParams = {
97
- processId: process.pid,
98
- rootUri,
99
- workspaceFolders: [{ uri: rootUri, name: "workspace" }],
100
- capabilities: { textDocument: { publishDiagnostics: {} } },
101
- };
102
- try {
103
- await this.sendRequest("initialize", initParams, timeout);
104
- }
105
- catch (e) {
106
- const msg = e instanceof Error ? e.message : String(e);
107
- this.logger?.warn(`LSP initialize failed (attempt 1): ${msg}`, {
108
- command: config.command,
109
- projectRoot,
110
- });
111
- // npx auto-install can blow past the initialize timeout on first run — retry once.
112
- if (!(e instanceof Error) || !e.message.includes("initialize"))
113
- throw e;
114
- await this.shutdown();
115
- await this.startServer(config, projectRoot);
116
- try {
117
- await this.sendRequest("initialize", initParams, timeout);
118
- }
119
- catch (retryErr) {
120
- const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
121
- this.logger?.error(`LSP initialize failed (attempt 2, giving up): ${retryMsg}`, {
122
- command: config.command,
123
- projectRoot,
124
- });
125
- throw retryErr;
126
- }
127
- }
128
- this.initialized = true;
129
- }
130
- async startServer(config, projectRoot) {
131
- if (config.autoInstall === false) {
132
- try {
133
- execSync(`where ${config.command}`, { stdio: "pipe", timeout: 3000 });
134
- }
135
- catch {
136
- throw new Error(`${config.command} not found in PATH`);
137
- }
138
- }
139
- // When the command is npx, try to find the actual binary globally first.
140
- // npx downloads packages on every invocation (slow on Windows, ~8-15s),
141
- // even when the binary is already installed globally.
142
- let effectiveCommand = config.command;
143
- let effectiveArgs = config.args ?? [];
144
- if (config.command === "npx" && effectiveArgs.length > 0) {
145
- const binaryName = this.extractBinaryFromNpxArgs(effectiveArgs);
146
- if (binaryName) {
147
- const whichCmd = platform() === "win32" ? `where ${binaryName}` : `which ${binaryName}`;
148
- try {
149
- execSync(whichCmd, { stdio: "pipe", timeout: 3000 });
150
- // Binary found globally — use it directly, skip npx.
151
- effectiveCommand = binaryName;
152
- effectiveArgs = effectiveArgs.filter((a) => a !== "--yes" && a !== "--package" && a !== binaryName && !this.isPackageVersion(a));
153
- this.logger?.debug(`LSP: using globally installed ${binaryName} (skipped npx)`);
154
- }
155
- catch {
156
- // Not found globally — fall back to npx (will auto-install).
157
- this.logger?.debug(`LSP: ${binaryName} not found globally, falling back to npx`);
158
- }
159
- }
160
- }
161
- return new Promise((resolve, reject) => {
162
- const args = effectiveArgs;
163
- const isWin = platform() === "win32";
164
- let spawnCommand = resolveSpawnCommand(effectiveCommand);
165
- let spawnArgs = args;
166
- const spawnOpts = {
167
- stdio: ["pipe", "pipe", "pipe"],
168
- env: { ...process.env, ...config.env },
169
- cwd: projectRoot,
170
- };
171
- if (isWin) {
172
- // A `.cmd` shim can't be spawned directly under Node (`spawn npx EINVAL`) — run via cmd.exe.
173
- spawnCommand = buildWinCommandLine(spawnCommand, args);
174
- spawnArgs = [];
175
- spawnOpts.shell = true;
176
- }
177
- const proc = spawn(spawnCommand, spawnArgs, spawnOpts);
178
- proc.on("error", reject);
179
- proc.stdout.on("data", (chunk) => {
180
- this.handleData(chunk);
181
- });
182
- proc.stderr.on("data", () => { });
183
- proc.once("spawn", () => {
184
- resolve();
185
- });
186
- this.process = proc;
187
- setTimeout(() => {
188
- if (!this.initialized && this.process) {
189
- const msg = "LSP server start timeout";
190
- this.logger?.error(msg, { command: config.command, projectRoot, timeout: config.timeout ?? 10000 });
191
- reject(new Error(msg));
192
- }
193
- }, config.timeout ?? 10000);
194
- });
195
- }
196
- handleData(chunk) {
197
- this.buffer += chunk.toString();
198
- this.parseMessages();
199
- }
200
- parseMessages() {
201
- while (true) {
202
- if (this.contentLength === -1) {
203
- const headerEnd = this.buffer.indexOf("\r\n\r\n");
204
- if (headerEnd === -1)
205
- return;
206
- const header = this.buffer.slice(0, headerEnd);
207
- const match = header.match(/Content-Length: (\d+)/i);
208
- if (!match) {
209
- this.buffer = this.buffer.slice(headerEnd + 4);
210
- this.contentLength = -1;
211
- continue;
212
- }
213
- this.contentLength = parseInt(match[1], 10);
214
- // Guard against malicious/buggy servers sending absurd Content-Length
215
- if (this.contentLength > 10 * 1024 * 1024) {
216
- this.buffer = this.buffer.slice(headerEnd + 4);
217
- this.contentLength = -1;
218
- continue;
219
- }
220
- this.buffer = this.buffer.slice(headerEnd + 4);
221
- }
222
- if (this.buffer.length < this.contentLength)
223
- return;
224
- const body = this.buffer.slice(0, this.contentLength);
225
- this.buffer = this.buffer.slice(this.contentLength);
226
- this.contentLength = -1;
227
- try {
228
- const msg = JSON.parse(body);
229
- this.handleMessage(msg);
230
- }
231
- catch (e) {
232
- this.logger?.debug(`LSP JSON parse error: ${e instanceof Error ? e.message : String(e)}`);
233
- }
234
- }
235
- }
236
- handleMessage(msg) {
237
- if (msg.method === "textDocument/publishDiagnostics") {
238
- const params = msg.params;
239
- if (params?.diagnostics) {
240
- this.diagnostics = params.diagnostics;
241
- if (this.diagnosticsTimer) {
242
- clearTimeout(this.diagnosticsTimer);
243
- this.diagnosticsTimer = null;
244
- }
245
- this.diagnosticsResolve?.(this.diagnostics);
246
- this.diagnosticsResolve = null;
247
- }
248
- return;
249
- }
250
- if (msg.id !== undefined && msg.id !== null) {
251
- const pending = this.pending.get(msg.id);
252
- if (pending) {
253
- this.pending.delete(msg.id);
254
- if (msg.error) {
255
- pending.reject(new Error(String(msg.error.message ?? "LSP error")));
256
- }
257
- else {
258
- pending.resolve(msg.result);
259
- }
260
- }
261
- }
262
- }
263
- sendRequest(method, params, timeout) {
264
- return new Promise((resolve, reject) => {
265
- const id = ++this.requestId;
266
- this.pending.set(id, { resolve, reject });
267
- const message = JSON.stringify({ jsonrpc: "2.0", id, method, params });
268
- this.write(message);
269
- setTimeout(() => {
270
- if (this.pending.has(id)) {
271
- this.pending.delete(id);
272
- const msg = `LSP request timeout: ${method}`;
273
- this.logger?.warn(msg, { method, timeout });
274
- reject(new Error(msg));
275
- }
276
- }, timeout);
277
- });
278
- }
279
- sendNotification(method, params) {
280
- const message = JSON.stringify({ jsonrpc: "2.0", method, params });
281
- this.write(message);
282
- }
283
- write(message) {
284
- if (!this.process?.stdin?.writable) {
285
- this.logger?.debug("LSP write failed: process stdin not writable");
286
- return;
287
- }
288
- const header = `Content-Length: ${Buffer.byteLength(message)}\r\n\r\n`;
289
- try {
290
- this.process.stdin.write(header + message);
291
- }
292
- catch (e) {
293
- this.logger?.debug(`LSP write error: ${e instanceof Error ? e.message : String(e)}`);
294
- }
295
- }
296
- async shutdown() {
297
- try {
298
- if (this.process && this.initialized && this.process.stdin?.writable) {
299
- // Await the shutdown response (with timeout) so the server has time to
300
- // acknowledge before we send exit and kill the process. The old code
301
- // fired shutdown as fire-and-forget, then killed immediately — the
302
- // server never had a chance to reply, producing spurious timeout warnings.
303
- try {
304
- await this.sendRequest("shutdown", null, 3000);
305
- }
306
- catch (e) {
307
- this.logger?.debug(`LSP shutdown request failed: ${e instanceof Error ? e.message : String(e)}`);
308
- }
309
- this.sendNotification("exit", null);
310
- await new Promise((r) => setTimeout(r, 200));
311
- }
312
- }
313
- catch (e) {
314
- this.logger?.debug(`LSP shutdown error: ${e instanceof Error ? e.message : String(e)}`);
315
- }
316
- finally {
317
- if (this.process) {
318
- // The direct child on win32 is the cmd.exe wrapper; killing it alone
319
- // orphans the npx → node → tsserver tree (observed as leaked node
320
- // processes after every check). Tree-kill so the whole chain dies.
321
- try {
322
- killTree(this.process);
323
- }
324
- catch (e) {
325
- this.logger?.debug(`LSP killTree error: ${e instanceof Error ? e.message : String(e)}`);
326
- }
327
- this.process = null;
328
- }
329
- this.initialized = false;
330
- this.buffer = "";
331
- this.contentLength = -1;
332
- if (this.diagnosticsTimer) {
333
- clearTimeout(this.diagnosticsTimer);
334
- this.diagnosticsTimer = null;
335
- }
336
- }
337
- }
338
- pathToUri(filePath) {
339
- const normalized = filePath.replace(/\\/g, "/");
340
- return /^[a-zA-Z]:/.test(normalized) ? `file:///${normalized}` : `file://${normalized}`;
341
- }
342
- languageFromPath(filePath) {
343
- const ext = filePath.split(".").pop()?.toLowerCase();
344
- const map = {
345
- ts: "typescript",
346
- tsx: "typescriptreact",
347
- mts: "typescript",
348
- cts: "typescript",
349
- js: "javascript",
350
- jsx: "javascriptreact",
351
- mjs: "javascript",
352
- cjs: "javascript",
353
- py: "python",
354
- go: "go",
355
- rs: "rust",
356
- json: "json",
357
- html: "html",
358
- css: "css",
359
- scss: "scss",
360
- md: "markdown",
361
- yaml: "yaml",
362
- yml: "yaml",
363
- };
364
- return map[ext ?? ""] ?? "plaintext";
365
- }
366
- /**
367
- * Extract the actual binary name from npx args.
368
- * For `npx --yes --package typescript-language-server --package typescript@5 typescript-language-server --stdio`
369
- * returns `typescript-language-server` (the last non-flag arg before `--stdio`).
370
- */
371
- extractBinaryFromNpxArgs(args) {
372
- // Find the binary: last arg that doesn't start with -- and isn't a package version
373
- for (let i = args.length - 1; i >= 0; i--) {
374
- const arg = args[i];
375
- if (arg === "--stdio")
376
- continue;
377
- if (arg.startsWith("--"))
378
- return null; // unexpected format
379
- if (this.isPackageVersion(arg))
380
- continue;
381
- return arg;
382
- }
383
- return null;
384
- }
385
- /** Check if a string looks like a package version specifier (e.g. "typescript@5"). */
386
- isPackageVersion(s) {
387
- return /^[\w-]+@[\d.+*-]/.test(s);
388
- }
389
- }
@@ -1,60 +0,0 @@
1
- import { delimiter, join } from "path";
2
- import { existsSync } from "fs";
3
- import { platform } from "os";
4
- const WIN_EXTS = [".cmd", ".bat", ".exe", ".com"];
5
- /**
6
- * Resolve the command string passed to `child_process.spawn` on Windows.
7
- *
8
- * Node's `spawn` cannot execute `.cmd`/`.bat` shims directly without a shell,
9
- * and a bare `npx` fails with `spawn npx ENOENT` because on Windows the
10
- * real executable is `npx.cmd`. This returns the first existing shim
11
- * (`npx.cmd`, `npx.bat`, `npx.exe`, ...) found on PATH, or the bare command
12
- * when nothing exists (the spawn will then fail with a meaningful ENOENT).
13
- *
14
- * Non-Windows platforms and commands that already carry an extension or a
15
- * path separator are returned unchanged.
16
- */
17
- export function resolveSpawnCommand(command, platformName = platform(), pathEnv = process.env.PATH ?? "") {
18
- if (platformName !== "win32")
19
- return command;
20
- // Already a path or has an extension — pass through.
21
- if (command.includes("/") ||
22
- command.includes("\\") ||
23
- WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
24
- return command;
25
- }
26
- const dirs = pathEnv.split(delimiter).filter(Boolean);
27
- for (const dir of dirs) {
28
- for (const ext of WIN_EXTS) {
29
- const candidate = join(dir, `${command}${ext}`);
30
- if (existsSync(candidate))
31
- return `${command}${ext}`;
32
- }
33
- }
34
- return command;
35
- }
36
- /**
37
- * Join a resolved command and its args into a single cmd.exe command line.
38
- *
39
- * Under Node on Windows, `spawn` of a `.cmd`/`.bat` shim WITHOUT a shell throws
40
- * `spawn EINVAL` (CreateProcess cannot run batch files directly). Resolving
41
- * `npx` → `npx.cmd` fixes the old `ENOENT` but not the `EINVAL` — the spawn
42
- * still has no shell. The reliable fix is to run the whole command line through
43
- * `cmd.exe /d /s /c` (i.e. `spawn(line, { shell: true })`). This helper builds
44
- * that line, quoting any argument that contains cmd.exe metacharacters so the
45
- * package names and flags in LSP configs (`typescript-language-server --stdio`,
46
- * `pyright --stdio`) survive the round-trip.
47
- *
48
- * Non-Windows platforms never call this (they spawn the resolved command +
49
- * args directly, no shell).
50
- */
51
- export function buildWinCommandLine(command, args) {
52
- const quote = (part) => {
53
- if (part === "")
54
- return '""';
55
- if (!/[\s"&|^<>()%!]/.test(part))
56
- return part;
57
- return `"${part.replace(/"/g, '\\"')}"`;
58
- };
59
- return [command, ...args].map(quote).join(" ");
60
- }
@@ -1,135 +0,0 @@
1
- /**
2
- * LSP server defaults.
3
- *
4
- * Strategy: prefer `npx` (auto-downloads) over globally installed binaries.
5
- * Servers using system tools (rust-analyzer, gopls) have `autoInstall: false`
6
- * and are skipped silently when not found.
7
- */
8
- export const DEFAULT_LSP_CONFIG = {
9
- enabled: true,
10
- timeout: 15000,
11
- servers: {
12
- typescript: {
13
- command: "npx",
14
- args: [
15
- "--yes",
16
- "--package",
17
- "typescript-language-server",
18
- "--package",
19
- "typescript@5",
20
- "typescript-language-server",
21
- "--stdio",
22
- ],
23
- timeout: 30000,
24
- autoInstall: true,
25
- workspaceMarkers: ["package.json", "tsconfig.json"],
26
- },
27
- javascript: {
28
- command: "npx",
29
- args: [
30
- "--yes",
31
- "--package",
32
- "typescript-language-server",
33
- "--package",
34
- "typescript@5",
35
- "typescript-language-server",
36
- "--stdio",
37
- ],
38
- timeout: 30000,
39
- autoInstall: true,
40
- workspaceMarkers: ["package.json", "tsconfig.json"],
41
- },
42
- python: {
43
- command: "npx",
44
- args: ["pyright", "--stdio"],
45
- timeout: 15000,
46
- autoInstall: true,
47
- workspaceMarkers: ["pyproject.toml", "setup.py", "requirements.txt"],
48
- },
49
- rust: {
50
- command: "rust-analyzer",
51
- timeout: 15000,
52
- autoInstall: false,
53
- workspaceMarkers: ["Cargo.toml"],
54
- },
55
- go: {
56
- command: "gopls",
57
- timeout: 15000,
58
- autoInstall: false,
59
- workspaceMarkers: ["go.mod"],
60
- },
61
- json: {
62
- command: "npx",
63
- args: [
64
- "--yes",
65
- "--package",
66
- "vscode-langservers-extracted",
67
- "vscode-json-language-server",
68
- "--stdio",
69
- ],
70
- timeout: 30000,
71
- autoInstall: true,
72
- workspaceMarkers: ["package.json"],
73
- },
74
- html: {
75
- command: "npx",
76
- args: [
77
- "--yes",
78
- "--package",
79
- "vscode-langservers-extracted",
80
- "--package",
81
- "typescript@5",
82
- "vscode-html-language-server",
83
- "--stdio",
84
- ],
85
- timeout: 60000,
86
- autoInstall: true,
87
- workspaceMarkers: ["package.json"],
88
- },
89
- css: {
90
- command: "npx",
91
- args: [
92
- "--yes",
93
- "--package",
94
- "vscode-langservers-extracted",
95
- "--package",
96
- "typescript@5",
97
- "vscode-css-language-server",
98
- "--stdio",
99
- ],
100
- timeout: 60000,
101
- autoInstall: true,
102
- workspaceMarkers: ["package.json"],
103
- },
104
- },
105
- };
106
- const LANGUAGE_MAP = {
107
- ts: "typescript",
108
- tsx: "typescript",
109
- mts: "typescript",
110
- cts: "typescript",
111
- js: "javascript",
112
- jsx: "javascript",
113
- mjs: "javascript",
114
- cjs: "javascript",
115
- py: "python",
116
- rs: "rust",
117
- go: "go",
118
- json: "json",
119
- html: "html",
120
- css: "css",
121
- scss: "css",
122
- };
123
- /** Language id for a file extension (via LANGUAGE_MAP), or null when unsupported. */
124
- export function getLanguageForFile(filePath) {
125
- const ext = filePath.split(".").pop()?.toLowerCase();
126
- if (!ext)
127
- return null;
128
- return LANGUAGE_MAP[ext] ?? null;
129
- }
130
- export function getServerForFile(filePath, config) {
131
- const lang = getLanguageForFile(filePath);
132
- if (!lang)
133
- return null;
134
- return config.servers[lang] ?? null;
135
- }
@@ -1,3 +0,0 @@
1
- export { LspModule } from "./module";
2
- export { LspClient, FileOnlyLogger } from "./client";
3
- export { getServerForFile, DEFAULT_LSP_CONFIG } from "./config";