igel-qe-core 1.0.14 → 1.0.16
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 +57 -32
- package/package.json +2 -1
- package/src/cli/index.ts +60 -29
package/dist/cli/index.js
CHANGED
|
@@ -229,34 +229,43 @@ function isCopilotCliAvailable() {
|
|
|
229
229
|
});
|
|
230
230
|
return check.status === 0 && !check.error;
|
|
231
231
|
}
|
|
232
|
-
function isCopilotAuthenticated(
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
|
|
232
|
+
function isCopilotAuthenticated() {
|
|
233
|
+
// Use a lightweight auth-status check instead of spawning a full agent session.
|
|
234
|
+
// "copilot auth status" exits 0 when authenticated, non-zero otherwise.
|
|
235
|
+
// Fallback: if the sub-command doesn't exist, treat as unauthenticated.
|
|
236
|
+
const probe = spawnSync("copilot", ["auth", "status"], {
|
|
236
237
|
encoding: "utf-8",
|
|
237
238
|
shell: process.platform === "win32",
|
|
238
|
-
timeout:
|
|
239
|
-
input: "", // close stdin immediately so it doesn't wait for user input
|
|
239
|
+
timeout: 10_000, // 10 s max — simple status call should be instant
|
|
240
240
|
});
|
|
241
241
|
return probe.status === 0 && !probe.error;
|
|
242
242
|
}
|
|
243
243
|
function ensureCopilotLogin(workspaceRoot) {
|
|
244
244
|
if (!isCopilotCliAvailable())
|
|
245
245
|
return false;
|
|
246
|
-
if (isCopilotAuthenticated(
|
|
246
|
+
if (isCopilotAuthenticated())
|
|
247
247
|
return true;
|
|
248
248
|
console.log(chalk.yellow(" ⚠ GitHub Copilot CLI is not authenticated."));
|
|
249
249
|
console.log(chalk.yellow(" → Please complete Copilot login to continue context enrichment."));
|
|
250
250
|
const login = spawnSync("copilot", ["login"], { stdio: "inherit", encoding: "utf-8", shell: process.platform === "win32" });
|
|
251
251
|
if (login.status !== 0)
|
|
252
252
|
return false;
|
|
253
|
-
return isCopilotAuthenticated(
|
|
253
|
+
return isCopilotAuthenticated();
|
|
254
254
|
}
|
|
255
|
+
// Maximum number of context.md files to enrich per init run.
|
|
256
|
+
// Prevents extremely long waits on repos with many folders.
|
|
257
|
+
const MAX_ENRICHMENT_FILES = 15;
|
|
255
258
|
function enrichWithCopilotCli(workspaceRoot, contextFiles) {
|
|
256
259
|
let updated = 0;
|
|
257
260
|
let failed = 0;
|
|
258
|
-
|
|
259
|
-
|
|
261
|
+
// Limit the number of files processed in one init run.
|
|
262
|
+
const filesToProcess = contextFiles.slice(0, MAX_ENRICHMENT_FILES);
|
|
263
|
+
const total = filesToProcess.length;
|
|
264
|
+
for (let i = 0; i < filesToProcess.length; i++) {
|
|
265
|
+
const absPath = filesToProcess[i];
|
|
266
|
+
const relPath = absPath.replace(`${workspaceRoot}/`, "").replace(`${workspaceRoot}\\`, "");
|
|
267
|
+
// Show per-file progress so the user knows work is happening.
|
|
268
|
+
process.stdout.write(` [${i + 1}/${total}] Enriching ${relPath}…`);
|
|
260
269
|
const prompt = [
|
|
261
270
|
`Update the markdown file at path '${relPath}' in place.`,
|
|
262
271
|
"Goal: make it both human-understandable and LLM-ready for automation framework reasoning.",
|
|
@@ -280,10 +289,12 @@ function enrichWithCopilotCli(workspaceRoot, contextFiles) {
|
|
|
280
289
|
timeout: 120_000, // 2 min per file — prevents indefinite hangs
|
|
281
290
|
input: "", // close stdin immediately
|
|
282
291
|
});
|
|
283
|
-
if (result.status === 0) {
|
|
292
|
+
if (result.status === 0 && !result.error) {
|
|
293
|
+
process.stdout.write(" ✓\n");
|
|
284
294
|
updated += 1;
|
|
285
295
|
}
|
|
286
296
|
else {
|
|
297
|
+
process.stdout.write(" ✗\n");
|
|
287
298
|
failed += 1;
|
|
288
299
|
}
|
|
289
300
|
}
|
|
@@ -409,7 +420,9 @@ program
|
|
|
409
420
|
// Wrap both the python path and requirements path in quotes so
|
|
410
421
|
// Windows paths that contain spaces (e.g. "IGEL Automation July 2026")
|
|
411
422
|
// are treated as a single argument by the shell.
|
|
412
|
-
|
|
423
|
+
// --prefer-binary: use pre-built wheels instead of compiling from source
|
|
424
|
+
// (avoids Rust/Cargo requirement for packages like tokenizers, crawl4ai)
|
|
425
|
+
execSync(`"${pyBin}" -m pip install -q --prefer-binary -r "${reqPath}"`, {
|
|
413
426
|
cwd: workspaceRoot, stdio: "inherit",
|
|
414
427
|
});
|
|
415
428
|
console.log(chalk.green(" ✓ Dependencies installed"));
|
|
@@ -436,29 +449,41 @@ program
|
|
|
436
449
|
else {
|
|
437
450
|
console.log(chalk.green(" ✓ Framework context files already up to date"));
|
|
438
451
|
}
|
|
439
|
-
// Step
|
|
452
|
+
// Step 3d — Copilot CLI enrichment pass.
|
|
453
|
+
// Only run when --with-copilot / --with-all is explicitly requested.
|
|
454
|
+
// Skipped silently on plain `igel-qe init` to avoid unexpected long waits.
|
|
455
|
+
const runEnrichment = options.withCopilot || options.withAll;
|
|
440
456
|
console.log(chalk.yellow("3d. Enriching context via GitHub Copilot CLI…"));
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
+
if (!runEnrichment) {
|
|
458
|
+
console.log(chalk.gray(" - Skipped (pass --with-copilot to enable Copilot context enrichment)"));
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
try {
|
|
462
|
+
const allContextFiles = listFrameworkContextFiles(workspaceRoot);
|
|
463
|
+
if (allContextFiles.length === 0) {
|
|
464
|
+
console.log(chalk.yellow(" ⚠ No context.md files found for Copilot enrichment"));
|
|
465
|
+
}
|
|
466
|
+
else if (!isCopilotCliAvailable()) {
|
|
467
|
+
console.log(chalk.yellow(" ⚠ Copilot CLI not installed; skipping Copilot enrichment"));
|
|
468
|
+
}
|
|
469
|
+
else if (!ensureCopilotLogin(workspaceRoot)) {
|
|
470
|
+
console.log(chalk.yellow(" ⚠ Copilot login was not completed; skipping Copilot enrichment"));
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
const cap = Math.min(allContextFiles.length, MAX_ENRICHMENT_FILES);
|
|
474
|
+
if (allContextFiles.length > MAX_ENRICHMENT_FILES) {
|
|
475
|
+
console.log(chalk.gray(` - ${allContextFiles.length} context files found; enriching first ${MAX_ENRICHMENT_FILES} (re-run to continue)`));
|
|
476
|
+
}
|
|
477
|
+
const run = enrichWithCopilotCli(workspaceRoot, allContextFiles);
|
|
478
|
+
console.log(chalk.green(` ✓ Copilot updated ${run.updated}/${cap} context.md file(s)`));
|
|
479
|
+
if (run.failed > 0) {
|
|
480
|
+
console.log(chalk.yellow(` ⚠ Copilot failed to update ${run.failed} context.md file(s)`));
|
|
481
|
+
}
|
|
457
482
|
}
|
|
458
483
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
484
|
+
catch (e) {
|
|
485
|
+
console.log(chalk.yellow(` ⚠ Copilot context enrichment skipped: ${e instanceof Error ? e.message : String(e)}`));
|
|
486
|
+
}
|
|
462
487
|
}
|
|
463
488
|
// Step 3 — write MCP config (default: Copilot when no explicit platform flags)
|
|
464
489
|
console.log(chalk.yellow("4. Configuring MCP server…"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "igel-qe-core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.16",
|
|
4
4
|
"description": "IGEL QE Developer Experience Layer (CLI & MCP)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
18
|
"build": "tsc",
|
|
19
|
+
"prepublishOnly": "tsc",
|
|
19
20
|
"start:mcp": "node ./dist/mcp/server.js"
|
|
20
21
|
},
|
|
21
22
|
"dependencies": {
|
package/src/cli/index.ts
CHANGED
|
@@ -241,17 +241,17 @@ function isCopilotCliAvailable(): boolean {
|
|
|
241
241
|
return check.status === 0 && !check.error;
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
function isCopilotAuthenticated(
|
|
245
|
-
//
|
|
246
|
-
//
|
|
244
|
+
function isCopilotAuthenticated(): boolean {
|
|
245
|
+
// Use a lightweight auth-status check instead of spawning a full agent session.
|
|
246
|
+
// "copilot auth status" exits 0 when authenticated, non-zero otherwise.
|
|
247
|
+
// Fallback: if the sub-command doesn't exist, treat as unauthenticated.
|
|
247
248
|
const probe = spawnSync(
|
|
248
249
|
"copilot",
|
|
249
|
-
["
|
|
250
|
+
["auth", "status"],
|
|
250
251
|
{
|
|
251
252
|
encoding: "utf-8",
|
|
252
253
|
shell: process.platform === "win32",
|
|
253
|
-
timeout:
|
|
254
|
-
input: "", // close stdin immediately so it doesn't wait for user input
|
|
254
|
+
timeout: 10_000, // 10 s max — simple status call should be instant
|
|
255
255
|
},
|
|
256
256
|
);
|
|
257
257
|
return probe.status === 0 && !probe.error;
|
|
@@ -259,22 +259,38 @@ function isCopilotAuthenticated(workspaceRoot: string): boolean {
|
|
|
259
259
|
|
|
260
260
|
function ensureCopilotLogin(workspaceRoot: string): boolean {
|
|
261
261
|
if (!isCopilotCliAvailable()) return false;
|
|
262
|
-
if (isCopilotAuthenticated(
|
|
262
|
+
if (isCopilotAuthenticated()) return true;
|
|
263
263
|
|
|
264
264
|
console.log(chalk.yellow(" ⚠ GitHub Copilot CLI is not authenticated."));
|
|
265
265
|
console.log(chalk.yellow(" → Please complete Copilot login to continue context enrichment."));
|
|
266
266
|
|
|
267
267
|
const login = spawnSync("copilot", ["login"], { stdio: "inherit", encoding: "utf-8", shell: process.platform === "win32" });
|
|
268
268
|
if (login.status !== 0) return false;
|
|
269
|
-
return isCopilotAuthenticated(
|
|
269
|
+
return isCopilotAuthenticated();
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
-
|
|
272
|
+
// Maximum number of context.md files to enrich per init run.
|
|
273
|
+
// Prevents extremely long waits on repos with many folders.
|
|
274
|
+
const MAX_ENRICHMENT_FILES = 15;
|
|
275
|
+
|
|
276
|
+
function enrichWithCopilotCli(
|
|
277
|
+
workspaceRoot: string,
|
|
278
|
+
contextFiles: string[],
|
|
279
|
+
): { updated: number; failed: number } {
|
|
273
280
|
let updated = 0;
|
|
274
281
|
let failed = 0;
|
|
275
282
|
|
|
276
|
-
|
|
277
|
-
|
|
283
|
+
// Limit the number of files processed in one init run.
|
|
284
|
+
const filesToProcess = contextFiles.slice(0, MAX_ENRICHMENT_FILES);
|
|
285
|
+
const total = filesToProcess.length;
|
|
286
|
+
|
|
287
|
+
for (let i = 0; i < filesToProcess.length; i++) {
|
|
288
|
+
const absPath = filesToProcess[i];
|
|
289
|
+
const relPath = absPath.replace(`${workspaceRoot}/`, "").replace(`${workspaceRoot}\\`, "");
|
|
290
|
+
|
|
291
|
+
// Show per-file progress so the user knows work is happening.
|
|
292
|
+
process.stdout.write(` [${i + 1}/${total}] Enriching ${relPath}…`);
|
|
293
|
+
|
|
278
294
|
const prompt = [
|
|
279
295
|
`Update the markdown file at path '${relPath}' in place.`,
|
|
280
296
|
"Goal: make it both human-understandable and LLM-ready for automation framework reasoning.",
|
|
@@ -304,9 +320,11 @@ function enrichWithCopilotCli(workspaceRoot: string, contextFiles: string[]): {
|
|
|
304
320
|
},
|
|
305
321
|
);
|
|
306
322
|
|
|
307
|
-
if (result.status === 0) {
|
|
323
|
+
if (result.status === 0 && !result.error) {
|
|
324
|
+
process.stdout.write(" ✓\n");
|
|
308
325
|
updated += 1;
|
|
309
326
|
} else {
|
|
327
|
+
process.stdout.write(" ✗\n");
|
|
310
328
|
failed += 1;
|
|
311
329
|
}
|
|
312
330
|
}
|
|
@@ -439,7 +457,9 @@ program
|
|
|
439
457
|
// Wrap both the python path and requirements path in quotes so
|
|
440
458
|
// Windows paths that contain spaces (e.g. "IGEL Automation July 2026")
|
|
441
459
|
// are treated as a single argument by the shell.
|
|
442
|
-
|
|
460
|
+
// --prefer-binary: use pre-built wheels instead of compiling from source
|
|
461
|
+
// (avoids Rust/Cargo requirement for packages like tokenizers, crawl4ai)
|
|
462
|
+
execSync(`"${pyBin}" -m pip install -q --prefer-binary -r "${reqPath}"`, {
|
|
443
463
|
cwd: workspaceRoot, stdio: "inherit",
|
|
444
464
|
});
|
|
445
465
|
console.log(chalk.green(" ✓ Dependencies installed"));
|
|
@@ -467,25 +487,36 @@ program
|
|
|
467
487
|
}
|
|
468
488
|
|
|
469
489
|
|
|
470
|
-
// Step
|
|
490
|
+
// Step 3d — Copilot CLI enrichment pass.
|
|
491
|
+
// Only run when --with-copilot / --with-all is explicitly requested.
|
|
492
|
+
// Skipped silently on plain `igel-qe init` to avoid unexpected long waits.
|
|
493
|
+
const runEnrichment = options.withCopilot || options.withAll;
|
|
471
494
|
console.log(chalk.yellow("3d. Enriching context via GitHub Copilot CLI…"));
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
495
|
+
if (!runEnrichment) {
|
|
496
|
+
console.log(chalk.gray(" - Skipped (pass --with-copilot to enable Copilot context enrichment)"));
|
|
497
|
+
} else {
|
|
498
|
+
try {
|
|
499
|
+
const allContextFiles = listFrameworkContextFiles(workspaceRoot);
|
|
500
|
+
if (allContextFiles.length === 0) {
|
|
501
|
+
console.log(chalk.yellow(" ⚠ No context.md files found for Copilot enrichment"));
|
|
502
|
+
} else if (!isCopilotCliAvailable()) {
|
|
503
|
+
console.log(chalk.yellow(" ⚠ Copilot CLI not installed; skipping Copilot enrichment"));
|
|
504
|
+
} else if (!ensureCopilotLogin(workspaceRoot)) {
|
|
505
|
+
console.log(chalk.yellow(" ⚠ Copilot login was not completed; skipping Copilot enrichment"));
|
|
506
|
+
} else {
|
|
507
|
+
const cap = Math.min(allContextFiles.length, MAX_ENRICHMENT_FILES);
|
|
508
|
+
if (allContextFiles.length > MAX_ENRICHMENT_FILES) {
|
|
509
|
+
console.log(chalk.gray(` - ${allContextFiles.length} context files found; enriching first ${MAX_ENRICHMENT_FILES} (re-run to continue)`));
|
|
510
|
+
}
|
|
511
|
+
const run = enrichWithCopilotCli(workspaceRoot, allContextFiles);
|
|
512
|
+
console.log(chalk.green(` ✓ Copilot updated ${run.updated}/${cap} context.md file(s)`));
|
|
513
|
+
if (run.failed > 0) {
|
|
514
|
+
console.log(chalk.yellow(` ⚠ Copilot failed to update ${run.failed} context.md file(s)`));
|
|
515
|
+
}
|
|
485
516
|
}
|
|
517
|
+
} catch (e: unknown) {
|
|
518
|
+
console.log(chalk.yellow(` ⚠ Copilot context enrichment skipped: ${e instanceof Error ? e.message : String(e)}`));
|
|
486
519
|
}
|
|
487
|
-
} catch (e: unknown) {
|
|
488
|
-
console.log(chalk.yellow(` ⚠ Copilot context enrichment skipped: ${e instanceof Error ? e.message : String(e)}`));
|
|
489
520
|
}
|
|
490
521
|
|
|
491
522
|
// Step 3 — write MCP config (default: Copilot when no explicit platform flags)
|