@tablation/crew 0.19.0 → 0.19.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/cli.js +54 -9
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2735,7 +2735,20 @@ function patchIdOf(cwd, from, to) {
2735
2735
  return null;
2736
2736
  }
2737
2737
  }
2738
+ var BRANCH_TIP_TRAILER = "Branch-tip";
2739
+ function findSquashByBranchTip(cwd, key, branch, range) {
2740
+ const tip = gitOk(cwd, ["rev-parse", "--verify", "-q", `${branch}^{commit}`]);
2741
+ if (!tip) return null;
2742
+ const wanted = `${BRANCH_TIP_TRAILER}: ${tip}`;
2743
+ for (const sha of keyCommitsInRange(cwd, key, range)) {
2744
+ const body = gitOk(cwd, ["show", "-s", "--format=%B", sha]) ?? "";
2745
+ if (body.split("\n").some((l) => l.trim() === wanted)) return sha;
2746
+ }
2747
+ return null;
2748
+ }
2738
2749
  function findSquashOfBranch(cwd, key, branch, base, range) {
2750
+ const byTip = findSquashByBranchTip(cwd, key, branch, range);
2751
+ if (byTip) return byTip;
2739
2752
  const candidates = keyCommitsInRange(cwd, key, range);
2740
2753
  if (candidates.length === 0) return null;
2741
2754
  const mb = gitOk(cwd, ["merge-base", base, branch]);
@@ -6478,14 +6491,9 @@ function planMerge(cwd, tickets, contract, lastReleased, branchFor = (t) => bran
6478
6491
  skipReason: "never-built"
6479
6492
  };
6480
6493
  }
6481
- const squash = findSquashOfBranch(
6482
- cwd,
6483
- referenceKeys(ticket),
6484
- branch,
6485
- base,
6486
- lastReleased ? `${lastReleased}..${base}` : base
6487
- );
6494
+ const squash = findSquashOfBranch(cwd, referenceKeys(ticket), branch, base, base);
6488
6495
  if (squash) {
6496
+ const released = !!lastReleased && isAncestor(cwd, squash, lastReleased);
6489
6497
  return {
6490
6498
  ticket,
6491
6499
  branch,
@@ -6493,7 +6501,7 @@ function planMerge(cwd, tickets, contract, lastReleased, branchFor = (t) => bran
6493
6501
  usedFallback: false,
6494
6502
  bump: "patch",
6495
6503
  majorRequested: false,
6496
- skipReason: "already-merged",
6504
+ skipReason: released ? "already-released" : "already-merged",
6497
6505
  mergedSha: squash
6498
6506
  };
6499
6507
  }
@@ -6511,6 +6519,20 @@ function planMerge(cwd, tickets, contract, lastReleased, branchFor = (t) => bran
6511
6519
  };
6512
6520
  });
6513
6521
  }
6522
+ function planReleasedBranches(cwd, tickets, contract, branchFor, base = "main", tagPattern = "v*") {
6523
+ const eligible = /* @__PURE__ */ new Set([contract.statuses.building, contract.statuses.needsHuman]);
6524
+ const out = [];
6525
+ for (const ticket of tickets) {
6526
+ if (!eligible.has(ticket.status)) continue;
6527
+ const branch = branchFor(ticket);
6528
+ if (!branch) continue;
6529
+ const sha = findSquashByBranchTip(cwd, referenceKeys(ticket), branch, base);
6530
+ if (!sha) continue;
6531
+ const tag = firstReleaseTagContaining(cwd, sha, tagPattern);
6532
+ if (tag) out.push({ ticket, sha, tag });
6533
+ }
6534
+ return out;
6535
+ }
6514
6536
  function requestedBump(bodies) {
6515
6537
  const asks = [...bodies.matchAll(BUMP_LINE)].map((m) => m[1].toLowerCase());
6516
6538
  const majorRequested = asks.includes("major");
@@ -6973,9 +6995,13 @@ function mergeOne(o, c) {
6973
6995
  );
6974
6996
  return "noop";
6975
6997
  }
6998
+ const tip = gitOk(o.cwd, ["rev-parse", "--verify", "-q", `${c.branch}^{commit}`]);
6999
+ const trailer = tip ? `
7000
+
7001
+ ${BRANCH_TIP_TRAILER}: ${tip}` : "";
6976
7002
  git(o.cwd, ["commit", "-m", `${subject}
6977
7003
 
6978
- Closes ${c.ticket.issue_id}.`]);
7004
+ Closes ${c.ticket.issue_id}.${trailer}`]);
6979
7005
  const sha = headSha(o.cwd);
6980
7006
  o.emit.emit(`merged ${c.branch}`, { ticket: c.ticket.issue_id });
6981
7007
  return { applied: true, sha };
@@ -10990,6 +11016,25 @@ ${changed2.map((c) => ` - ${c}
10990
11016
  target.dir
10991
11017
  );
10992
11018
  }
11019
+ for (const r of planReleasedBranches(
11020
+ target.dir,
11021
+ tickets,
11022
+ tracker.contract,
11023
+ (t) => locateBranchForTicket(target.dir, repo, t)?.branch ?? null,
11024
+ repo.branch.base,
11025
+ repo.release.tagPattern ?? "v*"
11026
+ )) {
11027
+ remit.enter("reconcile");
11028
+ await applyStamp(
11029
+ tracker,
11030
+ [{ ticket: r.ticket, reason: `branch already released in ${r.tag}`, sha: r.sha }],
11031
+ r.tag.replace(/^v/, ""),
11032
+ tracker.contract,
11033
+ remit,
11034
+ dryRun,
11035
+ target.dir
11036
+ );
11037
+ }
10993
11038
  if (outcome.gateRed && !dryRun) {
10994
11039
  try {
10995
11040
  const g = outcome.gateRed;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tablation/crew",
3
- "version": "0.19.0",
3
+ "version": "0.19.1",
4
4
  "description": "A standing team of headless agents that picks work off a Tablation board, does it on a machine you control, and reports back.",
5
5
  "type": "module",
6
6
  "license": "MIT",