@rtrentjones/greenlight 0.2.21 → 0.2.22

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/bin.js +47 -7
  2. package/package.json +5 -5
package/dist/bin.js CHANGED
@@ -443,7 +443,7 @@ function tokensForTool(tool) {
443
443
  }
444
444
 
445
445
  // src/version.ts
446
- var MODULE_REF = "v0.2.21";
446
+ var MODULE_REF = "v0.2.22";
447
447
  var MODULE_SOURCE_BASE = "git::https://github.com/RTrentJones/greenlight.git//infra/modules";
448
448
  function moduleSource(module, ref = MODULE_REF) {
449
449
  return `${MODULE_SOURCE_BASE}/${module}?ref=${ref}`;
@@ -2607,8 +2607,21 @@ function git(repoDir, args) {
2607
2607
  function gitOut(repoDir, args) {
2608
2608
  return execFileSync5("git", args, { cwd: repoDir, encoding: "utf8" }).trim();
2609
2609
  }
2610
+ function tryRev(repoDir, ref) {
2611
+ try {
2612
+ return gitOut(repoDir, ["rev-parse", "--verify", "--quiet", ref]);
2613
+ } catch {
2614
+ return null;
2615
+ }
2616
+ }
2617
+ function fetchRefs(repoDir, branches) {
2618
+ try {
2619
+ git(repoDir, ["fetch", "--no-tags", "origin", ...branches]);
2620
+ } catch {
2621
+ }
2622
+ }
2610
2623
  function resolveRef(repoDir, branch) {
2611
- for (const ref of [branch, `origin/${branch}`]) {
2624
+ for (const ref of [`origin/${branch}`, branch]) {
2612
2625
  try {
2613
2626
  git(repoDir, ["rev-parse", "--verify", "--quiet", ref]);
2614
2627
  return ref;
@@ -2617,19 +2630,35 @@ function resolveRef(repoDir, branch) {
2617
2630
  }
2618
2631
  return null;
2619
2632
  }
2633
+ function staleLocalWarnings(repoDir, branches) {
2634
+ const warnings = [];
2635
+ for (const branch of branches) {
2636
+ const local = tryRev(repoDir, branch);
2637
+ const origin = tryRev(repoDir, `origin/${branch}`);
2638
+ if (local && origin && local !== origin) {
2639
+ warnings.push(
2640
+ `local "${branch}" (${local.slice(0, 7)}) differs from origin/${branch} (${origin.slice(0, 7)}) \u2014 promoting the origin (verified) state. Sync with \`git fetch && git branch -f ${branch} origin/${branch}\`.`
2641
+ );
2642
+ }
2643
+ }
2644
+ return warnings;
2645
+ }
2620
2646
  function canPromote(repoDir, from = "develop", to = "main") {
2647
+ fetchRefs(repoDir, [from, to]);
2621
2648
  const fromRef = resolveRef(repoDir, from);
2622
2649
  const toRef = resolveRef(repoDir, to);
2623
2650
  if (!fromRef || !toRef) {
2624
2651
  return { canPromote: false, reason: `branch "${from}" or "${to}" not found in ${repoDir}` };
2625
2652
  }
2653
+ const warnings = staleLocalWarnings(repoDir, [from, to]);
2626
2654
  try {
2627
2655
  git(repoDir, ["merge-base", "--is-ancestor", toRef, fromRef]);
2628
- return { canPromote: true, reason: `"${to}" can fast-forward to "${from}"` };
2656
+ return { canPromote: true, reason: `"${to}" can fast-forward to "${from}"`, warnings };
2629
2657
  } catch {
2630
2658
  return {
2631
2659
  canPromote: false,
2632
- reason: `"${to}" has diverged from "${from}" \u2014 fast-forward refused. Reconcile first (rebase "${from}" onto "${to}", or merge "${to}" into "${from}") before promoting.`
2660
+ reason: `"${to}" has diverged from "${from}" \u2014 fast-forward refused. Reconcile first (rebase "${from}" onto "${to}", or merge "${to}" into "${from}") before promoting.`,
2661
+ warnings
2633
2662
  };
2634
2663
  }
2635
2664
  }
@@ -2637,7 +2666,10 @@ function promote(repoDir, opts = {}) {
2637
2666
  const from = opts.from ?? "develop";
2638
2667
  const to = opts.to ?? "main";
2639
2668
  const check = canPromote(repoDir, from, to);
2640
- if (!check.canPromote) return { promoted: false, from, to, reason: check.reason };
2669
+ if (!check.canPromote) {
2670
+ return { promoted: false, from, to, reason: check.reason, warnings: check.warnings };
2671
+ }
2672
+ const warnings = check.warnings;
2641
2673
  const fromRef = resolveRef(repoDir, from);
2642
2674
  const fromCommit = gitOut(repoDir, ["rev-parse", fromRef]);
2643
2675
  const current = gitOut(repoDir, ["rev-parse", "--abbrev-ref", "HEAD"]);
@@ -2649,14 +2681,20 @@ function promote(repoDir, opts = {}) {
2649
2681
  } catch {
2650
2682
  }
2651
2683
  }
2652
- return { promoted: true, from, to, reason: `"${to}" fast-forwarded to "${from}" and pushed` };
2684
+ return {
2685
+ promoted: true,
2686
+ from,
2687
+ to,
2688
+ reason: `"${to}" fast-forwarded to "${from}" and pushed`,
2689
+ warnings
2690
+ };
2653
2691
  }
2654
2692
  if (current === to) {
2655
2693
  git(repoDir, ["merge", "--ff-only", fromRef]);
2656
2694
  } else {
2657
2695
  git(repoDir, ["update-ref", `refs/heads/${to}`, fromCommit]);
2658
2696
  }
2659
- return { promoted: true, from, to, reason: `"${to}" fast-forwarded to "${from}"` };
2697
+ return { promoted: true, from, to, reason: `"${to}" fast-forwarded to "${from}"`, warnings };
2660
2698
  }
2661
2699
 
2662
2700
  // src/commands/promote.ts
@@ -2666,11 +2704,13 @@ async function promoteCommand(args) {
2666
2704
  const cwd = process.cwd();
2667
2705
  if (!perform) {
2668
2706
  const check = canPromote(cwd);
2707
+ for (const w of check.warnings ?? []) console.warn(`\u26A0 ${w}`);
2669
2708
  console.log(`${check.canPromote ? "\u2714" : "\u2718"} ${check.reason}`);
2670
2709
  if (check.canPromote) console.log("\nEligible. Re-run with --perform (and --push) to promote.");
2671
2710
  process.exit(check.canPromote ? 0 : 1);
2672
2711
  }
2673
2712
  const result = promote(cwd, { push });
2713
+ for (const w of result.warnings ?? []) console.warn(`\u26A0 ${w}`);
2674
2714
  console.log(`${result.promoted ? "\u2714" : "\u2718"} ${result.reason}`);
2675
2715
  process.exit(result.promoted ? 0 : 1);
2676
2716
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtrentjones/greenlight",
3
- "version": "0.2.21",
3
+ "version": "0.2.22",
4
4
  "description": "Greenlight CLI — setup and lifecycle for the harness.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -31,10 +31,10 @@
31
31
  "@anthropic-ai/sdk": "^0.69.0"
32
32
  },
33
33
  "devDependencies": {
34
- "@rtrentjones/greenlight-adapters": "0.2.4",
35
- "@rtrentjones/greenlight-shared": "0.2.4",
36
- "@rtrentjones/greenlight-verify": "0.2.4",
37
- "@rtrentjones/greenlight-loop": "0.2.4"
34
+ "@rtrentjones/greenlight-adapters": "0.2.22",
35
+ "@rtrentjones/greenlight-verify": "0.2.22",
36
+ "@rtrentjones/greenlight-loop": "0.2.22",
37
+ "@rtrentjones/greenlight-shared": "0.2.22"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "node scripts/copy-assets.mjs && tsup",