@smartergpt/lexrunner 1.4.1 → 1.5.1

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.
@@ -2956,10 +2956,10 @@ function prompt(question) {
2956
2956
  input: process.stdin,
2957
2957
  output: process.stdout
2958
2958
  });
2959
- return new Promise((resolve5) => {
2959
+ return new Promise((resolve6) => {
2960
2960
  rl.question(question, (answer) => {
2961
2961
  rl.close();
2962
- resolve5(answer.trim());
2962
+ resolve6(answer.trim());
2963
2963
  });
2964
2964
  });
2965
2965
  }
@@ -3160,7 +3160,7 @@ async function terminateProcessTree(child, options = {}) {
3160
3160
  return { method: "taskkill", forceKilled: true, descendantsReaped: reaped };
3161
3161
  }
3162
3162
  const killGroup = options.killGroup ?? process.kill.bind(process);
3163
- const wait = options.wait ?? ((durationMs) => new Promise((resolve5) => setTimeout(resolve5, durationMs)));
3163
+ const wait = options.wait ?? ((durationMs) => new Promise((resolve6) => setTimeout(resolve6, durationMs)));
3164
3164
  const graceMs = options.graceMs ?? 500;
3165
3165
  let method = "process-group";
3166
3166
  try {
@@ -3193,17 +3193,178 @@ function groupExists(pid, killGroup) {
3193
3193
  }
3194
3194
  }
3195
3195
  function runTaskkill(pid) {
3196
- return new Promise((resolve5) => {
3196
+ return new Promise((resolve6) => {
3197
3197
  const killer = spawn("taskkill", ["/PID", String(pid), "/T", "/F"], {
3198
3198
  stdio: "ignore",
3199
3199
  windowsHide: true
3200
3200
  });
3201
- killer.once("error", () => resolve5(false));
3202
- killer.once("close", (code) => resolve5(code === 0 || code === 128));
3201
+ killer.once("error", () => resolve6(false));
3202
+ killer.once("close", (code) => resolve6(code === 0 || code === 128));
3203
3203
  });
3204
3204
  }
3205
3205
 
3206
+ // src/gates/execution-receipt.ts
3207
+ import { randomUUID } from "crypto";
3208
+ import {
3209
+ copyFileSync as copyFileSync2,
3210
+ existsSync as existsSync9,
3211
+ mkdirSync as mkdirSync5,
3212
+ readFileSync as readFileSync10,
3213
+ realpathSync,
3214
+ renameSync as renameSync2,
3215
+ statSync as statSync2,
3216
+ writeFileSync as writeFileSync5
3217
+ } from "fs";
3218
+ import { basename as basename2, delimiter, dirname, extname, isAbsolute as isAbsolute2, join as join9, resolve as resolve5 } from "path";
3219
+ var GATE_EXECUTION_RECEIPT_SCHEMA_VERSION = "lexrunner-gate-execution-receipt/v1";
3220
+ var MAX_GATE_RECEIPT_OUTPUT_BYTES = 64 * 1024;
3221
+ function resolveSpawnExecutable(command, environment, workingDirectory, platform2 = process.platform) {
3222
+ if (isAbsolute2(command) || /[\\/]/u.test(command)) {
3223
+ return requireExecutable(resolve5(workingDirectory, command));
3224
+ }
3225
+ const pathValue = environmentValue(environment, "PATH", platform2) ?? "";
3226
+ const extensions = platform2 === "win32" ? executableExtensions(command, environmentValue(environment, "PATHEXT", platform2)) : [""];
3227
+ for (const directory of pathValue.split(delimiter).filter(Boolean)) {
3228
+ for (const extension of extensions) {
3229
+ const candidate = resolve5(directory, `${command}${extension}`);
3230
+ if (isExecutableFile(candidate)) return realpathSync(candidate);
3231
+ }
3232
+ }
3233
+ throw new Error(`Unable to resolve local gate shell executable '${command}'.`);
3234
+ }
3235
+ function fileIdentity(filePath) {
3236
+ try {
3237
+ const stats = statSync2(filePath);
3238
+ if (!stats.isFile()) return null;
3239
+ const realPath = realpathSync(filePath);
3240
+ const content = readFileSync10(realPath);
3241
+ return {
3242
+ path: resolve5(filePath),
3243
+ realPath,
3244
+ bytes: content.byteLength,
3245
+ mtimeMs: stats.mtimeMs,
3246
+ sha256: `sha256:${sha256(content)}`
3247
+ };
3248
+ } catch {
3249
+ return null;
3250
+ }
3251
+ }
3252
+ function captureDeclaredArtifactBaselines(declaredPaths, workingDirectory) {
3253
+ return declaredPaths.map((declaredPath) => {
3254
+ const resolvedPath = resolve5(workingDirectory, declaredPath);
3255
+ return { declaredPath, resolvedPath, before: fileIdentity(resolvedPath) };
3256
+ });
3257
+ }
3258
+ function collectFreshGateArtifacts(baselines, gateArtifactDirectory) {
3259
+ mkdirSync5(gateArtifactDirectory, { recursive: true });
3260
+ const paths = [];
3261
+ const usedNames = /* @__PURE__ */ new Set();
3262
+ const identities = baselines.map((baseline, index) => {
3263
+ const source = fileIdentity(baseline.resolvedPath);
3264
+ if (!existsSync9(baseline.resolvedPath)) {
3265
+ return { ...baseline, status: "missing", source: null };
3266
+ }
3267
+ if (!source) {
3268
+ return { ...baseline, status: "unsupported", source: null };
3269
+ }
3270
+ if (baseline.before?.sha256 === source.sha256) {
3271
+ return { ...baseline, status: "stale", source };
3272
+ }
3273
+ let retainedName = basename2(baseline.resolvedPath);
3274
+ if (usedNames.has(retainedName)) retainedName = `${index + 1}-${retainedName}`;
3275
+ usedNames.add(retainedName);
3276
+ const retainedPath = join9(gateArtifactDirectory, retainedName);
3277
+ try {
3278
+ copyFileSync2(baseline.resolvedPath, retainedPath);
3279
+ const retained = fileIdentity(retainedPath);
3280
+ if (!retained || retained.sha256 !== source.sha256 || retained.bytes !== source.bytes) {
3281
+ return {
3282
+ ...baseline,
3283
+ status: "collection_error",
3284
+ source,
3285
+ retainedPath,
3286
+ error: "Retained artifact identity does not match its source."
3287
+ };
3288
+ }
3289
+ paths.push(retainedPath);
3290
+ return { ...baseline, status: "collected", source, retainedPath, retained };
3291
+ } catch (error) {
3292
+ return {
3293
+ ...baseline,
3294
+ status: "collection_error",
3295
+ source,
3296
+ retainedPath,
3297
+ error: boundedError(error)
3298
+ };
3299
+ }
3300
+ });
3301
+ return {
3302
+ paths,
3303
+ identities,
3304
+ complete: identities.every(({ status }) => status === "collected")
3305
+ };
3306
+ }
3307
+ function gateOutputEvidence(value) {
3308
+ const bytes = Buffer.isBuffer(value) ? value : Buffer.from(value, "utf8");
3309
+ return {
3310
+ bytes: bytes.byteLength,
3311
+ sha256: `sha256:${sha256(bytes)}`,
3312
+ truncated: bytes.byteLength > MAX_GATE_RECEIPT_OUTPUT_BYTES,
3313
+ content: utf8Prefix(bytes, MAX_GATE_RECEIPT_OUTPUT_BYTES)
3314
+ };
3315
+ }
3316
+ function writeLocalGateExecutionReceipt(artifactDirectory, receipt) {
3317
+ mkdirSync5(artifactDirectory, { recursive: true });
3318
+ const receiptPath = join9(
3319
+ artifactDirectory,
3320
+ `gate-execution-receipt.attempt-${receipt.attempt}.json`
3321
+ );
3322
+ const temporaryPath = join9(
3323
+ dirname(receiptPath),
3324
+ `.${basename2(receiptPath)}.${process.pid}.${randomUUID()}.tmp`
3325
+ );
3326
+ writeFileSync5(temporaryPath, canonicalJSONStringify(receipt), "utf8");
3327
+ renameSync2(temporaryPath, receiptPath);
3328
+ return receiptPath;
3329
+ }
3330
+ function requireExecutable(candidate) {
3331
+ if (!isExecutableFile(candidate)) {
3332
+ throw new Error(`Local gate shell executable does not exist at '${candidate}'.`);
3333
+ }
3334
+ return realpathSync(candidate);
3335
+ }
3336
+ function isExecutableFile(candidate) {
3337
+ try {
3338
+ return statSync2(candidate).isFile();
3339
+ } catch {
3340
+ return false;
3341
+ }
3342
+ }
3343
+ function environmentValue(environment, name, platform2) {
3344
+ if (platform2 !== "win32") return environment[name];
3345
+ const match = Object.keys(environment).find((key) => key.toUpperCase() === name);
3346
+ return match ? environment[match] : void 0;
3347
+ }
3348
+ function executableExtensions(command, pathExt) {
3349
+ if (extname(command)) return [""];
3350
+ return (pathExt || ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean).map((extension) => extension.toLowerCase());
3351
+ }
3352
+ function utf8Prefix(value, maxBytes) {
3353
+ if (value.byteLength <= maxBytes) return value.toString("utf8");
3354
+ return value.subarray(0, maxBytes).toString("utf8");
3355
+ }
3356
+ function boundedError(error) {
3357
+ const value = error instanceof Error ? error.message : String(error);
3358
+ return value.length <= 1024 ? value : `${value.slice(0, 1024)}\u2026`;
3359
+ }
3360
+
3206
3361
  // src/gates.ts
3362
+ function resolveLocalGateShell(command, platform2 = process.platform) {
3363
+ return platform2 === "win32" ? {
3364
+ command: "pwsh",
3365
+ arguments: ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", command]
3366
+ } : { command: "bash", arguments: ["-c", command] };
3367
+ }
3207
3368
  async function executeGate(gate, policy, artifactDir, timeoutMs = 3e4, itemName, skipValidation = false, repoRoot, turnCostTracker, suppressStdout = false) {
3208
3369
  if (!skipValidation && gate.input) {
3209
3370
  try {
@@ -3234,7 +3395,7 @@ async function executeGate(gate, policy, artifactDir, timeoutMs = 3e4, itemName,
3234
3395
  `\u23F3 Retrying gate '${gate.name}' (attempt ${attempt}/${retryConfig.maxAttempts}) after ${retryConfig.backoffSeconds}s delay...`
3235
3396
  );
3236
3397
  }
3237
- await new Promise((resolve5) => setTimeout(resolve5, delayMs));
3398
+ await new Promise((resolve6) => setTimeout(resolve6, delayMs));
3238
3399
  }
3239
3400
  const result = await executeGateAttempt(gate, artifactDir, attempt, timeoutMs, repoRoot);
3240
3401
  lastResult = result;
@@ -3375,6 +3536,55 @@ async function executeGateAttempt(gate, artifactDir, attempt, timeoutMs, repoRoo
3375
3536
  }
3376
3537
  }
3377
3538
  async function executeLocalGate(gate, artifactDir, attempt, startedAt, startTime, timeoutMs, repoRoot) {
3539
+ const workingDirectory = path9.resolve(gate.cwd || repoRoot || process.cwd());
3540
+ const gateArtifactDirectory = path9.join(artifactDir, gate.name);
3541
+ const environment = { ...process.env, ...gate.env };
3542
+ const shell = resolveLocalGateShell(gate.run);
3543
+ const artifactBaselines = captureDeclaredArtifactBaselines(
3544
+ gate.artifacts ?? [],
3545
+ workingDirectory
3546
+ );
3547
+ let shellExecutable;
3548
+ let shellIdentityBefore = null;
3549
+ try {
3550
+ shellExecutable = resolveSpawnExecutable(
3551
+ shell.command,
3552
+ environment,
3553
+ workingDirectory,
3554
+ process.platform
3555
+ );
3556
+ shellIdentityBefore = fileIdentity(shellExecutable);
3557
+ if (!shellIdentityBefore) throw new Error("Resolved shell is not an evidence-bindable file.");
3558
+ } catch (error) {
3559
+ const errorMessage = error instanceof Error ? error.message : String(error);
3560
+ return finalizeLocalGateAttempt({
3561
+ gate,
3562
+ artifactBaselines,
3563
+ gateArtifactDirectory,
3564
+ workingDirectory,
3565
+ attempt,
3566
+ startedAt,
3567
+ startTime,
3568
+ shell,
3569
+ shellExecutable: null,
3570
+ shellIdentityBefore: null,
3571
+ spawned: false,
3572
+ stdout: Buffer.alloc(0),
3573
+ stderr: Buffer.from(errorMessage, "utf8"),
3574
+ result: {
3575
+ gate: gate.name,
3576
+ status: "fail",
3577
+ exitCode: 1,
3578
+ duration: Date.now() - startTime,
3579
+ stdout: "",
3580
+ stderr: errorMessage,
3581
+ failureKind: "spawn_error",
3582
+ artifacts: [],
3583
+ attempts: attempt,
3584
+ lastAttempt: startedAt
3585
+ }
3586
+ });
3587
+ }
3378
3588
  try {
3379
3589
  const { getCommandValidator } = await import("./commandValidator-LVEMJTZP.js");
3380
3590
  const validator = getCommandValidator();
@@ -3382,34 +3592,50 @@ async function executeLocalGate(gate, artifactDir, attempt, startedAt, startTime
3382
3592
  } catch (validationError) {
3383
3593
  const duration = Date.now() - startTime;
3384
3594
  const errorMessage = validationError instanceof Error ? validationError.message : String(validationError);
3385
- return {
3386
- gate: gate.name,
3387
- status: "fail",
3388
- exitCode: 1,
3389
- duration,
3390
- stdout: "",
3391
- stderr: `Command validation failed: ${errorMessage}`,
3392
- artifacts: [],
3393
- attempts: attempt,
3394
- lastAttempt: startedAt
3395
- };
3595
+ return finalizeLocalGateAttempt({
3596
+ gate,
3597
+ artifactBaselines,
3598
+ gateArtifactDirectory,
3599
+ workingDirectory,
3600
+ attempt,
3601
+ startedAt,
3602
+ startTime,
3603
+ shell,
3604
+ shellExecutable,
3605
+ shellIdentityBefore,
3606
+ spawned: false,
3607
+ stdout: Buffer.alloc(0),
3608
+ stderr: Buffer.from(`Command validation failed: ${errorMessage}`, "utf8"),
3609
+ result: {
3610
+ gate: gate.name,
3611
+ status: "fail",
3612
+ exitCode: 1,
3613
+ duration,
3614
+ stdout: "",
3615
+ stderr: `Command validation failed: ${errorMessage}`,
3616
+ artifacts: [],
3617
+ attempts: attempt,
3618
+ lastAttempt: startedAt
3619
+ }
3620
+ });
3396
3621
  }
3397
- return new Promise((resolve5) => {
3622
+ return new Promise((resolve6) => {
3398
3623
  let timedOut = false;
3399
- const workingDirectory = gate.cwd || repoRoot || process.cwd();
3400
- const childProcess = spawn2("bash", ["-c", gate.run], {
3624
+ let settled = false;
3625
+ const childProcess = spawn2(shellExecutable, shell.arguments, {
3401
3626
  cwd: workingDirectory,
3402
- env: { ...process.env, ...gate.env },
3627
+ env: environment,
3403
3628
  stdio: ["pipe", "pipe", "pipe"],
3404
- detached: process.platform !== "win32"
3629
+ detached: process.platform !== "win32",
3630
+ windowsHide: true
3405
3631
  });
3406
- let stdout = "";
3407
- let stderr = "";
3632
+ const stdoutChunks = [];
3633
+ const stderrChunks = [];
3408
3634
  childProcess.stdout?.on("data", (data) => {
3409
- stdout += data.toString();
3635
+ stdoutChunks.push(Buffer.isBuffer(data) ? data : Buffer.from(data));
3410
3636
  });
3411
3637
  childProcess.stderr?.on("data", (data) => {
3412
- stderr += data.toString();
3638
+ stderrChunks.push(Buffer.isBuffer(data) ? data : Buffer.from(data));
3413
3639
  });
3414
3640
  let timeoutCleanup;
3415
3641
  const timeout = setTimeout(() => {
@@ -3417,44 +3643,146 @@ async function executeLocalGate(gate, artifactDir, attempt, startedAt, startTime
3417
3643
  timeoutCleanup = terminateProcessTree(childProcess);
3418
3644
  }, timeoutMs);
3419
3645
  childProcess.on("close", async (exitCode) => {
3646
+ if (settled) return;
3647
+ settled = true;
3420
3648
  clearTimeout(timeout);
3421
3649
  const cleanup = timeoutCleanup ? await timeoutCleanup : void 0;
3422
3650
  const duration = Date.now() - startTime;
3423
- const artifacts = collectArtifacts(gate, artifactDir);
3424
- resolve5({
3425
- gate: gate.name,
3426
- status: exitCode === 0 && !timedOut ? "pass" : "fail",
3427
- exitCode: timedOut ? 124 : exitCode ?? 1,
3428
- duration,
3429
- stdout: stdout.trim(),
3430
- stderr: timedOut ? `GATE_TIMEOUT: exceeded ${timeoutMs}ms; descendantsReaped=${cleanup?.descendantsReaped ?? false}` : stderr.trim(),
3431
- failureKind: timedOut ? "timeout" : exitCode === 0 ? void 0 : "nonzero_exit",
3432
- ...cleanup ? { timeoutCleanup: cleanup } : {},
3433
- artifacts,
3434
- attempts: attempt,
3435
- lastAttempt: startedAt
3436
- });
3651
+ const stdout = Buffer.concat(stdoutChunks);
3652
+ const stderr = Buffer.concat(stderrChunks);
3653
+ const stdoutText = stdout.toString("utf8");
3654
+ const stderrText = stderr.toString("utf8");
3655
+ const projectedStderr = timedOut ? `GATE_TIMEOUT: exceeded ${timeoutMs}ms; descendantsReaped=${cleanup?.descendantsReaped ?? false}` : stderrText.trim();
3656
+ resolve6(
3657
+ finalizeLocalGateAttempt({
3658
+ gate,
3659
+ artifactBaselines,
3660
+ gateArtifactDirectory,
3661
+ workingDirectory,
3662
+ attempt,
3663
+ startedAt,
3664
+ startTime,
3665
+ shell,
3666
+ shellExecutable,
3667
+ shellIdentityBefore,
3668
+ spawned: true,
3669
+ stdout,
3670
+ stderr,
3671
+ result: {
3672
+ gate: gate.name,
3673
+ status: exitCode === 0 && !timedOut ? "pass" : "fail",
3674
+ exitCode: timedOut ? 124 : exitCode ?? 1,
3675
+ duration,
3676
+ stdout: stdoutText.trim(),
3677
+ stderr: projectedStderr,
3678
+ failureKind: timedOut ? "timeout" : exitCode === 0 ? void 0 : "nonzero_exit",
3679
+ ...cleanup ? { timeoutCleanup: cleanup } : {},
3680
+ artifacts: [],
3681
+ attempts: attempt,
3682
+ lastAttempt: startedAt
3683
+ }
3684
+ })
3685
+ );
3437
3686
  });
3438
3687
  childProcess.on("error", (error) => {
3688
+ if (settled) return;
3689
+ settled = true;
3439
3690
  clearTimeout(timeout);
3440
3691
  const duration = Date.now() - startTime;
3692
+ const stdout = Buffer.concat(stdoutChunks);
3441
3693
  const classified = classifyError(error, `Gate '${gate.name}' process error`);
3442
3694
  console.error(formatErrorForUser(classified));
3443
- resolve5({
3444
- gate: gate.name,
3445
- status: "fail",
3446
- exitCode: 1,
3447
- duration,
3448
- stdout: stdout.trim(),
3449
- stderr: `${classified.context}: ${error.message}`,
3450
- failureKind: "spawn_error",
3451
- artifacts: [],
3452
- attempts: attempt,
3453
- lastAttempt: startedAt
3454
- });
3695
+ const projectedStderr = `${classified.context}: ${error.message}`;
3696
+ resolve6(
3697
+ finalizeLocalGateAttempt({
3698
+ gate,
3699
+ artifactBaselines,
3700
+ gateArtifactDirectory,
3701
+ workingDirectory,
3702
+ attempt,
3703
+ startedAt,
3704
+ startTime,
3705
+ shell,
3706
+ shellExecutable,
3707
+ shellIdentityBefore,
3708
+ spawned: false,
3709
+ stdout,
3710
+ stderr: Buffer.from(projectedStderr, "utf8"),
3711
+ result: {
3712
+ gate: gate.name,
3713
+ status: "fail",
3714
+ exitCode: 1,
3715
+ duration,
3716
+ stdout: stdout.toString("utf8").trim(),
3717
+ stderr: projectedStderr,
3718
+ failureKind: "spawn_error",
3719
+ artifacts: [],
3720
+ attempts: attempt,
3721
+ lastAttempt: startedAt
3722
+ }
3723
+ })
3724
+ );
3455
3725
  });
3456
3726
  });
3457
3727
  }
3728
+ function finalizeLocalGateAttempt(input) {
3729
+ const collected = collectFreshGateArtifacts(input.artifactBaselines, input.gateArtifactDirectory);
3730
+ const shellIdentityAfter = input.shellExecutable ? fileIdentity(input.shellExecutable) : null;
3731
+ const shellUnchanged = input.shellIdentityBefore !== null && shellIdentityAfter !== null && input.shellIdentityBefore.sha256 === shellIdentityAfter.sha256 && input.shellIdentityBefore.bytes === shellIdentityAfter.bytes;
3732
+ const evidenceComplete = collected.complete && (!input.spawned || input.shellIdentityBefore !== null && shellUnchanged);
3733
+ const result = { ...input.result };
3734
+ if (result.status === "pass" && !evidenceComplete) {
3735
+ result.status = "fail";
3736
+ result.exitCode = 1;
3737
+ result.failureKind = "evidence_error";
3738
+ result.stderr = [
3739
+ result.stderr,
3740
+ "GATE_EVIDENCE_INVALID: declared output or shell identity failed"
3741
+ ].filter(Boolean).join("\n");
3742
+ }
3743
+ const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
3744
+ const duration = Date.now() - input.startTime;
3745
+ result.duration = duration;
3746
+ const receiptPath = writeLocalGateExecutionReceipt(input.gateArtifactDirectory, {
3747
+ schemaVersion: GATE_EXECUTION_RECEIPT_SCHEMA_VERSION,
3748
+ attempt: input.attempt,
3749
+ declaredGate: {
3750
+ name: input.gate.name,
3751
+ run: input.gate.run,
3752
+ cwd: input.gate.cwd ?? null,
3753
+ runtime: input.gate.runtime,
3754
+ artifacts: [...input.gate.artifacts ?? []]
3755
+ },
3756
+ execution: {
3757
+ cwd: input.workingDirectory,
3758
+ startedAt: input.startedAt,
3759
+ finishedAt,
3760
+ durationMs: duration,
3761
+ shell: {
3762
+ command: input.shell.command,
3763
+ executable: input.shellIdentityBefore,
3764
+ argv: [...input.shell.arguments],
3765
+ identityAfter: shellIdentityAfter,
3766
+ unchanged: shellUnchanged,
3767
+ spawned: input.spawned
3768
+ }
3769
+ },
3770
+ outcome: {
3771
+ status: result.status,
3772
+ exitCode: result.exitCode ?? null,
3773
+ failureKind: result.failureKind ?? null,
3774
+ timeoutCleanup: result.timeoutCleanup ?? null,
3775
+ evidenceComplete
3776
+ },
3777
+ output: {
3778
+ stdout: gateOutputEvidence(input.stdout),
3779
+ stderr: gateOutputEvidence(input.stderr)
3780
+ },
3781
+ artifacts: collected.identities
3782
+ });
3783
+ result.artifacts = [...collected.paths, receiptPath];
3784
+ return result;
3785
+ }
3458
3786
  async function executeContainerGate(gate, artifactDir, attempt, startedAt, startTime, timeoutMs, repoRoot) {
3459
3787
  console.warn(
3460
3788
  `\u26A0\uFE0F Container runtime for gate '${gate.name}' not yet implemented, falling back to local execution`
@@ -3476,28 +3804,6 @@ async function executeCiServiceGate(gate, artifactDir, attempt, startedAt, start
3476
3804
  lastAttempt: startedAt
3477
3805
  };
3478
3806
  }
3479
- function collectArtifacts(gate, artifactDir) {
3480
- if (!gate.artifacts || gate.artifacts.length === 0) {
3481
- return [];
3482
- }
3483
- const collected = [];
3484
- const gateArtifactDir = path9.join(artifactDir, gate.name);
3485
- if (!fs9.existsSync(gateArtifactDir)) {
3486
- fs9.mkdirSync(gateArtifactDir, { recursive: true });
3487
- }
3488
- for (const artifactPath of gate.artifacts) {
3489
- try {
3490
- if (fs9.existsSync(artifactPath)) {
3491
- const destPath = path9.join(gateArtifactDir, path9.basename(artifactPath));
3492
- fs9.copyFileSync(artifactPath, destPath);
3493
- collected.push(destPath);
3494
- }
3495
- } catch (error) {
3496
- console.warn(`Failed to collect artifact ${artifactPath}:`, error);
3497
- }
3498
- }
3499
- return collected;
3500
- }
3501
3807
  function checkVulnGate(artifactDir, policy) {
3502
3808
  const startTime = Date.now();
3503
3809
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -3823,13 +4129,13 @@ async function executeGatesWithPolicy(plan, executionState, artifactDir, timeout
3823
4129
  if (promises.length > 0) {
3824
4130
  await Promise.race(promises);
3825
4131
  } else if (executing.size > 0) {
3826
- await new Promise((resolve5) => setTimeout(resolve5, 50));
4132
+ await new Promise((resolve6) => setTimeout(resolve6, 50));
3827
4133
  } else {
3828
4134
  break;
3829
4135
  }
3830
4136
  }
3831
4137
  while (executing.size > 0) {
3832
- await new Promise((resolve5) => setTimeout(resolve5, 50));
4138
+ await new Promise((resolve6) => setTimeout(resolve6, 50));
3833
4139
  }
3834
4140
  }
3835
4141
  function buildExecutionOrder(plan) {
@@ -4642,8 +4948,8 @@ var FileAnalyzer = class {
4642
4948
  * Extract module name from test file
4643
4949
  */
4644
4950
  getTestedModule(testFilename) {
4645
- const basename2 = testFilename.split("/").pop() || "";
4646
- return basename2.replace(/\.(test|spec)\.(ts|js|tsx|jsx)$/, "");
4951
+ const basename3 = testFilename.split("/").pop() || "";
4952
+ return basename3.replace(/\.(test|spec)\.(ts|js|tsx|jsx)$/, "");
4647
4953
  }
4648
4954
  /**
4649
4955
  * Perform complete file analysis on a set of PRs