igel-qe-core 1.0.11 → 1.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.
package/dist/cli/index.js CHANGED
@@ -221,12 +221,24 @@ function listFrameworkContextFiles(workspaceRoot) {
221
221
  return Array.from(new Set(found)).sort();
222
222
  }
223
223
  function isCopilotCliAvailable() {
224
- const check = spawnSync("copilot", ["--version"], { encoding: "utf-8", shell: process.platform === "win32" });
225
- return check.status === 0;
224
+ // Use a short timeout so this never blocks if copilot hangs on startup.
225
+ const check = spawnSync("copilot", ["--version"], {
226
+ encoding: "utf-8",
227
+ shell: process.platform === "win32",
228
+ timeout: 10_000,
229
+ });
230
+ return check.status === 0 && !check.error;
226
231
  }
227
232
  function isCopilotAuthenticated(workspaceRoot) {
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" });
229
- return probe.status === 0;
233
+ // A strict timeout prevents the init command from hanging forever when
234
+ // Copilot waits for interactive input or a network response.
235
+ const probe = spawnSync("copilot", ["-C", workspaceRoot, "-p", "Reply with exactly OK.", "--allow-all-tools", "--no-color", "-s"], {
236
+ encoding: "utf-8",
237
+ shell: process.platform === "win32",
238
+ timeout: 30_000, // 30 s max — return false if Copilot doesn't answer
239
+ input: "", // close stdin immediately so it doesn't wait for user input
240
+ });
241
+ return probe.status === 0 && !probe.error;
230
242
  }
231
243
  function ensureCopilotLogin(workspaceRoot) {
232
244
  if (!isCopilotCliAvailable())
@@ -262,7 +274,12 @@ function enrichWithCopilotCli(workspaceRoot, contextFiles) {
262
274
  "--allow-all-paths",
263
275
  "--no-color",
264
276
  "-s",
265
- ], { encoding: "utf-8", shell: process.platform === "win32" });
277
+ ], {
278
+ encoding: "utf-8",
279
+ shell: process.platform === "win32",
280
+ timeout: 120_000, // 2 min per file — prevents indefinite hangs
281
+ input: "", // close stdin immediately
282
+ });
266
283
  if (result.status === 0) {
267
284
  updated += 1;
268
285
  }
@@ -388,7 +405,11 @@ program
388
405
  }
