@tested/cli 0.1.1 → 0.1.3

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
@@ -2,12 +2,11 @@
2
2
 
3
3
  Coverage your agent can use. CLI for patch + project coverage with agent-readable JSON output.
4
4
 
5
- **→ [Getting started (simple path)](docs/GETTING-STARTED.md)**
6
- **→ [GitHub Action](action/README.md)** (`action/action.yml` composite)
5
+ Docs: https://tested.dev/docs
7
6
 
8
7
  ## Install
9
8
 
10
- Node >= 20.19.
9
+ Node 24+.
11
10
 
12
11
  ```bash
13
12
  pnpm add -D @tested/cli
@@ -15,16 +14,21 @@ pnpm add -D @tested/cli
15
14
  npx @tested/cli # runs `tested` (`td` is the same CLI after install)
16
15
  ```
17
16
 
18
- CI uses the composite Action (`tested-hq/cli/action@main`). The Action clones this repo and builds the CLI.
17
+ ```bash
18
+ npx @tested/cli --version
19
+ # after a local install, pnpm swallows --version unless you use exec:
20
+ pnpm exec -- tested --version
21
+ ```
22
+
23
+ CI uses the composite Action (`tested-hq/cli/action@main`). It installs `@tested/cli` from npm.
19
24
 
20
25
  ```yaml
21
26
  - uses: tested-hq/cli/action@main
22
27
  with:
28
+ version: 0.1.3
23
29
  token: ${{ secrets.TESTED_TOKEN }}
24
30
  ```
25
31
 
26
- Pin `cli-ref` to a SHA in production. See [action/README.md](action/README.md).
27
-
28
32
  ## First 10 minutes
29
33
 
30
34
  ```
@@ -85,7 +89,7 @@ The hook runs `tested run && tested diff` against the upstream branch (or `HEAD~
85
89
  ```yaml
86
90
  thresholds:
87
91
  patch: 80 # % of newly-added lines that must be covered
88
- project: 60 # % of the whole project that must be covered
92
+ project: 90 # % of the whole project that must be covered
89
93
  ```
90
94
 
91
95
  ```
@@ -93,7 +97,7 @@ $ tested check
93
97
  tested.dev — coverage gate [PASS]
94
98
 
95
99
  Patch 87.3% (threshold 80) [PASS]
96
- Project 64.1% (threshold 60) [PASS]
100
+ Project 92.1% (threshold 90) [PASS]
97
101
 
98
102
  thresholds met
99
103
  $ echo $?
@@ -103,7 +107,7 @@ $ tested check
103
107
  tested.dev — coverage gate [FAIL]
104
108
 
105
109
  Patch 42.7% (threshold 80) [FAIL]
106
- Project 64.1% (threshold 60) [PASS]
110
+ Project 92.1% (threshold 90) [PASS]
107
111
 
108
112
  → add tests for uncovered ranges: tested diff
109
113
  $ echo $?
@@ -117,7 +121,7 @@ $ tested check
117
121
  tested.dev — coverage gate [PASS]
118
122
 
119
123
  Patch - no executable lines in the patch [SKIP]
120
- Project 64.1% (threshold 60) [PASS]
124
+ Project 92.1% (threshold 90) [PASS]
121
125
 
122
126
  No executable lines in the patch — patch gate skipped. Project threshold met.
123
127
  ```
@@ -129,6 +133,7 @@ If `thresholds` is missing from `.tested.yaml`, `tested check` prints a notice o
129
133
  ```yaml
130
134
  - uses: tested-hq/cli/action@main
131
135
  with:
136
+ version: 0.1.3
132
137
  push: true
133
138
  pr-number: ${{ github.event.pull_request.number }}
134
139
  token: ${{ secrets.TESTED_TOKEN }}
@@ -140,7 +145,7 @@ For programmatic consumers:
140
145
 
141
146
  ```
142
147
  $ tested check --json
