@whittlelabs/sifter 0.30.2 → 0.30.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 (3) hide show
  1. package/bin.js +52 -19
  2. package/bin.js.map +2 -2
  3. package/package.json +1 -1
package/bin.js CHANGED
@@ -10097,7 +10097,7 @@ var require_claude_code = __commonJS({
10097
10097
  const { response, readPaths, toolInputs } = await this.runClaude(prompt, spec, runCwd, childEnv, signal, hintedModel, reporter, void 0, dispatch.job.id);
10098
10098
  if (workspace) {
10099
10099
  const reads = [...readPaths];
10100
- for (const rel of creditOverlayReads(toolInputs, workspace.overlay?.writtenPaths ?? [])) {
10100
+ for (const rel of creditOverlayReads(toolInputs, workspace.overlay?.writtenPaths ?? [], runCwd)) {
10101
10101
  reads.push(path_1.default.join(runCwd, rel));
10102
10102
  }
10103
10103
  response.outputs.push({
@@ -10425,7 +10425,7 @@ var require_claude_code = __commonJS({
10425
10425
  return { finalText, readPaths, usage, resultMeta, structuredOutput, sessionId, toolInputs };
10426
10426
  }
10427
10427
  var MAX_REPORTED_READS = 2e3;
10428
- function relativeWorkspaceReads(readPaths, cwd) {
10428
+ function workspaceRoots(cwd) {
10429
10429
  const root = path_1.default.resolve(cwd);
10430
10430
  const roots = [root];
10431
10431
  try {
@@ -10434,6 +10434,11 @@ var require_claude_code = __commonJS({
10434
10434
  roots.push(real);
10435
10435
  } catch {
10436
10436
  }
10437
+ return roots;
10438
+ }
10439
+ function relativeWorkspaceReads(readPaths, cwd) {
10440
+ const roots = workspaceRoots(cwd);
10441
+ const root = roots[0];
10437
10442
  const out = /* @__PURE__ */ new Set();
10438
10443
  for (const p of readPaths) {
10439
10444
  const resolved = path_1.default.resolve(root, p);
@@ -10493,9 +10498,10 @@ var require_claude_code = __commonJS({
10493
10498
  }
10494
10499
  return new RegExp(`${re}$`);
10495
10500
  }
10496
- function creditOverlayReads(toolInputs, writtenPaths) {
10501
+ function creditOverlayReads(toolInputs, writtenPaths, runCwd) {
10497
10502
  if (writtenPaths.length === 0 || toolInputs.length === 0)
10498
10503
  return [];
10504
+ const roots = runCwd ? workspaceRoots(runCwd) : [];
10499
10505
  const dirs = /* @__PURE__ */ new Set();
10500
10506
  for (const rel of writtenPaths) {
10501
10507
  const parts = rel.split("/");
@@ -10503,27 +10509,29 @@ var require_claude_code = __commonJS({
10503
10509
  dirs.add(`${parts.slice(0, i).join("/")}/`);
10504
10510
  }
10505
10511
  const dirAlt = [...dirs].map(escapeRegExp).join("|");
10506
- const wordRe = dirs.size > 0 ? new RegExp(`(?:${dirAlt})[^\\s"'\`;|&<>(),\\\\]*`, "g") : null;
10512
+ const wordRe = dirs.size > 0 ? new RegExp(`(?:${dirAlt})[^\\s"'\`;|&<>()\\\\]*`, "g") : null;
10507
10513
  const findRe = dirs.size > 0 ? new RegExp(`\\bfind\\s+(?:\\./)?(${[...dirs].map((d) => escapeRegExp(d.slice(0, -1))).join("|")})/?(?=\\s|$)`, "g") : null;
10508
- const readerRe = /(?:^|[\s"])(?:-exec|-execdir|xargs)\b[^;|&]*\b(?:cat|head|tail|sed|awk|less|more|bat)\b/;
10514
+ const readerRe = new RegExp(`(?:^|[\\s"])(?:-exec|-execdir|xargs)\\b[^;|&]*\\b${READERS}\\b`);
10515
+ const plainReaderRe = new RegExp(`(?:^|[\\s"'\`;|&(])${READERS}\\b`);
10509
10516
  const credited = /* @__PURE__ */ new Set();
10510
- for (const input of toolInputs) {
10517
+ for (const raw of toolInputs) {
10518
+ const input = roots.reduce((s, r) => s.split(`${r}/`).join(""), raw);
10511
10519
  for (const rel of writtenPaths) {
10512
10520
  if (input.includes(rel))
10513
10521
  credited.add(rel);
10514
10522
  }
10515
- if (!wordRe)
10516
- continue;
10517
- for (const match of input.matchAll(wordRe)) {
10518
- const word = match[0];
10519
- if (!GLOB_CHARS.test(word))
10520
- continue;
10521
- const re = globToRegExp(word);
10522
- if (!re)
10523
- continue;
10524
- for (const rel of writtenPaths) {
10525
- if (re.test(rel))
10526
- credited.add(rel);
10523
+ if (wordRe) {
10524
+ for (const match of input.matchAll(wordRe)) {
10525
+ const word = match[0];
10526
+ if (!GLOB_CHARS.test(word))
10527
+ continue;
10528
+ const re = globToRegExp(word);
10529
+ if (!re)
10530
+ continue;
10531
+ for (const rel of writtenPaths) {
10532
+ if (re.test(rel))
10533
+ credited.add(rel);
10534
+ }
10527
10535
  }
10528
10536
  }
10529
10537
  if (findRe && readerRe.test(input)) {
@@ -10535,9 +10543,27 @@ var require_claude_code = __commonJS({
10535
10543
  }
10536
10544
  }
10537
10545
  }
10546
+ if (!plainReaderRe.test(input))
10547
+ continue;
10548
+ for (const match of input.matchAll(CD_RE)) {
10549
+ const target = match[1].replace(/^\.\//, "").replace(/\/+$/, "");
10550
+ const base = target.length > 0 ? `${target}/` : "";
10551
+ for (const rel of writtenPaths) {
10552
+ if (!rel.startsWith(base))
10553
+ continue;
10554
+ if (namesBareWord(input, rel.slice(base.length)))
10555
+ credited.add(rel);
10556
+ }
10557
+ }
10538
10558
  }
10539
10559
  return [...credited].sort();
10540
10560
  }
10561
+ var READERS = "(?:cat|head|tail|sed|awk|less|more|bat)";
10562
+ var CD_RE = /(?:^|[\s"'`;|&(])cd\s+(?:--\s+)?["']?([^\s"'`;|&<>()\\]+)/g;
10563
+ function namesBareWord(input, word) {
10564
+ const edge = String.raw`[\s"'\`;|&<>(),\\]`;
10565
+ return new RegExp(`(?:^|${edge})${escapeRegExp(word)}(?=$|${edge})`).test(input);
10566
+ }
10541
10567
  async function keepTranscript(dir, name, stdout) {
10542
10568
  try {
10543
10569
  await fs_1.promises.mkdir(dir, { recursive: true });
@@ -25539,7 +25565,7 @@ var import_path = require("path");
25539
25565
  var import_promises = require("fs/promises");
25540
25566
  var import_yaml = __toESM(require_dist4());
25541
25567
  var import_shuttle = __toESM(require_dist5());
25542
- var buildVersion = true ? "0.30.2" : pkg.version;
25568
+ var buildVersion = true ? "0.30.4" : pkg.version;
25543
25569
  var sifterBrand = {
25544
25570
  product: {
25545
25571
  id: "sifter",
@@ -25583,6 +25609,13 @@ var sifterBrand = {
25583
25609
  overlayAllowedHosts: [
25584
25610
  "https://api.sift.whittlelabs.com",
25585
25611
  "https://api.sift.stage.whittlelabs.com",
25612
+ // The test tier signs overlay URLs too, and a Sifter the E2E suite
25613
+ // runs on the runner reaches Sift by this host rather than by the
25614
+ // in-cluster service name the hosted worker uses. Without it that
25615
+ // Sifter passes its own preflight — the check asks only that the list
25616
+ // is non-empty — and then runs every review standards-blind, which is
25617
+ // the exact silence of 2026-07-13.
25618
+ "https://api.sift.test.whittlelabs.com",
25586
25619
  "http://localhost:3008"
25587
25620
  ],
25588
25621
  // Transcript retention is a diagnostic switch a person flips for one