@biffo/cli 0.304.1 → 0.304.3

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/dist/index.js CHANGED
@@ -717,12 +717,28 @@ function checkCoreOwnership({
717
717
  isInstance,
718
718
  branch = "",
719
719
  commitMessage = "",
720
- warnOnly = []
720
+ warnOnly = [],
721
+ templateShippedPaths = null
721
722
  }) {
722
- const empty = { blocked: [], warned: [], divergenceReason: null, convergenceReason: null };
723
+ const empty = {
724
+ blocked: [],
725
+ warned: [],
726
+ divergenceReason: null,
727
+ convergenceReason: null,
728
+ knownOrphans: []
729
+ };
723
730
  if (!isInstance) return { skipped: "template", ...empty };
724
731
  if (branch.startsWith(UPGRADE_BRANCH_PREFIX)) return { skipped: "upgrade-branch", ...empty };
725
- const templateOwned = changedFiles.filter((f) => isTemplateOwned(f, manifest));
732
+ const manifestTemplateOwned = changedFiles.filter((f) => isTemplateOwned(f, manifest));
733
+ const knownOrphans = [];
734
+ const templateOwned = [];
735
+ for (const path of manifestTemplateOwned) {
736
+ if (templateShippedPaths != null && !templateShippedPaths.has(path)) {
737
+ knownOrphans.push(path);
738
+ } else {
739
+ templateOwned.push(path);
740
+ }
741
+ }
726
742
  const acknowledged = (path) => warnOnly.filter((entry) => path.startsWith(entry.prefix)).reduce(
727
743
  (best, entry) => !best || entry.prefix.length > best.prefix.length ? entry : best,
728
744
  void 0
@@ -743,7 +759,8 @@ function checkCoreOwnership({
743
759
  blocked: [],
744
760
  warned,
745
761
  divergenceReason,
746
- convergenceReason: null
762
+ convergenceReason: null,
763
+ knownOrphans
747
764
  };
748
765
  }
749
766
  if (convergenceReason !== null) {
@@ -752,7 +769,8 @@ function checkCoreOwnership({
752
769
  blocked: [],
753
770
  warned,
754
771
  divergenceReason: null,
755
- convergenceReason
772
+ convergenceReason,
773
+ knownOrphans
756
774
  };
757
775
  }
758
776
  }
@@ -761,7 +779,8 @@ function checkCoreOwnership({
761
779
  blocked: offending,
762
780
  warned,
763
781
  divergenceReason: null,
764
- convergenceReason: null
782
+ convergenceReason: null,
783
+ knownOrphans
765
784
  };
766
785
  }
767
786
 
@@ -12255,6 +12274,37 @@ async function runCoreDirectPathsCheck(opts = {}) {
12255
12274
  console.log(`\u2713 core-direct-paths guard: ${report.summary}`);
12256
12275
  }
12257
12276
 
12277
+ // src/lib/template-shipped-paths.ts
12278
+ var TEMPLATE_UPSTREAM_OWNER = "keiranholloway";
12279
+ var TEMPLATE_UPSTREAM_REPO = "biffo-template";
12280
+ var TEMPLATE_UPSTREAM_BRANCH = "dev";
12281
+ var defaultRunner = async (args, cwd) => {
12282
+ const result = await execa("git", args, { cwd, reject: false, timeout: 15e3 });
12283
+ return { stdout: String(result.stdout ?? ""), exitCode: result.exitCode ?? null };
12284
+ };
12285
+ async function fetchTemplateShippedPaths(repoRoot, runner = defaultRunner) {
12286
+ const url = `https://github.com/${TEMPLATE_UPSTREAM_OWNER}/${TEMPLATE_UPSTREAM_REPO}.git`;
12287
+ let fetched;
12288
+ try {
12289
+ fetched = await runner(
12290
+ ["fetch", "--depth", "1", "--quiet", url, TEMPLATE_UPSTREAM_BRANCH],
12291
+ repoRoot
12292
+ );
12293
+ } catch {
12294
+ return null;
12295
+ }
12296
+ if (fetched.exitCode !== 0) return null;
12297
+ let tree;
12298
+ try {
12299
+ tree = await runner(["ls-tree", "-r", "--name-only", "FETCH_HEAD"], repoRoot);
12300
+ } catch {
12301
+ return null;
12302
+ }
12303
+ if (tree.exitCode !== 0) return null;
12304
+ const paths = tree.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
12305
+ return paths.length > 0 ? new Set(paths) : null;
12306
+ }
12307
+
12258
12308
  // src/scripts/check-core-ownership.ts
12259
12309
  var BOLD = "\x1B[1m";
12260
12310
  var DIM = "\x1B[2m";
@@ -12310,14 +12360,29 @@ async function runOwnershipCheck(argv) {
12310
12360
  reject: false
12311
12361
  });
12312
12362
  const branch = resolveBranch(process.env, gitBranch);
12363
+ const templateShippedPaths = staged ? null : await fetchTemplateShippedPaths(root);
12364
+ if (!staged && templateShippedPaths === null) {
12365
+ console.error(
12366
+ `${YELLOW}\u26A0 core ownership guard: could not fetch biffo-template's dev tree (offline, network failure, or timeout) \u2014 falling back to the manifest prefix list alone, which cannot tell an instance-only file from a real template file under the same prefix (#1912).${OFF}`
12367
+ );
12368
+ }
12313
12369
  const result = checkCoreOwnership({
12314
12370
  changedFiles,
12315
12371
  manifest: readCoreManifest(root),
12316
12372
  isInstance: true,
12317
12373
  branch,
12318
12374
  commitMessage,
12319
- warnOnly: readDivergenceConfig(root).warnOnly
12375
+ warnOnly: readDivergenceConfig(root).warnOnly,
12376
+ templateShippedPaths
12320
12377
  });
12378
+ if (result.knownOrphans.length > 0) {
12379
+ console.log(
12380
+ `${DIM}\u2139 ${result.knownOrphans.length} path(s) matched a template-owned prefix, but biffo-template's dev branch does not ship them \u2014 treated as instance-owned, no Core-Divergence trailer needed (#1912):${OFF}`
12381
+ );
12382
+ for (const path of result.knownOrphans) {
12383
+ console.log(` ${DIM}${path}${OFF}`);
12384
+ }
12385
+ }
12321
12386
  for (const { path, entry } of result.warned) {
12322
12387
  console.error(
12323
12388
  `${YELLOW}\u26A0 ${path}${OFF} ${DIM}\u2014 known divergence in ${entry.prefix} (${entry.upstream}); still conflicts at the next core upgrade.${OFF}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.304.1",
3
+ "version": "0.304.3",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/scripts/verify.sh CHANGED
@@ -75,6 +75,38 @@
75
75
 
76
76
  set -u
77
77
 
78
+ # Orphaned-scratch backstop (#1930). Every check below that creates a temp
79
+ # dir/file already cleans it up inline on its own pass/fail paths (an
80
+ # explicit `rm -rf`/`rm -f`, sometimes a per-function trap) -- that cleanup is
81
+ # left exactly as it is, as defensive belt-and-braces. What none of them cover
82
+ # is verify.sh itself dying abnormally (SIGTERM from a CI timeout, an
83
+ # interrupted local Ctrl-C, `kill`) partway through one of those functions,
84
+ # before its own inline cleanup line is reached. `gitleaks_tracked_only`'s
85
+ # `_gl_dir` has the largest such window: mirror-copy every tracked file, then
86
+ # a full `gitleaks detect` run, all between the `mktemp -d` and the `rm -rf`
87
+ # that only fires if the function returns normally.
88
+ #
89
+ # That gap is exactly what accumulated hundreds of stale `bt-verify`,
90
+ # `biffo-template-verify`, `dev-check-*` and `tmp.*` scratch dirs in /tmp with
91
+ # no eviction, driving it to 100% inode usage and breaking every `fleet.sh`
92
+ # command that writes a temp file.
93
+ #
94
+ # Idiom matches the other trap-using scripts in this directory
95
+ # (`js-dependency-audit.sh`, `shared-sync.sh`): accumulate every path this run
96
+ # creates in one variable, and let a single EXIT/HUP/INT/TERM trap sweep all
97
+ # of them however the script leaves. Declared here, at the very top, so the
98
+ # trap has a function to call no matter how early an abnormal exit happens.
99
+ _VERIFY_TMP_PATHS=""
100
+ _verify_track_tmp() {
101
+ _VERIFY_TMP_PATHS="$_VERIFY_TMP_PATHS $1"
102
+ }
103
+ _verify_cleanup_tmp() {
104
+ # shellcheck disable=SC2086 -- word-splitting is the point: one or more
105
+ # space-separated paths accumulated over the run.
106
+ [ -n "$_VERIFY_TMP_PATHS" ] && rm -rf $_VERIFY_TMP_PATHS
107
+ }
108
+ trap _verify_cleanup_tmp EXIT HUP INT TERM
109
+
78
110
  LIST=""
79
111
  [ "${1:-}" = "--list" ] && LIST=1
80
112
 
@@ -537,6 +569,7 @@ run_check() {
537
569
  return 0
538
570
  fi
539
571
  start=$(date +%s)
572
+ _verify_track_tmp "/tmp/biffo-verify.$$"
540
573
  if "$@" >"/tmp/biffo-verify.$$" 2>&1; then
541
574
  PASSED="$PASSED $name"
542
575
  LAST_CHECK_SECONDS=$(($(date +%s) - start))
@@ -651,6 +684,7 @@ run_check_js() {
651
684
  return 0
652
685
  fi
653
686
  start=$(date +%s)
687
+ _verify_track_tmp "/tmp/biffo-verify.$$"
654
688
  if "$@" >"/tmp/biffo-verify.$$" 2>&1; then
655
689
  PASSED="$PASSED $name"
656
690
  LAST_CHECK_SECONDS=$(($(date +%s) - start))
@@ -1027,6 +1061,7 @@ pg_xdist_ready() {
1027
1061
 
1028
1062
  pg_test_run() {
1029
1063
  _out="/tmp/biffo-verify-pg.$$"
1064
+ _verify_track_tmp "$_out"
1030
1065
  _pg_started=$(date +%s)
1031
1066
 
1032
1067
  if pg_xdist_ready "$1"; then
@@ -1287,6 +1322,7 @@ else
1287
1322
  echo pg_test_run "$_pg_dir" "$_pg_rel"
1288
1323
  else
1289
1324
  _pg_check_start=$(date +%s)
1325
+ _verify_track_tmp "/tmp/biffo-verify-pg-check.$$"
1290
1326
  # shellcheck disable=SC2086
1291
1327
  pg_test_run "$_pg_dir" "$_pg_rel" >"/tmp/biffo-verify-pg-check.$$" 2>&1
1292
1328
  _pg_check_rc=$?
@@ -1567,6 +1603,7 @@ fi
1567
1603
  # existing path-based `.gitleaks.toml` allowlist entries keep working unchanged.
1568
1604
  gitleaks_tracked_only() {
1569
1605
  _gl_dir=$(mktemp -d "${TMPDIR:-/tmp}/biffo-gitleaks.XXXXXX") || return 1
1606
+ _verify_track_tmp "$_gl_dir"
1570
1607
  _gl_root=$(git rev-parse --show-toplevel) || {
1571
1608
  rm -rf "$_gl_dir"
1572
1609
  return 1