verifika 0.0.2 → 0.0.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/CHANGELOG.md +24 -0
- package/README.md +26 -12
- package/dist/cli.js +4 -0
- package/dist/init.js +39 -1
- package/dist/logs.js +58 -17
- package/dist/main.js +96 -22
- package/dist/pager.js +92 -0
- package/dist/planner.js +20 -7
- package/dist/preview.js +66 -7
- package/dist/process.js +9 -2
- package/dist/reporters/agent.js +5 -8
- package/dist/reporters/human.js +71 -21
- package/dist/reporters/live.js +209 -0
- package/dist/reporters/plan.js +4 -2
- package/dist/reporters/reporter.js +25 -1
- package/dist/runner.js +14 -1
- package/dist/runs.js +39 -0
- package/package.json +3 -3
- package/skills/verifika/SKILL.md +19 -4
package/dist/runner.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { constants } from "node:os";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { formatSeconds } from "./format.js";
|
|
4
|
+
import { LastLine } from "./preview.js";
|
|
4
5
|
import { execCheck } from "./process.js";
|
|
5
6
|
import { createRun, logPath, pruneRuns, readLatest, releaseRun, writeRunResult } from "./runs.js";
|
|
6
7
|
import { schedule } from "./scheduler.js";
|
|
@@ -47,6 +48,7 @@ export async function runVerification(options) {
|
|
|
47
48
|
selection,
|
|
48
49
|
selected: selected.map((check) => check.name),
|
|
49
50
|
concurrency: options.concurrency,
|
|
51
|
+
dependsOn: Object.fromEntries(selected.map((check) => [check.name, check.dependsOn])),
|
|
50
52
|
});
|
|
51
53
|
const env = { ...(options.env ?? process.env), VERIFIKA: "1", VERIFIKA_RUN_ID: runId };
|
|
52
54
|
let firstFailure = null;
|
|
@@ -54,6 +56,11 @@ export async function runVerification(options) {
|
|
|
54
56
|
const check = byName.get(task.name);
|
|
55
57
|
reporter.onCheckStart?.(check.name);
|
|
56
58
|
const log = logPath(runId, check.name);
|
|
59
|
+
const onCheckOutput = reporter.onCheckOutput?.bind(reporter);
|
|
60
|
+
const followers = onCheckOutput && {
|
|
61
|
+
stdout: new LastLine((line) => onCheckOutput(check.name, line)),
|
|
62
|
+
stderr: new LastLine((line) => onCheckOutput(check.name, line)),
|
|
63
|
+
};
|
|
57
64
|
const outcome = await execCheck({
|
|
58
65
|
command: check.command,
|
|
59
66
|
cwd: root,
|
|
@@ -62,6 +69,7 @@ export async function runVerification(options) {
|
|
|
62
69
|
logFile: path.join(root, log),
|
|
63
70
|
previewLines: options.previewLines,
|
|
64
71
|
signal,
|
|
72
|
+
...(followers ? { onOutput: (stream, text) => followers[stream].write(text) } : {}),
|
|
65
73
|
});
|
|
66
74
|
const checkResult = completedResult(results.get(check.name), check, outcome, log);
|
|
67
75
|
results.set(check.name, checkResult);
|
|
@@ -172,7 +180,12 @@ function completedResult(base, check, outcome, log) {
|
|
|
172
180
|
}
|
|
173
181
|
function notRunResult(base, outcome, interrupted, firstFailure) {
|
|
174
182
|
if (outcome.state === "blocked") {
|
|
175
|
-
return {
|
|
183
|
+
return {
|
|
184
|
+
...base,
|
|
185
|
+
status: "blocked",
|
|
186
|
+
reason: `dependency ${outcome.dependency} did not pass`,
|
|
187
|
+
blockedBy: outcome.dependency,
|
|
188
|
+
};
|
|
176
189
|
}
|
|
177
190
|
if (outcome.state !== "not_started")
|
|
178
191
|
return null;
|
package/dist/runs.js
CHANGED
|
@@ -155,6 +155,45 @@ function isProcessAlive(pid) {
|
|
|
155
155
|
return error.code === "EPERM";
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Estimates the time saved by skipping `names`: each check's duration in the most
|
|
160
|
+
* recent retained run where it ran to completion (passed or failed).
|
|
161
|
+
*/
|
|
162
|
+
export async function estimateSkipped(root, names) {
|
|
163
|
+
const found = new Map();
|
|
164
|
+
let runs = [];
|
|
165
|
+
try {
|
|
166
|
+
runs = (await readdir(path.join(root, STATE_DIR, RUNS_DIR)))
|
|
167
|
+
.filter((name) => RUN_ID_PATTERN.test(name))
|
|
168
|
+
.sort()
|
|
169
|
+
.reverse();
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// No runs yet: nothing is known.
|
|
173
|
+
}
|
|
174
|
+
const wanted = new Set(names);
|
|
175
|
+
for (const id of runs) {
|
|
176
|
+
if (found.size === wanted.size)
|
|
177
|
+
break;
|
|
178
|
+
let run;
|
|
179
|
+
try {
|
|
180
|
+
run = JSON.parse(await readFile(path.join(runDirectory(root, id), RESULT_FILE), "utf8"));
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
for (const check of run.checks ?? []) {
|
|
186
|
+
if (wanted.has(check.name) &&
|
|
187
|
+
!found.has(check.name) &&
|
|
188
|
+
(check.status === "passed" || check.status === "failed") &&
|
|
189
|
+
typeof check.durationMs === "number") {
|
|
190
|
+
found.set(check.name, check.durationMs);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const knownMs = [...found.values()].reduce((total, ms) => total + ms, 0);
|
|
195
|
+
return { knownMs, unknown: wanted.size - found.size };
|
|
196
|
+
}
|
|
158
197
|
export async function readRun(root, runId) {
|
|
159
198
|
const id = runId ?? (await readLatest(root));
|
|
160
199
|
if (id === null) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "verifika",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Deterministic, agent-friendly repository verification: run the checks your changes need, concurrently, with minimal output.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"verify",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"test": "vitest run",
|
|
52
52
|
"test:pack": "node scripts/pack-smoke.mjs",
|
|
53
53
|
"check:skill": "node scripts/check-skill.mjs",
|
|
54
|
-
"
|
|
55
|
-
"verify": "node src/cli.ts --all",
|
|
54
|
+
"verify": "node src/cli.ts",
|
|
55
|
+
"verify:ci": "node src/cli.ts --all",
|
|
56
56
|
"prepack": "npm run build"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
package/skills/verifika/SKILL.md
CHANGED
|
@@ -10,7 +10,7 @@ Verifika runs a repository's configured checks (lint, typecheck, tests, build, .
|
|
|
10
10
|
|
|
11
11
|
## Is it set up here?
|
|
12
12
|
|
|
13
|
-
Look for `verifika.config.json` in the repository root (or the package directory in a monorepo). Its `checks` object lists every check name and command. Run the CLI the way the repository does: `npx vfk` when it is a devDependency, `vfk` when installed globally, or
|
|
13
|
+
Look for `verifika.config.json` in the repository root (or the package directory in a monorepo). Its `checks` object lists every check name and command. Run the CLI the way the repository does: `npx vfk` when it is a devDependency, `vfk` when installed globally, or the repository's scripts. Projects set up with the init command have `npm run verify` (runs `vfk`: selective) and `npm run verify:ci` (runs `vfk --all`: the full gate). `npm run verify` is not the full gate. `vfk` is short for `verifika`; both commands are identical. The examples below write `vfk`.
|
|
14
14
|
|
|
15
15
|
## Workflow
|
|
16
16
|
|
|
@@ -34,7 +34,7 @@ Look for `verifika.config.json` in the repository root (or the package directory
|
|
|
34
34
|
vfk --check typecheck
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
4. **Before claiming the task is complete, committing, or opening a pull request**, always run the full suite:
|
|
37
|
+
4. **Before claiming the task is complete, committing, or opening a pull request**, always run the full suite (`npm run verify:ci` where that script exists):
|
|
38
38
|
|
|
39
39
|
```sh
|
|
40
40
|
vfk --all
|
|
@@ -59,7 +59,22 @@ On failure, one line per problem, a short preview, and the command for full logs
|
|
|
59
59
|
FAIL 3/4 (3.2s) full run (--all)
|
|
60
60
|
typecheck: exit 2
|
|
61
61
|
src/cart.ts(14,7): error TS2322: Type 'string' is not assignable to type 'number'.
|
|
62
|
-
Run:
|
|
62
|
+
Run: vfk logs typecheck
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Previews are shown for at most three failed checks. Any further failed check says where its output is instead:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
FAIL 1/5 (9.8s) full run (--all)
|
|
69
|
+
format: exit 1
|
|
70
|
+
[warn] src/cart.ts
|
|
71
|
+
lint: exit 1
|
|
72
|
+
/repo/src/cart.ts
|
|
73
|
+
12:9 error 'total' is assigned a value but never used no-unused-vars
|
|
74
|
+
typecheck: exit 2
|
|
75
|
+
src/cart.ts(14,7): error TS2322: Type 'string' is not assignable to type 'number'.
|
|
76
|
+
test: exit 1 (preview omitted: vfk logs test)
|
|
77
|
+
Run: vfk logs --failed
|
|
63
78
|
```
|
|
64
79
|
|
|
65
80
|
| Exit code | Meaning |
|
|
@@ -83,7 +98,7 @@ Check statuses: `passed`, `failed`, `timed_out`, `error` (could not start, or le
|
|
|
83
98
|
## Rules
|
|
84
99
|
|
|
85
100
|
- Do not claim success unless you saw `PASS` and exit code 0 from a finished run. Say what ran: "selective verification passed (2 checks)" is not "all checks pass".
|
|
86
|
-
- A selective `PASS` only covers the checks it selected. Skipped checks were not verified. Run `vfk --all` before delivery, every time.
|
|
101
|
+
- A selective `PASS` only covers the checks it selected. Skipped checks were not verified. Run `vfk --all` (or `npm run verify:ci`) before delivery, every time; `npm run verify` is selective and does not count.
|
|
87
102
|
- `PASS 0/0` means nothing matched your changes and nothing was verified.
|
|
88
103
|
- Do not read logs of passing checks or use `vfk logs` after a `PASS`; there is nothing to diagnose.
|
|
89
104
|
- Do not edit `verifika.config.json`, remove checks, narrow `paths`, raise timeouts, or pass `--check` to dodge a failing check, unless the user asked for that change.
|