supercov 0.0.42 → 0.0.43

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 (34) hide show
  1. package/README.md +23 -3
  2. package/analyzers/typescript/README.md +55 -0
  3. package/analyzers/typescript/bin/compiler-identity.mjs +78 -0
  4. package/analyzers/typescript/bin/identity.mjs +67 -0
  5. package/analyzers/typescript/bin/query.mjs +29 -0
  6. package/analyzers/typescript/dist/analyze.js +3972 -0
  7. package/analyzers/typescript/dist/archive.js +309 -0
  8. package/analyzers/typescript/dist/build-identity.json +1 -0
  9. package/analyzers/typescript/dist/compiler.js +32 -0
  10. package/analyzers/typescript/dist/frontend.js +75 -0
  11. package/analyzers/typescript/dist/native-frontend.js +271 -0
  12. package/analyzers/typescript/dist/pragmas.js +143 -0
  13. package/analyzers/typescript/dist/types.js +1 -0
  14. package/analyzers/typescript/package.json +27 -0
  15. package/analyzers/typescript/src/analyze.ts +4538 -0
  16. package/analyzers/typescript/src/archive.ts +438 -0
  17. package/analyzers/typescript/src/compiler.ts +49 -0
  18. package/analyzers/typescript/src/frontend.ts +136 -0
  19. package/analyzers/typescript/src/native-frontend.ts +315 -0
  20. package/analyzers/typescript/src/pragmas.ts +218 -0
  21. package/analyzers/typescript/src/types.ts +45 -0
  22. package/analyzers/typescript/tsconfig.json +12 -0
  23. package/docs/agent-loop.md +13 -0
  24. package/docs/assertion-evidence.md +135 -0
  25. package/docs/cli.md +10 -0
  26. package/docs/code-verification.md +182 -0
  27. package/docs/supported-suites.md +40 -9
  28. package/docs/verification.md +12 -0
  29. package/package.json +33 -15
  30. package/runtime/javascript/jest.cjs +134 -0
  31. package/runtime/javascript/jest.config.mjs +39 -0
  32. package/runtime/javascript/jestReporter.mjs +77 -0
  33. package/runtime/javascript/register.mjs +22 -4
  34. package/runtime/javascript/runtime.mjs +51 -13
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- ![Supercov: Coverage for coding agents working overnight](https://raw.githubusercontent.com/supercorp-ai/supercov/main/supercov.jpg)
1
+ ![Coverage for coding agents and software factories 🌙](https://raw.githubusercontent.com/supercorp-ai/supercov/main/supercov.jpg)
2
2
 
3
- **Coverage for coding agents working overnight.**
3
+ **Coverage for coding agents and software factories 🌙**
4
4
 
5
5
  **Supercov gives your coding agent the next useful test to write.** It runs the test command you already use, records local coverage evidence, and turns uncovered paths into small, actionable queries. Your agent writes a focused test, reruns the suite, proves what improved, and keeps going while useful gaps remain.
6
6
 
@@ -10,6 +10,9 @@ No account, config file, import, custom reporter, or hosted service is required.
10
10
 
11
11
  Supported by [Supercorp](https://supercorp.ai).
12
12
 
13
+ [Try the worked example](https://supercov.com/docs/code-verification): find an
14
+ untested session-expiry condition, run an additional test, and compare the results.
15
+
13
16
  ## Start with the suite you already have
14
17
 
15
18
  ```bash
@@ -43,6 +46,23 @@ npx supercov -- python -m unittest
43
46
  npx supercov -- bundle exec rspec
44
47
  ```
45
48
 
49
+ ## Inspect assertion evidence (JS/TS)
50
+
51
+ After a run, inspect what existing assertions appear to check:
52
+
53
+ ```sh
54
+ npx supercov runs latest assertions --limit 5
55
+ npx supercov runs latest assertions --pragmas --json
56
+ npx supercov runs latest assertions --evidence /tests --limit 5 --json
57
+ ```
58
+
59
+ This npm-only query uses the run archive and matching source; it adds no new
60
+ test-time instrumentation. It requires a compatible project TypeScript compiler
61
+ API (5.8.3 and native 7.0.2 are tested). Results are candidates, not proof
62
+ that changes are safe or a verified assertion percentage. Follow
63
+ [`assertion-evidence.md`](docs/assertion-evidence.md) for provenance, optional
64
+ assertion hints, pagination, and limitations.
65
+
46
66
  ## Give Supercov a job
47
67
 
48
68
  Paste one of these prompts into Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, or any coding agent that can run terminal commands.
@@ -150,7 +170,7 @@ Supercov uses exact per-test attribution where an adapter is available. For othe
150
170
  | --- | --- |
151
171
  | Playwright | Exact per test, worker, retry, outcome, action, and assertion phase |
152
172
  | Vitest | Exact per test, with setup execution kept separate |
153
- | Jest | Exact per test, including concurrent and parameterized tests |
173
+ | Jest | Exact per test, including parameterized tests; `expect` assertions link the evidence they check |
154
174
  | `node:test` | Exact per test |
155
175
  | AVA and Mocha | Aggregate structural coverage |
156
176
  | Cargo's standard libtest runner | Exact test, attempt, and passing-assertion identity |
@@ -0,0 +1,55 @@
1
+ # JS/TS assertion analyzer (internal)
2
+
3
+ This private package is the post-run analysis component used by Supercov's
4
+ `runs <run> assertions` command. It is bundled in the npm distribution, not
5
+ published as a separate CLI or SDK.
6
+
7
+ See [Assertion evidence](../../docs/assertion-evidence.md) for public commands,
8
+ pragma syntax, report interpretation and supported scope.
9
+
10
+ ## Product boundary
11
+
12
+ - `bin/query.mjs` is the CLI-to-analyzer JSON transport. It accepts an ordinary
13
+ archive representation prepared by Rust, validates identities and returns facts.
14
+ - `bin/identity.mjs` checks the analyzer source/build identity; its direct
15
+ invocation writes that identity during the build.
16
+ - `bin/compiler-identity.mjs` fingerprints the project's compiler implementation.
17
+ - `src/archive.ts` validates the archive protocol, source positions and attempt
18
+ ownership, then constructs query-local evidence in memory.
19
+ - `src/analyze.ts` extracts source-flow facts and exact assertion witnesses.
20
+ The Rust engine joins those facts into candidate classifications.
21
+ - `src/frontend.ts` and `src/native-frontend.ts` implement the legacy and native
22
+ TypeScript compiler boundaries. `src/pragmas.ts` validates optional hints.
23
+
24
+ There is no converted-input command, on-disk research input, V8 remapping,
25
+ mutation runner or diagnostic-ablation option in the product interface.
26
+ Source files ship to support build-identity verification; tests and research
27
+ tools do not ship. Assertion candidates remain unverified, not safety proofs.
28
+ Only executable JavaScript and its build identity ship from `dist`; there is no
29
+ public SDK declaration surface or generated source-map payload.
30
+
31
+ ## Build and test
32
+
33
+ From this directory:
34
+
35
+ ```sh
36
+ npm ci --ignore-scripts
37
+ npm test
38
+ ```
39
+
40
+ The build uses pinned TypeScript 5.8.3 explicitly. Project analysis uses the
41
+ project's compiler; native 7.0.2 has a separate frontend and identity checks.
42
+ Native compiler processes close after both successful and failed queries.
43
+
44
+ From the repository root, exercise real Node/Vitest archives and the installed
45
+ npm package:
46
+
47
+ ```sh
48
+ npm run test:asserted-integration
49
+ npm run test:asserted-package
50
+ ```
51
+
52
+ Controlled unit fixtures test parser, flow and witness rules. The ordinary-archive
53
+ integration tests execute real suites and explicit behavioral counterexamples.
54
+ Compiler-path and identity regressions run across supported CI platforms.
55
+ Historical external-cohort research is not part of the default suite or product.
@@ -0,0 +1,78 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFileSync, readdirSync } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+ import { createRequire } from "node:module";
5
+ import { pathToFileURL } from "node:url";
6
+ import { projectCompilerPath } from "../dist/compiler.js";
7
+
8
+ /** Hash the native implementation as well as its JS client; version.cjs alone is not the compiler. */
9
+ export function compilerIdentity(projectRoot) {
10
+ return compilerIdentityFromEntry(projectCompilerPath(projectRoot));
11
+ }
12
+
13
+ export function compilerIdentityFromEntry(entry) {
14
+ const require = createRequire(pathToFileURL(entry));
15
+ const { version } = require(entry);
16
+ const entrySha256 = createHash("sha256")
17
+ .update(readFileSync(entry))
18
+ .digest("hex");
19
+ if (version !== "7.0.2")
20
+ return { backend: "typescript-legacy", version, sha256: entrySha256 };
21
+ const packageRoot = dirname(require.resolve("typescript/package.json"));
22
+ const platform = `@typescript/typescript-${process.platform}-${process.arch}`;
23
+ let nativeRoot;
24
+ try {
25
+ nativeRoot = dirname(require.resolve(`${platform}/package.json`));
26
+ } catch (cause) {
27
+ throw new Error(
28
+ `TypeScript 7's native compiler dependency ${platform} is missing. Install the project's optional TypeScript dependencies before recapturing tests.`,
29
+ { cause },
30
+ );
31
+ }
32
+ const nativeMetadata = JSON.parse(
33
+ readFileSync(resolve(nativeRoot, "package.json"), "utf8"),
34
+ );
35
+ if (nativeMetadata.name !== platform || nativeMetadata.version !== version)
36
+ throw new Error(
37
+ `TypeScript native package identity mismatch: expected ${platform}@${version}`,
38
+ );
39
+ const executable = resolve(
40
+ nativeRoot,
41
+ "lib",
42
+ process.platform === "win32" ? "tsc.exe" : "tsc",
43
+ );
44
+ const nativeSha256 = createHash("sha256")
45
+ .update(readFileSync(executable))
46
+ .digest("hex");
47
+ const hash = createHash("sha256");
48
+ let files = 0;
49
+ function walk(root, relative = "") {
50
+ for (const file of readdirSync(resolve(root, relative), {
51
+ withFileTypes: true,
52
+ }).sort((a, b) => a.name.localeCompare(b.name))) {
53
+ if (file.name === "node_modules") continue;
54
+ const path = relative ? `${relative}/${file.name}` : file.name;
55
+ if (file.isDirectory()) walk(root, path);
56
+ else if (file.isFile()) {
57
+ hash
58
+ .update(path)
59
+ .update("\0")
60
+ .update(readFileSync(resolve(root, path)))
61
+ .update("\0");
62
+ files++;
63
+ } else throw new Error(`Unsupported compiler package entry: ${path}`);
64
+ }
65
+ }
66
+ hash.update("typescript-package\0");
67
+ walk(packageRoot);
68
+ hash.update("native-package\0");
69
+ walk(nativeRoot);
70
+ return {
71
+ backend: "typescript-native-7",
72
+ version,
73
+ sha256: hash.digest("hex"),
74
+ nativePackage: platform,
75
+ nativeSha256,
76
+ files,
77
+ };
78
+ }
@@ -0,0 +1,67 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFileSync, writeFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const root = resolve(import.meta.dirname, "..");
7
+ const sources = [
8
+ "src/analyze.ts",
9
+ "src/archive.ts",
10
+ "src/compiler.ts",
11
+ "src/frontend.ts",
12
+ "src/native-frontend.ts",
13
+ "src/types.ts",
14
+ "src/pragmas.ts",
15
+ "bin/query.mjs",
16
+ "bin/compiler-identity.mjs",
17
+ "bin/identity.mjs",
18
+ "tsconfig.json",
19
+ // npm excludes package-lock.json from tarballs. Hash shipped build inputs,
20
+ // not a checkout-only file, so installed and development checks are identical.
21
+ "package.json",
22
+ ];
23
+ const outputs = [
24
+ "dist/analyze.js",
25
+ "dist/archive.js",
26
+ "dist/compiler.js",
27
+ "dist/frontend.js",
28
+ "dist/native-frontend.js",
29
+ "dist/types.js",
30
+ "dist/pragmas.js",
31
+ ];
32
+ function digest(files) {
33
+ const hash = createHash("sha256");
34
+ for (const file of files)
35
+ hash
36
+ .update(file)
37
+ .update("\0")
38
+ .update(readFileSync(resolve(root, file)))
39
+ .update("\0");
40
+ return hash.digest("hex");
41
+ }
42
+ export function identity() {
43
+ return {
44
+ schema: 1,
45
+ sourceSha256: digest(sources),
46
+ compiledSha256: digest(outputs),
47
+ };
48
+ }
49
+ export function checkedIdentity() {
50
+ const built = JSON.parse(
51
+ readFileSync(resolve(root, "dist/build-identity.json"), "utf8"),
52
+ );
53
+ const current = identity();
54
+ if (JSON.stringify(built) !== JSON.stringify(current))
55
+ throw new Error(
56
+ "Assertion analyzer build is stale or modified; rebuild analyzers/typescript",
57
+ );
58
+ return current;
59
+ }
60
+ if (
61
+ process.argv[1] &&
62
+ resolve(process.argv[1]) === fileURLToPath(import.meta.url)
63
+ )
64
+ writeFileSync(
65
+ resolve(root, "dist/build-identity.json"),
66
+ JSON.stringify(identity()) + "\n",
67
+ );
@@ -0,0 +1,29 @@
1
+ // First-party query transport, never executed by the test runner.
2
+ import { readFileSync } from "node:fs";
3
+ import { checkedIdentity } from "./identity.mjs";
4
+
5
+ try {
6
+ const analyzer = checkedIdentity();
7
+ const input = JSON.parse(readFileSync(0, "utf8"));
8
+ // Check the build before importing executable analyzer code.
9
+ const { compilerIdentity } = await import("./compiler-identity.mjs");
10
+ const { analyzeArchive } = await import("../dist/archive.js");
11
+ const compiler = compilerIdentity(input.projectRoot);
12
+ const compilerSha256 = compiler.sha256;
13
+ const result = analyzeArchive(input);
14
+ if (
15
+ JSON.stringify(compilerIdentity(input.projectRoot)) !==
16
+ JSON.stringify(compiler) ||
17
+ JSON.stringify(checkedIdentity()) !== JSON.stringify(analyzer)
18
+ )
19
+ throw new Error("Analyzer or compiler changed during analysis");
20
+ process.stdout.write(
21
+ JSON.stringify({
22
+ ...result,
23
+ analyzer: { ...analyzer, compilerSha256, compiler },
24
+ }),
25
+ );
26
+ } catch (error) {
27
+ console.error(error instanceof Error ? error.message : String(error));
28
+ process.exitCode = 1;
29
+ }