@great-arrow/cli 0.1.49 → 0.1.50

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 +58 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9399,7 +9399,7 @@ function isNodeError(value) {
9399
9399
 
9400
9400
  // src/lib/version.ts
9401
9401
  var CLI_PACKAGE_NAME = "@great-arrow/cli";
9402
- var CLI_VERSION = "0.1.49";
9402
+ var CLI_VERSION = "0.1.50";
9403
9403
  var GAD_INSTALL_VERSION = "2026.08.08";
9404
9404
  var GAD_INSTALL_MIN_VERSION = "2026.06.22";
9405
9405
  var GAD_INSTALL_HEADER = "X-GAD-Install-Version";
@@ -10543,12 +10543,13 @@ var EXIT_SESSION_EXPIRED = 2;
10543
10543
  var EXIT_NOT_OAUTH = 3;
10544
10544
  function authCommand() {
10545
10545
  const cmd = new Command("auth").description("Authentication helpers");
10546
- cmd.command("token").description("Print a fresh OAuth access token, refreshing it if needed").option("--json", "Output {accessToken, accessExpiresAt, apiUrl} as JSON").action(async (options) => {
10546
+ cmd.command("token").description("Print a fresh OAuth access token, refreshing it if needed").option("--json", "Output {accessToken, accessExpiresAt, apiUrl} as JSON").action(async (options, actionCommand) => {
10547
10547
  try {
10548
10548
  const t = await getFreshOAuthAccessToken();
10549
10549
  writeCliLocator();
10550
+ const jsonOutput = options.json || actionCommand.optsWithGlobals().json;
10550
10551
  process.stdout.write(
10551
- options.json ? `${JSON.stringify(t)}
10552
+ jsonOutput ? `${JSON.stringify(t)}
10552
10553
  ` : `${t.accessToken}
10553
10554
  `
10554
10555
  );
@@ -11958,6 +11959,29 @@ import { readFileSync } from "node:fs";
11958
11959
 
11959
11960
  // src/lib/work-status.ts
11960
11961
  import { execFile as execFile2, execFileSync as execFileSync2 } from "node:child_process";
11962
+
11963
+ // ../../src/lib/work-risk/push-state.ts
11964
+ var REMOTE_BRANCH_REF_PREFIX = "refs/remotes/origin/";
11965
+ var REMOTE_BRANCH_TIPS_FORMAT = "%(refname)%09%(objectname)";
11966
+ function parseRemoteBranchTips(raw) {
11967
+ const tips = /* @__PURE__ */ new Map();
11968
+ for (const line of raw.split("\n")) {
11969
+ const [refname, sha] = line.split(" ");
11970
+ if (!refname?.startsWith(REMOTE_BRANCH_REF_PREFIX) || !sha) continue;
11971
+ const branch = refname.slice(REMOTE_BRANCH_REF_PREFIX.length);
11972
+ if (!branch || branch === "HEAD") continue;
11973
+ tips.set(branch, sha.trim());
11974
+ }
11975
+ return tips;
11976
+ }
11977
+ function remoteHasHead(branch, head, tips, isAncestor2) {
11978
+ const tip = tips.get(branch);
11979
+ if (!tip) return false;
11980
+ if (tip === head) return true;
11981
+ return isAncestor2(head, tip);
11982
+ }
11983
+
11984
+ // src/lib/work-status.ts
11961
11985
  var LOCAL_COMMAND_TIMEOUT_MS = 2e4;
11962
11986
  function run(command, args, cwd) {
11963
11987
  try {
@@ -12070,9 +12094,31 @@ function auditLocalBranches(root) {
12070
12094
  root
12071
12095
  ).split("\n").filter(Boolean)
12072
12096
  );
12097
+ const tipsResult = git(
12098
+ [
12099
+ "for-each-ref",
12100
+ `--format=${REMOTE_BRANCH_TIPS_FORMAT}`,
12101
+ "refs/remotes/origin"
12102
+ ],
12103
+ root
12104
+ );
12105
+ const tips = parseRemoteBranchTips(
12106
+ tipsResult.status === 0 ? tipsResult.stdout : ""
12107
+ );
12073
12108
  return raw.split("\n").filter(Boolean).flatMap((line) => {
12074
12109
  const parsed = parseLocalBranchLine(line, exact, unmerged);
12075
- return parsed ? [parsed] : [];
12110
+ if (!parsed) return [];
12111
+ return [
12112
+ {
12113
+ ...parsed,
12114
+ remoteHasHead: remoteHasHead(
12115
+ parsed.branch,
12116
+ parsed.head,
12117
+ tips,
12118
+ (ancestor, descendant) => isAncestor(ancestor, descendant, root)
12119
+ )
12120
+ }
12121
+ ];
12076
12122
  });
12077
12123
  }
12078
12124
  function parseLocalBranchLine(line, exact, unmerged) {
@@ -12131,7 +12177,7 @@ function classifyWorktree(audit) {
12131
12177
  if (audit.path.includes("/.claude/worktrees/")) return "agent-harness";
12132
12178
  if (audit.mergedToMain) return "cleanup-ready";
12133
12179
  if (audit.upstreamGone) return "upstream-gone";
12134
- if (!audit.upstream) return "local-rescue";
12180
+ if (!audit.remoteHasHead) return "local-rescue";
12135
12181
  return "active-unmerged";
12136
12182
  }
12137
12183
  async function auditWorktrees(root, localBranches) {
@@ -12159,6 +12205,7 @@ async function auditWorktrees(root, localBranches) {
12159
12205
  mergedToMain: branch?.mergedToMain ?? false,
12160
12206
  upstream: branch?.upstream ?? null,
12161
12207
  upstreamGone: branch?.upstreamGone ?? false,
12208
+ remoteHasHead: branch?.remoteHasHead ?? false,
12162
12209
  behindMain: branch?.behindMain ?? 0,
12163
12210
  aheadMain: branch?.aheadMain ?? 0,
12164
12211
  countsExact: branch?.countsExact ?? false
@@ -12178,6 +12225,7 @@ function auditDetachedLocalBranches(localBranches, checkedOutBranches) {
12178
12225
  countsExact,
12179
12226
  upstream,
12180
12227
  upstreamGone,
12228
+ remoteHasHead: remoteHasHead2,
12181
12229
  committedAt
12182
12230
  }) => ({
12183
12231
  branch,
@@ -12186,12 +12234,13 @@ function auditDetachedLocalBranches(localBranches, checkedOutBranches) {
12186
12234
  behindMain,
12187
12235
  aheadMain,
12188
12236
  countsExact,
12189
- // `upstream` is what separates "never left this disk" from "pushed,
12190
- // just has no PR yet" — the single bit that decides whether work can
12191
- // actually be lost. It was computed and then dropped here, so the
12192
- // server classified both as one undifferentiated "stranded".
12237
+ // `remoteHasHead` is what separates "never left this disk" from
12238
+ // "pushed, just has no PR yet" — the single bit that decides whether
12239
+ // work can actually be lost. `upstream` alone cannot: a task branch
12240
+ // could carry origin/main as its upstream without ever being pushed.
12193
12241
  upstream,
12194
12242
  upstreamGone,
12243
+ remoteHasHead: remoteHasHead2,
12195
12244
  // Without this the grace window read `ageMs = Infinity` for every
12196
12245
  // branch, so a branch was "stranded" from its first second.
12197
12246
  committedAt
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@great-arrow/cli",
3
- "version": "0.1.49",
3
+ "version": "0.1.50",
4
4
  "description": "GreatArrow.ai CLI tool",
5
5
  "type": "module",
6
6
  "bin": {