@tested/cli 0.1.0 → 0.1.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.
package/README.md CHANGED
@@ -12,7 +12,7 @@ Node >= 20.19.
12
12
  ```bash
13
13
  pnpm add -D @tested/cli
14
14
  # or
15
- npx @tested/cli
15
+ npx @tested/cli # runs `tested` (`td` is the same CLI after install)
16
16
  ```
17
17
 
18
18
  CI uses the composite Action (`tested-hq/cli/action@main`). The Action clones this repo and builds the CLI.
@@ -110,6 +110,18 @@ $ echo $?
110
110
  1
111
111
  ```
112
112
 
113
+ If the patch has no executable lines in scope (tests-only, comments-only, docs-only, or ignored files), the patch gate is **skipped** — not reported as 0% coverage. Project still applies.
114
+
115
+ ```
116
+ $ tested check
117
+ tested.dev — coverage gate [PASS]
118
+
119
+ Patch - no executable lines in the patch [SKIP]
120
+ Project 64.1% (threshold 60) [PASS]
121
+
122
+ No executable lines in the patch — patch gate skipped. Project threshold met.
123
+ ```
124
+
113
125
  If `thresholds` is missing from `.tested.yaml`, `tested check` prints a notice on stderr and exits 0 — configs that haven't opted in stay green.
114
126
 
115
127
  ### GitHub Actions
package/dist/td.js CHANGED
@@ -44,6 +44,8 @@ function badge(kind) {
44
44
  return pc.yellow("[WARN]");
45
45
  case "info":
46
46
  return pc.cyan("[INFO]");
47
+ case "skip":
48
+ return pc.cyan("[SKIP]");
47
49
  }
48
50
  }
49
51
  function metricBar(pct3, width = 10) {
@@ -179,6 +181,8 @@ function buildInitYaml(args) {
179
181
  if (args.testRunner) {
180
182
  lines.push(`testRunner: ${args.testRunner}`);
181
183
  }
184
+ lines.push("# Patch gate is skipped when the diff has no executable lines");
185
+ lines.push("# (tests-only, comments-only, docs-only, or ignored files).");
182
186
  lines.push("thresholds:");
183
187
  lines.push(" patch: 80");
184
188
  lines.push(" project: 60");
@@ -545,7 +549,9 @@ var FileCoverageSchema = z2.object({
545
549
  var CoverageTotalsSchema = z2.object({
546
550
  executable: z2.number().int().nonnegative(),
547
551
  covered: z2.number().int().nonnegative(),
548
- pct: z2.number().min(0).max(100)
552
+ pct: z2.number().min(0).max(100),
553
+ /** Present when executable === 0 — not a 0% coverage result. */
554
+ empty: z2.literal(true).optional()
549
555
  });
550
556
  var ProjectTotalsSchema = CoverageTotalsSchema.extend({
551
557
  delta: z2.number().nullable()
@@ -614,7 +620,14 @@ async function headSha(ctx) {
614
620
  return (await ctx.git.revparse(["HEAD"])).trim();
615
621
  }
616
622
  async function unifiedDiff(ctx, base) {
617
- return ctx.git.diff([`${base}...HEAD`]);
623
+ try {
624
+ const mergeBase = (await ctx.git.raw(["merge-base", base, "HEAD"])).trim();
625
+ if (mergeBase) {
626
+ return ctx.git.diff([`${base}...HEAD`]);
627
+ }
628
+ } catch {
629
+ }
630
+ return ctx.git.diff([base, "HEAD"]);
618
631
  }
619
632
  async function remoteUrl(ctx, remote = "origin") {
620
633
  return (await ctx.git.raw(["remote", "get-url", remote])).trim();
@@ -763,6 +776,10 @@ function assertWithinRoot(root, resolvedPath) {
763
776
  }
764
777
 
765
778
  // src/core/patch.ts
779
+ var EMPTY_PATCH_REASON = "no executable lines in the patch";
780
+ function isEmptyPatch(totals) {
781
+ return totals.executable === 0;
782
+ }
766
783
  function pct(covered, executable) {
767
784
  if (executable === 0) return 0;
768
785
  return Math.round(covered / executable * 1e3) / 10;
@@ -862,10 +879,10 @@ function uncoveredRanges(file) {
862
879
  function buildDiffOutput(args) {
863
880
  const patch = computePatchCoverage(args.files, args.addedByFile);
864
881
  const project = computeProjectCoverage(args.files);
865
- const fileNames = /* @__PURE__ */ new Set([
866
- ...patch.byFile.keys(),
867
- ...project.byFile.keys()
868
- ]);
882
+ const emptyPatch = isEmptyPatch(patch.totals);
883
+ const fileNames = new Set(
884
+ emptyPatch ? [] : [...patch.byFile.keys(), ...project.byFile.keys()]
885
+ );
869
886
  const files = [];
870
887
  for (const name of fileNames) {
871
888
  const file = args.files.find((f) => f.path === name);
@@ -882,7 +899,7 @@ function buildDiffOutput(args) {
882
899
  schemaVersion: 1,
883
900
  base: args.base,
884
901
  head: args.head,
885
- patch: patch.totals,
902
+ patch: emptyPatch ? { ...patch.totals, empty: true } : patch.totals,
886
903
  project: { ...project.totals, delta: args.projectDelta ?? null },
887
904
  files,
888
905
  ignored: [...args.ignored]
@@ -1865,8 +1882,6 @@ function buildCiSnippet() {
1865
1882
  " runs-on: ubuntu-latest",
1866
1883
  " steps:",
1867
1884
  " - uses: actions/checkout@v4",
1868
- " with:",
1869
- " fetch-depth: 0",
1870
1885
  " - uses: tested-hq/cli/action@main",
1871
1886
  " with:",
1872
1887
  " # pin ref for reproducible installs (do not use floating tags in prod)",
@@ -1931,6 +1946,12 @@ function formatSetupHuman(opts) {
1931
1946
  ])
1932
1947
  );
1933
1948
  lines.push("");
1949
+ lines.push(
1950
+ dim(
1951
+ "Patch gate is skipped when the diff has no executable lines (tests-only, docs, comments)."
1952
+ )
1953
+ );
1954
+ lines.push("");
1934
1955
  lines.push(tip("re-check anytime: tested doctor"));
1935
1956
  lines.push("");
1936
1957
  return lines.join("\n");
@@ -2196,8 +2217,8 @@ function coloredPctCell(pct3, width = 6) {
2196
2217
  function formatMetricRow(label, pct3, covered, executable, emptyNote) {
2197
2218
  const labelPad = label.padEnd(8);
2198
2219
  if (executable === 0) {
2199
- const note = emptyNote ?? "no executable lines";
2200
- return ` ${labelPad} ${dim("-".padEnd(6))} ${dim(note)}`;
2220
+ const note = emptyNote ?? EMPTY_PATCH_REASON;
2221
+ return ` ${labelPad} ${dim("-".padEnd(6))} ${note}`;
2201
2222
  }
2202
2223
  const pctStr = coloredPctCell(pct3);
2203
2224
  const bar = metricBar(pct3);
@@ -2216,7 +2237,7 @@ function formatHuman(out, opts = {}) {
2216
2237
  out.patch.pct,
2217
2238
  out.patch.covered,
2218
2239
  out.patch.executable,
2219
- "no executable lines in patch"
2240
+ EMPTY_PATCH_REASON
2220
2241
  )
2221
2242
  );
2222
2243
  const projectRow = formatMetricRow(
@@ -2229,7 +2250,7 @@ function formatHuman(out, opts = {}) {
2229
2250
  if (opts.thresholds) {
2230
2251
  const patchPass = out.patch.pct >= opts.thresholds.patch;
2231
2252
  const projectPass = out.project.pct >= opts.thresholds.project;
2232
- const patchOk = out.patch.executable === 0 ? true : patchPass;
2253
+ const patchOk = isEmptyPatch(out.patch) ? true : patchPass;
2233
2254
  const overall = patchOk && projectPass;
2234
2255
  const details = [];
2235
2256
  if (!patchOk) {
@@ -2240,7 +2261,7 @@ function formatHuman(out, opts = {}) {
2240
2261
  `project ${out.project.pct.toFixed(1)}% < ${opts.thresholds.project}%`
2241
2262
  );
2242
2263
  }
2243
- const detail = details.length > 0 ? dim(` ${details.join("; ")}`) : "";
2264
+ const detail = details.length > 0 ? dim(` ${details.join("; ")}`) : isEmptyPatch(out.patch) ? dim(` ${EMPTY_PATCH_REASON}`) : "";
2244
2265
  lines.push(
2245
2266
  ` ${"Gate".padEnd(8)} ${overall ? badge("pass") : badge("fail")}${detail}`
2246
2267
  );
@@ -2253,12 +2274,15 @@ function formatHuman(out, opts = {}) {
2253
2274
  );
2254
2275
  }
2255
2276
  }
2256
- if (out.files.length > 0) {
2277
+ if (isEmptyPatch(out.patch)) {
2278
+ lines.push("");
2279
+ lines.push(dim("No executable lines in the patch \u2014 patch gate does not apply."));
2280
+ } else if (out.files.length > 0) {
2257
2281
  lines.push("");
2258
2282
  lines.push(heading("Files in diff:"));
2259
2283
  const anyPatch = out.files.some((f) => f.patchCoverage !== null);
2260
2284
  if (!anyPatch) {
2261
- lines.push(dim(" (project coverage \u2014 no executable lines in patch)"));
2285
+ lines.push(dim(` (project coverage \u2014 ${EMPTY_PATCH_REASON})`));
2262
2286
  }
2263
2287
  for (const f of out.files) {
2264
2288
  const hasPatch = f.patchCoverage !== null;
@@ -2344,7 +2368,7 @@ ${tip("add thresholds.patch / thresholds.project to enforce")}
2344
2368
  const projectPct = diff.project.pct;
2345
2369
  const patchThreshold = config.thresholds.patch;
2346
2370
  const projectThreshold = config.thresholds.project;
2347
- const patchSkipped = diff.patch.executable === 0;
2371
+ const patchSkipped = isEmptyPatch(diff.patch);
2348
2372
  const patchPass = patchSkipped ? true : patchPct >= patchThreshold;
2349
2373
  const projectPass = projectPct >= projectThreshold;
2350
2374
  const overall = patchPass && projectPass ? "pass" : "fail";
@@ -2355,10 +2379,11 @@ ${tip("add thresholds.patch / thresholds.project to enforce")}
2355
2379
  pct: patchPct,
2356
2380
  threshold: patchThreshold,
2357
2381
  pass: patchPass,
2358
- ...patchSkipped ? { skipped: true } : {}
2382
+ ...patchSkipped ? { skipped: true, reason: EMPTY_PATCH_REASON } : {}
2359
2383
  },
2360
2384
  project: { pct: projectPct, threshold: projectThreshold, pass: projectPass },
2361
- overall
2385
+ overall,
2386
+ ...patchSkipped ? { note: EMPTY_PATCH_REASON } : {}
2362
2387
  };
2363
2388
  return {
2364
2389
  skipped: false,
@@ -2377,7 +2402,7 @@ ${tip("add thresholds.patch / thresholds.project to enforce")}
2377
2402
  lines.push("");
2378
2403
  if (patchSkipped) {
2379
2404
  lines.push(
2380
- ` ${"Patch".padEnd(8)} ${dim("-")} ${dim("(no executable lines \u2014 skipped)")} ${badge("info")}`
2405
+ ` ${"Patch".padEnd(8)} ${dim("-")} ${EMPTY_PATCH_REASON} ${badge("skip")}`
2381
2406
  );
2382
2407
  } else {
2383
2408
  lines.push(formatMetricLine("Patch", patchPct, patchThreshold, patchPass));
@@ -2385,10 +2410,17 @@ ${tip("add thresholds.patch / thresholds.project to enforce")}
2385
2410
  lines.push(formatMetricLine("Project", projectPct, projectThreshold, projectPass));
2386
2411
  if (overall === "fail") {
2387
2412
  lines.push("");
2413
+ if (patchSkipped) {
2414
+ lines.push(dim("No executable lines in the patch \u2014 patch gate skipped."));
2415
+ }
2388
2416
  lines.push(tip("add tests for uncovered ranges: tested diff"));
2389
2417
  } else {
2390
2418
  lines.push("");
2391
- lines.push(dim(patchSkipped ? "project thresholds met (patch skipped)" : "thresholds met"));
2419
+ lines.push(
2420
+ dim(
2421
+ patchSkipped ? "No executable lines in the patch \u2014 patch gate skipped. Project threshold met." : "thresholds met"
2422
+ )
2423
+ );
2392
2424
  }
2393
2425
  lines.push("");
2394
2426
  return {
@@ -2561,7 +2593,7 @@ function createProgram() {
2561
2593
  "Agent loop:",
2562
2594
  " tested setup \u2192 tested run \u2192 tested diff \u2192 tested check \u2192 tested push --pr <n>"
2563
2595
  ].join("\n")
2564
- ).version("0.1.0");
2596
+ ).version("0.1.1");
2565
2597
  registerSetupCommand(program2);
2566
2598
  registerDoctorCommand(program2);
2567
2599
  registerInitCommand(program2);
package/dist/tested.js CHANGED
@@ -44,6 +44,8 @@ function badge(kind) {
44
44
  return pc.yellow("[WARN]");
45
45
  case "info":
46
46
  return pc.cyan("[INFO]");
47
+ case "skip":
48
+ return pc.cyan("[SKIP]");
47
49
  }
48
50
  }
49
51
  function metricBar(pct3, width = 10) {
@@ -179,6 +181,8 @@ function buildInitYaml(args) {
179
181
  if (args.testRunner) {
180
182
  lines.push(`testRunner: ${args.testRunner}`);
181
183
  }
184
+ lines.push("# Patch gate is skipped when the diff has no executable lines");
185
+ lines.push("# (tests-only, comments-only, docs-only, or ignored files).");
182
186
  lines.push("thresholds:");
183
187
  lines.push(" patch: 80");
184
188
  lines.push(" project: 60");
@@ -545,7 +549,9 @@ var FileCoverageSchema = z2.object({
545
549
  var CoverageTotalsSchema = z2.object({
546
550
  executable: z2.number().int().nonnegative(),
547
551
  covered: z2.number().int().nonnegative(),
548
- pct: z2.number().min(0).max(100)
552
+ pct: z2.number().min(0).max(100),
553
+ /** Present when executable === 0 — not a 0% coverage result. */
554
+ empty: z2.literal(true).optional()
549
555
  });
550
556
  var ProjectTotalsSchema = CoverageTotalsSchema.extend({
551
557
  delta: z2.number().nullable()
@@ -614,7 +620,14 @@ async function headSha(ctx) {
614
620
  return (await ctx.git.revparse(["HEAD"])).trim();
615
621
  }
616
622
  async function unifiedDiff(ctx, base) {
617
- return ctx.git.diff([`${base}...HEAD`]);
623
+ try {
624
+ const mergeBase = (await ctx.git.raw(["merge-base", base, "HEAD"])).trim();
625
+ if (mergeBase) {
626
+ return ctx.git.diff([`${base}...HEAD`]);
627
+ }
628
+ } catch {
629
+ }
630
+ return ctx.git.diff([base, "HEAD"]);
618
631
  }
619
632
  async function remoteUrl(ctx, remote = "origin") {
620
633
  return (await ctx.git.raw(["remote", "get-url", remote])).trim();
@@ -763,6 +776,10 @@ function assertWithinRoot(root, resolvedPath) {
763
776
  }
764
777
 
765
778
  // src/core/patch.ts
779
+ var EMPTY_PATCH_REASON = "no executable lines in the patch";
780
+ function isEmptyPatch(totals) {
781
+ return totals.executable === 0;
782
+ }
766
783
  function pct(covered, executable) {
767
784
  if (executable === 0) return 0;
768
785
  return Math.round(covered / executable * 1e3) / 10;
@@ -862,10 +879,10 @@ function uncoveredRanges(file) {
862
879
  function buildDiffOutput(args) {
863
880
  const patch = computePatchCoverage(args.files, args.addedByFile);
864
881
  const project = computeProjectCoverage(args.files);
865
- const fileNames = /* @__PURE__ */ new Set([
866
- ...patch.byFile.keys(),
867
- ...project.byFile.keys()
868
- ]);
882
+ const emptyPatch = isEmptyPatch(patch.totals);
883
+ const fileNames = new Set(
884
+ emptyPatch ? [] : [...patch.byFile.keys(), ...project.byFile.keys()]
885
+ );
869
886
  const files = [];
870
887
  for (const name of fileNames) {
871
888
  const file = args.files.find((f) => f.path === name);
@@ -882,7 +899,7 @@ function buildDiffOutput(args) {
882
899
  schemaVersion: 1,
883
900
  base: args.base,
884
901
  head: args.head,
885
- patch: patch.totals,
902
+ patch: emptyPatch ? { ...patch.totals, empty: true } : patch.totals,
886
903
  project: { ...project.totals, delta: args.projectDelta ?? null },
887
904
  files,
888
905
  ignored: [...args.ignored]
@@ -1865,8 +1882,6 @@ function buildCiSnippet() {
1865
1882
  " runs-on: ubuntu-latest",
1866
1883
  " steps:",
1867
1884
  " - uses: actions/checkout@v4",
1868
- " with:",
1869
- " fetch-depth: 0",
1870
1885
  " - uses: tested-hq/cli/action@main",
1871
1886
  " with:",
1872
1887
  " # pin ref for reproducible installs (do not use floating tags in prod)",
@@ -1931,6 +1946,12 @@ function formatSetupHuman(opts) {
1931
1946
  ])
1932
1947
  );
1933
1948
  lines.push("");
1949
+ lines.push(
1950
+ dim(
1951
+ "Patch gate is skipped when the diff has no executable lines (tests-only, docs, comments)."
1952
+ )
1953
+ );
1954
+ lines.push("");
1934
1955
  lines.push(tip("re-check anytime: tested doctor"));
1935
1956
  lines.push("");
1936
1957
  return lines.join("\n");
@@ -2196,8 +2217,8 @@ function coloredPctCell(pct3, width = 6) {
2196
2217
  function formatMetricRow(label, pct3, covered, executable, emptyNote) {
2197
2218
  const labelPad = label.padEnd(8);
2198
2219
  if (executable === 0) {
2199
- const note = emptyNote ?? "no executable lines";
2200
- return ` ${labelPad} ${dim("-".padEnd(6))} ${dim(note)}`;
2220
+ const note = emptyNote ?? EMPTY_PATCH_REASON;
2221
+ return ` ${labelPad} ${dim("-".padEnd(6))} ${note}`;
2201
2222
  }
2202
2223
  const pctStr = coloredPctCell(pct3);
2203
2224
  const bar = metricBar(pct3);
@@ -2216,7 +2237,7 @@ function formatHuman(out, opts = {}) {
2216
2237
  out.patch.pct,
2217
2238
  out.patch.covered,
2218
2239
  out.patch.executable,
2219
- "no executable lines in patch"
2240
+ EMPTY_PATCH_REASON
2220
2241
  )
2221
2242
  );
2222
2243
  const projectRow = formatMetricRow(
@@ -2229,7 +2250,7 @@ function formatHuman(out, opts = {}) {
2229
2250
  if (opts.thresholds) {
2230
2251
  const patchPass = out.patch.pct >= opts.thresholds.patch;
2231
2252
  const projectPass = out.project.pct >= opts.thresholds.project;
2232
- const patchOk = out.patch.executable === 0 ? true : patchPass;
2253
+ const patchOk = isEmptyPatch(out.patch) ? true : patchPass;
2233
2254
  const overall = patchOk && projectPass;
2234
2255
  const details = [];
2235
2256
  if (!patchOk) {
@@ -2240,7 +2261,7 @@ function formatHuman(out, opts = {}) {
2240
2261
  `project ${out.project.pct.toFixed(1)}% < ${opts.thresholds.project}%`
2241
2262
  );
2242
2263
  }
2243
- const detail = details.length > 0 ? dim(` ${details.join("; ")}`) : "";
2264
+ const detail = details.length > 0 ? dim(` ${details.join("; ")}`) : isEmptyPatch(out.patch) ? dim(` ${EMPTY_PATCH_REASON}`) : "";
2244
2265
  lines.push(
2245
2266
  ` ${"Gate".padEnd(8)} ${overall ? badge("pass") : badge("fail")}${detail}`
2246
2267
  );
@@ -2253,12 +2274,15 @@ function formatHuman(out, opts = {}) {
2253
2274
  );
2254
2275
  }
2255
2276
  }
2256
- if (out.files.length > 0) {
2277
+ if (isEmptyPatch(out.patch)) {
2278
+ lines.push("");
2279
+ lines.push(dim("No executable lines in the patch \u2014 patch gate does not apply."));
2280
+ } else if (out.files.length > 0) {
2257
2281
  lines.push("");
2258
2282
  lines.push(heading("Files in diff:"));
2259
2283
  const anyPatch = out.files.some((f) => f.patchCoverage !== null);
2260
2284
  if (!anyPatch) {
2261
- lines.push(dim(" (project coverage \u2014 no executable lines in patch)"));
2285
+ lines.push(dim(` (project coverage \u2014 ${EMPTY_PATCH_REASON})`));
2262
2286
  }
2263
2287
  for (const f of out.files) {
2264
2288
  const hasPatch = f.patchCoverage !== null;
@@ -2344,7 +2368,7 @@ ${tip("add thresholds.patch / thresholds.project to enforce")}
2344
2368
  const projectPct = diff.project.pct;
2345
2369
  const patchThreshold = config.thresholds.patch;
2346
2370
  const projectThreshold = config.thresholds.project;
2347
- const patchSkipped = diff.patch.executable === 0;
2371
+ const patchSkipped = isEmptyPatch(diff.patch);
2348
2372
  const patchPass = patchSkipped ? true : patchPct >= patchThreshold;
2349
2373
  const projectPass = projectPct >= projectThreshold;
2350
2374
  const overall = patchPass && projectPass ? "pass" : "fail";
@@ -2355,10 +2379,11 @@ ${tip("add thresholds.patch / thresholds.project to enforce")}
2355
2379
  pct: patchPct,
2356
2380
  threshold: patchThreshold,
2357
2381
  pass: patchPass,
2358
- ...patchSkipped ? { skipped: true } : {}
2382
+ ...patchSkipped ? { skipped: true, reason: EMPTY_PATCH_REASON } : {}
2359
2383
  },
2360
2384
  project: { pct: projectPct, threshold: projectThreshold, pass: projectPass },
2361
- overall
2385
+ overall,
2386
+ ...patchSkipped ? { note: EMPTY_PATCH_REASON } : {}
2362
2387
  };
2363
2388
  return {
2364
2389
  skipped: false,
@@ -2377,7 +2402,7 @@ ${tip("add thresholds.patch / thresholds.project to enforce")}
2377
2402
  lines.push("");
2378
2403
  if (patchSkipped) {
2379
2404
  lines.push(
2380
- ` ${"Patch".padEnd(8)} ${dim("-")} ${dim("(no executable lines \u2014 skipped)")} ${badge("info")}`
2405
+ ` ${"Patch".padEnd(8)} ${dim("-")} ${EMPTY_PATCH_REASON} ${badge("skip")}`
2381
2406
  );
2382
2407
  } else {
2383
2408
  lines.push(formatMetricLine("Patch", patchPct, patchThreshold, patchPass));
@@ -2385,10 +2410,17 @@ ${tip("add thresholds.patch / thresholds.project to enforce")}
2385
2410
  lines.push(formatMetricLine("Project", projectPct, projectThreshold, projectPass));
2386
2411
  if (overall === "fail") {
2387
2412
  lines.push("");
2413
+ if (patchSkipped) {
2414
+ lines.push(dim("No executable lines in the patch \u2014 patch gate skipped."));
2415
+ }
2388
2416
  lines.push(tip("add tests for uncovered ranges: tested diff"));
2389
2417
  } else {
2390
2418
  lines.push("");
2391
- lines.push(dim(patchSkipped ? "project thresholds met (patch skipped)" : "thresholds met"));
2419
+ lines.push(
2420
+ dim(
2421
+ patchSkipped ? "No executable lines in the patch \u2014 patch gate skipped. Project threshold met." : "thresholds met"
2422
+ )
2423
+ );
2392
2424
  }
2393
2425
  lines.push("");
2394
2426
  return {
@@ -2561,7 +2593,7 @@ function createProgram() {
2561
2593
  "Agent loop:",
2562
2594
  " tested setup \u2192 tested run \u2192 tested diff \u2192 tested check \u2192 tested push --pr <n>"
2563
2595
  ].join("\n")
2564
- ).version("0.1.0");
2596
+ ).version("0.1.1");
2565
2597
  registerSetupCommand(program2);
2566
2598
  registerDoctorCommand(program2);
2567
2599
  registerInitCommand(program2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tested/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
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",
@@ -18,7 +18,7 @@
18
18
  "packageManager": "pnpm@11.3.0",
19
19
  "bin": {
20
20
  "tested": "./dist/tested.js",
21
- "td": "./dist/td.js"
21
+ "td": "./dist/tested.js"
22
22
  },
23
23
  "files": [
24
24
  "dist",