igel-qe-core 1.0.8 → 1.0.10
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/index.js +39 -13
- package/dist/mcp/server.js +23 -8
- package/package.json +1 -1
- package/src/cli/index.ts +40 -13
- package/src/deploy/requirements.txt +1 -0
- package/src/mcp/server.ts +22 -8
package/dist/cli/index.js
CHANGED
|
@@ -15,9 +15,34 @@ program
|
|
|
15
15
|
.description("IGEL QE Developer Experience CLI")
|
|
16
16
|
.version("1.0.0");
|
|
17
17
|
// ── helpers ────────────────────────────────────────────────────────────────────
|
|
18
|
-
function
|
|
19
|
-
const
|
|
20
|
-
|
|
18
|
+
function getSystemPython() {
|
|
19
|
+
for (const cmd of ["python3", "python", "py"]) {
|
|
20
|
+
try {
|
|
21
|
+
const res = spawnSync(cmd, ["-c", "import sys; print(sys.version)"], { encoding: "utf-8" });
|
|
22
|
+
if (!res.error && res.status === 0 && res.stdout.includes("3.")) {
|
|
23
|
+
return cmd;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Continue
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return "python3";
|
|
31
|
+
}
|
|
32
|
+
function getPythonBin(workspaceRoot) {
|
|
33
|
+
const root = workspaceRoot || process.cwd();
|
|
34
|
+
const isWin = process.platform === "win32";
|
|
35
|
+
const localVenv = isWin
|
|
36
|
+
? join(root, ".venv", "Scripts", "python.exe")
|
|
37
|
+
: join(root, ".venv", "bin", "python");
|
|
38
|
+
if (existsSync(localVenv))
|
|
39
|
+
return localVenv;
|
|
40
|
+
const globalVenv = isWin
|
|
41
|
+
? join(PROJECT_ROOT, ".venv", "Scripts", "python.exe")
|
|
42
|
+
: join(PROJECT_ROOT, ".venv", "bin", "python");
|
|
43
|
+
if (existsSync(globalVenv))
|
|
44
|
+
return globalVenv;
|
|
45
|
+
return getSystemPython();
|
|
21
46
|
}
|
|
22
47
|
function resolveRequirementsPath() {
|
|
23
48
|
const primary = join(PROJECT_ROOT, "requirements.txt");
|
|
@@ -196,11 +221,11 @@ function listFrameworkContextFiles(workspaceRoot) {
|
|
|
196
221
|
return Array.from(new Set(found)).sort();
|
|
197
222
|
}
|
|
198
223
|
function isCopilotCliAvailable() {
|
|
199
|
-
const check = spawnSync("copilot", ["--version"], { encoding: "utf-8" });
|
|
224
|
+
const check = spawnSync("copilot", ["--version"], { encoding: "utf-8", shell: process.platform === "win32" });
|
|
200
225
|
return check.status === 0;
|
|
201
226
|
}
|
|
202
227
|
function isCopilotAuthenticated(workspaceRoot) {
|
|
203
|
-
const probe = spawnSync("copilot", ["-C", workspaceRoot, "-p", "Reply with exactly OK.", "--allow-all-tools", "--no-color", "-s"], { encoding: "utf-8" });
|
|
228
|
+
const probe = spawnSync("copilot", ["-C", workspaceRoot, "-p", "Reply with exactly OK.", "--allow-all-tools", "--no-color", "-s"], { encoding: "utf-8", shell: process.platform === "win32" });
|
|
204
229
|
return probe.status === 0;
|
|
205
230
|
}
|
|
206
231
|
function ensureCopilotLogin(workspaceRoot) {
|
|
@@ -210,7 +235,7 @@ function ensureCopilotLogin(workspaceRoot) {
|
|
|
210
235
|
return true;
|
|
211
236
|
console.log(chalk.yellow(" ⚠ GitHub Copilot CLI is not authenticated."));
|
|
212
237
|
console.log(chalk.yellow(" → Please complete Copilot login to continue context enrichment."));
|
|
213
|
-
const login = spawnSync("copilot", ["login"], { stdio: "inherit", encoding: "utf-8" });
|
|
238
|
+
const login = spawnSync("copilot", ["login"], { stdio: "inherit", encoding: "utf-8", shell: process.platform === "win32" });
|
|
214
239
|
if (login.status !== 0)
|
|
215
240
|
return false;
|
|
216
241
|
return isCopilotAuthenticated(workspaceRoot);
|
|
@@ -237,7 +262,7 @@ function enrichWithCopilotCli(workspaceRoot, contextFiles) {
|
|
|
237
262
|
"--allow-all-paths",
|
|
238
263
|
"--no-color",
|
|
239
264
|
"-s",
|
|
240
|
-
], { encoding: "utf-8" });
|
|
265
|
+
], { encoding: "utf-8", shell: process.platform === "win32" });
|
|
241
266
|
if (result.status === 0) {
|
|
242
267
|
updated += 1;
|
|
243
268
|
}
|
|
@@ -308,7 +333,8 @@ function scaffoldGithubAgents(targetDir) {
|
|
|
308
333
|
*/
|
|
309
334
|
function runWorkflow(action, args) {
|
|
310
335
|
return new Promise((resolve, reject) => {
|
|
311
|
-
const
|
|
336
|
+
const workspaceRoot = process.cwd();
|
|
337
|
+
const py = getPythonBin(workspaceRoot);
|
|
312
338
|
const proc = spawn(py, ["-m", "src.cli.workflow_cli", "--action", action, "--args", JSON.stringify(args)], { cwd: PROJECT_ROOT, env: process.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
313
339
|
let stdout = "";
|
|
314
340
|
let stderr = "";
|
|
@@ -341,11 +367,11 @@ program
|
|
|
341
367
|
const workspaceRoot = process.cwd();
|
|
342
368
|
console.log(chalk.blue("\nInitializing IGEL QE AI Platform…\n"));
|
|
343
369
|
// Step 1 — venv + pip
|
|
344
|
-
const venvPath = join(
|
|
370
|
+
const venvPath = join(workspaceRoot, ".venv");
|
|
345
371
|
if (!existsSync(venvPath)) {
|
|
346
|
-
console.log(chalk.yellow("1. Creating virtual environment…"));
|
|
372
|
+
console.log(chalk.yellow("1. Creating virtual environment in workspace…"));
|
|
347
373
|
try {
|
|
348
|
-
execSync(
|
|
374
|
+
execSync(`${getSystemPython()} -m venv .venv`, { cwd: workspaceRoot, stdio: "inherit" });
|
|
349
375
|
console.log(chalk.green(" ✓ venv created"));
|
|
350
376
|
}
|
|
351
377
|
catch (e) {
|
|
@@ -362,8 +388,8 @@ program
|
|
|
362
388
|
}
|
|
363
389
|
else {
|
|
364
390
|
try {
|
|
365
|
-
execSync(`${getPythonBin()} -m pip install -q -r \"${reqPath}\"`, {
|
|
366
|
-
cwd:
|
|
391
|
+
execSync(`${getPythonBin(workspaceRoot)} -m pip install -q -r \"${reqPath}\"`, {
|
|
392
|
+
cwd: workspaceRoot, stdio: "inherit",
|
|
367
393
|
});
|
|
368
394
|
console.log(chalk.green(" ✓ Dependencies installed"));
|
|
369
395
|
}
|
package/dist/mcp/server.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
5
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
-
import { spawn } from "child_process";
|
|
6
|
+
import { spawn, spawnSync } from "child_process";
|
|
7
7
|
import path from "path";
|
|
8
8
|
import { fileURLToPath } from "url";
|
|
9
9
|
import fs from "fs";
|
|
@@ -11,18 +11,33 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
11
11
|
// Project root: dist/mcp/server.js -> ../../ = project root
|
|
12
12
|
const PROJECT_ROOT = path.resolve(__dirname, '..', '..');
|
|
13
13
|
// Resolve the correct Python executable:
|
|
14
|
-
// 1. Check for a local .venv
|
|
15
|
-
// 2. Fall back to system python3 / python
|
|
14
|
+
// 1. Check for a local .venv (Linux or Windows path layouts)
|
|
15
|
+
// 2. Fall back to system python3 / python / py
|
|
16
16
|
function resolvePythonExecutable() {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
const isWin = process.platform === 'win32';
|
|
18
|
+
const candidates = isWin
|
|
19
|
+
? [
|
|
20
|
+
path.join(PROJECT_ROOT, '.venv', 'Scripts', 'python.exe'),
|
|
21
|
+
path.join(PROJECT_ROOT, '.venv', 'Scripts', 'python'),
|
|
22
|
+
]
|
|
23
|
+
: [
|
|
24
|
+
path.join(PROJECT_ROOT, '.venv', 'bin', 'python'),
|
|
25
|
+
path.join(PROJECT_ROOT, '.venv', 'bin', 'python3'),
|
|
26
|
+
];
|
|
21
27
|
for (const c of candidates) {
|
|
22
28
|
if (fs.existsSync(c))
|
|
23
29
|
return c;
|
|
24
30
|
}
|
|
25
|
-
// Check system python3 / python
|
|
31
|
+
// Check system python3 / python / py
|
|
32
|
+
for (const cmd of ['python3', 'python', 'py']) {
|
|
33
|
+
try {
|
|
34
|
+
const res = spawnSync(cmd, ['--version'], { stdio: 'ignore' });
|
|
35
|
+
if (res.status === 0 || res.status === null) {
|
|
36
|
+
return cmd;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch { }
|
|
40
|
+
}
|
|
26
41
|
return 'python3';
|
|
27
42
|
}
|
|
28
43
|
const server = new Server({
|
package/package.json
CHANGED
package/src/cli/index.ts
CHANGED
|
@@ -21,9 +21,35 @@ program
|
|
|
21
21
|
|
|
22
22
|
// ── helpers ────────────────────────────────────────────────────────────────────
|
|
23
23
|
|
|
24
|
-
function
|
|
25
|
-
const
|
|
26
|
-
|
|
24
|
+
function getSystemPython(): string {
|
|
25
|
+
for (const cmd of ["python3", "python", "py"]) {
|
|
26
|
+
try {
|
|
27
|
+
const res = spawnSync(cmd, ["-c", "import sys; print(sys.version)"], { encoding: "utf-8" });
|
|
28
|
+
if (!res.error && res.status === 0 && res.stdout.includes("3.")) {
|
|
29
|
+
return cmd;
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
// Continue
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return "python3";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getPythonBin(workspaceRoot?: string): string {
|
|
39
|
+
const root = workspaceRoot || process.cwd();
|
|
40
|
+
const isWin = process.platform === "win32";
|
|
41
|
+
|
|
42
|
+
const localVenv = isWin
|
|
43
|
+
? join(root, ".venv", "Scripts", "python.exe")
|
|
44
|
+
: join(root, ".venv", "bin", "python");
|
|
45
|
+
if (existsSync(localVenv)) return localVenv;
|
|
46
|
+
|
|
47
|
+
const globalVenv = isWin
|
|
48
|
+
? join(PROJECT_ROOT, ".venv", "Scripts", "python.exe")
|
|
49
|
+
: join(PROJECT_ROOT, ".venv", "bin", "python");
|
|
50
|
+
if (existsSync(globalVenv)) return globalVenv;
|
|
51
|
+
|
|
52
|
+
return getSystemPython();
|
|
27
53
|
}
|
|
28
54
|
|
|
29
55
|
function resolveRequirementsPath(): string | null {
|
|
@@ -206,7 +232,7 @@ function listFrameworkContextFiles(workspaceRoot: string): string[] {
|
|
|
206
232
|
}
|
|
207
233
|
|
|
208
234
|
function isCopilotCliAvailable(): boolean {
|
|
209
|
-
const check = spawnSync("copilot", ["--version"], { encoding: "utf-8" });
|
|
235
|
+
const check = spawnSync("copilot", ["--version"], { encoding: "utf-8", shell: process.platform === "win32" });
|
|
210
236
|
return check.status === 0;
|
|
211
237
|
}
|
|
212
238
|
|
|
@@ -214,7 +240,7 @@ function isCopilotAuthenticated(workspaceRoot: string): boolean {
|
|
|
214
240
|
const probe = spawnSync(
|
|
215
241
|
"copilot",
|
|
216
242
|
["-C", workspaceRoot, "-p", "Reply with exactly OK.", "--allow-all-tools", "--no-color", "-s"],
|
|
217
|
-
{ encoding: "utf-8" },
|
|
243
|
+
{ encoding: "utf-8", shell: process.platform === "win32" },
|
|
218
244
|
);
|
|
219
245
|
return probe.status === 0;
|
|
220
246
|
}
|
|
@@ -226,7 +252,7 @@ function ensureCopilotLogin(workspaceRoot: string): boolean {
|
|
|
226
252
|
console.log(chalk.yellow(" ⚠ GitHub Copilot CLI is not authenticated."));
|
|
227
253
|
console.log(chalk.yellow(" → Please complete Copilot login to continue context enrichment."));
|
|
228
254
|
|
|
229
|
-
const login = spawnSync("copilot", ["login"], { stdio: "inherit", encoding: "utf-8" });
|
|
255
|
+
const login = spawnSync("copilot", ["login"], { stdio: "inherit", encoding: "utf-8", shell: process.platform === "win32" });
|
|
230
256
|
if (login.status !== 0) return false;
|
|
231
257
|
return isCopilotAuthenticated(workspaceRoot);
|
|
232
258
|
}
|
|
@@ -258,7 +284,7 @@ function enrichWithCopilotCli(workspaceRoot: string, contextFiles: string[]): {
|
|
|
258
284
|
"--no-color",
|
|
259
285
|
"-s",
|
|
260
286
|
],
|
|
261
|
-
{ encoding: "utf-8" },
|
|
287
|
+
{ encoding: "utf-8", shell: process.platform === "win32" },
|
|
262
288
|
);
|
|
263
289
|
|
|
264
290
|
if (result.status === 0) {
|
|
@@ -334,7 +360,8 @@ function scaffoldGithubAgents(targetDir: string): string[] {
|
|
|
334
360
|
*/
|
|
335
361
|
function runWorkflow(action: string, args: Record<string, unknown>): Promise<unknown> {
|
|
336
362
|
return new Promise((resolve, reject) => {
|
|
337
|
-
const
|
|
363
|
+
const workspaceRoot = process.cwd();
|
|
364
|
+
const py = getPythonBin(workspaceRoot);
|
|
338
365
|
const proc = spawn(
|
|
339
366
|
py,
|
|
340
367
|
["-m", "src.cli.workflow_cli", "--action", action, "--args", JSON.stringify(args)],
|
|
@@ -372,11 +399,11 @@ program
|
|
|
372
399
|
console.log(chalk.blue("\nInitializing IGEL QE AI Platform…\n"));
|
|
373
400
|
|
|
374
401
|
// Step 1 — venv + pip
|
|
375
|
-
const venvPath = join(
|
|
402
|
+
const venvPath = join(workspaceRoot, ".venv");
|
|
376
403
|
if (!existsSync(venvPath)) {
|
|
377
|
-
console.log(chalk.yellow("1. Creating virtual environment…"));
|
|
404
|
+
console.log(chalk.yellow("1. Creating virtual environment in workspace…"));
|
|
378
405
|
try {
|
|
379
|
-
execSync(
|
|
406
|
+
execSync(`${getSystemPython()} -m venv .venv`, { cwd: workspaceRoot, stdio: "inherit" });
|
|
380
407
|
console.log(chalk.green(" ✓ venv created"));
|
|
381
408
|
} catch (e: unknown) {
|
|
382
409
|
console.log(chalk.yellow(` ⚠ venv setup skipped: ${e instanceof Error ? e.message : String(e)}`));
|
|
@@ -391,8 +418,8 @@ program
|
|
|
391
418
|
console.log(chalk.yellow(" ⚠ requirements file not found; skipping Python dependency install"));
|
|
392
419
|
} else {
|
|
393
420
|
try {
|
|
394
|
-
execSync(`${getPythonBin()} -m pip install -q -r \"${reqPath}\"`, {
|
|
395
|
-
cwd:
|
|
421
|
+
execSync(`${getPythonBin(workspaceRoot)} -m pip install -q -r \"${reqPath}\"`, {
|
|
422
|
+
cwd: workspaceRoot, stdio: "inherit",
|
|
396
423
|
});
|
|
397
424
|
console.log(chalk.green(" ✓ Dependencies installed"));
|
|
398
425
|
} catch (e: unknown) {
|
|
@@ -28,6 +28,7 @@ pydantic>=2.7.0
|
|
|
28
28
|
eval_type_backport>=0.2.0; python_version < "3.10"
|
|
29
29
|
tenacity==9.0.0
|
|
30
30
|
rich==13.9.4
|
|
31
|
+
PyYAML>=6.0.1
|
|
31
32
|
|
|
32
33
|
# OSS local reranker (CrossEncoder — free, runs on CPU/GPU)
|
|
33
34
|
# Default model: BAAI/bge-reranker-v2-m3 (multilingual, best open-source for IGEL DE/EN)
|
package/src/mcp/server.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
5
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
-
import { spawn } from "child_process";
|
|
6
|
+
import { spawn, spawnSync } from "child_process";
|
|
7
7
|
import path from "path";
|
|
8
8
|
import { fileURLToPath } from "url";
|
|
9
9
|
import fs from "fs";
|
|
@@ -14,17 +14,31 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
14
14
|
const PROJECT_ROOT = path.resolve(__dirname, '..', '..');
|
|
15
15
|
|
|
16
16
|
// Resolve the correct Python executable:
|
|
17
|
-
// 1. Check for a local .venv
|
|
18
|
-
// 2. Fall back to system python3 / python
|
|
17
|
+
// 1. Check for a local .venv (Linux or Windows path layouts)
|
|
18
|
+
// 2. Fall back to system python3 / python / py
|
|
19
19
|
function resolvePythonExecutable(): string {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
const isWin = process.platform === 'win32';
|
|
21
|
+
const candidates = isWin
|
|
22
|
+
? [
|
|
23
|
+
path.join(PROJECT_ROOT, '.venv', 'Scripts', 'python.exe'),
|
|
24
|
+
path.join(PROJECT_ROOT, '.venv', 'Scripts', 'python'),
|
|
25
|
+
]
|
|
26
|
+
: [
|
|
27
|
+
path.join(PROJECT_ROOT, '.venv', 'bin', 'python'),
|
|
28
|
+
path.join(PROJECT_ROOT, '.venv', 'bin', 'python3'),
|
|
29
|
+
];
|
|
24
30
|
for (const c of candidates) {
|
|
25
31
|
if (fs.existsSync(c)) return c;
|
|
26
32
|
}
|
|
27
|
-
// Check system python3 / python
|
|
33
|
+
// Check system python3 / python / py
|
|
34
|
+
for (const cmd of ['python3', 'python', 'py']) {
|
|
35
|
+
try {
|
|
36
|
+
const res = spawnSync(cmd, ['--version'], { stdio: 'ignore' });
|
|
37
|
+
if (res.status === 0 || res.status === null) {
|
|
38
|
+
return cmd;
|
|
39
|
+
}
|
|
40
|
+
} catch {}
|
|
41
|
+
}
|
|
28
42
|
return 'python3';
|
|
29
43
|
}
|
|
30
44
|
|