143
- {"patch":{"pct":87.3,"threshold":80,"pass":true},"project":{"pct":64.1,"threshold":60,"pass":true},"overall":"pass"}
148
+ {"patch":{"pct":87.3,"threshold":80,"pass":true},"project":{"pct":92.1,"threshold":90,"pass":true},"overall":"pass"}
144
149
  ```
145
150
 
146
151
  `--json` suppresses the human layout; the exit code is unchanged.
package/dist/td.js CHANGED
@@ -132,6 +132,10 @@ function formatCliError(message) {
132
132
 
133
133
  // src/commands/init.ts
134
134
  import pc2 from "picocolors";
135
+ var DEFAULT_INIT_THRESHOLDS = {
136
+ patch: 80,
137
+ project: 90
138
+ };
135
139
  var INIT_YAML_HEADER = "# Config schema \u2014 see https://tested.dev/docs/config\n";
136
140
  var DEFAULT_INIT_IGNORES = [
137
141
  "**/*.test.ts",
@@ -184,8 +188,8 @@ function buildInitYaml(args) {
184
188
  lines.push("# Patch gate is skipped when the diff has no executable lines");
185
189
  lines.push("# (tests-only, comments-only, docs-only, or ignored files).");
186
190
  lines.push("thresholds:");
187
- lines.push(" patch: 80");
188
- lines.push(" project: 60");
191
+ lines.push(` patch: ${DEFAULT_INIT_THRESHOLDS.patch}`);
192
+ lines.push(` project: ${DEFAULT_INIT_THRESHOLDS.project}`);
189
193
  lines.push("ignores:");
190
194
  for (const pattern of DEFAULT_INIT_IGNORES) {
191
195
  lines.push(` - "${pattern}"`);
@@ -1049,7 +1053,9 @@ function assertSafeApiBase(raw) {
1049
1053
  }
1050
1054
  function resolveApiBase(opts) {
1051
1055
  const env = opts.env ?? process.env;
1052
- const raw = opts.flag ?? env.TESTED_API_URL ?? DEFAULT_API_BASE;
1056
+ const flag = opts.flag?.trim();
1057
+ const fromEnv = env.TESTED_API_URL?.trim();
1058
+ const raw = flag || fromEnv || DEFAULT_API_BASE;
1053
1059
  return assertSafeApiBase(raw);
1054
1060
  }
1055
1061
  function redactGitRemote(url) {
@@ -1525,6 +1531,7 @@ function registerPushCommand(program2) {
1525
1531
 
1526
1532
  // src/commands/doctor.ts
1527
1533
  var TESTED_BIN_BASENAME_RE = /^tested(\.js)?$/;
1534
+ var MIN_NODE_MAJOR = 24;
1528
1535
  function statusBadge(status) {
1529
1536
  const kind = status === "pass" ? "pass" : status === "fail" ? "fail" : status === "warn" ? "warn" : "info";
1530
1537
  return badge(kind);
@@ -1591,20 +1598,19 @@ async function runDoctor(deps) {
1591
1598
  const checks = [];
1592
1599
  const major = parseNodeMajor(nodeVersion);
1593
1600
  const nodeDisplay = nodeVersion.replace(/^v/, "v");
1594
- if (major !== null && major >= 22) {
1601
+ if (major !== null && major >= MIN_NODE_MAJOR) {
1595
1602
  checks.push({
1596
1603
  id: "node",
1597
1604
  label: "Node.js",
1598
1605
  status: "pass",
1599
- detail: `${nodeDisplay} (>= 20.19; 22+ recommended)`
1606
+ detail: `${nodeDisplay} (>= ${MIN_NODE_MAJOR})`
1600
1607
  });
1601
1608
  } else {
1602
1609
  checks.push({
1603
1610
  id: "node",
1604
1611
  label: "Node.js",
1605
- status: "warn",
1606
- detail: `${nodeDisplay} runs this CLI. Node >= 22 recommended.`,
1607
- optional: true
1612
+ status: "fail",
1613
+ detail: `${nodeDisplay} is below ${MIN_NODE_MAJOR}. Node >= ${MIN_NODE_MAJOR} required.`
1608
1614
  });
1609
1615
  }
1610
1616
  let isRepo = false;
@@ -1826,7 +1832,7 @@ async function runDoctor(deps) {
1826
1832
  optional: true
1827
1833
  });
1828
1834
  }
1829
- const hardFailIds = /* @__PURE__ */ new Set(["git", "config", "origin"]);
1835
+ const hardFailIds = /* @__PURE__ */ new Set(["node", "git", "config", "origin"]);
1830
1836
  const safetyFailIds = /* @__PURE__ */ new Set(["api_url", "tested_bin", "token"]);
1831
1837
  const hasHardFail = checks.some(
1832
1838
  (c) => c.status === "fail" && hardFailIds.has(c.id)
@@ -1871,6 +1877,73 @@ function registerDoctorCommand(program2) {
1871
1877
 
1872
1878
  // src/commands/setup.ts
1873
1879
  import pc3 from "picocolors";
1880
+
1881
+ // package.json
1882
+ var package_default = {
1883
+ name: "@tested/cli",
1884
+ version: "0.1.3",
1885
+ description: "Coverage your agent can use. CLI for patch + project coverage with agent-readable JSON output.",
1886
+ license: "MIT",
1887
+ homepage: "https://tested.dev",
1888
+ repository: {
1889
+ type: "git",
1890
+ url: "git+https://github.com/tested-hq/cli.git"
1891
+ },
1892
+ bugs: {
1893
+ url: "https://github.com/tested-hq/cli/issues"
1894
+ },
1895
+ publishConfig: {
1896
+ access: "public"
1897
+ },
1898
+ type: "module",
1899
+ packageManager: "pnpm@11.3.0",
1900
+ bin: {
1901
+ tested: "./dist/tested.js",
1902
+ td: "./dist/tested.js"
1903
+ },
1904
+ files: [
1905
+ "dist",
1906
+ "README.md",
1907
+ "LICENSE"
1908
+ ],
1909
+ scripts: {
1910
+ build: "tsup",
1911
+ dev: "tsx bin/tested.ts",
1912
+ test: "vitest run",
1913
+ "test:watch": "vitest",
1914
+ "test:coverage": "vitest run --coverage",
1915
+ typecheck: "tsc --noEmit",
1916
+ prepare: "node ./scripts/prepare.mjs",
1917
+ prepublishOnly: "pnpm run build"
1918
+ },
1919
+ engines: {
1920
+ node: ">=24"
1921
+ },
1922
+ dependencies: {
1923
+ commander: "14.0.3",
1924
+ minimatch: "10.2.5",
1925
+ picocolors: "1.1.1",
1926
+ "simple-git": "3.36.0",
1927
+ yaml: "2.9.0",
1928
+ zod: "4.4.3"
1929
+ },
1930
+ devDependencies: {
1931
+ "@types/node": "25.9.1",
1932
+ "@vitest/coverage-v8": "4.1.7",
1933
+ husky: "9.1.7",
1934
+ "is-ci": "3.0.1",
1935
+ tsup: "8.5.1",
1936
+ tsx: "4.22.3",
1937
+ typescript: "6.0.3",
1938
+ vite: "8.0.14",
1939
+ vitest: "4.1.7"
1940
+ }
1941
+ };
1942
+
1943
+ // src/version.ts
1944
+ var CLI_VERSION = package_default.version;
1945
+
1946
+ // src/commands/setup.ts
1874
1947
  var PINNED_CLI = "@tested/cli";
1875
1948
  function buildCiSnippet() {
1876
1949
  return [
@@ -1884,8 +1957,7 @@ function buildCiSnippet() {
1884
1957
  " - uses: actions/checkout@v4",
1885
1958
  " - uses: tested-hq/cli/action@main",
1886
1959
  " with:",
1887
- " # pin ref for reproducible installs (do not use floating tags in prod)",
1888
- " cli-ref: main",
1960
+ ` version: ${CLI_VERSION}`,
1889
1961
  " push: true",
1890
1962
  " pr-number: ${{ github.event.pull_request.number }}",
1891
1963
  " token: ${{ secrets.TESTED_TOKEN }}"
@@ -1902,6 +1974,7 @@ function buildTokenInstructions() {
1902
1974
  function buildInstallInstructions() {
1903
1975
  return [
1904
1976
  "Install CLI:",
1977
+ " Node 24+",
1905
1978
  ` pnpm add -D ${PINNED_CLI}`,
1906
1979
  ` # or: npx ${PINNED_CLI}`,
