@biffo/cli 0.167.0 → 0.167.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.
Files changed (2) hide show
  1. package/dist/index.js +41 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -948,6 +948,27 @@ var GitAdapter = class {
948
948
  async fetchPrune(cwd, remote = "origin") {
949
949
  await execa2("git", ["fetch", "--quiet", "--prune", remote], { cwd, reject: false });
950
950
  }
951
+ /**
952
+ * Is `cwd` the primary checkout, rather than a linked worktree?
953
+ *
954
+ * The distinction decides whether being off the integration branch is a
955
+ * defect or the mandated state: AGENTS.md §1 requires all work to happen in a
956
+ * worktree on its own branch, while §2 requires the primary to stay on `dev`.
957
+ * Reporting the former as a problem is a false positive in the one place
958
+ * everybody works.
959
+ *
960
+ * A linked worktree's git dir points inside `.git/worktrees/<name>`, while the
961
+ * common dir is the shared `.git`. They are equal only in the primary.
962
+ */
963
+ async isPrimaryWorktree(cwd) {
964
+ const opts = { cwd, reject: false };
965
+ const [dir, common] = await Promise.all([
966
+ execa2("git", ["rev-parse", "--absolute-git-dir"], opts),
967
+ execa2("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], opts)
968
+ ]);
969
+ if (dir.exitCode !== 0 || common.exitCode !== 0) return true;
970
+ return dir.stdout.trim() === common.stdout.trim();
971
+ }
951
972
  /**
952
973
  * Worktrees other than the primary, with the branch each is on (#797).
953
974
  *
@@ -9131,7 +9152,7 @@ function checkCheckoutCurrency(facts) {
9131
9152
  });
9132
9153
  return findings;
9133
9154
  }
9134
- if (facts.currentBranch !== facts.integrationBranch) {
9155
+ if (facts.isPrimary && facts.currentBranch !== facts.integrationBranch) {
9135
9156
  findings.push({
9136
9157
  check: "checkout-off-integration",
9137
9158
  severity: "error",
@@ -9139,12 +9160,24 @@ function checkCheckoutCurrency(facts) {
9139
9160
  remedy: `git switch ${facts.integrationBranch} && git pull (do the work in a worktree instead)`
9140
9161
  });
9141
9162
  }
9163
+ if (facts.isPrimary && facts.isDirty) {
9164
+ findings.push({
9165
+ check: "checkout-dirty",
9166
+ severity: "warn",
9167
+ detail: "The primary checkout has uncommitted changes, so what it contains is neither the integration branch nor anything reviewed. Editing the primary directly is what AGENTS.md \xA71 exists to prevent; work belongs in a worktree.",
9168
+ remedy: 'git stash push -m "<what this is>" or commit it on a branch, then work in a worktree'
9169
+ });
9170
+ }
9142
9171
  if (facts.hasUpstream && facts.behind > 0) {
9143
9172
  const diverged = facts.ahead > 0 ? `, and ${String(facts.ahead)} ahead (diverged)` : "";
9173
+ const where = facts.isPrimary ? "The primary checkout" : "This worktree";
9144
9174
  findings.push({
9145
9175
  check: "checkout-behind",
9146
- severity: "error",
9147
- detail: `The primary checkout is ${String(facts.behind)} commit(s) behind its upstream${diverged}. Every file read from it may be stale, including the ones that look like authoritative state.`,
9176
+ // In a worktree, behind-its-own-upstream means someone else pushed to the
9177
+ // branch worth knowing, but not a reason to distrust everything read
9178
+ // from it the way a stale primary is.
9179
+ severity: facts.isPrimary ? "error" : "warn",
9180
+ detail: `${where} is ${String(facts.behind)} commit(s) behind its upstream${diverged}. Every file read from it may be stale, including the ones that look like authoritative state.`,
9148
9181
  remedy: "git pull --ff-only"
9149
9182
  });
9150
9183
  }
@@ -9153,6 +9186,7 @@ function checkCheckoutCurrency(facts) {
9153
9186
  function checkCoreVersionCurrency(facts) {
9154
9187
  if (facts.localCoreVersion === null || facts.remoteCoreVersion === null) return [];
9155
9188
  if (facts.localCoreVersion === facts.remoteCoreVersion) return [];
9189
+ if (!facts.isPrimary) return [];
9156
9190
  return [
9157
9191
  {
9158
9192
  check: "core-version-stale",
@@ -9247,6 +9281,8 @@ async function runDoctor(options, deps = { git: new GitAdapter() }) {
9247
9281
  }
9248
9282
  if (options.fetch) await git.fetchPrune(options.cwd);
9249
9283
  const currentBranch = await git.currentBranch(options.cwd);
9284
+ const isPrimary = await git.isPrimaryWorktree(options.cwd);
9285
+ const isDirty = await git.hasUncommittedChanges(options.cwd);
9250
9286
  const { ahead, behind, hasUpstream } = await git.aheadBehind(options.cwd);
9251
9287
  const branches = await git.listBranchRefs(options.cwd);
9252
9288
  const worktreePaths = await git.listWorktrees(options.cwd);
@@ -9258,10 +9294,12 @@ async function runDoctor(options, deps = { git: new GitAdapter() }) {
9258
9294
  );
9259
9295
  const facts = {
9260
9296
  currentBranch,
9297
+ isPrimary,
9261
9298
  integrationBranch: INTEGRATION_BRANCH,
9262
9299
  ahead,
9263
9300
  behind,
9264
9301
  hasUpstream,
9302
+ isDirty,
9265
9303
  localCoreVersion: readLocalCoreVersion(options.cwd),
9266
9304
  remoteCoreVersion: parseCoreRecord(
9267
9305
  await git.showFileAtRef(options.cwd, `origin/${INTEGRATION_BRANCH}`, INSTANCE_CORE_FILE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.167.0",
3
+ "version": "0.167.1",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",