codeblast 0.3.3 → 0.3.4

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.
Files changed (2) hide show
  1. package/dist/bin.js +30 -8
  2. package/package.json +2 -1
package/dist/bin.js CHANGED
@@ -899,6 +899,13 @@ var init_cli = __esm(() => {
899
899
  if (pyFiles > 0)
900
900
  console.error(`python files ingested: ${pyFiles}`);
901
901
  }
902
+ if (failures === 0) {
903
+ const stale = db.prepare("SELECT path FROM files").all().filter((row) => !seenFiles.has(row.path));
904
+ transaction(db, () => {
905
+ for (const row of stale)
906
+ invalidateFile(db, row.path);
907
+ })();
908
+ }
902
909
  dt = ((performance.now() - t0) / 1000).toFixed(1);
903
910
  console.log(JSON.stringify({
904
911
  db: dbPath,
@@ -2046,6 +2053,7 @@ function reviewDecision(input) {
2046
2053
  const { diff, prodNodesAdded, bodyChanged, affectedTests, truncated, blindSpotCount } = input;
2047
2054
  const apiContractions = diff.visibilityChanged.filter((v) => !v.nowExported).length;
2048
2055
  const apiChanges = apiContractions + diff.signatureChanged.length;
2056
+ const renames = diff.renamed.length;
2049
2057
  const removals = diff.nodesRemoved.length;
2050
2058
  const behaviorChanges = bodyChanged.length;
2051
2059
  const reasons = [];
@@ -2053,7 +2061,7 @@ function reviewDecision(input) {
2053
2061
  let risk = "low";
2054
2062
  if (apiContractions > 0 || removals > 0 || truncated)
2055
2063
  risk = "high";
2056
- else if (apiChanges > 0 || behaviorChanges > 0 || affectedTests > 0 || blindSpotCount > 0)
2064
+ else if (apiChanges > 0 || renames > 0 || behaviorChanges > 0 || affectedTests > 0 || blindSpotCount > 0)
2057
2065
  risk = "medium";
2058
2066
  if (apiContractions > 0)
2059
2067
  reasons.push(`${apiContractions} exported symbol${apiContractions === 1 ? " is" : "s are"} no longer public`);
@@ -2061,10 +2069,10 @@ function reviewDecision(input) {
2061
2069
  reasons.push(`${removals} symbol${removals === 1 ? " was" : "s were"} removed`);
2062
2070
  if (diff.signatureChanged.length > 0)
2063
2071
  reasons.push(`${diff.signatureChanged.length} exported signature${diff.signatureChanged.length === 1 ? " changed" : "s changed"}`);
2072
+ if (renames > 0)
2073
+ reasons.push(`${renames} symbol${renames === 1 ? " was" : "s were"} renamed`);
2064
2074
  if (behaviorChanges > 0)
2065
2075
  reasons.push(`${behaviorChanges} function bod${behaviorChanges === 1 ? "y" : "ies"} changed`);
2066
- if (affectedTests > 0)
2067
- reasons.push(`${affectedTests} test file${affectedTests === 1 ? " is" : "s are"} in the predicted impact set`);
2068
2076
  if (truncated)
2069
2077
  reasons.push("the impact set exceeded the reporting limit");
2070
2078
  if (blindSpotCount > 0)
@@ -2197,7 +2205,9 @@ var init_pr_comment = __esm(async () => {
2197
2205
  if (diff2.renamed.length > 0) {
2198
2206
  lines3.push(`### 重命名`, ``);
2199
2207
  for (const r of diff2.renamed.slice(0, 10)) {
2200
- lines3.push(`- \`${r.from}\` → \`${r.to}\` (${r.kind})`);
2208
+ const targetName = r.to.includes("#") ? r.to.split("#").pop() : r.to;
2209
+ const target = dbB2.prepare("SELECT line FROM nodes WHERE file = ? AND name = ? ORDER BY line LIMIT 1").get(r.file, targetName);
2210
+ lines3.push(`- \`${r.from}\` → \`${r.to}\` (${r.kind})${target ? ` (${link(r.file, target.line)})` : ""}`);
2201
2211
  }
2202
2212
  if (diff2.renamed.length > 10)
2203
2213
  lines3.push(`- …及另外 ${diff2.renamed.length - 10} 项`);
@@ -2338,7 +2348,7 @@ var SCHEMA_VERSION = "1", EXIT_OK = 0, EXIT_REVIEW = 1, EXIT_ERROR = 2, readVers
2338
2348
  nodes: Number(db.prepare("SELECT COUNT(*) c FROM nodes").get().c),
2339
2349
  edges: Number(db.prepare("SELECT COUNT(*) c FROM edges").get().c),
2340
2350
  blind_spots: Number(db.prepare("SELECT COUNT(*) c FROM blind_spots").get().c)
2341
- }), healthBase, healthHead, diff3, healthWarnings, prodNodesAdded2, total3, affectedTests = 0, truncated = false, blindSpots = 0, bodyChanged2, diffText, currentFile = "", diffLineCount2, decision2, output;
2351
+ }), healthBase, healthHead, diff3, healthWarnings, prodNodesAdded2, total3, affectedTests = 0, truncated = false, blindSpots = 0, bodyChanged2, structuralIds2, diffText, currentFile = "", diffLineCount2, changedFiles2, auxOnly, decision2, output;
2342
2352
  var init_check_change = __esm(() => {
2343
2353
  init_db();
2344
2354
  init_proc();
@@ -2383,6 +2393,10 @@ var init_check_change = __esm(() => {
2383
2393
  } catch {}
2384
2394
  }
2385
2395
  bodyChanged2 = [];
2396
+ structuralIds2 = new Set([
2397
+ ...diff3.nodesAdded.map((node) => node.id),
2398
+ ...diff3.renamed.map((rename) => `${rename.file}#${rename.to}`)
2399
+ ]);
2386
2400
  diffText = spawnSync(["git", "diff", "--unified=0", baseSha2, headSha2, "--", "*.ts", "*.tsx"], { cwd: repo3 }).stdout;
2387
2401
  for (const line of diffText.split(`
2388
2402
  `)) {
@@ -2392,10 +2406,10 @@ var init_check_change = __esm(() => {
2392
2406
  continue;
2393
2407
  }
2394
2408
  const hunk = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)/);
2395
- if (!hunk || !currentFile || TEST_RE3.test(currentFile))
2409
+ if (!hunk || !currentFile || TEST_RE3.test(currentFile) || AUX_RE.test(currentFile))
2396
2410
  continue;
2397
2411
  const row = dbB3.prepare("SELECT id, name, kind, file, line FROM nodes WHERE file = ? AND kind IN ('function','method') AND line <= ? AND end_line >= ? ORDER BY (end_line - line) ASC LIMIT 1").get(currentFile, Number(hunk[1]), Number(hunk[1]));
2398
- if (row && !bodyChanged2.some((item) => item.id === row.id))
2412
+ if (row && !structuralIds2.has(row.id) && !bodyChanged2.some((item) => item.id === row.id))
2399
2413
  bodyChanged2.push(row);
2400
2414
  }
2401
2415
  diffLineCount2 = spawnSync(["git", "diff", "--numstat", baseSha2, headSha2], { cwd: repo3 }).stdout.split(`
@@ -2403,11 +2417,19 @@ var init_check_change = __esm(() => {
2403
2417
  const match = line.match(/^(\d+)\t(\d+)\t/);
2404
2418
  return sum + (match ? Number(match[1]) + Number(match[2]) : 0);
2405
2419
  }, 0);
2420
+ changedFiles2 = spawnSync(["git", "diff", "--name-only", baseSha2, headSha2], { cwd: repo3 }).stdout.split(`
2421
+ `).filter(Boolean);
2422
+ auxOnly = changedFiles2.length > 0 && changedFiles2.every((file) => AUX_RE.test(file));
2406
2423
  decision2 = reviewDecision({ diff: diff3, prodNodesAdded: prodNodesAdded2, bodyChanged: bodyChanged2, affectedTests, truncated, blindSpotCount: blindSpots });
2407
2424
  if (healthWarnings.length > 0) {
2408
2425
  decision2.risk = "high";
2409
2426
  decision2.reasons.push(...healthWarnings);
2410
2427
  decision2.recommendedActions.unshift("Rebuild or inspect the graph before relying on this decision.");
2428
+ } else if (auxOnly) {
2429
+ decision2.risk = "low";
2430
+ decision2.summary = "Low structural risk: only auxiliary-directory changes were found.";
2431
+ decision2.reasons = ["only auxiliary-directory changes were found"];
2432
+ decision2.recommendedActions = ["No code review signal; inspect the auxiliary change directly if needed."];
2411
2433
  }
2412
2434
  output = {
2413
2435
  schema_version: SCHEMA_VERSION,
@@ -2426,7 +2448,7 @@ var init_check_change = __esm(() => {
2426
2448
  signals: {
2427
2449
  core_named: coreNamedCount(diff3, prodNodesAdded2),
2428
2450
  body: bodySignalCount(bodyChanged2, diffLineCount2, () => false),
2429
- aux_only: total3 > 0 && coreNamedCount(diff3, prodNodesAdded2) === 0 && bodyChanged2.length === 0
2451
+ aux_only: auxOnly
2430
2452
  },
2431
2453
  diff: diff3
2432
2454
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeblast",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Know what breaks before you merge — mutation-tested code graph with architecture, change & impact maps. Evidence on every edge. For humans and AI agents.",
5
5
  "keywords": [
6
6
  "impact-analysis",
@@ -40,6 +40,7 @@
40
40
  "typecheck": "tsc -p .",
41
41
  "agent-smoke": "bun run build && node eval/agent-workflow-smoke.mjs",
42
42
  "guidance-stability": "node eval/guidance-stability.mjs",
43
+ "incremental-equivalence": "bun run build && node eval/incremental-equivalence.mjs",
43
44
  "offline-replay": "bun run build && node eval/offline-replay.mjs",
44
45
  "pilot-summary": "node eval/pilot-summary.mjs",
45
46
  "release-smoke": "node eval/release-smoke.mjs",