orquesta-cli 0.2.107 → 0.2.111
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/dist/cli.js +27 -4
- package/dist/core/commands/help.js +4 -0
- package/dist/core/commands/index.js +7 -0
- package/dist/core/commands/lsp.d.ts +3 -0
- package/dist/core/commands/lsp.js +37 -0
- package/dist/core/commands/mcp.d.ts +3 -0
- package/dist/core/commands/mcp.js +46 -0
- package/dist/core/commands/undo.d.ts +4 -0
- package/dist/core/commands/undo.js +45 -0
- package/dist/core/config/auto-detect.js +4 -4
- package/dist/core/config/config-manager.d.ts +7 -1
- package/dist/core/config/config-manager.js +36 -0
- package/dist/core/config/providers.d.ts +3 -0
- package/dist/core/config/providers.js +87 -3
- package/dist/core/file-snapshot-store.d.ts +25 -0
- package/dist/core/file-snapshot-store.js +104 -0
- package/dist/core/lsp/index.d.ts +6 -0
- package/dist/core/lsp/index.js +75 -0
- package/dist/core/lsp/jsonrpc.d.ts +18 -0
- package/dist/core/lsp/jsonrpc.js +38 -0
- package/dist/core/lsp/lsp-client.d.ts +40 -0
- package/dist/core/lsp/lsp-client.js +201 -0
- package/dist/core/lsp/server-registry.d.ts +14 -0
- package/dist/core/lsp/server-registry.js +85 -0
- package/dist/eval/eval-runner.js +14 -0
- package/dist/orchestration/plan-executor.js +2 -0
- package/dist/tools/llm/simple/file-tools.js +8 -2
- package/dist/tools/mcp/index.d.ts +3 -0
- package/dist/tools/mcp/index.js +3 -0
- package/dist/tools/mcp/mcp-client.d.ts +16 -0
- package/dist/tools/mcp/mcp-client.js +180 -0
- package/dist/tools/mcp/mcp-config.d.ts +4 -0
- package/dist/tools/mcp/mcp-config.js +87 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/ui/hooks/slashCommandProcessor.js +17 -0
- package/package.json +2 -1
- package/dist/core/git-auto-updater.d.ts +0 -58
- package/dist/core/git-auto-updater.js +0 -374
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { findServerForFile } from './server-registry.js';
|
|
4
|
+
import { getOrCreateClient, shutdownAllLspClients, getActiveLspClientCount } from './lsp-client.js';
|
|
5
|
+
import { configManager } from '../config/config-manager.js';
|
|
6
|
+
import { logger } from '../../utils/logger.js';
|
|
7
|
+
const ROOT_MARKERS = ['tsconfig.json', 'package.json', 'pyproject.toml', 'go.mod', 'Cargo.toml', '.git'];
|
|
8
|
+
function findProjectRoot(absPath) {
|
|
9
|
+
let dir = path.dirname(absPath);
|
|
10
|
+
for (;;) {
|
|
11
|
+
for (const marker of ROOT_MARKERS) {
|
|
12
|
+
if (fs.existsSync(path.join(dir, marker)))
|
|
13
|
+
return dir;
|
|
14
|
+
}
|
|
15
|
+
const parent = path.dirname(dir);
|
|
16
|
+
if (parent === dir)
|
|
17
|
+
return path.dirname(absPath);
|
|
18
|
+
dir = parent;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function isEnabled() {
|
|
22
|
+
try {
|
|
23
|
+
return configManager.isLspEnabled();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const SEVERITY_LABEL = { 1: 'error', 2: 'warning', 3: 'info', 4: 'hint' };
|
|
30
|
+
export function formatDiagnostics(relPath, diags) {
|
|
31
|
+
const relevant = diags.filter((d) => d.severity <= 2);
|
|
32
|
+
if (relevant.length === 0)
|
|
33
|
+
return '';
|
|
34
|
+
relevant.sort((a, b) => a.severity - b.severity || a.line - b.line);
|
|
35
|
+
const MAX = 20;
|
|
36
|
+
const shown = relevant.slice(0, MAX);
|
|
37
|
+
const lines = shown.map((d) => {
|
|
38
|
+
const label = SEVERITY_LABEL[d.severity] ?? 'error';
|
|
39
|
+
const src = d.source ? ` (${d.source})` : '';
|
|
40
|
+
return ` ${label} [${d.line + 1}:${d.character + 1}]${src}: ${d.message.replace(/\s+/g, ' ').trim()}`;
|
|
41
|
+
});
|
|
42
|
+
const errorCount = relevant.filter((d) => d.severity === 1).length;
|
|
43
|
+
const warnCount = relevant.length - errorCount;
|
|
44
|
+
const header = `Diagnostics for ${relPath} — ${errorCount} error(s), ${warnCount} warning(s):`;
|
|
45
|
+
const more = relevant.length > MAX ? `\n …and ${relevant.length - MAX} more` : '';
|
|
46
|
+
return `\n\n${header}\n${lines.join('\n')}${more}`;
|
|
47
|
+
}
|
|
48
|
+
export async function getDiagnosticsForFile(absPath) {
|
|
49
|
+
if (!isEnabled())
|
|
50
|
+
return '';
|
|
51
|
+
try {
|
|
52
|
+
const server = findServerForFile(absPath);
|
|
53
|
+
if (!server)
|
|
54
|
+
return '';
|
|
55
|
+
let text;
|
|
56
|
+
try {
|
|
57
|
+
text = fs.readFileSync(absPath, 'utf-8');
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return '';
|
|
61
|
+
}
|
|
62
|
+
const root = findProjectRoot(absPath);
|
|
63
|
+
const client = getOrCreateClient(server.def, root);
|
|
64
|
+
const diags = await client.getDiagnostics(absPath, text);
|
|
65
|
+
const rel = path.relative(process.cwd(), absPath) || path.basename(absPath);
|
|
66
|
+
return formatDiagnostics(rel, diags);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
logger.warn('LSP diagnostics failed', { path: absPath, error: err instanceof Error ? err.message : String(err) });
|
|
70
|
+
return '';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export { shutdownAllLspClients, getActiveLspClientCount };
|
|
74
|
+
export { findServerForFile, getServerDefs, resolveServerBinary } from './server-registry.js';
|
|
75
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface JsonRpcMessage {
|
|
2
|
+
jsonrpc: '2.0';
|
|
3
|
+
id?: number | string;
|
|
4
|
+
method?: string;
|
|
5
|
+
params?: unknown;
|
|
6
|
+
result?: unknown;
|
|
7
|
+
error?: {
|
|
8
|
+
code: number;
|
|
9
|
+
message: string;
|
|
10
|
+
data?: unknown;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export declare function encodeMessage(msg: JsonRpcMessage): Buffer;
|
|
14
|
+
export declare class MessageDecoder {
|
|
15
|
+
private buffer;
|
|
16
|
+
push(chunk: Buffer): JsonRpcMessage[];
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=jsonrpc.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export function encodeMessage(msg) {
|
|
2
|
+
const json = JSON.stringify(msg);
|
|
3
|
+
const body = Buffer.from(json, 'utf-8');
|
|
4
|
+
const header = Buffer.from(`Content-Length: ${body.length}\r\n\r\n`, 'ascii');
|
|
5
|
+
return Buffer.concat([header, body]);
|
|
6
|
+
}
|
|
7
|
+
export class MessageDecoder {
|
|
8
|
+
buffer = Buffer.alloc(0);
|
|
9
|
+
push(chunk) {
|
|
10
|
+
this.buffer = this.buffer.length === 0 ? chunk : Buffer.concat([this.buffer, chunk]);
|
|
11
|
+
const out = [];
|
|
12
|
+
for (;;) {
|
|
13
|
+
const headerEnd = this.buffer.indexOf('\r\n\r\n');
|
|
14
|
+
if (headerEnd === -1)
|
|
15
|
+
break;
|
|
16
|
+
const header = this.buffer.subarray(0, headerEnd).toString('ascii');
|
|
17
|
+
const match = /Content-Length:\s*(\d+)/i.exec(header);
|
|
18
|
+
if (!match) {
|
|
19
|
+
this.buffer = this.buffer.subarray(headerEnd + 4);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const contentLength = parseInt(match[1], 10);
|
|
23
|
+
const bodyStart = headerEnd + 4;
|
|
24
|
+
const bodyEnd = bodyStart + contentLength;
|
|
25
|
+
if (this.buffer.length < bodyEnd)
|
|
26
|
+
break;
|
|
27
|
+
const body = this.buffer.subarray(bodyStart, bodyEnd).toString('utf-8');
|
|
28
|
+
this.buffer = this.buffer.subarray(bodyEnd);
|
|
29
|
+
try {
|
|
30
|
+
out.push(JSON.parse(body));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=jsonrpc.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { fileURLToPath } from 'url';
|
|
2
|
+
import { LspServerDef } from './server-registry.js';
|
|
3
|
+
export interface Diagnostic {
|
|
4
|
+
severity: number;
|
|
5
|
+
line: number;
|
|
6
|
+
character: number;
|
|
7
|
+
message: string;
|
|
8
|
+
source?: string;
|
|
9
|
+
}
|
|
10
|
+
declare class LspClient {
|
|
11
|
+
private def;
|
|
12
|
+
private rootDir;
|
|
13
|
+
private proc;
|
|
14
|
+
private decoder;
|
|
15
|
+
private nextId;
|
|
16
|
+
private pendingRequests;
|
|
17
|
+
private diagnostics;
|
|
18
|
+
private diagWaiters;
|
|
19
|
+
private openDocs;
|
|
20
|
+
private initialized;
|
|
21
|
+
private version;
|
|
22
|
+
constructor(def: LspServerDef, rootDir: string);
|
|
23
|
+
private send;
|
|
24
|
+
private request;
|
|
25
|
+
private notify;
|
|
26
|
+
private handleMessage;
|
|
27
|
+
start(): Promise<void>;
|
|
28
|
+
getDiagnostics(absPath: string, text: string): Promise<Diagnostic[]>;
|
|
29
|
+
private onceDiagnostics;
|
|
30
|
+
private delay;
|
|
31
|
+
private waitFor;
|
|
32
|
+
private teardown;
|
|
33
|
+
stop(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export declare function getOrCreateClient(def: LspServerDef, rootDir: string): LspClient;
|
|
36
|
+
export declare function shutdownAllLspClients(): Promise<void>;
|
|
37
|
+
export declare function getActiveLspClientCount(): number;
|
|
38
|
+
export { fileURLToPath };
|
|
39
|
+
export type { LspClient };
|
|
40
|
+
//# sourceMappingURL=lsp-client.d.ts.map
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { pathToFileURL, fileURLToPath } from 'url';
|
|
4
|
+
import { encodeMessage, MessageDecoder } from './jsonrpc.js';
|
|
5
|
+
import { logger } from '../../utils/logger.js';
|
|
6
|
+
const INIT_TIMEOUT_MS = Number(process.env['ORQUESTA_LSP_INIT_TIMEOUT_MS']) || 12000;
|
|
7
|
+
const DIAGNOSTICS_WAIT_MS = Number(process.env['ORQUESTA_LSP_DIAG_TIMEOUT_MS']) || 2500;
|
|
8
|
+
class LspClient {
|
|
9
|
+
def;
|
|
10
|
+
rootDir;
|
|
11
|
+
proc = null;
|
|
12
|
+
decoder = new MessageDecoder();
|
|
13
|
+
nextId = 1;
|
|
14
|
+
pendingRequests = new Map();
|
|
15
|
+
diagnostics = new Map();
|
|
16
|
+
diagWaiters = new Map();
|
|
17
|
+
openDocs = new Set();
|
|
18
|
+
initialized = false;
|
|
19
|
+
version = new Map();
|
|
20
|
+
constructor(def, rootDir) {
|
|
21
|
+
this.def = def;
|
|
22
|
+
this.rootDir = rootDir;
|
|
23
|
+
}
|
|
24
|
+
send(msg) {
|
|
25
|
+
if (!this.proc)
|
|
26
|
+
return;
|
|
27
|
+
this.proc.stdin.write(encodeMessage({ jsonrpc: '2.0', ...msg }));
|
|
28
|
+
}
|
|
29
|
+
request(method, params) {
|
|
30
|
+
const id = this.nextId++;
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
this.pendingRequests.set(id, { resolve: resolve, reject });
|
|
33
|
+
this.send({ id, method, params });
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
notify(method, params) {
|
|
37
|
+
this.send({ method, params });
|
|
38
|
+
}
|
|
39
|
+
handleMessage(msg) {
|
|
40
|
+
if (msg.id !== undefined && (msg.result !== undefined || msg.error !== undefined)) {
|
|
41
|
+
const pending = this.pendingRequests.get(msg.id);
|
|
42
|
+
if (pending) {
|
|
43
|
+
this.pendingRequests.delete(msg.id);
|
|
44
|
+
if (msg.error)
|
|
45
|
+
pending.reject(new Error(msg.error.message));
|
|
46
|
+
else
|
|
47
|
+
pending.resolve(msg.result);
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (msg.method === 'textDocument/publishDiagnostics') {
|
|
52
|
+
const params = msg.params;
|
|
53
|
+
const diags = (params.diagnostics || []).map((d) => ({
|
|
54
|
+
severity: d.severity ?? 1,
|
|
55
|
+
line: d.range?.start?.line ?? 0,
|
|
56
|
+
character: d.range?.start?.character ?? 0,
|
|
57
|
+
message: d.message ?? '',
|
|
58
|
+
source: d.source,
|
|
59
|
+
}));
|
|
60
|
+
this.diagnostics.set(params.uri, diags);
|
|
61
|
+
const waiters = this.diagWaiters.get(params.uri);
|
|
62
|
+
if (waiters) {
|
|
63
|
+
this.diagWaiters.delete(params.uri);
|
|
64
|
+
for (const w of waiters)
|
|
65
|
+
w();
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (msg.id !== undefined && msg.method) {
|
|
70
|
+
this.send({ id: msg.id, result: null });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async start() {
|
|
74
|
+
if (this.initialized)
|
|
75
|
+
return;
|
|
76
|
+
if (this.proc) {
|
|
77
|
+
await this.waitFor(() => this.initialized, INIT_TIMEOUT_MS);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
logger.flow('LSP starting server', { id: this.def.id, root: this.rootDir });
|
|
81
|
+
const proc = spawn(this.def.command, this.def.args, {
|
|
82
|
+
cwd: this.rootDir,
|
|
83
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
84
|
+
env: process.env,
|
|
85
|
+
});
|
|
86
|
+
this.proc = proc;
|
|
87
|
+
proc.stdout.on('data', (chunk) => {
|
|
88
|
+
for (const msg of this.decoder.push(chunk))
|
|
89
|
+
this.handleMessage(msg);
|
|
90
|
+
});
|
|
91
|
+
proc.stderr.on('data', () => {
|
|
92
|
+
});
|
|
93
|
+
proc.on('error', (err) => {
|
|
94
|
+
logger.warn('LSP server process error', { id: this.def.id, error: err.message });
|
|
95
|
+
this.teardown();
|
|
96
|
+
});
|
|
97
|
+
proc.on('exit', () => this.teardown());
|
|
98
|
+
await this.request('initialize', {
|
|
99
|
+
processId: process.pid,
|
|
100
|
+
rootUri: pathToFileURL(this.rootDir).toString(),
|
|
101
|
+
rootPath: this.rootDir,
|
|
102
|
+
capabilities: {
|
|
103
|
+
textDocument: {
|
|
104
|
+
synchronization: { didSave: true, dynamicRegistration: false },
|
|
105
|
+
publishDiagnostics: { relatedInformation: false },
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
workspaceFolders: [{ uri: pathToFileURL(this.rootDir).toString(), name: path.basename(this.rootDir) }],
|
|
109
|
+
});
|
|
110
|
+
this.notify('initialized', {});
|
|
111
|
+
this.initialized = true;
|
|
112
|
+
logger.flow('LSP server initialized', { id: this.def.id });
|
|
113
|
+
}
|
|
114
|
+
async getDiagnostics(absPath, text) {
|
|
115
|
+
await this.start();
|
|
116
|
+
const uri = pathToFileURL(absPath).toString();
|
|
117
|
+
this.diagnostics.delete(uri);
|
|
118
|
+
const arrived = this.onceDiagnostics(uri);
|
|
119
|
+
if (!this.openDocs.has(uri)) {
|
|
120
|
+
this.openDocs.add(uri);
|
|
121
|
+
this.version.set(uri, 1);
|
|
122
|
+
this.notify('textDocument/didOpen', {
|
|
123
|
+
textDocument: { uri, languageId: this.def.id, version: 1, text },
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
const v = (this.version.get(uri) ?? 1) + 1;
|
|
128
|
+
this.version.set(uri, v);
|
|
129
|
+
this.notify('textDocument/didChange', {
|
|
130
|
+
textDocument: { uri, version: v },
|
|
131
|
+
contentChanges: [{ text }],
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
this.notify('textDocument/didSave', { textDocument: { uri }, text });
|
|
135
|
+
await Promise.race([arrived, this.delay(DIAGNOSTICS_WAIT_MS)]);
|
|
136
|
+
return this.diagnostics.get(uri) ?? [];
|
|
137
|
+
}
|
|
138
|
+
onceDiagnostics(uri) {
|
|
139
|
+
return new Promise((resolve) => {
|
|
140
|
+
const list = this.diagWaiters.get(uri) ?? [];
|
|
141
|
+
list.push(resolve);
|
|
142
|
+
this.diagWaiters.set(uri, list);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
delay(ms) {
|
|
146
|
+
return new Promise((r) => {
|
|
147
|
+
const t = setTimeout(r, ms);
|
|
148
|
+
if (typeof t.unref === 'function')
|
|
149
|
+
t.unref();
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
async waitFor(cond, timeoutMs) {
|
|
153
|
+
const start = Date.now();
|
|
154
|
+
while (!cond() && Date.now() - start < timeoutMs) {
|
|
155
|
+
await this.delay(50);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
teardown() {
|
|
159
|
+
this.initialized = false;
|
|
160
|
+
for (const [, p] of this.pendingRequests)
|
|
161
|
+
p.reject(new Error('LSP server exited'));
|
|
162
|
+
this.pendingRequests.clear();
|
|
163
|
+
this.proc = null;
|
|
164
|
+
}
|
|
165
|
+
async stop() {
|
|
166
|
+
if (!this.proc)
|
|
167
|
+
return;
|
|
168
|
+
try {
|
|
169
|
+
await Promise.race([this.request('shutdown', null), this.delay(1000)]);
|
|
170
|
+
this.notify('exit', null);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
this.proc.kill();
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
}
|
|
179
|
+
this.teardown();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const clients = new Map();
|
|
183
|
+
export function getOrCreateClient(def, rootDir) {
|
|
184
|
+
const key = `${def.id}::${rootDir}`;
|
|
185
|
+
let client = clients.get(key);
|
|
186
|
+
if (!client) {
|
|
187
|
+
client = new LspClient(def, rootDir);
|
|
188
|
+
clients.set(key, client);
|
|
189
|
+
}
|
|
190
|
+
return client;
|
|
191
|
+
}
|
|
192
|
+
export async function shutdownAllLspClients() {
|
|
193
|
+
const all = Array.from(clients.values());
|
|
194
|
+
clients.clear();
|
|
195
|
+
await Promise.all(all.map((c) => c.stop().catch(() => undefined)));
|
|
196
|
+
}
|
|
197
|
+
export function getActiveLspClientCount() {
|
|
198
|
+
return clients.size;
|
|
199
|
+
}
|
|
200
|
+
export { fileURLToPath };
|
|
201
|
+
//# sourceMappingURL=lsp-client.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface LspServerDef {
|
|
2
|
+
id: string;
|
|
3
|
+
extensions: string[];
|
|
4
|
+
command: string;
|
|
5
|
+
args: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function resolveServerBinary(command: string): string | null;
|
|
8
|
+
export declare function getServerDefs(): LspServerDef[];
|
|
9
|
+
export declare function findServerForFile(absPath: string): {
|
|
10
|
+
def: LspServerDef;
|
|
11
|
+
binary: string;
|
|
12
|
+
} | null;
|
|
13
|
+
export declare function clearResolveCache(): void;
|
|
14
|
+
//# sourceMappingURL=server-registry.d.ts.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { configManager } from '../config/config-manager.js';
|
|
4
|
+
const DEFAULT_SERVERS = [
|
|
5
|
+
{
|
|
6
|
+
id: 'typescript',
|
|
7
|
+
extensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.mts', '.cts'],
|
|
8
|
+
command: 'typescript-language-server',
|
|
9
|
+
args: ['--stdio'],
|
|
10
|
+
},
|
|
11
|
+
{ id: 'python', extensions: ['.py', '.pyi'], command: 'pyright-langserver', args: ['--stdio'] },
|
|
12
|
+
{ id: 'rust', extensions: ['.rs'], command: 'rust-analyzer', args: [] },
|
|
13
|
+
{ id: 'go', extensions: ['.go'], command: 'gopls', args: [] },
|
|
14
|
+
{ id: 'ruby', extensions: ['.rb'], command: 'solargraph', args: ['stdio'] },
|
|
15
|
+
];
|
|
16
|
+
function execCandidates(command) {
|
|
17
|
+
if (path.isAbsolute(command))
|
|
18
|
+
return [command];
|
|
19
|
+
if (process.platform === 'win32') {
|
|
20
|
+
const exts = (process.env['PATHEXT'] || '.COM;.EXE;.BAT;.CMD').split(';');
|
|
21
|
+
return [command, ...exts.map((e) => command + e.toLowerCase()), ...exts.map((e) => command + e)];
|
|
22
|
+
}
|
|
23
|
+
return [command];
|
|
24
|
+
}
|
|
25
|
+
const resolveCache = new Map();
|
|
26
|
+
export function resolveServerBinary(command) {
|
|
27
|
+
if (resolveCache.has(command))
|
|
28
|
+
return resolveCache.get(command);
|
|
29
|
+
const tryFile = (p) => {
|
|
30
|
+
try {
|
|
31
|
+
const st = fs.statSync(p);
|
|
32
|
+
if (st.isFile())
|
|
33
|
+
return p;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
};
|
|
39
|
+
let found = null;
|
|
40
|
+
if (path.isAbsolute(command) || command.includes('/') || command.includes('\\')) {
|
|
41
|
+
for (const cand of execCandidates(command)) {
|
|
42
|
+
found = tryFile(path.resolve(cand));
|
|
43
|
+
if (found)
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const pathDirs = (process.env['PATH'] || '').split(path.delimiter).filter(Boolean);
|
|
49
|
+
outer: for (const dir of pathDirs) {
|
|
50
|
+
for (const cand of execCandidates(command)) {
|
|
51
|
+
found = tryFile(path.join(dir, cand));
|
|
52
|
+
if (found)
|
|
53
|
+
break outer;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
resolveCache.set(command, found);
|
|
58
|
+
return found;
|
|
59
|
+
}
|
|
60
|
+
export function getServerDefs() {
|
|
61
|
+
let custom = [];
|
|
62
|
+
try {
|
|
63
|
+
custom = configManager.getLspServers();
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
}
|
|
67
|
+
return [...custom, ...DEFAULT_SERVERS];
|
|
68
|
+
}
|
|
69
|
+
export function findServerForFile(absPath) {
|
|
70
|
+
const ext = path.extname(absPath).toLowerCase();
|
|
71
|
+
if (!ext)
|
|
72
|
+
return null;
|
|
73
|
+
for (const def of getServerDefs()) {
|
|
74
|
+
if (!def.extensions.includes(ext))
|
|
75
|
+
continue;
|
|
76
|
+
const binary = resolveServerBinary(def.command);
|
|
77
|
+
if (binary)
|
|
78
|
+
return { def: { ...def, command: binary }, binary };
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
export function clearResolveCache() {
|
|
83
|
+
resolveCache.clear();
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=server-registry.js.map
|
package/dist/eval/eval-runner.js
CHANGED
|
@@ -40,6 +40,12 @@ export class EvalRunner {
|
|
|
40
40
|
if (input.working_dir) {
|
|
41
41
|
process.chdir(input.working_dir);
|
|
42
42
|
}
|
|
43
|
+
try {
|
|
44
|
+
const { initializeMcpServers } = await import('../tools/mcp/index.js');
|
|
45
|
+
await initializeMcpServers(process.cwd());
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
}
|
|
43
49
|
const startEvent = {
|
|
44
50
|
event: 'start',
|
|
45
51
|
timestamp: now(),
|
|
@@ -58,6 +64,14 @@ export class EvalRunner {
|
|
|
58
64
|
this.emitError(error instanceof Error ? error.message : String(error));
|
|
59
65
|
this.emitEnd(false);
|
|
60
66
|
}
|
|
67
|
+
finally {
|
|
68
|
+
try {
|
|
69
|
+
const { shutdownAllLspClients } = await import('../core/lsp/index.js');
|
|
70
|
+
await shutdownAllLspClients();
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
}
|
|
74
|
+
}
|
|
61
75
|
}
|
|
62
76
|
async execute(prompt) {
|
|
63
77
|
if (!this.llmClient) {
|
|
@@ -2,6 +2,7 @@ import { PlanningLLM } from '../agents/planner/index.js';
|
|
|
2
2
|
import { sessionManager } from '../core/session/session-manager.js';
|
|
3
3
|
import { CompactManager, contextTracker, buildCompactedMessages, } from '../core/compact/index.js';
|
|
4
4
|
import { configManager } from '../core/config/config-manager.js';
|
|
5
|
+
import { fileSnapshotStore } from '../core/file-snapshot-store.js';
|
|
5
6
|
import { setTodoWriteCallback, clearTodoCallbacks, } from '../tools/llm/simple/todo-tools.js';
|
|
6
7
|
import { setGetTodosCallback, setFinalResponseCallback, setMarkTodosCompletedCallback, clearFinalResponseCallbacks, } from '../tools/llm/simple/final-response-tool.js';
|
|
7
8
|
import { eventBus, Events } from '../core/event-bus.js';
|
|
@@ -54,6 +55,7 @@ export class PlanExecutor {
|
|
|
54
55
|
});
|
|
55
56
|
this.currentLLMClient = llmClient;
|
|
56
57
|
setDocsSearchLLMClientGetter(() => this.currentLLMClient);
|
|
58
|
+
fileSnapshotStore.beginTurn(userMessage);
|
|
57
59
|
isInterruptedRef.current = false;
|
|
58
60
|
callbacks.setIsInterrupted(false);
|
|
59
61
|
callbacks.setTodos([]);
|
|
@@ -3,6 +3,8 @@ import * as path from 'path';
|
|
|
3
3
|
import { logger } from '../../../utils/logger.js';
|
|
4
4
|
import { shouldIgnore } from '../../../core/ignore-filter.js';
|
|
5
5
|
import { getCachedFile, setCachedFile, invalidateCache } from '../../../core/file-cache.js';
|
|
6
|
+
import { fileSnapshotStore } from '../../../core/file-snapshot-store.js';
|
|
7
|
+
import { getDiagnosticsForFile } from '../../../core/lsp/index.js';
|
|
6
8
|
const EXCLUDED_DIRS = new Set([
|
|
7
9
|
'node_modules',
|
|
8
10
|
'.git',
|
|
@@ -193,10 +195,12 @@ async function _executeCreateFile(args) {
|
|
|
193
195
|
}
|
|
194
196
|
const dir = path.dirname(resolvedPath);
|
|
195
197
|
await fs.mkdir(dir, { recursive: true });
|
|
198
|
+
fileSnapshotStore.record(resolvedPath, null);
|
|
196
199
|
await fs.writeFile(resolvedPath, content, 'utf-8');
|
|
197
200
|
invalidateCache(resolvedPath);
|
|
198
201
|
const lines = content.split('\n').length;
|
|
199
202
|
logger.toolSuccess('create_file', args, { file: displayPath, lines }, 0);
|
|
203
|
+
const diagnostics = await getDiagnosticsForFile(resolvedPath);
|
|
200
204
|
return {
|
|
201
205
|
success: true,
|
|
202
206
|
result: JSON.stringify({
|
|
@@ -204,7 +208,7 @@ async function _executeCreateFile(args) {
|
|
|
204
208
|
file: displayPath,
|
|
205
209
|
lines: lines,
|
|
206
210
|
message: `Created ${displayPath} (${lines} lines)`,
|
|
207
|
-
}),
|
|
211
|
+
}) + diagnostics,
|
|
208
212
|
};
|
|
209
213
|
}
|
|
210
214
|
catch (error) {
|
|
@@ -356,6 +360,7 @@ async function _executeEditFile(args) {
|
|
|
356
360
|
error: `Modified content too large (${(newContentSize / 1024 / 1024).toFixed(2)}MB). Maximum: ${MAX_WRITE_SIZE / 1024 / 1024}MB`,
|
|
357
361
|
};
|
|
358
362
|
}
|
|
363
|
+
fileSnapshotStore.record(resolvedPath, originalContent);
|
|
359
364
|
await fs.writeFile(resolvedPath, newContent, 'utf-8');
|
|
360
365
|
invalidateCache(resolvedPath);
|
|
361
366
|
const oldLinesArr = oldString.split('\n');
|
|
@@ -371,6 +376,7 @@ async function _executeEditFile(args) {
|
|
|
371
376
|
if (newLinesArr.length > 5)
|
|
372
377
|
diffPreview.push('+ ...');
|
|
373
378
|
logger.toolSuccess('edit_file', args, { file: displayPath, replacements, oldLines: oldLinesArr.length, newLines: newLinesArr.length }, 0);
|
|
379
|
+
const diagnostics = await getDiagnosticsForFile(resolvedPath);
|
|
374
380
|
return {
|
|
375
381
|
success: true,
|
|
376
382
|
result: JSON.stringify({
|
|
@@ -383,7 +389,7 @@ async function _executeEditFile(args) {
|
|
|
383
389
|
? `Replaced ${replacements} occurrence(s) in ${displayPath}`
|
|
384
390
|
: `Updated ${displayPath}`,
|
|
385
391
|
diff: diffPreview,
|
|
386
|
-
}),
|
|
392
|
+
}) + diagnostics,
|
|
387
393
|
};
|
|
388
394
|
}
|
|
389
395
|
catch (error) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare function namespacedToolName(server: string, tool: string): string;
|
|
2
|
+
export interface McpInitResult {
|
|
3
|
+
servers: number;
|
|
4
|
+
tools: number;
|
|
5
|
+
errors: Array<{
|
|
6
|
+
server: string;
|
|
7
|
+
error: string;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
export declare function initializeMcpServers(cwd?: string): Promise<McpInitResult>;
|
|
11
|
+
export declare function getConnectedMcpServers(): Array<{
|
|
12
|
+
name: string;
|
|
13
|
+
tools: string[];
|
|
14
|
+
}>;
|
|
15
|
+
export declare function disconnectMcpServers(): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=mcp-client.d.ts.map
|