@tested/cli 0.1.6 → 0.1.7

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/README.md CHANGED
@@ -25,7 +25,7 @@ CI uses the composite Action (`tested-hq/cli/action@main`). It installs `@tested
25
25
  ```yaml
26
26
  - uses: tested-hq/cli/action@main
27
27
  with:
28
- version: 0.1.6
28
+ version: 0.1.7
29
29
  token: ${{ secrets.TESTED_TOKEN }}
30
30
  ```
31
31
 
@@ -135,7 +135,7 @@ If `thresholds` is missing from `.tested.yaml`, `tested check` prints a notice o
135
135
  ```yaml
136
136
  - uses: tested-hq/cli/action@main
137
137
  with:
138
- version: 0.1.6
138
+ version: 0.1.7
139
139
  push: true
140
140
  pr-number: ${{ github.event.pull_request.number }}
141
141
  token: ${{ secrets.TESTED_TOKEN }}
package/dist/td.js CHANGED
@@ -631,6 +631,25 @@ import { resolve as resolve3 } from "path";
631
631
 
632
632
  // src/git.ts
633
633
  import { simpleGit as simpleGit2 } from "simple-git";
634
+
635
+ // src/git-ref.ts
636
+ var SAFE_GIT_REF_RE = /^[A-Za-z0-9_./@~^-]{1,256}$/;
637
+ function assertSafeGitRef(ref) {
638
+ if (!ref) {
639
+ throw new Error("git ref must not be empty");
640
+ }
641
+ if (ref.startsWith("-")) {
642
+ throw new Error(`git ref must not start with '-': ${ref}`);
643
+ }
644
+ if (!SAFE_GIT_REF_RE.test(ref)) {
645
+ throw new Error(
646
+ `git ref contains invalid characters or is too long (max 256): ${ref}`
647
+ );
648
+ }
649
+ return ref;
650
+ }
651
+
652
+ // src/git.ts
634
653
  async function openRepo(cwd) {
635
654
  const git = simpleGit2({ baseDir: cwd });
636
655
  const repoRoot = (await git.revparse(["--show-toplevel"])).trim();
@@ -669,6 +688,28 @@ async function resolveEffectiveBase(ctx, requested) {
669
688
  async function headSha(ctx) {
670
689
  return (await ctx.git.revparse(["HEAD"])).trim();
671
690
  }
691
+ async function fetchOriginRef(ctx, ref) {
692
+ const spec = ref.startsWith("origin/") ? ref.slice("origin/".length) : ref;
693
+ try {
694
+ assertSafeGitRef(spec);
695
+ } catch {
696
+ return false;
697
+ }
698
+ try {
699
+ await ctx.git.raw(["fetch", "--depth=1", "origin", spec]);
700
+ return true;
701
+ } catch {
702
+ return false;
703
+ }
704
+ }
705
+ async function resolveAfterFetch(ctx, ref) {
706
+ if (await tryRevparse(ctx, ref)) return ref;
707
+ if (!ref.startsWith("origin/")) {
708
+ const originRef = `origin/${ref}`;
709
+ if (await tryRevparse(ctx, originRef)) return originRef;
710
+ }
711
+ return tryRevparse(ctx, "FETCH_HEAD");
712
+ }
672
713
  async function unifiedDiff(ctx, base) {
673
714
  try {
674
715
  const mergeBase = (await ctx.git.raw(["merge-base", base, "HEAD"])).trim();
@@ -699,23 +740,6 @@ async function gitUserName(ctx) {
699
740
  }
700
741
  }
701
742
 
702
- // src/git-ref.ts
703
- var SAFE_GIT_REF_RE = /^[A-Za-z0-9_./@~^-]{1,256}$/;
704
- function assertSafeGitRef(ref) {
705
- if (!ref) {
706
- throw new Error("git ref must not be empty");
707
- }
708
- if (ref.startsWith("-")) {
709
- throw new Error(`git ref must not start with '-': ${ref}`);
710
- }
711
- if (!SAFE_GIT_REF_RE.test(ref)) {
712
- throw new Error(
713
- `git ref contains invalid characters or is too long (max 256): ${ref}`
714
- );
715
- }
716
- return ref;
717
- }
718
-
719
743
  // src/core/istanbul.ts
720
744
  import { readFile as readFile2 } from "fs/promises";
721
745
  import { isAbsolute, relative, resolve } from "path";
@@ -1170,6 +1194,125 @@ function sanitizeAuthor(name) {
1170
1194
  function toBranchName(ref) {
1171
1195
  return ref.replace(/^refs\/heads\//, "").replace(/^refs\/remotes\//, "").replace(/^origin\//, "");
1172
1196
  }
1197
+ var GITHUB_COMMIT_SHA_RE = /^[0-9a-f]{40,64}$/i;
1198
+ function githubApiToken(env) {
1199
+ const raw = env.GITHUB_TOKEN ?? env.GH_TOKEN;
1200
+ if (raw === void 0 || raw === "") return null;
1201
+ return raw;
1202
+ }
1203
+ function parseGitHubPullBase(parsed) {
1204
+ if (!parsed || typeof parsed !== "object" || !("base" in parsed)) return null;
1205
+ const base = parsed.base;
1206
+ if (!base || typeof base !== "object") return null;
1207
+ const ref = "ref" in base ? base.ref : void 0;
1208
+ const sha = "sha" in base ? base.sha : void 0;
1209
+ if (typeof ref !== "string" || typeof sha !== "string") return null;
1210
+ if (!GITHUB_COMMIT_SHA_RE.test(sha)) return null;
1211
+ try {
1212
+ return { ref: assertSafeGitRef(ref), sha: assertSafeGitRef(sha) };
1213
+ } catch {
1214
+ return null;
1215
+ }
1216
+ }
1217
+ async function fetchGitHubPullBase(opts) {
1218
+ if (!parseGitHubRepository(`${opts.owner}/${opts.name}`)) return null;
1219
+ if (!Number.isInteger(opts.prNumber) || opts.prNumber <= 0) return null;
1220
+ const fetchFn = opts.fetchFn ?? globalThis.fetch;
1221
+ const url = `https://api.github.com/repos/${opts.owner}/${opts.name}/pulls/${opts.prNumber}`;
1222
+ const headers = {
1223
+ Accept: "application/vnd.github+json",
1224
+ "X-GitHub-Api-Version": "2022-11-28",
1225
+ "User-Agent": "tested-cli"
1226
+ };
1227
+ const token = githubApiToken(opts.env ?? process.env);
1228
+ if (token) headers.Authorization = `Bearer ${token}`;
1229
+ let res;
1230
+ try {
1231
+ res = await fetchFn(url, { method: "GET", redirect: "manual", headers });
1232
+ } catch {
1233
+ return null;
1234
+ }
1235
+ if (res.status !== 200) return null;
1236
+ try {
1237
+ return parseGitHubPullBase(JSON.parse(await res.text()));
1238
+ } catch {
1239
+ return null;
1240
+ }
1241
+ }
1242
+ async function resolvePrPushBase(opts) {
1243
+ let requested;
1244
+ try {
1245
+ requested = assertSafeGitRef(opts.requested);
1246
+ } catch {
1247
+ return void 0;
1248
+ }
1249
+ if (await tryRevparse(opts.ctx, requested)) return requested;
1250
+ const branch = toBranchName(requested) || "main";
1251
+ const originRef = `origin/${branch}`;
1252
+ if (originRef !== requested && await tryRevparse(opts.ctx, originRef)) {
1253
+ return originRef;
1254
+ }
1255
+ let prBase = null;
1256
+ if (opts.owner && opts.name) {
1257
+ prBase = await fetchGitHubPullBase({
1258
+ owner: opts.owner,
1259
+ name: opts.name,
1260
+ prNumber: opts.prNumber,
1261
+ ...opts.fetchFn ? { fetchFn: opts.fetchFn } : {},
1262
+ ...opts.env ? { env: opts.env } : {}
1263
+ });
1264
+ }
1265
+ if (prBase && await tryRevparse(opts.ctx, prBase.sha)) return prBase.sha;
1266
+ const fetchTargets = [];
1267
+ if (prBase) {
1268
+ fetchTargets.push(prBase.sha, prBase.ref);
1269
+ }
1270
+ fetchTargets.push(branch);
1271
+ let announced = false;
1272
+ const seen = /* @__PURE__ */ new Set();
1273
+ for (const target of fetchTargets) {
1274
+ if (seen.has(target)) continue;
1275
+ seen.add(target);
1276
+ let spec;
1277
+ try {
1278
+ spec = assertSafeGitRef(target);
1279
+ } catch {
1280
+ continue;
1281
+ }
1282
+ if (!announced) {
1283
+ announced = true;
1284
+ opts.onProgress?.("fetching base\u2026");
1285
+ }
1286
+ if (!await fetchOriginRef(opts.ctx, spec)) continue;
1287
+ const resolved = await resolveAfterFetch(opts.ctx, spec);
1288
+ if (resolved) return resolved;
1289
+ if (prBase && await tryRevparse(opts.ctx, prBase.sha)) return prBase.sha;
1290
+ }
1291
+ return void 0;
1292
+ }
1293
+ async function peekRepoIdentity(opts) {
1294
+ let owner = opts.owner;
1295
+ let name = opts.name;
1296
+ if (!owner || !name) {
1297
+ const fromActions = parseGitHubRepository(opts.env.GITHUB_REPOSITORY);
1298
+ if (fromActions) {
1299
+ owner = owner ?? fromActions.owner;
1300
+ name = name ?? fromActions.name;
1301
+ }
1302
+ }
1303
+ if (!owner || !name) {
1304
+ try {
1305
+ const origin = await remoteUrl(opts.ctx, "origin");
1306
+ const parsed = parseGitHubRemote(origin);
1307
+ if (parsed) {
1308
+ owner = owner ?? parsed.owner;
1309
+ name = name ?? parsed.name;
1310
+ }
1311
+ } catch {
1312
+ }
1313
+ }
1314
+ return { owner: owner ?? null, name: name ?? null };
1315
+ }
1173
1316
  function buildIngestBody(input) {
1174
1317
  const baseRefName = toBranchName(input.baseRef);
1175
1318
  return {
@@ -1362,16 +1505,16 @@ function formatMissingTokenError(opts) {
1362
1505
  "or pass --token <token> (avoid on shared hosts: visible in ps)"
1363
1506
  ]);
1364
1507
  }
1365
- function formatPushError(status, message, code) {
1508
+ function formatPushError(status, message, code, identity) {
1366
1509
  if (status === 0) {
1367
1510
  return errorBlock(message);
1368
1511
  }
1369
1512
  const normalized = (code ?? message).toLowerCase();
1370
- if (normalized.includes("token_required") || normalized.includes("invalid token") || normalized.includes("unauthorized") || status === 401) {
1513
+ if (normalized.includes("token_required") || normalized.includes("invalid token") || normalized.includes("unauthorized") || normalized.includes("invalid credentials") || status === 401) {
1371
1514
  return errorBlock("ingest auth failed", [
1372
1515
  message,
1373
1516
  "",
1374
- ...tokenMintGuidance(),
1517
+ ...tokenMintGuidance(identity),
1375
1518
  "or --token"
1376
1519
  ]);
1377
1520
  }
@@ -1460,21 +1603,41 @@ async function executePush(cli, deps) {
1460
1603
  }
1461
1604
  const config = await loadConfigFn({ cwd: deps.cwd });
1462
1605
  const ctx = await openRepoFn(deps.cwd);
1463
- onProgress("computing diff\u2026");
1606
+ const peeked = await peekRepoIdentity({
1607
+ ...cli.owner !== void 0 ? { owner: cli.owner } : {},
1608
+ ...cli.name !== void 0 ? { name: cli.name } : {},
1609
+ env,
1610
+ ctx
1611
+ });
1464
1612
  let diff;
1465
1613
  try {
1614
+ let baseOverride = cli.base;
1615
+ if (baseOverride === void 0 && prNumber !== null) {
1616
+ const resolved = await resolvePrPushBase({
1617
+ ctx,
1618
+ requested: config.base,
1619
+ prNumber,
1620
+ ...peeked.owner != null ? { owner: peeked.owner } : {},
1621
+ ...peeked.name != null ? { name: peeked.name } : {},
1622
+ fetchFn,
1623
+ env,
1624
+ onProgress
1625
+ });
1626
+ if (resolved !== void 0) baseOverride = resolved;
1627
+ }
1628
+ onProgress("computing diff\u2026");
1466
1629
  diff = await computeDiffFn({
1467
1630
  cwd: deps.cwd,
1468
1631
  config,
1469
- ...cli.base !== void 0 ? { baseRef: cli.base } : {},
1632
+ ...baseOverride !== void 0 ? { baseRef: baseOverride } : {},
1470
1633
  ctx
1471
1634
  });
1472
1635
  } catch (err) {
1473
1636
  const message = err instanceof Error ? err.message : String(err);
1474
1637
  return { exitCode: 1, stdout: "", stderr: errorBlock(message) };
1475
1638
  }
1476
- let owner = cli.owner;
1477
- let name = cli.name;
1639
+ let owner = cli.owner ?? peeked.owner ?? void 0;
1640
+ let name = cli.name ?? peeked.name ?? void 0;
1478
1641
  if (!owner || !name) {
1479
1642
  const fromActions = parseGitHubRepository(env.GITHUB_REPOSITORY);
1480
1643
  if (fromActions) {
@@ -1562,7 +1725,10 @@ async function executePush(cli, deps) {
1562
1725
  return {
1563
1726
  exitCode: 1,
1564
1727
  stdout: "",
1565
- stderr: formatPushError(result.status, result.message, result.code)
1728
+ stderr: formatPushError(result.status, result.message, result.code, {
1729
+ owner,
1730
+ name
1731
+ })
1566
1732
  };
1567
1733
  }
1568
1734
  const formatted = formatPushSuccess(result.data, cli.json);
@@ -1961,7 +2127,7 @@ import pc3 from "picocolors";
1961
2127
  // package.json
1962
2128
  var package_default = {
1963
2129
  name: "@tested/cli",
1964
- version: "0.1.6",
2130
+ version: "0.1.7",
1965
2131
  description: "Coverage your agent can use. CLI for patch + project coverage with agent-readable JSON output.",
1966
2132
  license: "MIT",
1967
2133
  homepage: "https://tested.dev",
package/dist/tested.js CHANGED
@@ -631,6 +631,25 @@ import { resolve as resolve3 } from "path";
631
631
 
632
632
  // src/git.ts
633
633
  import { simpleGit as simpleGit2 } from "simple-git";
634
+
635
+ // src/git-ref.ts
636
+ var SAFE_GIT_REF_RE = /^[A-Za-z0-9_./@~^-]{1,256}$/;
637
+ function assertSafeGitRef(ref) {
638
+ if (!ref) {
639
+ throw new Error("git ref must not be empty");
640
+ }
641
+ if (ref.startsWith("-")) {
642
+ throw new Error(`git ref must not start with '-': ${ref}`);
643
+ }
644
+ if (!SAFE_GIT_REF_RE.test(ref)) {
645
+ throw new Error(
646
+ `git ref contains invalid characters or is too long (max 256): ${ref}`
647
+ );
648
+ }
649
+ return ref;
650
+ }
651
+
652
+ // src/git.ts
634
653
  async function openRepo(cwd) {
635
654
  const git = simpleGit2({ baseDir: cwd });
636
655
  const repoRoot = (await git.revparse(["--show-toplevel"])).trim();
@@ -669,6 +688,28 @@ async function resolveEffectiveBase(ctx, requested) {
669
688
  async function headSha(ctx) {
670
689
  return (await ctx.git.revparse(["HEAD"])).trim();
671
690
  }
691
+ async function fetchOriginRef(ctx, ref) {
692
+ const spec = ref.startsWith("origin/") ? ref.slice("origin/".length) : ref;
693
+ try {
694
+ assertSafeGitRef(spec);
695
+ } catch {
696
+ return false;
697
+ }
698
+ try {
699
+ await ctx.git.raw(["fetch", "--depth=1", "origin", spec]);
700
+ return true;
701
+ } catch {
702
+ return false;
703
+ }
704
+ }
705
+ async function resolveAfterFetch(ctx, ref) {
706
+ if (await tryRevparse(ctx, ref)) return ref;
707
+ if (!ref.startsWith("origin/")) {
708
+ const originRef = `origin/${ref}`;
709
+ if (await tryRevparse(ctx, originRef)) return originRef;
710
+ }
711
+ return tryRevparse(ctx, "FETCH_HEAD");
712
+ }
672
713
  async function unifiedDiff(ctx, base) {
673
714
  try {
674
715
  const mergeBase = (await ctx.git.raw(["merge-base", base, "HEAD"])).trim();
@@ -699,23 +740,6 @@ async function gitUserName(ctx) {
699
740
  }
700
741
  }
701
742
 
702
- // src/git-ref.ts
703
- var SAFE_GIT_REF_RE = /^[A-Za-z0-9_./@~^-]{1,256}$/;
704
- function assertSafeGitRef(ref) {
705
- if (!ref) {
706
- throw new Error("git ref must not be empty");
707
- }
708
- if (ref.startsWith("-")) {
709
- throw new Error(`git ref must not start with '-': ${ref}`);
710
- }
711
- if (!SAFE_GIT_REF_RE.test(ref)) {
712
- throw new Error(
713
- `git ref contains invalid characters or is too long (max 256): ${ref}`
714
- );
715
- }
716
- return ref;
717
- }
718
-
719
743
  // src/core/istanbul.ts
720
744
  import { readFile as readFile2 } from "fs/promises";
721
745
  import { isAbsolute, relative, resolve } from "path";
@@ -1170,6 +1194,125 @@ function sanitizeAuthor(name) {
1170
1194
  function toBranchName(ref) {
1171
1195
  return ref.replace(/^refs\/heads\//, "").replace(/^refs\/remotes\//, "").replace(/^origin\//, "");
1172
1196
  }
1197
+ var GITHUB_COMMIT_SHA_RE = /^[0-9a-f]{40,64}$/i;
1198
+ function githubApiToken(env) {
1199
+ const raw = env.GITHUB_TOKEN ?? env.GH_TOKEN;
1200
+ if (raw === void 0 || raw === "") return null;
1201
+ return raw;
1202
+ }
1203
+ function parseGitHubPullBase(parsed) {
1204
+ if (!parsed || typeof parsed !== "object" || !("base" in parsed)) return null;
1205
+ const base = parsed.base;
1206
+ if (!base || typeof base !== "object") return null;
1207
+ const ref = "ref" in base ? base.ref : void 0;
1208
+ const sha = "sha" in base ? base.sha : void 0;
1209
+ if (typeof ref !== "string" || typeof sha !== "string") return null;
1210
+ if (!GITHUB_COMMIT_SHA_RE.test(sha)) return null;
1211
+ try {
1212
+ return { ref: assertSafeGitRef(ref), sha: assertSafeGitRef(sha) };
1213
+ } catch {
1214
+ return null;
1215
+ }
1216
+ }
1217
+ async function fetchGitHubPullBase(opts) {
1218
+ if (!parseGitHubRepository(`${opts.owner}/${opts.name}`)) return null;
1219
+ if (!Number.isInteger(opts.prNumber) || opts.prNumber <= 0) return null;
1220
+ const fetchFn = opts.fetchFn ?? globalThis.fetch;
1221
+ const url = `https://api.github.com/repos/${opts.owner}/${opts.name}/pulls/${opts.prNumber}`;
1222
+ const headers = {
1223
+ Accept: "application/vnd.github+json",
1224
+ "X-GitHub-Api-Version": "2022-11-28",
1225
+ "User-Agent": "tested-cli"
1226
+ };
1227
+ const token = githubApiToken(opts.env ?? process.env);
1228
+ if (token) headers.Authorization = `Bearer ${token}`;
1229
+ let res;
1230
+ try {
1231
+ res = await fetchFn(url, { method: "GET", redirect: "manual", headers });
1232
+ } catch {
1233
+ return null;
1234
+ }
1235
+ if (res.status !== 200) return null;
1236
+ try {
1237
+ return parseGitHubPullBase(JSON.parse(await res.text()));
1238
+ } catch {
1239
+ return null;
1240
+ }
1241
+ }
1242
+ async function resolvePrPushBase(opts) {
1243
+ let requested;
1244
+ try {
1245
+ requested = assertSafeGitRef(opts.requested);
1246
+ } catch {
1247
+ return void 0;
1248
+ }
1249
+ if (await tryRevparse(opts.ctx, requested)) return requested;
1250
+ const branch = toBranchName(requested) || "main";
1251
+ const originRef = `origin/${branch}`;
1252
+ if (originRef !== requested && await tryRevparse(opts.ctx, originRef)) {
1253
+ return originRef;
1254
+ }
1255
+ let prBase = null;
1256
+ if (opts.owner && opts.name) {
1257
+ prBase = await fetchGitHubPullBase({
1258
+ owner: opts.owner,
1259
+ name: opts.name,
1260
+ prNumber: opts.prNumber,
1261
+ ...opts.fetchFn ? { fetchFn: opts.fetchFn } : {},
1262
+ ...opts.env ? { env: opts.env } : {}
1263
+ });
1264
+ }
1265
+ if (prBase && await tryRevparse(opts.ctx, prBase.sha)) return prBase.sha;
1266
+ const fetchTargets = [];
1267
+ if (prBase) {
1268
+ fetchTargets.push(prBase.sha, prBase.ref);
1269
+ }
1270
+ fetchTargets.push(branch);
1271
+ let announced = false;
1272
+ const seen = /* @__PURE__ */ new Set();
1273
+ for (const target of fetchTargets) {
1274
+ if (seen.has(target)) continue;
1275
+ seen.add(target);
1276
+ let spec;
1277
+ try {
1278
+ spec = assertSafeGitRef(target);
1279
+ } catch {
1280
+ continue;
1281
+ }
1282
+ if (!announced) {
1283
+ announced = true;
1284
+ opts.onProgress?.("fetching base\u2026");
1285
+ }
1286
+ if (!await fetchOriginRef(opts.ctx, spec)) continue;
1287
+ const resolved = await resolveAfterFetch(opts.ctx, spec);
1288
+ if (resolved) return resolved;
1289
+ if (prBase && await tryRevparse(opts.ctx, prBase.sha)) return prBase.sha;
1290
+ }
1291
+ return void 0;
1292
+ }
1293
+ async function peekRepoIdentity(opts) {
1294
+ let owner = opts.owner;
1295
+ let name = opts.name;
1296
+ if (!owner || !name) {
1297
+ const fromActions = parseGitHubRepository(opts.env.GITHUB_REPOSITORY);
1298
+ if (fromActions) {
1299
+ owner = owner ?? fromActions.owner;
1300
+ name = name ?? fromActions.name;
1301
+ }
1302
+ }
1303
+ if (!owner || !name) {
1304
+ try {
1305
+ const origin = await remoteUrl(opts.ctx, "origin");
1306
+ const parsed = parseGitHubRemote(origin);
1307
+ if (parsed) {
1308
+ owner = owner ?? parsed.owner;
1309
+ name = name ?? parsed.name;
1310
+ }
1311
+ } catch {
1312
+ }
1313
+ }
1314
+ return { owner: owner ?? null, name: name ?? null };
1315
+ }
1173
1316
  function buildIngestBody(input) {
1174
1317
  const baseRefName = toBranchName(input.baseRef);
1175
1318
  return {
@@ -1362,16 +1505,16 @@ function formatMissingTokenError(opts) {
1362
1505
  "or pass --token <token> (avoid on shared hosts: visible in ps)"
1363
1506
  ]);
1364
1507
  }
1365
- function formatPushError(status, message, code) {
1508
+ function formatPushError(status, message, code, identity) {
1366
1509
  if (status === 0) {
1367
1510
  return errorBlock(message);
1368
1511
  }
1369
1512
  const normalized = (code ?? message).toLowerCase();
1370
- if (normalized.includes("token_required") || normalized.includes("invalid token") || normalized.includes("unauthorized") || status === 401) {
1513
+ if (normalized.includes("token_required") || normalized.includes("invalid token") || normalized.includes("unauthorized") || normalized.includes("invalid credentials") || status === 401) {
1371
1514
  return errorBlock("ingest auth failed", [
1372
1515
  message,
1373
1516
  "",
1374
- ...tokenMintGuidance(),
1517
+ ...tokenMintGuidance(identity),
1375
1518
  "or --token"
1376
1519
  ]);
1377
1520
  }
@@ -1460,21 +1603,41 @@ async function executePush(cli, deps) {
1460
1603
  }
1461
1604
  const config = await loadConfigFn({ cwd: deps.cwd });
1462
1605
  const ctx = await openRepoFn(deps.cwd);
1463
- onProgress("computing diff\u2026");
1606
+ const peeked = await peekRepoIdentity({
1607
+ ...cli.owner !== void 0 ? { owner: cli.owner } : {},
1608
+ ...cli.name !== void 0 ? { name: cli.name } : {},
1609
+ env,
1610
+ ctx
1611
+ });
1464
1612
  let diff;
1465
1613
  try {
1614
+ let baseOverride = cli.base;
1615
+ if (baseOverride === void 0 && prNumber !== null) {
1616
+ const resolved = await resolvePrPushBase({
1617
+ ctx,
1618
+ requested: config.base,
1619
+ prNumber,
1620
+ ...peeked.owner != null ? { owner: peeked.owner } : {},
1621
+ ...peeked.name != null ? { name: peeked.name } : {},
1622
+ fetchFn,
1623
+ env,
1624
+ onProgress
1625
+ });
1626
+ if (resolved !== void 0) baseOverride = resolved;
1627
+ }
1628
+ onProgress("computing diff\u2026");
1466
1629
  diff = await computeDiffFn({
1467
1630
  cwd: deps.cwd,
1468
1631
  config,
1469
- ...cli.base !== void 0 ? { baseRef: cli.base } : {},
1632
+ ...baseOverride !== void 0 ? { baseRef: baseOverride } : {},
1470
1633
  ctx
1471
1634
  });
1472
1635
  } catch (err) {
1473
1636
  const message = err instanceof Error ? err.message : String(err);
1474
1637
  return { exitCode: 1, stdout: "", stderr: errorBlock(message) };
1475
1638
  }
1476
- let owner = cli.owner;
1477
- let name = cli.name;
1639
+ let owner = cli.owner ?? peeked.owner ?? void 0;
1640
+ let name = cli.name ?? peeked.name ?? void 0;
1478
1641
  if (!owner || !name) {
1479
1642
  const fromActions = parseGitHubRepository(env.GITHUB_REPOSITORY);
1480
1643
  if (fromActions) {
@@ -1562,7 +1725,10 @@ async function executePush(cli, deps) {
1562
1725
  return {
1563
1726
  exitCode: 1,
1564
1727
  stdout: "",
1565
- stderr: formatPushError(result.status, result.message, result.code)
1728
+ stderr: formatPushError(result.status, result.message, result.code, {
1729
+ owner,
1730
+ name
1731
+ })
1566
1732
  };
1567
1733
  }
1568
1734
  const formatted = formatPushSuccess(result.data, cli.json);
@@ -1961,7 +2127,7 @@ import pc3 from "picocolors";
1961
2127
  // package.json
1962
2128
  var package_default = {
1963
2129
  name: "@tested/cli",
1964
- version: "0.1.6",
2130
+ version: "0.1.7",
1965
2131
  description: "Coverage your agent can use. CLI for patch + project coverage with agent-readable JSON output.",
1966
2132
  license: "MIT",
1967
2133
  homepage: "https://tested.dev",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tested/cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Coverage your agent can use. CLI for patch + project coverage with agent-readable JSON output.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://tested.dev",