@bilalimamoglu/sift 0.4.3 → 0.4.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.
package/README.md CHANGED
@@ -266,6 +266,7 @@ sift rerun --goal diagnose --format json
266
266
  - CLI reference: [docs/cli-reference.md](docs/cli-reference.md)
267
267
  - Worked examples: [docs/examples](docs/examples)
268
268
  - Benchmark methodology: [BENCHMARK_NOTES.md](BENCHMARK_NOTES.md)
269
+ - Contributing and development notes: [CONTRIBUTING.md](CONTRIBUTING.md)
269
270
  - Release notes: [release-notes](release-notes)
270
271
 
271
272
  ---
package/dist/cli.js CHANGED
@@ -5,13 +5,15 @@ import { createRequire } from "module";
5
5
  import { cac } from "cac";
6
6
 
7
7
  // src/config/load.ts
8
- import fs from "fs";
8
+ import fs2 from "fs";
9
9
  import path2 from "path";
10
10
  import YAML from "yaml";
11
11
 
12
12
  // src/constants.ts
13
+ import fs from "fs";
13
14
  import os from "os";
14
15
  import path from "path";
16
+ import crypto from "crypto";
15
17
  var DEFAULT_CONFIG_FILENAME = "sift.config.yaml";
16
18
  function getDefaultCodexGlobalInstructionsPath(homeDir = os.homedir()) {
17
19
  return path.join(homeDir, ".codex", "AGENTS.md");
@@ -28,6 +30,26 @@ function getDefaultGlobalStateDir(homeDir = os.homedir()) {
28
30
  function getDefaultTestStatusStatePath(homeDir = os.homedir()) {
29
31
  return path.join(getDefaultGlobalStateDir(homeDir), "last-test-status.json");
30
32
  }
33
+ function getDefaultScopedTestStatusStateDir(homeDir = os.homedir()) {
34
+ return path.join(getDefaultGlobalStateDir(homeDir), "test-status", "by-cwd");
35
+ }
36
+ function getScopedTestStatusStatePath(cwd, homeDir = os.homedir()) {
37
+ const normalizedCwd = normalizeScopedCacheCwd(cwd);
38
+ const baseName = slugCachePathSegment(path.basename(normalizedCwd)) || "root";
39
+ const shortHash = crypto.createHash("sha256").update(normalizedCwd).digest("hex").slice(0, 10);
40
+ return path.join(getDefaultScopedTestStatusStateDir(homeDir), `${baseName}-${shortHash}.json`);
41
+ }
42
+ function slugCachePathSegment(value) {
43
+ return value.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
44
+ }
45
+ function normalizeScopedCacheCwd(cwd) {
46
+ const absoluteCwd = path.resolve(cwd);
47
+ try {
48
+ return fs.realpathSync.native(absoluteCwd);
49
+ } catch {
50
+ return absoluteCwd;
51
+ }
52
+ }
31
53
  function getDefaultConfigSearchPaths() {
32
54
  return [
33
55
  path.resolve(process.cwd(), "sift.config.yaml"),
@@ -44,13 +66,13 @@ var CAPTURE_OMITTED_MARKER = "\n...[captured output omitted]...\n";
44
66
  function findConfigPath(explicitPath) {
45
67
  if (explicitPath) {
46
68
  const resolved = path2.resolve(explicitPath);
47
- if (!fs.existsSync(resolved)) {
69
+ if (!fs2.existsSync(resolved)) {
48
70
  throw new Error(`Config file not found: ${resolved}`);
49
71
  }
50
72
  return resolved;
51
73
  }
52
74
  for (const candidate of getDefaultConfigSearchPaths()) {
53
- if (fs.existsSync(candidate)) {
75
+ if (fs2.existsSync(candidate)) {
54
76
  return candidate;
55
77
  }
56
78
  }
@@ -61,7 +83,7 @@ function loadRawConfig(explicitPath) {
61
83
  if (!configPath) {
62
84
  return {};
63
85
  }
64
- const content = fs.readFileSync(configPath, "utf8");
86
+ const content = fs2.readFileSync(configPath, "utf8");
65
87
  return YAML.parse(content) ?? {};
66
88
  }
67
89
 
@@ -472,7 +494,7 @@ function resolveConfig(options = {}) {
472
494
  }
473
495
 
474
496
  // src/config/write.ts
475
- import fs2 from "fs";
497
+ import fs3 from "fs";
476
498
  import path3 from "path";
477
499
  import YAML2 from "yaml";
478
500
  function writeExampleConfig(options = {}) {
@@ -480,41 +502,41 @@ function writeExampleConfig(options = {}) {
480
502
  throw new Error("Use either --path <path> or --global, not both.");
481
503
  }
482
504
  const resolved = options.global ? getDefaultGlobalConfigPath() : path3.resolve(options.targetPath ?? DEFAULT_CONFIG_FILENAME);
483
- if (fs2.existsSync(resolved)) {
505
+ if (fs3.existsSync(resolved)) {
484
506
  throw new Error(`Config file already exists at ${resolved}`);
485
507
  }
486
508
  const yaml = YAML2.stringify(defaultConfig);
487
- fs2.mkdirSync(path3.dirname(resolved), { recursive: true });
488
- fs2.writeFileSync(resolved, yaml, {
509
+ fs3.mkdirSync(path3.dirname(resolved), { recursive: true });
510
+ fs3.writeFileSync(resolved, yaml, {
489
511
  encoding: "utf8",
490
512
  mode: 384
491
513
  });
492
514
  try {
493
- fs2.chmodSync(resolved, 384);
515
+ fs3.chmodSync(resolved, 384);
494
516
  } catch {
495
517
  }
496
518
  return resolved;
497
519
  }
498
520
  function writeConfigFile(options) {
499
521
  const resolved = path3.resolve(options.targetPath);
500
- if (!options.overwrite && fs2.existsSync(resolved)) {
522
+ if (!options.overwrite && fs3.existsSync(resolved)) {
501
523
  throw new Error(`Config file already exists at ${resolved}`);
502
524
  }
503
525
  const yaml = YAML2.stringify(options.config);
504
- fs2.mkdirSync(path3.dirname(resolved), { recursive: true });
505
- fs2.writeFileSync(resolved, yaml, {
526
+ fs3.mkdirSync(path3.dirname(resolved), { recursive: true });
527
+ fs3.writeFileSync(resolved, yaml, {
506
528
  encoding: "utf8",
507
529
  mode: 384
508
530
  });
509
531
  try {
510
- fs2.chmodSync(resolved, 384);
532
+ fs3.chmodSync(resolved, 384);
511
533
  } catch {
512
534
  }
513
535
  return resolved;
514
536
  }
515
537
 
516
538
  // src/config/editable.ts
517
- import fs3 from "fs";
539
+ import fs4 from "fs";
518
540
  import path4 from "path";
519
541
  function isRecord2(value) {
520
542
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -527,7 +549,7 @@ function resolveEditableConfigPath(explicitPath) {
527
549
  }
528
550
  function loadEditableConfig(explicitPath) {
529
551
  const resolvedPath = resolveEditableConfigPath(explicitPath);
530
- const existed = fs3.existsSync(resolvedPath);
552
+ const existed = fs4.existsSync(resolvedPath);
531
553
  const rawConfig = existed ? loadRawConfig(resolvedPath) : {};
532
554
  const config = siftConfigSchema.parse(
533
555
  mergeDefined(defaultConfig, isRecord2(rawConfig) ? rawConfig : {})
@@ -1164,7 +1186,7 @@ function configUse(provider, configPath, env = process.env) {
1164
1186
  }
1165
1187
 
1166
1188
  // src/commands/agent.ts
1167
- import fs4 from "fs";
1189
+ import fs5 from "fs";
1168
1190
  import os2 from "os";
1169
1191
  import path6 from "path";
1170
1192
  import { createInterface as createInterface2 } from "readline/promises";
@@ -1794,20 +1816,20 @@ function joinAroundRemoval(before, after, eol) {
1794
1816
  return `${left}${eol}${eol}${right}`;
1795
1817
  }
1796
1818
  function readOptionalFile(targetPath) {
1797
- if (!fs4.existsSync(targetPath)) {
1819
+ if (!fs5.existsSync(targetPath)) {
1798
1820
  return void 0;
1799
1821
  }
1800
- const stats = fs4.statSync(targetPath);
1822
+ const stats = fs5.statSync(targetPath);
1801
1823
  if (!stats.isFile()) {
1802
1824
  throw new Error(`${targetPath} exists but is not a file.`);
1803
1825
  }
1804
- return fs4.readFileSync(targetPath, "utf8");
1826
+ return fs5.readFileSync(targetPath, "utf8");
1805
1827
  }
1806
1828
  function writeTextFileAtomic(targetPath, content) {
1807
- fs4.mkdirSync(path6.dirname(targetPath), { recursive: true });
1829
+ fs5.mkdirSync(path6.dirname(targetPath), { recursive: true });
1808
1830
  const tempPath = `${targetPath}.tmp-${process.pid}-${Date.now()}`;
1809
- fs4.writeFileSync(tempPath, content, "utf8");
1810
- fs4.renameSync(tempPath, targetPath);
1831
+ fs5.writeFileSync(tempPath, content, "utf8");
1832
+ fs5.renameSync(tempPath, targetPath);
1811
1833
  }
1812
1834
  function escapeRegExp(value) {
1813
1835
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -1983,6 +2005,7 @@ var OpenAIProvider = class {
1983
2005
  signal: controller.signal,
1984
2006
  headers: {
1985
2007
  "content-type": "application/json",
2008
+ connection: "close",
1986
2009
  ...this.apiKey ? { authorization: `Bearer ${this.apiKey}` } : {}
1987
2010
  },
1988
2011
  body: JSON.stringify({
@@ -2083,6 +2106,7 @@ var OpenAICompatibleProvider = class {
2083
2106
  signal: controller.signal,
2084
2107
  headers: {
2085
2108
  "content-type": "application/json",
2109
+ connection: "close",
2086
2110
  ...this.apiKey ? { authorization: `Bearer ${this.apiKey}` } : {}
2087
2111
  },
2088
2112
  body: JSON.stringify({
@@ -8265,7 +8289,7 @@ function emitStatsFooter(args) {
8265
8289
  }
8266
8290
 
8267
8291
  // src/core/testStatusState.ts
8268
- import fs5 from "fs";
8292
+ import fs6 from "fs";
8269
8293
  import path7 from "path";
8270
8294
  import { z as z3 } from "zod";
8271
8295
  var detailSchema = z3.enum(["standard", "focused", "verbose"]);
@@ -8715,7 +8739,7 @@ function migrateCachedTestStatusRun(state) {
8715
8739
  function readCachedTestStatusRun(statePath = getDefaultTestStatusStatePath()) {
8716
8740
  let raw = "";
8717
8741
  try {
8718
- raw = fs5.readFileSync(statePath, "utf8");
8742
+ raw = fs6.readFileSync(statePath, "utf8");
8719
8743
  } catch (error) {
8720
8744
  if (error.code === "ENOENT") {
8721
8745
  throw new MissingCachedTestStatusRunError();
@@ -8736,10 +8760,10 @@ function tryReadCachedTestStatusRun(statePath = getDefaultTestStatusStatePath())
8736
8760
  }
8737
8761
  }
8738
8762
  function writeCachedTestStatusRun(state, statePath = getDefaultTestStatusStatePath()) {
8739
- fs5.mkdirSync(path7.dirname(statePath), {
8763
+ fs6.mkdirSync(path7.dirname(statePath), {
8740
8764
  recursive: true
8741
8765
  });
8742
- fs5.writeFileSync(statePath, `${JSON.stringify(state, null, 2)}
8766
+ fs6.writeFileSync(statePath, `${JSON.stringify(state, null, 2)}
8743
8767
  `, "utf8");
8744
8768
  }
8745
8769
  function getNextEscalationDetail(detail) {
@@ -8901,7 +8925,8 @@ function resolveEscalationDetail(state, requested, showRaw = false) {
8901
8925
  return nextDetail;
8902
8926
  }
8903
8927
  async function runEscalate(request) {
8904
- const state = readCachedTestStatusRun();
8928
+ const scopedStatePath = getScopedTestStatusStatePath(process.cwd());
8929
+ const state = readCachedTestStatusRun(scopedStatePath);
8905
8930
  const detail = resolveEscalationDetail(state, request.detail, request.showRaw);
8906
8931
  if (request.verbose) {
8907
8932
  process.stderr.write(
@@ -8949,10 +8974,13 @@ async function runEscalate(request) {
8949
8974
  quiet: Boolean(request.quiet)
8950
8975
  });
8951
8976
  try {
8952
- writeCachedTestStatusRun({
8953
- ...state,
8954
- detail
8955
- });
8977
+ writeCachedTestStatusRun(
8978
+ {
8979
+ ...state,
8980
+ detail
8981
+ },
8982
+ scopedStatePath
8983
+ );
8956
8984
  } catch (error) {
8957
8985
  if (request.verbose) {
8958
8986
  const reason = error instanceof Error ? error.message : "unknown_error";
@@ -9293,10 +9321,11 @@ async function runExec(request) {
9293
9321
  const shellPath = process.env.SHELL || "/bin/bash";
9294
9322
  const commandPreview = buildCommandPreview(request);
9295
9323
  const commandCwd = request.cwd ?? process.cwd();
9324
+ const scopedStatePath = getScopedTestStatusStatePath(commandCwd);
9296
9325
  const isTestStatusPreset = request.presetName === "test-status";
9297
9326
  const readCachedBaseline = isTestStatusPreset && (request.readCachedBaseline ?? true);
9298
9327
  const writeCachedBaselineRequested = isTestStatusPreset && (request.writeCachedBaseline ?? (request.skipCacheWrite ? false : true));
9299
- const previousCachedRun = readCachedBaseline ? tryReadCachedTestStatusRun() : null;
9328
+ const previousCachedRun = readCachedBaseline ? tryReadCachedTestStatusRun(scopedStatePath) : null;
9300
9329
  if (request.config.runtime.verbose) {
9301
9330
  process.stderr.write(
9302
9331
  `${pc5.dim("sift")} exec mode=${hasShellCommand ? "shell" : "argv"} command=${commandPreview}
@@ -9499,7 +9528,7 @@ ${output}`;
9499
9528
  }
9500
9529
  if (currentCachedRun && shouldWriteCachedBaseline) {
9501
9530
  try {
9502
- writeCachedTestStatusRun(currentCachedRun);
9531
+ writeCachedTestStatusRun(currentCachedRun, scopedStatePath);
9503
9532
  } catch (error) {
9504
9533
  if (request.config.runtime.verbose) {
9505
9534
  const reason = error instanceof Error ? error.message : "unknown_error";
@@ -9535,7 +9564,7 @@ ${output}`;
9535
9564
 
9536
9565
  // src/core/rerun.ts
9537
9566
  async function runRerun(request) {
9538
- const state = readCachedTestStatusRun();
9567
+ const state = readCachedTestStatusRun(getScopedTestStatusStatePath(process.cwd()));
9539
9568
  if (!request.remaining) {
9540
9569
  return runExec({
9541
9570
  ...request,
package/dist/index.js CHANGED
@@ -4,8 +4,10 @@ import { constants as osConstants } from "os";
4
4
  import pc3 from "picocolors";
5
5
 
6
6
  // src/constants.ts
7
+ import fs from "fs";
7
8
  import os from "os";
8
9
  import path from "path";
10
+ import crypto from "crypto";
9
11
  function getDefaultGlobalConfigPath(homeDir = os.homedir()) {
10
12
  return path.join(homeDir, ".config", "sift", "config.yaml");
11
13
  }
@@ -15,6 +17,26 @@ function getDefaultGlobalStateDir(homeDir = os.homedir()) {
15
17
  function getDefaultTestStatusStatePath(homeDir = os.homedir()) {
16
18
  return path.join(getDefaultGlobalStateDir(homeDir), "last-test-status.json");
17
19
  }
20
+ function getDefaultScopedTestStatusStateDir(homeDir = os.homedir()) {
21
+ return path.join(getDefaultGlobalStateDir(homeDir), "test-status", "by-cwd");
22
+ }
23
+ function getScopedTestStatusStatePath(cwd, homeDir = os.homedir()) {
24
+ const normalizedCwd = normalizeScopedCacheCwd(cwd);
25
+ const baseName = slugCachePathSegment(path.basename(normalizedCwd)) || "root";
26
+ const shortHash = crypto.createHash("sha256").update(normalizedCwd).digest("hex").slice(0, 10);
27
+ return path.join(getDefaultScopedTestStatusStateDir(homeDir), `${baseName}-${shortHash}.json`);
28
+ }
29
+ function slugCachePathSegment(value) {
30
+ return value.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
31
+ }
32
+ function normalizeScopedCacheCwd(cwd) {
33
+ const absoluteCwd = path.resolve(cwd);
34
+ try {
35
+ return fs.realpathSync.native(absoluteCwd);
36
+ } catch {
37
+ return absoluteCwd;
38
+ }
39
+ }
18
40
  function getDefaultConfigSearchPaths() {
19
41
  return [
20
42
  path.resolve(process.cwd(), "sift.config.yaml"),
@@ -4741,6 +4763,7 @@ var OpenAIProvider = class {
4741
4763
  signal: controller.signal,
4742
4764
  headers: {
4743
4765
  "content-type": "application/json",
4766
+ connection: "close",
4744
4767
  ...this.apiKey ? { authorization: `Bearer ${this.apiKey}` } : {}
4745
4768
  },
4746
4769
  body: JSON.stringify({
@@ -4841,6 +4864,7 @@ var OpenAICompatibleProvider = class {
4841
4864
  signal: controller.signal,
4842
4865
  headers: {
4843
4866
  "content-type": "application/json",
4867
+ connection: "close",
4844
4868
  ...this.apiKey ? { authorization: `Bearer ${this.apiKey}` } : {}
4845
4869
  },
4846
4870
  body: JSON.stringify({
@@ -6413,7 +6437,7 @@ function emitStatsFooter(args) {
6413
6437
  }
6414
6438
 
6415
6439
  // src/core/testStatusState.ts
6416
- import fs from "fs";
6440
+ import fs2 from "fs";
6417
6441
  import path2 from "path";
6418
6442
  import { z as z2 } from "zod";
6419
6443
  var detailSchema = z2.enum(["standard", "focused", "verbose"]);
@@ -6863,7 +6887,7 @@ function migrateCachedTestStatusRun(state) {
6863
6887
  function readCachedTestStatusRun(statePath = getDefaultTestStatusStatePath()) {
6864
6888
  let raw = "";
6865
6889
  try {
6866
- raw = fs.readFileSync(statePath, "utf8");
6890
+ raw = fs2.readFileSync(statePath, "utf8");
6867
6891
  } catch (error) {
6868
6892
  if (error.code === "ENOENT") {
6869
6893
  throw new MissingCachedTestStatusRunError();
@@ -6884,10 +6908,10 @@ function tryReadCachedTestStatusRun(statePath = getDefaultTestStatusStatePath())
6884
6908
  }
6885
6909
  }
6886
6910
  function writeCachedTestStatusRun(state, statePath = getDefaultTestStatusStatePath()) {
6887
- fs.mkdirSync(path2.dirname(statePath), {
6911
+ fs2.mkdirSync(path2.dirname(statePath), {
6888
6912
  recursive: true
6889
6913
  });
6890
- fs.writeFileSync(statePath, `${JSON.stringify(state, null, 2)}
6914
+ fs2.writeFileSync(statePath, `${JSON.stringify(state, null, 2)}
6891
6915
  `, "utf8");
6892
6916
  }
6893
6917
  function buildTargetDelta(args) {
@@ -7273,10 +7297,11 @@ async function runExec(request) {
7273
7297
  const shellPath = process.env.SHELL || "/bin/bash";
7274
7298
  const commandPreview = buildCommandPreview(request);
7275
7299
  const commandCwd = request.cwd ?? process.cwd();
7300
+ const scopedStatePath = getScopedTestStatusStatePath(commandCwd);
7276
7301
  const isTestStatusPreset = request.presetName === "test-status";
7277
7302
  const readCachedBaseline = isTestStatusPreset && (request.readCachedBaseline ?? true);
7278
7303
  const writeCachedBaselineRequested = isTestStatusPreset && (request.writeCachedBaseline ?? (request.skipCacheWrite ? false : true));
7279
- const previousCachedRun = readCachedBaseline ? tryReadCachedTestStatusRun() : null;
7304
+ const previousCachedRun = readCachedBaseline ? tryReadCachedTestStatusRun(scopedStatePath) : null;
7280
7305
  if (request.config.runtime.verbose) {
7281
7306
  process.stderr.write(
7282
7307
  `${pc3.dim("sift")} exec mode=${hasShellCommand ? "shell" : "argv"} command=${commandPreview}
@@ -7479,7 +7504,7 @@ ${output}`;
7479
7504
  }
7480
7505
  if (currentCachedRun && shouldWriteCachedBaseline) {
7481
7506
  try {
7482
- writeCachedTestStatusRun(currentCachedRun);
7507
+ writeCachedTestStatusRun(currentCachedRun, scopedStatePath);
7483
7508
  } catch (error) {
7484
7509
  if (request.config.runtime.verbose) {
7485
7510
  const reason = error instanceof Error ? error.message : "unknown_error";
@@ -7585,19 +7610,19 @@ var defaultConfig = {
7585
7610
  };
7586
7611
 
7587
7612
  // src/config/load.ts
7588
- import fs2 from "fs";
7613
+ import fs3 from "fs";
7589
7614
  import path3 from "path";
7590
7615
  import YAML from "yaml";
7591
7616
  function findConfigPath(explicitPath) {
7592
7617
  if (explicitPath) {
7593
7618
  const resolved = path3.resolve(explicitPath);
7594
- if (!fs2.existsSync(resolved)) {
7619
+ if (!fs3.existsSync(resolved)) {
7595
7620
  throw new Error(`Config file not found: ${resolved}`);
7596
7621
  }
7597
7622
  return resolved;
7598
7623
  }
7599
7624
  for (const candidate of getDefaultConfigSearchPaths()) {
7600
- if (fs2.existsSync(candidate)) {
7625
+ if (fs3.existsSync(candidate)) {
7601
7626
  return candidate;
7602
7627
  }
7603
7628
  }
@@ -7608,7 +7633,7 @@ function loadRawConfig(explicitPath) {
7608
7633
  if (!configPath) {
7609
7634
  return {};
7610
7635
  }
7611
- const content = fs2.readFileSync(configPath, "utf8");
7636
+ const content = fs3.readFileSync(configPath, "utf8");
7612
7637
  return YAML.parse(content) ?? {};
7613
7638
  }
7614
7639
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bilalimamoglu/sift",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "Agent-first command-output reduction layer for agents, CI, and automation.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,8 +25,10 @@
25
25
  "bench:report": "node --import tsx scripts/bench/generate-progress-report.ts",
26
26
  "dev": "tsx src/cli.ts",
27
27
  "typecheck": "tsc --noEmit",
28
- "test": "vitest run",
29
- "test:coverage": "vitest run --coverage",
28
+ "test": "vitest run --config vitest.config.ts",
29
+ "test:smoke": "vitest run --config vitest.config.ts test/*.smoke.test.ts",
30
+ "test:e2e": "vitest run --config vitest.e2e.config.ts test/*.e2e.test.ts",
31
+ "test:coverage": "vitest run --config vitest.config.ts --coverage --exclude=\"test/**/*.smoke.test.ts\" --exclude=\"test/**/*.e2e.test.ts\"",
30
32
  "test:watch": "vitest",
31
33
  "prepublishOnly": "npm run typecheck && npm run test:coverage && npm run build"
32
34
  },