389
406
  else {
390
407
  try {
391
- execSync(`${getPythonBin(workspaceRoot)} -m pip install -q -r \"${reqPath}\"`, {
408
+ const pyBin = getPythonBin(workspaceRoot);
409
+ // Wrap both the python path and requirements path in quotes so
410
+ // Windows paths that contain spaces (e.g. "IGEL Automation July 2026")
411
+ // are treated as a single argument by the shell.
412
+ execSync(`"${pyBin}" -m pip install -q -r "${reqPath}"`, {
392
413
  cwd: workspaceRoot, stdio: "inherit",
393
414
  });
394
415
  console.log(chalk.green(" ✓ Dependencies installed"));
@@ -415,25 +436,6 @@ program
415
436
  else {
416
437
  console.log(chalk.green(" ✓ Framework context files already up to date"));
417
438
  }
418
- // Step 2c — enrich framework context files via AST/dependency graph + DB sync
419
- console.log(chalk.yellow("3c. Enriching framework context files (AST + dependency graph + DB sync)…"));
420
- try {
421
- const enrichResult = await runWorkflow("enrich_framework_context", {
422
- repo_path: workspaceRoot,
423
- });
424
- if (typeof enrichResult.enriched_count === "number") {
425
- console.log(chalk.green(` ✓ Enriched ${enrichResult.enriched_count} context.md file(s)`));
426
- }
427
- else if (enrichResult.raw) {
428
- console.log(chalk.green(" ✓ Context enrichment completed"));
429
- }
430
- else {
431
- console.log(chalk.yellow(" ⚠ Context enrichment returned no summary; continuing"));
432
- }
433
- }
434
- catch (e) {
435
- console.log(chalk.yellow(` ⚠ Context enrichment skipped: ${e instanceof Error ? e.message : String(e)}`));
436
- }
437
439
  // Step 2d — Copilot CLI enrichment pass (asks login if needed), then DB sync.
438
440
  console.log(chalk.yellow("3d. Enriching context via GitHub Copilot CLI…"));
439
441
  try {
@@ -453,14 +455,6 @@ program
453
455
  if (run.failed > 0) {
454
456
  console.log(chalk.yellow(` ⚠ Copilot failed to update ${run.failed} context.md file(s)`));
455
457
  }
456
- // Persist updated file content/metadata to DB without overwriting Copilot edits.
457
- const contextPaths = allContextFiles.map((p) => p.replace(`${workspaceRoot}/`, ""));
458
- await runWorkflow("enrich_framework_context", {
459
- repo_path: workspaceRoot,
460
- context_paths: contextPaths,
461
- persist_only: true,
462
- });
463
- console.log(chalk.green(" ✓ Synced Copilot-enriched context metadata to DB"));
464
458
  }
465
459
  }
466
460
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "igel-qe-core",
3
- "version": "1.0.11",
3
+ "version": "1.0.14",
4
4
  "description": "IGEL QE Developer Experience Layer (CLI & MCP)",
5
5
  "type": "module",
6
6
  "publishConfig": {
package/src/cli/index.ts CHANGED
@@ -232,17 +232,29 @@ function listFrameworkContextFiles(workspaceRoot: string): string[] {
232
232
  }
233
233
 
234
234
  function isCopilotCliAvailable(): boolean {
235
- const check = spawnSync("copilot", ["--version"], { encoding: "utf-8", shell: process.platform === "win32" });
236
- return check.status === 0;
235
+ // Use a short timeout so this never blocks if copilot hangs on startup.
236
+ const check = spawnSync("copilot", ["--version"], {
237
+ encoding: "utf-8",
238
+ shell: process.platform === "win32",
239
+ timeout: 10_000,
240
+ });
241
+ return check.status === 0 && !check.error;
237
242
  }
238
243
 
239
244
  function isCopilotAuthenticated(workspaceRoot: string): boolean {
245
+ // A strict timeout prevents the init command from hanging forever when
246
+ // Copilot waits for interactive input or a network response.
240
247
  const probe = spawnSync(
241
248
  "copilot",
242
249
  ["-C", workspaceRoot, "-p", "Reply with exactly OK.", "--allow-all-tools", "--no-color", "-s"],
243
- { encoding: "utf-8", shell: process.platform === "win32" },
250
+ {
251
+ encoding: "utf-8",
252
+ shell: process.platform === "win32",
253
+ timeout: 30_000, // 30 s max — return false if Copilot doesn't answer
254
+ input: "", // close stdin immediately so it doesn't wait for user input
255
+ },
244
256
  );
245
- return probe.status === 0;
257
+ return probe.status === 0 && !probe.error;
246
258
  }
247
259
 
248
260
  function ensureCopilotLogin(workspaceRoot: string): boolean {
@@ -284,7 +296,12 @@ function enrichWithCopilotCli(workspaceRoot: string, contextFiles: string[]): {
284
296
  "--no-color",
285
297
  "-s",
286
298
  ],
287
- { encoding: "utf-8", shell: process.platform === "win32" },
299
+ {
300
+ encoding: "utf-8",
301
+ shell: process.platform === "win32",
302
+ timeout: 120_000, // 2 min per file — prevents indefinite hangs
303
+ input: "", // close stdin immediately
304
+ },
288
305
  );
289
306
 
290
307
  if (result.status === 0) {
@@ -418,7 +435,11 @@ program
418
435
  console.log(chalk.yellow(" ⚠ requirements file not found; skipping Python dependency install"));
419
436
  } else {
420
437
  try {
421
- execSync(`${getPythonBin(workspaceRoot)} -m pip install -q -r \"${reqPath}\"`, {
438
+ const pyBin = getPythonBin(workspaceRoot);
439
+ // Wrap both the python path and requirements path in quotes so
440
+ // Windows paths that contain spaces (e.g. "IGEL Automation July 2026")
441
+ // are treated as a single argument by the shell.
442
+ execSync(`"${pyBin}" -m pip install -q -r "${reqPath}"`, {
422
443
  cwd: workspaceRoot, stdio: "inherit",
423
444
  });
424
445
  console.log(chalk.green(" ✓ Dependencies installed"));
@@ -445,23 +466,6 @@ program
445
466
  console.log(chalk.green(" ✓ Framework context files already up to date"));
446
467
  }
447
468
 
448
- // Step 2c — enrich framework context files via AST/dependency graph + DB sync
449
- console.log(chalk.yellow("3c. Enriching framework context files (AST + dependency graph + DB sync)…"));
450
- try {
451
- const enrichResult = await runWorkflow("enrich_framework_context", {
452
- repo_path: workspaceRoot,
453
- }) as { enriched_count?: number; status?: string; message?: string };
454
-
455
- if (typeof enrichResult.enriched_count === "number") {
456
- console.log(chalk.green(` ✓ Enriched ${enrichResult.enriched_count} context.md file(s)`));
457
- } else if ((enrichResult as { raw?: string }).raw) {
458
- console.log(chalk.green(" ✓ Context enrichment completed"));
459
- } else {
460
- console.log(chalk.yellow(" ⚠ Context enrichment returned no summary; continuing"));
461
- }
462
- } catch (e: unknown) {
463
- console.log(chalk.yellow(` ⚠ Context enrichment skipped: ${e instanceof Error ? e.message : String(e)}`));
464
- }
465
469
 
466
470
  // Step 2d — Copilot CLI enrichment pass (asks login if needed), then DB sync.
467
471
  console.log(chalk.yellow("3d. Enriching context via GitHub Copilot CLI…"));
@@ -479,15 +483,6 @@ program
479
483
  if (run.failed > 0) {
480
484
  console.log(chalk.yellow(` ⚠ Copilot failed to update ${run.failed} context.md file(s)`));
481
485
  }
482
-
483
- // Persist updated file content/metadata to DB without overwriting Copilot edits.
484
- const contextPaths = allContextFiles.map((p) => p.replace(`${workspaceRoot}/`, ""));
485
- await runWorkflow("enrich_framework_context", {
486
- repo_path: workspaceRoot,
487
- context_paths: contextPaths,
488
- persist_only: true,
489
- });
490
- console.log(chalk.green(" ✓ Synced Copilot-enriched context metadata to DB"));
491
486
  }
492
487
  } catch (e: unknown) {
493
488
  console.log(chalk.yellow(` ⚠ Copilot context enrichment skipped: ${e instanceof Error ? e.message : String(e)}`));