1907
1980
  "",
@@ -2593,7 +2666,7 @@ function createProgram() {
2593
2666
  "Agent loop:",
2594
2667
  " tested setup \u2192 tested run \u2192 tested diff \u2192 tested check \u2192 tested push --pr <n>"
2595
2668
  ].join("\n")
2596
- ).version("0.1.1");
2669
+ ).version(CLI_VERSION);
2597
2670
  registerSetupCommand(program2);
2598
2671
  registerDoctorCommand(program2);
2599
2672
  registerInitCommand(program2);
package/dist/tested.js CHANGED
@@ -132,6 +132,10 @@ function formatCliError(message) {
132
132
 
133
133
  // src/commands/init.ts
134
134
  import pc2 from "picocolors";
135
+ var DEFAULT_INIT_THRESHOLDS = {
136
+ patch: 80,
137
+ project: 90
138
+ };
135
139
  var INIT_YAML_HEADER = "# Config schema \u2014 see https://tested.dev/docs/config\n";
136
140
  var DEFAULT_INIT_IGNORES = [
137
141
  "**/*.test.ts",
@@ -184,8 +188,8 @@ function buildInitYaml(args) {
184
188
  lines.push("# Patch gate is skipped when the diff has no executable lines");
185
189
  lines.push("# (tests-only, comments-only, docs-only, or ignored files).");
186
190
  lines.push("thresholds:");
187
- lines.push(" patch: 80");
188
- lines.push(" project: 60");
191
+ lines.push(` patch: ${DEFAULT_INIT_THRESHOLDS.patch}`);
192
+ lines.push(` project: ${DEFAULT_INIT_THRESHOLDS.project}`);
189
193
  lines.push("ignores:");
190
194
  for (const pattern of DEFAULT_INIT_IGNORES) {
191
195
  lines.push(` - "${pattern}"`);
@@ -1049,7 +1053,9 @@ function assertSafeApiBase(raw) {
1049
1053
  }
1050
1054
  function resolveApiBase(opts) {
1051
1055
  const env = opts.env ?? process.env;
1052
- const raw = opts.flag ?? env.TESTED_API_URL ?? DEFAULT_API_BASE;
1056
+ const flag = opts.flag?.trim();
1057
+ const fromEnv = env.TESTED_API_URL?.trim();
1058
+ const raw = flag || fromEnv || DEFAULT_API_BASE;
1053
1059
  return assertSafeApiBase(raw);
1054
1060
  }
1055
1061
  function redactGitRemote(url) {
@@ -1525,6 +1531,7 @@ function registerPushCommand(program2) {
1525
1531
 
1526
1532
  // src/commands/doctor.ts
1527
1533
  var TESTED_BIN_BASENAME_RE = /^tested(\.js)?$/;
1534
+ var MIN_NODE_MAJOR = 24;
1528
1535
  function statusBadge(status) {
1529
1536
  const kind = status === "pass" ? "pass" : status === "fail" ? "fail" : status === "warn" ? "warn" : "info";
1530
1537
  return badge(kind);
@@ -1591,20 +1598,19 @@ async function runDoctor(deps) {
1591
1598
  const checks = [];
1592
1599
  const major = parseNodeMajor(nodeVersion);
1593
1600
  const nodeDisplay = nodeVersion.replace(/^v/, "v");
1594
- if (major !== null && major >= 22) {
1601
+ if (major !== null && major >= MIN_NODE_MAJOR) {
1595
1602
  checks.push({
1596
1603
  id: "node",
1597
1604
  label: "Node.js",
1598
1605
  status: "pass",
1599
- detail: `${nodeDisplay} (>= 20.19; 22+ recommended)`
1606
+ detail: `${nodeDisplay} (>= ${MIN_NODE_MAJOR})`
1600
1607
  });
1601
1608
  } else {
1602
1609
  checks.push({
1603
1610
  id: "node",
1604
1611
  label: "Node.js",
1605
- status: "warn",
1606
- detail: `${nodeDisplay} runs this CLI. Node >= 22 recommended.`,
1607
- optional: true
1612
+ status: "fail",
1613
+ detail: `${nodeDisplay} is below ${MIN_NODE_MAJOR}. Node >= ${MIN_NODE_MAJOR} required.`
1608
1614
  });
1609
1615
  }
1610
1616
  let isRepo = false;
@@ -1826,7 +1832,7 @@ async function runDoctor(deps) {
1826
1832
  optional: true
1827
1833
  });
1828
1834
  }
1829
- const hardFailIds = /* @__PURE__ */ new Set(["git", "config", "origin"]);
1835
+ const hardFailIds = /* @__PURE__ */ new Set(["node", "git", "config", "origin"]);
1830
1836
  const safetyFailIds = /* @__PURE__ */ new Set(["api_url", "tested_bin", "token"]);
1831
1837
  const hasHardFail = checks.some(
1832
1838
  (c) => c.status === "fail" && hardFailIds.has(c.id)
@@ -1871,6 +1877,73 @@ function registerDoctorCommand(program2) {
1871
1877
 
1872
1878
  // src/commands/setup.ts
1873
1879
  import pc3 from "picocolors";
1880
+
1881
+ // package.json
1882
+ var package_default = {
1883
+ name: "@tested/cli",
1884
+ version: "0.1.3",
1885
+ description: "Coverage your agent can use. CLI for patch + project coverage with agent-readable JSON output.",
1886
+ license: "MIT",
1887
+ homepage: "https://tested.dev",
1888
+ repository: {
1889
+ type: "git",
1890
+ url: "git+https://github.com/tested-hq/cli.git"
1891
+ },
1892
+ bugs: {
1893
+ url: "https://github.com/tested-hq/cli/issues"
1894
+ },
1895
+ publishConfig: {
1896
+ access: "public"
1897
+ },
1898
+ type: "module",
1899
+ packageManager: "pnpm@11.3.0",
1900
+ bin: {
1901
+ tested: "./dist/tested.js",
1902
+ td: "./dist/tested.js"
1903
+ },
1904
+ files: [
1905
+ "dist",
1906
+ "README.md",
1907
+ "LICENSE"
1908
+ ],
1909
+ scripts: {
1910
+ build: "tsup",
1911
+ dev: "tsx bin/tested.ts",
1912
+ test: "vitest run",
1913
+ "test:watch": "vitest",
1914
+ "test:coverage": "vitest run --coverage",
1915
+ typecheck: "tsc --noEmit",
1916
+ prepare: "node ./scripts/prepare.mjs",
1917
+ prepublishOnly: "pnpm run build"
1918
+ },
1919
+ engines: {
1920
+ node: ">=24"
1921
+ },
1922
+ dependencies: {
1923
+ commander: "14.0.3",
1924
+ minimatch: "10.2.5",
1925
+ picocolors: "1.1.1",
1926
+ "simple-git": "3.36.0",
1927
+ yaml: "2.9.0",
1928
+ zod: "4.4.3"
1929
+ },
1930
+ devDependencies: {
1931
+ "@types/node": "25.9.1",
1932
+ "@vitest/coverage-v8": "4.1.7",
1933
+ husky: "9.1.7",
1934
+ "is-ci": "3.0.1",
1935
+ tsup: "8.5.1",
1936
+ tsx: "4.22.3",
1937
+ typescript: "6.0.3",
1938
+ vite: "8.0.14",
1939
+ vitest: "4.1.7"
1940
+ }
1941
+ };
1942
+
1943
+ // src/version.ts
1944
+ var CLI_VERSION = package_default.version;
1945
+
1946
+ // src/commands/setup.ts
1874
1947
  var PINNED_CLI = "@tested/cli";
1875
1948
  function buildCiSnippet() {
1876
1949
  return [
@@ -1884,8 +1957,7 @@ function buildCiSnippet() {
1884
1957
  " - uses: actions/checkout@v4",
1885
1958
  " - uses: tested-hq/cli/action@main",
1886
1959
  " with:",
1887
- " # pin ref for reproducible installs (do not use floating tags in prod)",
1888
- " cli-ref: main",
1960
+ ` version: ${CLI_VERSION}`,
1889
1961
  " push: true",
1890
1962
  " pr-number: ${{ github.event.pull_request.number }}",
1891
1963
  " token: ${{ secrets.TESTED_TOKEN }}"
@@ -1902,6 +1974,7 @@ function buildTokenInstructions() {
1902
1974
  function buildInstallInstructions() {
1903
1975
  return [
1904
1976
  "Install CLI:",
1977
+ " Node 24+",
1905
1978
  ` pnpm add -D ${PINNED_CLI}`,
1906
1979
  ` # or: npx ${PINNED_CLI}`,
1907
1980
  "",
@@ -2593,7 +2666,7 @@ function createProgram() {
2593
2666
  "Agent loop:",
2594
2667
  " tested setup \u2192 tested run \u2192 tested diff \u2192 tested check \u2192 tested push --pr <n>"
2595
2668
  ].join("\n")
2596
- ).version("0.1.1");
2669
+ ).version(CLI_VERSION);
2597
2670
  registerSetupCommand(program2);
2598
2671
  registerDoctorCommand(program2);
2599
2672
  registerInitCommand(program2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tested/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
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",
@@ -36,7 +36,7 @@
36
36
  "prepublishOnly": "pnpm run build"
37
37
  },
38
38
  "engines": {
39
- "node": ">=20.19.0"
39
+ "node": ">=24"
40
40
  },
41
41
  "dependencies": {
42
42
  "commander": "14.0.3",