@tested/cli 0.1.1 → 0.1.2

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.2
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.2
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}"`);
@@ -1525,6 +1529,7 @@ function registerPushCommand(program2) {
1525
1529
 
1526
1530
  // src/commands/doctor.ts
1527
1531
  var TESTED_BIN_BASENAME_RE = /^tested(\.js)?$/;
1532
+ var MIN_NODE_MAJOR = 24;
1528
1533
  function statusBadge(status) {
1529
1534
  const kind = status === "pass" ? "pass" : status === "fail" ? "fail" : status === "warn" ? "warn" : "info";
1530
1535
  return badge(kind);
@@ -1591,20 +1596,19 @@ async function runDoctor(deps) {
1591
1596
  const checks = [];
1592
1597
  const major = parseNodeMajor(nodeVersion);
1593
1598
  const nodeDisplay = nodeVersion.replace(/^v/, "v");
1594
- if (major !== null && major >= 22) {
1599
+ if (major !== null && major >= MIN_NODE_MAJOR) {
1595
1600
  checks.push({
1596
1601
  id: "node",
1597
1602
  label: "Node.js",
1598
1603
  status: "pass",
1599
- detail: `${nodeDisplay} (>= 20.19; 22+ recommended)`
1604
+ detail: `${nodeDisplay} (>= ${MIN_NODE_MAJOR})`
1600
1605
  });
1601
1606
  } else {
1602
1607
  checks.push({
1603
1608
  id: "node",
1604
1609
  label: "Node.js",
1605
- status: "warn",
1606
- detail: `${nodeDisplay} runs this CLI. Node >= 22 recommended.`,
1607
- optional: true
1610
+ status: "fail",
1611
+ detail: `${nodeDisplay} is below ${MIN_NODE_MAJOR}. Node >= ${MIN_NODE_MAJOR} required.`
1608
1612
  });
1609
1613
  }
1610
1614
  let isRepo = false;
@@ -1826,7 +1830,7 @@ async function runDoctor(deps) {
1826
1830
  optional: true
1827
1831
  });
1828
1832
  }
1829
- const hardFailIds = /* @__PURE__ */ new Set(["git", "config", "origin"]);
1833
+ const hardFailIds = /* @__PURE__ */ new Set(["node", "git", "config", "origin"]);
1830
1834
  const safetyFailIds = /* @__PURE__ */ new Set(["api_url", "tested_bin", "token"]);
1831
1835
  const hasHardFail = checks.some(
1832
1836
  (c) => c.status === "fail" && hardFailIds.has(c.id)
@@ -1871,6 +1875,73 @@ function registerDoctorCommand(program2) {
1871
1875
 
1872
1876
  // src/commands/setup.ts
1873
1877
  import pc3 from "picocolors";
1878
+
1879
+ // package.json
1880
+ var package_default = {
1881
+ name: "@tested/cli",
1882
+ version: "0.1.2",
1883
+ description: "Coverage your agent can use. CLI for patch + project coverage with agent-readable JSON output.",
1884
+ license: "MIT",
1885
+ homepage: "https://tested.dev",
1886
+ repository: {
1887
+ type: "git",
1888
+ url: "git+https://github.com/tested-hq/cli.git"
1889
+ },
1890
+ bugs: {
1891
+ url: "https://github.com/tested-hq/cli/issues"
1892
+ },
1893
+ publishConfig: {
1894
+ access: "public"
1895
+ },
1896
+ type: "module",
1897
+ packageManager: "pnpm@11.3.0",
1898
+ bin: {
1899
+ tested: "./dist/tested.js",
1900
+ td: "./dist/tested.js"
1901
+ },
1902
+ files: [
1903
+ "dist",
1904
+ "README.md",
1905
+ "LICENSE"
1906
+ ],
1907
+ scripts: {
1908
+ build: "tsup",
1909
+ dev: "tsx bin/tested.ts",
1910
+ test: "vitest run",
1911
+ "test:watch": "vitest",
1912
+ "test:coverage": "vitest run --coverage",
1913
+ typecheck: "tsc --noEmit",
1914
+ prepare: "node ./scripts/prepare.mjs",
1915
+ prepublishOnly: "pnpm run build"
1916
+ },
1917
+ engines: {
1918
+ node: ">=24"
1919
+ },
1920
+ dependencies: {
1921
+ commander: "14.0.3",
1922
+ minimatch: "10.2.5",
1923
+ picocolors: "1.1.1",
1924
+ "simple-git": "3.36.0",
1925
+ yaml: "2.9.0",
1926
+ zod: "4.4.3"
1927
+ },
1928
+ devDependencies: {
1929
+ "@types/node": "25.9.1",
1930
+ "@vitest/coverage-v8": "4.1.7",
1931
+ husky: "9.1.7",
1932
+ "is-ci": "3.0.1",
1933
+ tsup: "8.5.1",
1934
+ tsx: "4.22.3",
1935
+ typescript: "6.0.3",
1936
+ vite: "8.0.14",
1937
+ vitest: "4.1.7"
1938
+ }
1939
+ };
1940
+
1941
+ // src/version.ts
1942
+ var CLI_VERSION = package_default.version;
1943
+
1944
+ // src/commands/setup.ts
1874
1945
  var PINNED_CLI = "@tested/cli";
1875
1946
  function buildCiSnippet() {
1876
1947
  return [
@@ -1884,8 +1955,7 @@ function buildCiSnippet() {
1884
1955
  " - uses: actions/checkout@v4",
1885
1956
  " - uses: tested-hq/cli/action@main",
1886
1957
  " with:",
1887
- " # pin ref for reproducible installs (do not use floating tags in prod)",
1888
- " cli-ref: main",
1958
+ ` version: ${CLI_VERSION}`,
1889
1959
  " push: true",
1890
1960
  " pr-number: ${{ github.event.pull_request.number }}",
1891
1961
  " token: ${{ secrets.TESTED_TOKEN }}"
@@ -1902,6 +1972,7 @@ function buildTokenInstructions() {
1902
1972
  function buildInstallInstructions() {
1903
1973
  return [
1904
1974
  "Install CLI:",
1975
+ " Node 24+",
1905
1976
  ` pnpm add -D ${PINNED_CLI}`,
1906
1977
  ` # or: npx ${PINNED_CLI}`,
1907
1978
  "",
@@ -2593,7 +2664,7 @@ function createProgram() {
2593
2664
  "Agent loop:",
2594
2665
  " tested setup \u2192 tested run \u2192 tested diff \u2192 tested check \u2192 tested push --pr <n>"
2595
2666
  ].join("\n")
2596
- ).version("0.1.1");
2667
+ ).version(CLI_VERSION);
2597
2668
  registerSetupCommand(program2);
2598
2669
  registerDoctorCommand(program2);
2599
2670
  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}"`);
@@ -1525,6 +1529,7 @@ function registerPushCommand(program2) {
1525
1529
 
1526
1530
  // src/commands/doctor.ts
1527
1531
  var TESTED_BIN_BASENAME_RE = /^tested(\.js)?$/;
1532
+ var MIN_NODE_MAJOR = 24;
1528
1533
  function statusBadge(status) {
1529
1534
  const kind = status === "pass" ? "pass" : status === "fail" ? "fail" : status === "warn" ? "warn" : "info";
1530
1535
  return badge(kind);
@@ -1591,20 +1596,19 @@ async function runDoctor(deps) {
1591
1596
  const checks = [];
1592
1597
  const major = parseNodeMajor(nodeVersion);
1593
1598
  const nodeDisplay = nodeVersion.replace(/^v/, "v");
1594
- if (major !== null && major >= 22) {
1599
+ if (major !== null && major >= MIN_NODE_MAJOR) {
1595
1600
  checks.push({
1596
1601
  id: "node",
1597
1602
  label: "Node.js",
1598
1603
  status: "pass",
1599
- detail: `${nodeDisplay} (>= 20.19; 22+ recommended)`
1604
+ detail: `${nodeDisplay} (>= ${MIN_NODE_MAJOR})`
1600
1605
  });
1601
1606
  } else {
1602
1607
  checks.push({
1603
1608
  id: "node",
1604
1609
  label: "Node.js",
1605
- status: "warn",
1606
- detail: `${nodeDisplay} runs this CLI. Node >= 22 recommended.`,
1607
- optional: true
1610
+ status: "fail",
1611
+ detail: `${nodeDisplay} is below ${MIN_NODE_MAJOR}. Node >= ${MIN_NODE_MAJOR} required.`
1608
1612
  });
1609
1613
  }
1610
1614
  let isRepo = false;
@@ -1826,7 +1830,7 @@ async function runDoctor(deps) {
1826
1830
  optional: true
1827
1831
  });
1828
1832
  }
1829
- const hardFailIds = /* @__PURE__ */ new Set(["git", "config", "origin"]);
1833
+ const hardFailIds = /* @__PURE__ */ new Set(["node", "git", "config", "origin"]);
1830
1834
  const safetyFailIds = /* @__PURE__ */ new Set(["api_url", "tested_bin", "token"]);
1831
1835
  const hasHardFail = checks.some(
1832
1836
  (c) => c.status === "fail" && hardFailIds.has(c.id)
@@ -1871,6 +1875,73 @@ function registerDoctorCommand(program2) {
1871
1875
 
1872
1876
  // src/commands/setup.ts
1873
1877
  import pc3 from "picocolors";
1878
+
1879
+ // package.json
1880
+ var package_default = {
1881
+ name: "@tested/cli",
1882
+ version: "0.1.2",
1883
+ description: "Coverage your agent can use. CLI for patch + project coverage with agent-readable JSON output.",
1884
+ license: "MIT",
1885
+ homepage: "https://tested.dev",
1886
+ repository: {
1887
+ type: "git",
1888
+ url: "git+https://github.com/tested-hq/cli.git"
1889
+ },
1890
+ bugs: {
1891
+ url: "https://github.com/tested-hq/cli/issues"
1892
+ },
1893
+ publishConfig: {
1894
+ access: "public"
1895
+ },
1896
+ type: "module",
1897
+ packageManager: "pnpm@11.3.0",
1898
+ bin: {
1899
+ tested: "./dist/tested.js",
1900
+ td: "./dist/tested.js"
1901
+ },
1902
+ files: [
1903
+ "dist",
1904
+ "README.md",
1905
+ "LICENSE"
1906
+ ],
1907
+ scripts: {
1908
+ build: "tsup",
1909
+ dev: "tsx bin/tested.ts",
1910
+ test: "vitest run",
1911
+ "test:watch": "vitest",
1912
+ "test:coverage": "vitest run --coverage",
1913
+ typecheck: "tsc --noEmit",
1914
+ prepare: "node ./scripts/prepare.mjs",
1915
+ prepublishOnly: "pnpm run build"
1916
+ },
1917
+ engines: {
1918
+ node: ">=24"
1919
+ },
1920
+ dependencies: {
1921
+ commander: "14.0.3",
1922
+ minimatch: "10.2.5",
1923
+ picocolors: "1.1.1",
1924
+ "simple-git": "3.36.0",
1925
+ yaml: "2.9.0",
1926
+ zod: "4.4.3"
1927
+ },
1928
+ devDependencies: {
1929
+ "@types/node": "25.9.1",
1930
+ "@vitest/coverage-v8": "4.1.7",
1931
+ husky: "9.1.7",
1932
+ "is-ci": "3.0.1",
1933
+ tsup: "8.5.1",
1934
+ tsx: "4.22.3",
1935
+ typescript: "6.0.3",
1936
+ vite: "8.0.14",
1937
+ vitest: "4.1.7"
1938
+ }
1939
+ };
1940
+
1941
+ // src/version.ts
1942
+ var CLI_VERSION = package_default.version;
1943
+
1944
+ // src/commands/setup.ts
1874
1945
  var PINNED_CLI = "@tested/cli";
1875
1946
  function buildCiSnippet() {
1876
1947
  return [
@@ -1884,8 +1955,7 @@ function buildCiSnippet() {
1884
1955
  " - uses: actions/checkout@v4",
1885
1956
  " - uses: tested-hq/cli/action@main",
1886
1957
  " with:",
1887
- " # pin ref for reproducible installs (do not use floating tags in prod)",
1888
- " cli-ref: main",
1958
+ ` version: ${CLI_VERSION}`,
1889
1959
  " push: true",
1890
1960
  " pr-number: ${{ github.event.pull_request.number }}",
1891
1961
  " token: ${{ secrets.TESTED_TOKEN }}"
@@ -1902,6 +1972,7 @@ function buildTokenInstructions() {
1902
1972
  function buildInstallInstructions() {
1903
1973
  return [
1904
1974
  "Install CLI:",
1975
+ " Node 24+",
1905
1976
  ` pnpm add -D ${PINNED_CLI}`,
1906
1977
  ` # or: npx ${PINNED_CLI}`,
1907
1978
  "",
@@ -2593,7 +2664,7 @@ function createProgram() {
2593
2664
  "Agent loop:",
2594
2665
  " tested setup \u2192 tested run \u2192 tested diff \u2192 tested check \u2192 tested push --pr <n>"
2595
2666
  ].join("\n")
2596
- ).version("0.1.1");
2667
+ ).version(CLI_VERSION);
2597
2668
  registerSetupCommand(program2);
2598
2669
  registerDoctorCommand(program2);
2599
2670
  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.2",
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",