autoremediator 0.1.2 → 0.2.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.
@@ -80,7 +80,7 @@ function getPackageManagerCommands(pm) {
80
80
  installPreferOffline: ["pnpm", "install", "--prefer-offline"],
81
81
  installDev: (pkg) => ["pnpm", "add", "-D", pkg],
82
82
  test: ["pnpm", "test"],
83
- list: ["pnpm", "list", "--json", "--depth=0"],
83
+ list: ["pnpm", "list", "--json", "--depth", "99"],
84
84
  lockfileName: "pnpm-lock.yaml"
85
85
  };
86
86
  }
@@ -90,7 +90,7 @@ function getPackageManagerCommands(pm) {
90
90
  installPreferOffline: ["yarn", "install"],
91
91
  installDev: (pkg) => ["yarn", "add", "--dev", pkg],
92
92
  test: ["yarn", "test"],
93
- list: ["yarn", "list", "--json", "--depth=0"],
93
+ list: ["yarn", "list", "--json"],
94
94
  lockfileName: "yarn.lock"
95
95
  };
96
96
  }
@@ -99,7 +99,7 @@ function getPackageManagerCommands(pm) {
99
99
  installPreferOffline: ["npm", "install", "--prefer-offline"],
100
100
  installDev: (pkg) => ["npm", "install", "--save-dev", pkg],
101
101
  test: ["npm", "test"],
102
- list: ["npm", "list", "--json", "--depth=0"],
102
+ list: ["npm", "list", "--json", "--all"],
103
103
  lockfileName: "package-lock.json"
104
104
  };
105
105
  }
@@ -134,13 +134,18 @@ function parseListOutput(pm, stdout) {
134
134
  return versions;
135
135
  }
136
136
  const root = Array.isArray(parsed) ? parsed[0] : parsed;
137
- const dependencies = root?.dependencies;
138
- for (const [name, entry] of Object.entries(dependencies ?? {})) {
139
- const version = entry?.version;
140
- if (typeof version === "string" && version) {
141
- versions.set(name, version);
137
+ function collectDependencies(tree) {
138
+ if (!tree) return;
139
+ for (const [name, entry] of Object.entries(tree)) {
140
+ if (!entry || typeof entry !== "object") continue;
141
+ const version = entry.version;
142
+ if (typeof version === "string" && version) {
143
+ versions.set(name, version);
144
+ }
145
+ collectDependencies(entry.dependencies);
142
146
  }
143
147
  }
148
+ collectDependencies(root?.dependencies);
144
149
  return versions;
145
150
  }
146
151
 
@@ -506,11 +511,18 @@ async function fetchPackageVersions(packageName) {
506
511
  const data = await res.json();
507
512
  return Object.keys(data.versions);
508
513
  }
509
- async function findSafeUpgradeVersion(packageName, installedVersion, firstPatchedVersion) {
514
+ async function findSafeUpgradeVersion(packageName, installedVersion, firstPatchedVersion, vulnerableRange) {
510
515
  const versions = await fetchPackageVersions(packageName);
511
516
  if (!versions.length) return void 0;
512
517
  const installedMajor = semver2.major(installedVersion);
513
- const candidates = versions.filter((v) => semver2.valid(v) && semver2.gte(v, firstPatchedVersion)).sort(semver2.compare);
518
+ const candidates = versions.filter((v) => semver2.valid(v) && semver2.gte(v, firstPatchedVersion)).filter((v) => {
519
+ if (!vulnerableRange) return true;
520
+ try {
521
+ return !semver2.satisfies(v, vulnerableRange, { includePrerelease: false });
522
+ } catch {
523
+ return true;
524
+ }
525
+ }).sort(semver2.compare);
514
526
  if (!candidates.length) return void 0;
515
527
  const sameMajor = candidates.find(
516
528
  (v) => semver2.major(v) === installedMajor
@@ -527,17 +539,20 @@ var findFixedVersionTool = tool4({
527
539
  installedVersion: z4.string().describe("The currently installed version (exact semver)"),
528
540
  firstPatchedVersion: z4.string().describe(
529
541
  "The first version that is NOT vulnerable (from lookup-cve). Use this as the floor."
530
- )
542
+ ),
543
+ vulnerableRange: z4.string().optional().describe("Optional vulnerable semver range used to exclude still-vulnerable versions")
531
544
  }),
532
545
  execute: async ({
533
546
  packageName,
534
547
  installedVersion,
535
- firstPatchedVersion
548
+ firstPatchedVersion,
549
+ vulnerableRange
536
550
  }) => {
537
551
  const safeVersion = await findSafeUpgradeVersion(
538
552
  packageName,
539
553
  installedVersion,
540
- firstPatchedVersion
554
+ firstPatchedVersion,
555
+ vulnerableRange
541
556
  );
542
557
  if (!safeVersion) {
543
558
  return {
@@ -570,8 +585,7 @@ import { join as join3 } from "path";
570
585
  var DEFAULT_POLICY = {
571
586
  allowMajorBumps: false,
572
587
  denyPackages: [],
573
- allowPackages: [],
574
- autoApply: true
588
+ allowPackages: []
575
589
  };
576
590
  function loadPolicy(cwd, explicitPath) {
577
591
  const candidate = explicitPath ?? join3(cwd, ".autoremediator.json");
@@ -581,8 +595,7 @@ function loadPolicy(cwd, explicitPath) {
581
595
  return {
582
596
  allowMajorBumps: parsed.allowMajorBumps ?? DEFAULT_POLICY.allowMajorBumps,
583
597
  denyPackages: parsed.denyPackages ?? DEFAULT_POLICY.denyPackages,
584
- allowPackages: parsed.allowPackages ?? DEFAULT_POLICY.allowPackages,
585
- autoApply: parsed.autoApply ?? DEFAULT_POLICY.autoApply
598
+ allowPackages: parsed.allowPackages ?? DEFAULT_POLICY.allowPackages
586
599
  };
587
600
  } catch {
588
601
  return DEFAULT_POLICY;
@@ -756,7 +769,7 @@ var applyVersionBumpTool = tool5({
756
769
  // src/remediation/tools/fetch-package-source.ts
757
770
  import { tool as tool6 } from "ai";
758
771
  import { z as z6 } from "zod";
759
- import { mkdir, readdir, readFile } from "fs/promises";
772
+ import { mkdir, readdir, readFile, rm } from "fs/promises";
760
773
  import { join as join5 } from "path";
761
774
  import { execa as execa3 } from "execa";
762
775
  var fetchPackageSourceTool = tool6({
@@ -831,7 +844,7 @@ var fetchPackageSourceTool = tool6({
831
844
  }
832
845
  return {
833
846
  success: true,
834
- sourceCode,
847
+ sourceFiles: sourceCode,
835
848
  packageDir: packageRootDir
836
849
  };
837
850
  } catch (err) {
@@ -846,6 +859,8 @@ var fetchPackageSourceTool = tool6({
846
859
  success: false,
847
860
  error: `Failed to fetch and extract package ${packageName}@${version}: ${message}`
848
861
  };
862
+ } finally {
863
+ await rm(tempBaseDir, { recursive: true, force: true });
849
864
  }
850
865
  }
851
866
  });
@@ -883,9 +898,19 @@ var generatePatchTool = tool7({
883
898
  dryRun
884
899
  }) => {
885
900
  try {
901
+ const resolvedSourceFiles = sourceFiles;
902
+ if (Object.keys(resolvedSourceFiles).length === 0) {
903
+ return {
904
+ success: false,
905
+ llmModel: "unknown",
906
+ confidence: 0,
907
+ riskLevel: "high",
908
+ error: "No source files were provided. Call fetch-package-source first and pass sourceFiles."
909
+ };
910
+ }
886
911
  const model = await createModel();
887
912
  const modelName = model.modelId || "unknown-model";
888
- const sourceContext = Object.entries(sourceFiles).map(([filePath, content]) => `
913
+ const sourceContext = Object.entries(resolvedSourceFiles).map(([filePath, content]) => `
889
914
  ### File: ${filePath}
890
915
  \`\`\`typescript
891
916
  ${content}
@@ -974,12 +999,12 @@ Important:
974
999
  for (const [filePath, fixedCode] of Object.entries(
975
1000
  analysis.fixedCode
976
1001
  )) {
977
- const originalCode = sourceFiles[filePath];
978
- if (!originalCode) {
1002
+ const sourceFile = resolvedSourceFiles[filePath];
1003
+ if (!sourceFile) {
979
1004
  continue;
980
1005
  }
981
1006
  const unifiedDiff = generateUnifiedDiff(
982
- originalCode,
1007
+ sourceFile,
983
1008
  fixedCode,
984
1009
  filePath
985
1010
  );
@@ -1002,6 +1027,7 @@ Important:
1002
1027
  return {
1003
1028
  success: true,
1004
1029
  patches,
1030
+ patchContent: patches[0]?.unifiedDiff,
1005
1031
  llmModel: modelName,
1006
1032
  confidence: analysis.confidence,
1007
1033
  riskLevel: analysis.riskLevel
@@ -1050,7 +1076,7 @@ function generateUnifiedDiff(original, fixed, filePath) {
1050
1076
  import { tool as tool8 } from "ai";
1051
1077
  import { z as z8 } from "zod";
1052
1078
  import { existsSync as existsSync3 } from "fs";
1053
- import { mkdir as mkdir2, mkdtemp, readFile as readFile2, rm, writeFile } from "fs/promises";
1079
+ import { mkdir as mkdir2, mkdtemp, readFile as readFile2, rm as rm2, writeFile } from "fs/promises";
1054
1080
  import { tmpdir } from "os";
1055
1081
  import { join as join6 } from "path";
1056
1082
  import { execa as execa4 } from "execa";
@@ -1059,40 +1085,81 @@ var applyPatchFileTool = tool8({
1059
1085
  parameters: z8.object({
1060
1086
  packageName: z8.string().min(1).describe("The npm package name"),
1061
1087
  vulnerableVersion: z8.string().describe("The vulnerable version string"),
1062
- patchContent: z8.string().min(10).describe("Unified diff patch content from generate-patch"),
1088
+ patchContent: z8.string().min(10).optional().describe("Unified diff patch content from generate-patch"),
1089
+ patches: z8.array(
1090
+ z8.object({
1091
+ filePath: z8.string().min(1),
1092
+ unifiedDiff: z8.string().min(10)
1093
+ })
1094
+ ).optional().describe("Patch list from generate-patch; first patch is applied"),
1063
1095
  patchesDir: z8.string().optional().default("./patches").describe("Directory to store patch files"),
1064
1096
  cwd: z8.string().describe("Project root directory (for package.json)"),
1065
1097
  packageManager: z8.enum(["npm", "pnpm", "yarn"]).optional().describe("Package manager used by the target project (auto-detected if omitted)"),
1066
- validateWithTests: z8.boolean().optional().default(true).describe("Run package manager test command to validate patch doesn't break anything")
1098
+ validateWithTests: z8.boolean().optional().default(true).describe("Run package manager test command to validate patch doesn't break anything"),
1099
+ dryRun: z8.boolean().optional().default(false).describe("If true, report but do not mutate files")
1100
+ }).refine((value) => Boolean(value.patchContent || value.patches && value.patches.length > 0), {
1101
+ message: "Either patchContent or patches must be provided"
1067
1102
  }),
1068
1103
  execute: async ({
1069
1104
  packageName,
1070
1105
  vulnerableVersion,
1071
1106
  patchContent,
1107
+ patches,
1072
1108
  patchesDir,
1073
1109
  cwd,
1074
1110
  packageManager,
1075
- validateWithTests
1111
+ validateWithTests,
1112
+ dryRun
1076
1113
  }) => {
1077
1114
  try {
1078
1115
  const pm = packageManager ?? detectPackageManager(cwd);
1116
+ const selectedPatch = patchContent ?? patches?.[0]?.unifiedDiff;
1117
+ if (!selectedPatch) {
1118
+ return {
1119
+ success: false,
1120
+ packageName,
1121
+ vulnerableVersion,
1122
+ applied: false,
1123
+ dryRun,
1124
+ message: "No patch content provided.",
1125
+ error: "No patch content provided."
1126
+ };
1127
+ }
1128
+ const patchFileName = buildPatchFileName(packageName, vulnerableVersion);
1129
+ const patchFilePath = join6(cwd, patchesDir, patchFileName);
1130
+ if (dryRun) {
1131
+ return {
1132
+ success: true,
1133
+ packageName,
1134
+ vulnerableVersion,
1135
+ applied: false,
1136
+ dryRun: true,
1137
+ message: `[DRY RUN] Would write and configure patch at ${patchFilePath}.`,
1138
+ patchFilePath,
1139
+ patchPath: patchFilePath
1140
+ };
1141
+ }
1079
1142
  const patchesDirPath = join6(cwd, patchesDir);
1080
1143
  await mkdir2(patchesDirPath, { recursive: true });
1081
- const patchFileName = `${packageName}+${vulnerableVersion}.patch`;
1082
- const patchFilePath = join6(patchesDirPath, patchFileName);
1083
- await writeFile(patchFilePath, patchContent, "utf8");
1144
+ await writeFile(patchFilePath, selectedPatch, "utf8");
1084
1145
  let validationResult;
1085
1146
  const patchMode = await resolvePatchMode(pm, cwd);
1086
- const applyResult = patchMode === "patch-package" ? await configurePatchPackagePostinstall(cwd) : await applyNativePatch({
1147
+ const applyResult = patchMode === "patch-package" ? await configurePatchPackagePostinstall(cwd, pm) : await applyNativePatch({
1087
1148
  cwd,
1088
1149
  packageName,
1089
1150
  vulnerableVersion,
1090
- patchContent,
1151
+ patchContent: selectedPatch,
1091
1152
  patchMode
1092
1153
  });
1093
1154
  if (!applyResult.success) {
1094
1155
  return {
1095
1156
  success: false,
1157
+ packageName,
1158
+ vulnerableVersion,
1159
+ applied: false,
1160
+ dryRun: false,
1161
+ message: applyResult.error,
1162
+ patchFilePath,
1096
1163
  patchPath: patchFilePath,
1097
1164
  patchMode,
1098
1165
  postinstallConfigured: patchMode === "patch-package" ? false : void 0,
@@ -1101,9 +1168,32 @@ var applyPatchFileTool = tool8({
1101
1168
  }
1102
1169
  if (validateWithTests) {
1103
1170
  validationResult = await validatePatchWithTests(cwd, pm);
1171
+ if (!validationResult.passed) {
1172
+ const validationError = "Patch validation failed after apply; patch marked unresolved.";
1173
+ return {
1174
+ success: false,
1175
+ packageName,
1176
+ vulnerableVersion,
1177
+ applied: false,
1178
+ dryRun: false,
1179
+ message: validationError,
1180
+ patchFilePath,
1181
+ patchPath: patchFilePath,
1182
+ patchMode,
1183
+ postinstallConfigured: patchMode === "patch-package",
1184
+ validation: validationResult,
1185
+ error: validationError
1186
+ };
1187
+ }
1104
1188
  }
1105
1189
  return {
1106
1190
  success: true,
1191
+ packageName,
1192
+ vulnerableVersion,
1193
+ applied: true,
1194
+ dryRun: false,
1195
+ message: `Patch applied successfully for ${packageName}@${vulnerableVersion}.`,
1196
+ patchFilePath,
1107
1197
  patchPath: patchFilePath,
1108
1198
  patchMode,
1109
1199
  postinstallConfigured: patchMode === "patch-package",
@@ -1113,6 +1203,11 @@ var applyPatchFileTool = tool8({
1113
1203
  const message = err instanceof Error ? err.message : String(err);
1114
1204
  return {
1115
1205
  success: false,
1206
+ packageName,
1207
+ vulnerableVersion,
1208
+ applied: false,
1209
+ dryRun,
1210
+ message: `Failed to apply patch file: ${message}`,
1116
1211
  error: `Failed to apply patch file: ${message}`
1117
1212
  };
1118
1213
  }
@@ -1133,7 +1228,11 @@ async function resolvePatchMode(packageManager, cwd) {
1133
1228
  return "patch-package";
1134
1229
  }
1135
1230
  }
1136
- async function configurePatchPackagePostinstall(cwd) {
1231
+ function buildPatchFileName(packageName, vulnerableVersion) {
1232
+ const safeName = packageName.replace(/^@/, "").replace(/\//g, "+");
1233
+ return `${safeName}+${vulnerableVersion}.patch`;
1234
+ }
1235
+ async function configurePatchPackagePostinstall(cwd, packageManager) {
1137
1236
  const pkgJsonPath = join6(cwd, "package.json");
1138
1237
  let pkgJson;
1139
1238
  try {
@@ -1144,6 +1243,22 @@ async function configurePatchPackagePostinstall(cwd) {
1144
1243
  error: `Could not read package.json at ${pkgJsonPath}`
1145
1244
  };
1146
1245
  }
1246
+ const devDependencies = pkgJson.devDependencies ?? {};
1247
+ if (!devDependencies["patch-package"]) {
1248
+ try {
1249
+ const commands = getPackageManagerCommands(packageManager);
1250
+ const [cmd, ...args] = commands.installDev("patch-package");
1251
+ await execa4(cmd, args, {
1252
+ cwd,
1253
+ stdio: "pipe"
1254
+ });
1255
+ } catch (err) {
1256
+ return {
1257
+ success: false,
1258
+ error: `Failed to install patch-package: ${err instanceof Error ? err.message : String(err)}`
1259
+ };
1260
+ }
1261
+ }
1147
1262
  if (!pkgJson.scripts) {
1148
1263
  pkgJson.scripts = {};
1149
1264
  }
@@ -1160,10 +1275,11 @@ async function configurePatchPackagePostinstall(cwd) {
1160
1275
  async function applyNativePatch(params) {
1161
1276
  const { cwd, packageName, vulnerableVersion, patchContent, patchMode } = params;
1162
1277
  const packageSpec = `${packageName}@${vulnerableVersion}`;
1163
- const createArgs = patchMode === "native-pnpm" ? ["pnpm", ["patch", packageSpec]] : ["yarn", ["patch", packageSpec]];
1278
+ const createCommand = patchMode === "native-pnpm" ? "pnpm" : "yarn";
1279
+ const createArgs = ["patch", packageSpec];
1164
1280
  let patchDir;
1165
1281
  try {
1166
- const createResult = await execa4(createArgs[0], createArgs[1], {
1282
+ const createResult = await execa4(createCommand, createArgs, {
1167
1283
  cwd,
1168
1284
  stdio: "pipe"
1169
1285
  });
@@ -1189,8 +1305,9 @@ ${createResult.stderr}`);
1189
1305
  cwd: patchDir,
1190
1306
  stdio: "pipe"
1191
1307
  });
1192
- const commitArgs = patchMode === "native-pnpm" ? ["pnpm", ["patch-commit", patchDir]] : ["yarn", ["patch-commit", "-s", patchDir]];
1193
- await execa4(commitArgs[0], commitArgs[1], {
1308
+ const commitCommand = patchMode === "native-pnpm" ? "pnpm" : "yarn";
1309
+ const commitArgs = patchMode === "native-pnpm" ? ["patch-commit", patchDir] : ["patch-commit", "-s", patchDir];
1310
+ await execa4(commitCommand, commitArgs, {
1194
1311
  cwd,
1195
1312
  stdio: "pipe"
1196
1313
  });
@@ -1200,7 +1317,7 @@ ${createResult.stderr}`);
1200
1317
  error: `Failed to apply native patch for ${packageSpec}: ${err instanceof Error ? err.message : String(err)}`
1201
1318
  };
1202
1319
  } finally {
1203
- await rm(tempPatchDir, { recursive: true, force: true });
1320
+ await rm2(tempPatchDir, { recursive: true, force: true });
1204
1321
  }
1205
1322
  return { success: true };
1206
1323
  }
@@ -1265,10 +1382,10 @@ function extractFailedTests(output) {
1265
1382
  }
1266
1383
 
1267
1384
  // src/remediation/pipeline.ts
1268
- async function runHealAgent(cveId, options = {}) {
1385
+ async function runRemediationPipeline(cveId, options = {}) {
1269
1386
  const provider = resolveProvider(options);
1270
1387
  if (provider === "local") {
1271
- return runLocalHealPipeline(cveId, options);
1388
+ return runLocalRemediationPipeline(cveId, options);
1272
1389
  }
1273
1390
  const cwd = options.cwd ?? process.cwd();
1274
1391
  const packageManager = options.packageManager ?? detectPackageManager(cwd);
@@ -1291,7 +1408,6 @@ async function runHealAgent(cveId, options = {}) {
1291
1408
  const vulnerablePackages = [];
1292
1409
  let cveDetails = null;
1293
1410
  let agentSteps = 0;
1294
- let lastGeneratedPatches = null;
1295
1411
  const result = await generateText2({
1296
1412
  model,
1297
1413
  system: systemPrompt,
@@ -1321,35 +1437,22 @@ async function runHealAgent(cveId, options = {}) {
1321
1437
  if (tr.toolName === "apply-version-bump") {
1322
1438
  collectedResults.push(toolResult);
1323
1439
  }
1324
- if (tr.toolName === "fetch-package-source" && toolResult?.success) {
1325
- const sourceData = {
1326
- success: toolResult.success,
1327
- sourceFiles: toolResult.sourceFiles,
1328
- packageDir: toolResult.packageDir
1329
- };
1330
- }
1331
- if (tr.toolName === "generate-patch" && toolResult?.success) {
1332
- const patchData = {
1333
- success: toolResult.success,
1334
- patches: toolResult.patches,
1335
- confidence: toolResult.confidence,
1336
- riskLevel: toolResult.riskLevel
1337
- };
1338
- lastGeneratedPatches = patchData.patches || null;
1339
- }
1340
1440
  if (tr.toolName === "apply-patch-file" && toolResult) {
1341
- const patchFileResult = {
1342
- success: toolResult.success,
1343
- patchPath: toolResult.patchPath,
1344
- postinstallConfigured: toolResult.postinstallConfigured,
1345
- validation: toolResult.validation
1346
- };
1347
- if (patchFileResult.success) {
1348
- collectedResults.push({
1349
- ...toolResult,
1350
- strategy: "patch-file"
1351
- });
1352
- }
1441
+ const validation = toolResult.validation;
1442
+ const message = typeof toolResult.message === "string" ? toolResult.message : typeof toolResult.error === "string" ? toolResult.error : "Patch-file strategy finished.";
1443
+ collectedResults.push({
1444
+ packageName: typeof toolResult.packageName === "string" ? toolResult.packageName : "unknown-package",
1445
+ strategy: "patch-file",
1446
+ fromVersion: typeof toolResult.vulnerableVersion === "string" ? toolResult.vulnerableVersion : "unknown",
1447
+ patchFilePath: typeof toolResult.patchFilePath === "string" ? toolResult.patchFilePath : typeof toolResult.patchPath === "string" ? toolResult.patchPath : void 0,
1448
+ applied: Boolean(toolResult.applied),
1449
+ dryRun: Boolean(toolResult.dryRun),
1450
+ message,
1451
+ validation: validation && typeof validation.passed === "boolean" ? {
1452
+ passed: validation.passed,
1453
+ error: typeof validation.error === "string" ? validation.error : void 0
1454
+ } : void 0
1455
+ });
1353
1456
  }
1354
1457
  }
1355
1458
  }
@@ -1363,7 +1466,7 @@ async function runHealAgent(cveId, options = {}) {
1363
1466
  summary: result.text
1364
1467
  };
1365
1468
  }
1366
- async function runLocalHealPipeline(cveId, options = {}) {
1469
+ async function runLocalRemediationPipeline(cveId, options = {}) {
1367
1470
  const cwd = options.cwd ?? process.cwd();
1368
1471
  const packageManager = options.packageManager ?? detectPackageManager(cwd);
1369
1472
  const dryRun = options.dryRun ?? false;
@@ -1447,6 +1550,17 @@ async function runLocalHealPipeline(cveId, options = {}) {
1447
1550
  for (const vulnerable of vulnerablePackages) {
1448
1551
  const pkg = vulnerable.installed;
1449
1552
  const firstPatchedVersion = vulnerable.affected.firstPatchedVersion;
1553
+ if (pkg.type === "indirect") {
1554
+ collectedResults.push({
1555
+ packageName: pkg.name,
1556
+ strategy: "none",
1557
+ fromVersion: pkg.version,
1558
+ applied: false,
1559
+ dryRun,
1560
+ message: `"${pkg.name}" is an indirect dependency; automatic version bump is limited to direct dependencies in local mode.`
1561
+ });
1562
+ continue;
1563
+ }
1450
1564
  if (!firstPatchedVersion) {
1451
1565
  collectedResults.push({
1452
1566
  packageName: pkg.name,
@@ -1461,7 +1575,8 @@ async function runLocalHealPipeline(cveId, options = {}) {
1461
1575
  const safeVersion = await findSafeUpgradeVersion(
1462
1576
  pkg.name,
1463
1577
  pkg.version,
1464
- firstPatchedVersion
1578
+ firstPatchedVersion,
1579
+ vulnerable.affected.vulnerableRange
1465
1580
  );
1466
1581
  agentSteps += 1;
1467
1582
  if (!safeVersion) {
@@ -1727,14 +1842,13 @@ function writeEvidenceLog(cwd, log) {
1727
1842
  }
1728
1843
 
1729
1844
  // src/api.ts
1730
- var runRemediationPipeline = runHealAgent;
1731
1845
  async function remediate(cveId, options = {}) {
1732
1846
  if (!/^CVE-\d{4}-\d+$/i.test(cveId)) {
1733
1847
  throw new Error(
1734
1848
  `Invalid CVE ID: "${cveId}". Expected format: CVE-YYYY-NNNNN (e.g. CVE-2021-23337).`
1735
1849
  );
1736
1850
  }
1737
- return runHealAgent(cveId.toUpperCase(), options);
1851
+ return runRemediationPipeline(cveId.toUpperCase(), options);
1738
1852
  }
1739
1853
  async function remediateFromScan(inputPath, options = {}) {
1740
1854
  const cwd = options.cwd ?? process.cwd();
@@ -1751,7 +1865,7 @@ async function remediateFromScan(inputPath, options = {}) {
1751
1865
  let patchFileCount = 0;
1752
1866
  for (const cveId of cveIds) {
1753
1867
  try {
1754
- addEvidenceStep(evidence, "heal.start", { cveId });
1868
+ addEvidenceStep(evidence, "remediate.start", { cveId });
1755
1869
  const report = await remediate(cveId, {
1756
1870
  ...options,
1757
1871
  patchesDir
@@ -1770,11 +1884,11 @@ async function remediateFromScan(inputPath, options = {}) {
1770
1884
  }
1771
1885
  }
1772
1886
  reports.push(report);
1773
- addEvidenceStep(evidence, "heal.finish", { cveId }, { results: report.results.length });
1887
+ addEvidenceStep(evidence, "remediate.finish", { cveId }, { results: report.results.length });
1774
1888
  } catch (error) {
1775
1889
  const message = error instanceof Error ? error.message : String(error);
1776
1890
  errors.push({ cveId, message });
1777
- addEvidenceStep(evidence, "heal.error", { cveId }, void 0, message);
1891
+ addEvidenceStep(evidence, "remediate.error", { cveId }, void 0, message);
1778
1892
  }
1779
1893
  }
1780
1894
  let successCount = 0;
@@ -1837,11 +1951,10 @@ function ciExitCode(summary) {
1837
1951
  }
1838
1952
 
1839
1953
  export {
1840
- runHealAgent,
1841
1954
  runRemediationPipeline,
1842
1955
  remediate,
1843
1956
  remediateFromScan,
1844
1957
  toCiSummary,
1845
1958
  ciExitCode
1846
1959
  };
1847
- //# sourceMappingURL=chunk-H4ICCI3K.js.map
1960
+ //# sourceMappingURL=chunk-DQKT2CUG.js.map