@codacy/verity-cli 0.34.0-experimental.5602fd5 → 0.34.0-experimental.675f6d2
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/bin/verity.js +69 -100
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -17221,7 +17221,7 @@ function readConfigFile(path) {
|
|
|
17221
17221
|
return {
|
|
17222
17222
|
git_moments: [...new Set(moments)],
|
|
17223
17223
|
...source2 ? { git_moments_source: source2 } : {},
|
|
17224
|
-
...raw.formal === "push"
|
|
17224
|
+
...raw.formal === "push" ? { formal: "push" } : {}
|
|
17225
17225
|
};
|
|
17226
17226
|
} catch {
|
|
17227
17227
|
return DEFAULTS;
|
|
@@ -24152,7 +24152,7 @@ function registerConfigCommands(program2) {
|
|
|
24152
24152
|
config.command("formal [state]").description('Get or set formal verification at push: "push" or "off" (needs Lean \u2014 verity lean status)').action((state) => {
|
|
24153
24153
|
if (state === void 0) {
|
|
24154
24154
|
const cfg = readProjectConfig();
|
|
24155
|
-
process.stdout.write((cfg.formal
|
|
24155
|
+
process.stdout.write((cfg.formal ?? "off") + "\n");
|
|
24156
24156
|
if (cfg.formal_refused) printWarn(formalRefusalMessage(cfg.formal_refused));
|
|
24157
24157
|
return;
|
|
24158
24158
|
}
|
|
@@ -24160,7 +24160,7 @@ function registerConfigCommands(program2) {
|
|
|
24160
24160
|
printError(`Unrecognised state: ${state}. Use "push" or "off".`);
|
|
24161
24161
|
process.exit(1);
|
|
24162
24162
|
}
|
|
24163
|
-
writeProjectConfig({ formal: state === "push" ? "push" :
|
|
24163
|
+
writeProjectConfig({ formal: state === "push" ? "push" : void 0 });
|
|
24164
24164
|
const refused2 = state === "push" ? readProjectConfig().formal_refused : void 0;
|
|
24165
24165
|
if (refused2) {
|
|
24166
24166
|
printWarn(`Formal verification at push: still off \u2014 ${formalRefusalMessage(refused2)}`);
|
|
@@ -27073,7 +27073,7 @@ function channelSilence(input) {
|
|
|
27073
27073
|
// src/lib/cli-version.ts
|
|
27074
27074
|
function cliVersion() {
|
|
27075
27075
|
try {
|
|
27076
|
-
return true ? "0.34.0-experimental.
|
|
27076
|
+
return true ? "0.34.0-experimental.675f6d2" : "dev";
|
|
27077
27077
|
} catch {
|
|
27078
27078
|
return "dev";
|
|
27079
27079
|
}
|
|
@@ -33869,11 +33869,6 @@ async function rankViaServer(candidates2, ctx, auth2) {
|
|
|
33869
33869
|
cmd: "prove-rank"
|
|
33870
33870
|
});
|
|
33871
33871
|
if (!res.ok) return { ok: false, ranker: "luna", error: res.error, ranked: fallback };
|
|
33872
|
-
const off = res.data;
|
|
33873
|
-
if (off?.enabled === false) {
|
|
33874
|
-
const why = typeof off.reason === "string" ? off.reason.slice(0, 40) : "disabled";
|
|
33875
|
-
return { ok: false, ranker: "luna", error: `formal is off for this project (${why})`, ranked: fallback, disabled: why };
|
|
33876
|
-
}
|
|
33877
33872
|
const items = Array.isArray(res.data?.items) ? res.data.items : [];
|
|
33878
33873
|
return { ok: true, ranker: "luna", ranked: applyAnnotations(candidates2, items), costUsd: typeof res.data?.cost_usd === "number" ? res.data.cost_usd : null };
|
|
33879
33874
|
}
|
|
@@ -34598,8 +34593,6 @@ async function generateModel(target, opts) {
|
|
|
34598
34593
|
});
|
|
34599
34594
|
if (!res.ok) return { ok: false, error: res.error };
|
|
34600
34595
|
const d = res.data ?? {};
|
|
34601
|
-
const off = d;
|
|
34602
|
-
if (off.enabled === false) return { ok: false, error: `formal is off for this project (${typeof off.reason === "string" ? off.reason.slice(0, 40) : "disabled"})` };
|
|
34603
34596
|
if (d.error && typeof d.error === "object") return { ok: false, error: `${d.error.code ?? "SERVICE_ERROR"}: ${d.error.message ?? "the service failed"}` };
|
|
34604
34597
|
const usage2 = d.usage && typeof d.usage === "object" ? { inputTokens: Number(d.usage.inputTokens ?? 0), outputTokens: Number(d.usage.outputTokens ?? 0) } : null;
|
|
34605
34598
|
return acceptAnswer(d, usage2, typeof d.cost_usd === "number" ? d.cost_usd : null);
|
|
@@ -34779,7 +34772,8 @@ Rules:
|
|
|
34779
34772
|
5. Write the harness as ONE file and run it in the SAME shell call that writes it (a heredoc followed by the run). TypeScript: node --experimental-strip-types harness.ts (detect runtimes only if that fails: node --version, python3 --version); if strip-types is unavailable, remove type annotations ONLY on lines that are not part of the function under test's logic, and say so. Python: python3 harness.py.
|
|
34780
34773
|
6. Nothing you run can reach the network. Do not try.
|
|
34781
34774
|
7. Keep it under about eight shell calls. Output tokens are time.
|
|
34782
|
-
8. Answer with the JSON object only: verdict (reproduced | diverged | unreplayable), reason (2-4 sentences: what you ran, what the real code did, and how that compares to the trace's final state), harness_files (every file you wrote: path and its line count \u2014 do NOT paste contents, your shell calls already carry them), executed_output (the last relevant stdout, at most 2000 characters).
|
|
34775
|
+
8. Answer with the JSON object only: verdict (reproduced | diverged | unreplayable), reason (2-4 sentences: what you ran, what the real code did, and how that compares to the trace's final state), harness_files (every file you wrote: path and its line count \u2014 do NOT paste contents, your shell calls already carry them), executed_output (the last relevant stdout, at most 2000 characters), impact (one word, below).
|
|
34776
|
+
9. impact \u2014 AFTER the verdict, and never a reason to change it: what the violation you ran costs a user of this code, the most serious one the run showed. money: a balance, charge, refund, price or stock is wrong. access: someone gets access they should not have, or an auth check is bypassed. data: a user's records are lost, corrupted or wrongly duplicated. external: an effect outside the system happens twice or never (a charge, an email, a shipment, a webhook). count: a counter, metric or statistic is off. cache: a cached or derived value is stale until it refreshes. internal: the program's own bookkeeping is off, with no effect a user would see. none: the verdict is not reproduced.
|
|
34783
34777
|
|
|
34784
34778
|
"reproduced" means the real code, driven by the trace, reached the property violation the model describes. "diverged" means it did not \u2014 the model is wrong about the code, which is a useful answer. "unreplayable" means you could not run the real function faithfully; say why.`;
|
|
34785
34779
|
var REPLAY_SCHEMA = {
|
|
@@ -34797,9 +34791,10 @@ var REPLAY_SCHEMA = {
|
|
|
34797
34791
|
required: ["path", "lines"]
|
|
34798
34792
|
}
|
|
34799
34793
|
},
|
|
34800
|
-
executed_output: { type: "string" }
|
|
34794
|
+
executed_output: { type: "string" },
|
|
34795
|
+
impact: { type: "string", enum: ["money", "access", "data", "external", "count", "cache", "internal", "none"] }
|
|
34801
34796
|
},
|
|
34802
|
-
required: ["verdict", "reason", "harness_files", "executed_output"]
|
|
34797
|
+
required: ["verdict", "reason", "harness_files", "executed_output", "impact"]
|
|
34803
34798
|
};
|
|
34804
34799
|
function renderBriefInput(brief) {
|
|
34805
34800
|
const p = brief.property;
|
|
@@ -34826,6 +34821,8 @@ function renderBriefInput(brief) {
|
|
|
34826
34821
|
}
|
|
34827
34822
|
return parts2.join("\n");
|
|
34828
34823
|
}
|
|
34824
|
+
var IMPACTS = ["money", "access", "data", "external", "count", "cache", "internal", "none"];
|
|
34825
|
+
var isImpact = (v) => typeof v === "string" && IMPACTS.includes(v);
|
|
34829
34826
|
function stringsIn(value, out2 = [], depth = 0) {
|
|
34830
34827
|
if (depth > 8) return out2;
|
|
34831
34828
|
if (typeof value === "string") out2.push(value);
|
|
@@ -34867,7 +34864,8 @@ function parseReplayOutput(output) {
|
|
|
34867
34864
|
verdict,
|
|
34868
34865
|
reason: typeof o.reason === "string" ? o.reason.slice(0, 2e3) : "",
|
|
34869
34866
|
harness_files: Array.isArray(o.harness_files) ? o.harness_files.filter((f) => typeof f.path === "string").map((f) => ({ path: String(f.path).slice(0, 200), lines: Number.isInteger(f.lines) ? f.lines : 0 })) : [],
|
|
34870
|
-
executed_output: typeof o.executed_output === "string" ? o.executed_output.slice(0, 2e3) : ""
|
|
34867
|
+
executed_output: typeof o.executed_output === "string" ? o.executed_output.slice(0, 2e3) : "",
|
|
34868
|
+
impact: isImpact(o.impact) ? o.impact : "none"
|
|
34871
34869
|
};
|
|
34872
34870
|
}
|
|
34873
34871
|
} catch {
|
|
@@ -34875,10 +34873,10 @@ function parseReplayOutput(output) {
|
|
|
34875
34873
|
}
|
|
34876
34874
|
return { claim, shellCalls, executedCalls, shellTexts, outputTexts };
|
|
34877
34875
|
}
|
|
34878
|
-
var RESULT_LINE = /REPLAY_RESULT=(reproduced|diverged)\b
|
|
34876
|
+
var RESULT_LINE = /REPLAY_RESULT=(reproduced|diverged)\b/;
|
|
34879
34877
|
function printedResult(outputTexts) {
|
|
34880
34878
|
let last = null;
|
|
34881
|
-
for (const t of outputTexts) for (const m of t.matchAll(RESULT_LINE)) last = m[1];
|
|
34879
|
+
for (const t of outputTexts) for (const m of t.matchAll(new RegExp(RESULT_LINE.source, "g"))) last = m[1];
|
|
34882
34880
|
return last;
|
|
34883
34881
|
}
|
|
34884
34882
|
var RESULT_MISSING = "the harness never printed REPLAY_RESULT=reproduced on its own stdout \u2014 the verdict was the model's word, not the run's";
|
|
@@ -35068,6 +35066,7 @@ async function runReplayInContainer(brief, opts) {
|
|
|
35068
35066
|
...judged,
|
|
35069
35067
|
executedCalls,
|
|
35070
35068
|
shellCalls,
|
|
35069
|
+
...judged.verdict === "reproduced" && parsed.claim ? { impact: parsed.claim.impact } : {},
|
|
35071
35070
|
executedOutput: parsed.claim?.executed_output ?? "",
|
|
35072
35071
|
harnessFiles: parsed.claim?.harness_files ?? [],
|
|
35073
35072
|
usage,
|
|
@@ -35114,11 +35113,6 @@ async function runReplayViaServer(brief, auth2, budgetMs = 24e4) {
|
|
|
35114
35113
|
return { claimed: null, verdict: "unverified", reason: "", downgrade: res.error, executedCalls: 0, shellCalls: 0, verbatim: none, executedOutput: "", harnessFiles: [], usage: null, durationMs: Date.now() - started, containerId: null, error: res.error };
|
|
35115
35114
|
}
|
|
35116
35115
|
const d = res.data ?? {};
|
|
35117
|
-
if (d.enabled === false) {
|
|
35118
|
-
const why = d.reason;
|
|
35119
|
-
const msg = `formal is off for this project (${typeof why === "string" ? why.slice(0, 40) : "disabled"})`;
|
|
35120
|
-
return { claimed: null, verdict: "unverified", reason: "", downgrade: msg, executedCalls: 0, shellCalls: 0, verbatim: none, executedOutput: "", harnessFiles: [], usage: null, durationMs: Date.now() - started, containerId: null, error: msg };
|
|
35121
|
-
}
|
|
35122
35116
|
if (d.error && typeof d.error === "object") {
|
|
35123
35117
|
const e = d.error;
|
|
35124
35118
|
const msg = `${e.code ?? "SERVICE_ERROR"}: ${e.message ?? "the service failed"}`;
|
|
@@ -35131,6 +35125,7 @@ async function runReplayViaServer(brief, auth2, budgetMs = 24e4) {
|
|
|
35131
35125
|
verdict: verdict === "reproduced" || verdict === "diverged" || verdict === "unreplayable" ? verdict : "unverified",
|
|
35132
35126
|
reason: typeof d.reason === "string" ? d.reason : "",
|
|
35133
35127
|
downgrade: typeof d.downgrade === "string" ? d.downgrade : null,
|
|
35128
|
+
...isImpact(d.impact) ? { impact: d.impact } : {},
|
|
35134
35129
|
executedCalls: Number(d.executed_calls ?? 0),
|
|
35135
35130
|
shellCalls: Number(d.shell_calls ?? 0),
|
|
35136
35131
|
verbatim: { covered: Number(v.covered ?? 0), total: Number(v.total ?? 0), ratio: Number(v.ratio ?? 0), basis: v.basis === "symbol" || v.basis === "file" ? v.basis : "none" },
|
|
@@ -35915,10 +35910,9 @@ function verityLeanHome(env = process.env) {
|
|
|
35915
35910
|
function findToolchain(env = process.env) {
|
|
35916
35911
|
const managedBin = (0, import_node_path43.join)(verityLeanHome(env), LEAN_TOOLCHAIN.replace(/^leanprover\/lean4:/, ""), "bin");
|
|
35917
35912
|
const elanBin = (0, import_node_path43.join)(env.HOME ?? (0, import_node_os9.homedir)(), ".elan", "bin");
|
|
35918
|
-
const
|
|
35919
|
-
const userPath = (env.PATH ?? "").split(import_node_path43.delimiter).filter((d) => d && (elanHas || (0, import_node_path43.resolve)(d) !== (0, import_node_path43.resolve)(elanBin)));
|
|
35920
|
-
const path = [managedBin, ...elanHas ? [elanBin] : [], ...userPath].join(import_node_path43.delimiter);
|
|
35913
|
+
const path = [managedBin, elanBin, env.PATH ?? ""].filter(Boolean).join(import_node_path43.delimiter);
|
|
35921
35914
|
const merged = { ...env, PATH: path, ELAN_TOOLCHAIN: env.ELAN_TOOLCHAIN ?? LEAN_TOOLCHAIN };
|
|
35915
|
+
const elanHas = (0, import_node_fs58.existsSync)((0, import_node_path43.join)(env.HOME ?? (0, import_node_os9.homedir)(), ".elan", "toolchains", LEAN_TOOLCHAIN.replace("/", "--").replace(":", "---")));
|
|
35922
35916
|
const exe = process.platform === "win32" ? "lake.exe" : "lake";
|
|
35923
35917
|
const candidates2 = [(0, import_node_path43.join)(managedBin, exe), ...elanHas ? [(0, import_node_path43.join)(elanBin, exe)] : [], exe];
|
|
35924
35918
|
for (const candidate of candidates2) {
|
|
@@ -36113,18 +36107,33 @@ function writeResult(root, report) {
|
|
|
36113
36107
|
function isCrashTrace(trace) {
|
|
36114
36108
|
return trace.some((s) => /\b(crash\w*|kill\w*|restart\w*|interrupt\w*|power|abort\w*|process (dies|exit\w*)|lost (reply|response))\b/i.test(s));
|
|
36115
36109
|
}
|
|
36110
|
+
var SEVERITY_BY_IMPACT = {
|
|
36111
|
+
money: "high",
|
|
36112
|
+
access: "high",
|
|
36113
|
+
data: "high",
|
|
36114
|
+
external: "high",
|
|
36115
|
+
count: "medium",
|
|
36116
|
+
cache: "medium",
|
|
36117
|
+
internal: "medium",
|
|
36118
|
+
// A reproduced finding always has a real code; 'none' here is a malformed answer, so it blocks.
|
|
36119
|
+
none: "high"
|
|
36120
|
+
};
|
|
36121
|
+
function formalSeverity(f) {
|
|
36122
|
+
return f.impact && SEVERITY_BY_IMPACT[f.impact] || "high";
|
|
36123
|
+
}
|
|
36116
36124
|
function mergeFormalFindings(response, outcome, pushedFiles) {
|
|
36117
|
-
if (!outcome) return { blocking: 0 };
|
|
36125
|
+
if (!outcome) return { blocking: 0, warning: 0 };
|
|
36118
36126
|
const norm2 = (p) => p.replace(/\\/g, "/");
|
|
36119
36127
|
const pushed = new Set(pushedFiles.map(norm2));
|
|
36120
|
-
const
|
|
36121
|
-
if (
|
|
36128
|
+
const reproduced = outcome.findings.filter((f) => f.verdict === "reproduced" && !f.waived && pushed.has(norm2(f.file)));
|
|
36129
|
+
if (reproduced.length === 0) return { blocking: 0, warning: 0 };
|
|
36130
|
+
const blocking = reproduced.filter((f) => formalSeverity(f) === "high");
|
|
36122
36131
|
const existing = Array.isArray(response.findings) ? response.findings : [];
|
|
36123
36132
|
response.findings = [
|
|
36124
36133
|
...existing,
|
|
36125
|
-
...
|
|
36134
|
+
...reproduced.map((f) => ({
|
|
36126
36135
|
pattern_id: "formal-counterexample",
|
|
36127
|
-
severity:
|
|
36136
|
+
severity: formalSeverity(f),
|
|
36128
36137
|
scope: "change",
|
|
36129
36138
|
file: f.file,
|
|
36130
36139
|
line: outcome.target?.lines?.from ?? null,
|
|
@@ -36132,14 +36141,15 @@ function mergeFormalFindings(response, outcome, pushedFiles) {
|
|
|
36132
36141
|
// as a title it read backwards (e2e, 2026-09-26). A trace that needs a
|
|
36133
36142
|
// crash between two writes is labelled: reproducing it means injecting
|
|
36134
36143
|
// the crash, so it is a crash-consistency finding, not a race.
|
|
36135
|
-
title: `Formal: ${terminalText(f.symbol, 128)} breaks "${terminalText(f.desc, 280)}"${isCrashTrace(f.trace) ? " after a crash (crash consistency)" : ""} \u2014 reproduced on the real code`,
|
|
36144
|
+
title: `Formal: ${terminalText(f.symbol, 128)} breaks "${terminalText(f.desc, 280)}"${isCrashTrace(f.trace) ? " after a crash (crash consistency)" : ""} \u2014 reproduced on the real code${f.impact && f.impact !== "none" ? ` (impact: ${f.impact})` : ""}`,
|
|
36136
36145
|
description: terminalText(f.reason ?? "", 2e3),
|
|
36137
36146
|
fix: { description: `Trace: ${terminalText(f.trace.join(" \u2192 ") || "(initial state)", 2e3)}. Replay: ${terminalText(f.reason ?? "reproduced in the container", 2e3)}` },
|
|
36138
36147
|
source: "formal"
|
|
36139
36148
|
}))
|
|
36140
36149
|
];
|
|
36141
|
-
if (
|
|
36142
|
-
|
|
36150
|
+
if (blocking.length > 0) response.gate_decision = "FAIL";
|
|
36151
|
+
else if (response.gate_decision === "PASS" || response.gate_decision == null) response.gate_decision = "WARN";
|
|
36152
|
+
return { blocking: blocking.length, warning: reproduced.length - blocking.length };
|
|
36143
36153
|
}
|
|
36144
36154
|
|
|
36145
36155
|
// src/lib/prove/scalpel.ts
|
|
@@ -36458,7 +36468,9 @@ async function runFormalPhase(input) {
|
|
|
36458
36468
|
symbol: f.symbol,
|
|
36459
36469
|
verdict: "reproduced",
|
|
36460
36470
|
reason: f.waived ? `waived ${f.waived.at.slice(0, 10)}: ${f.waived.reason} (standing since ${f.at.slice(0, 10)}; the file has not changed)` : `${f.reason ?? "reproduced on the real code"} (standing since ${f.at.slice(0, 10)}; the file has not changed)`,
|
|
36461
|
-
...f.waived ? { waived: true } : {}
|
|
36471
|
+
...f.waived ? { waived: true } : {},
|
|
36472
|
+
// A hand-edited file cannot invent a code: unknown values read as absent (HIGH).
|
|
36473
|
+
...isImpact(f.impact) ? { impact: f.impact } : {}
|
|
36462
36474
|
});
|
|
36463
36475
|
}
|
|
36464
36476
|
}
|
|
@@ -36497,7 +36509,6 @@ async function runFormalPhase(input) {
|
|
|
36497
36509
|
return done({ status: "skipped", skip: "not-eligible", detail: `${best.file}: ${isEligible(best, largePush).why}` });
|
|
36498
36510
|
}
|
|
36499
36511
|
const ranked = await deps.rank(eligible, root, input.changedLines);
|
|
36500
|
-
if (!ranked.ok && ranked.disabled) return done({ status: "skipped", skip: "disabled-by-server", detail: ranked.error });
|
|
36501
36512
|
if (ranked.ok) spend(ranked);
|
|
36502
36513
|
candidates2 = ranked.ranked.slice(0, 5).map((c) => ({ file: c.file, symbol: c.ai?.symbol ?? null, score: c.ai?.score ?? null, criteria: c.ai?.criteria ?? null, reasked: !!c.ai?.reasked, reasons: (c.ai?.reasons ?? []).map((r) => r.slice(0, 200)) }));
|
|
36503
36514
|
if (cancelled()) return done({ status: "skipped", skip: "deadline", detail: "cut off after ranking" });
|
|
@@ -36732,7 +36743,7 @@ async function runFormalPhase(input) {
|
|
|
36732
36743
|
continue;
|
|
36733
36744
|
}
|
|
36734
36745
|
const verdict = r.verdict === "reproduced" ? "reproduced" : r.verdict === "diverged" ? "diverged" : r.verdict === "unreplayable" ? "model-only" : "unverified";
|
|
36735
|
-
findings.push({ ...baseOf(p), verdict, reason: r.reason || r.downgrade || void 0 });
|
|
36746
|
+
findings.push({ ...baseOf(p), verdict, reason: r.reason || r.downgrade || void 0, ...verdict === "reproduced" && r.impact ? { impact: r.impact } : {} });
|
|
36736
36747
|
}
|
|
36737
36748
|
const reproduced = findings.filter((f) => f.verdict === "reproduced");
|
|
36738
36749
|
if (reproduced.length > 0 && !cancelled()) {
|
|
@@ -36740,7 +36751,7 @@ async function runFormalPhase(input) {
|
|
|
36740
36751
|
const others = readPersistedFindings(root).filter((f) => f.file !== top.file);
|
|
36741
36752
|
writePersistedFindings(root, [
|
|
36742
36753
|
...others,
|
|
36743
|
-
...reproduced.map((f) => ({ file: f.file, symbol: f.symbol, sha256: sha2562, property: f.property, desc: f.desc, kind: f.kind, trace: f.trace, model: modelName, reason: f.reason, ...lines ? { lines } : {}, at: now }))
|
|
36754
|
+
...reproduced.map((f) => ({ file: f.file, symbol: f.symbol, sha256: sha2562, property: f.property, desc: f.desc, kind: f.kind, trace: f.trace, model: modelName, reason: f.reason, ...f.impact ? { impact: f.impact } : {}, ...lines ? { lines } : {}, at: now }))
|
|
36744
36755
|
]);
|
|
36745
36756
|
}
|
|
36746
36757
|
const clean2 = findings.every((f) => f.verdict === "diverged");
|
|
@@ -37480,6 +37491,8 @@ async function runGuard(opts, globals) {
|
|
|
37480
37491
|
rounds: formalOutcome.model?.rounds ?? null,
|
|
37481
37492
|
properties: formalOutcome.properties?.map((p) => `${p.id}:${p.result}`) ?? [],
|
|
37482
37493
|
findings: formalOutcome.findings.map((f) => `${f.property}:${f.verdict}`),
|
|
37494
|
+
// Decision 82: the replay's impact code per reproduced finding; count/cache/internal warn, the rest block.
|
|
37495
|
+
impacts: formalOutcome.findings.filter((f) => f.impact).map((f) => `${f.property}:${f.impact}`),
|
|
37483
37496
|
// Decision 81: what each property rests on (a rule, or "line"), what was
|
|
37484
37497
|
// sent back or dropped as ungrounded, and which counterexamples lack their
|
|
37485
37498
|
// property's trigger (shadow). Ids and rule names only, never code.
|
|
@@ -38789,22 +38802,6 @@ var import_promises18 = require("node:stream/promises");
|
|
|
38789
38802
|
var import_node_stream = require("node:stream");
|
|
38790
38803
|
var RELEASES = "https://releases.lean-lang.org/lean4";
|
|
38791
38804
|
var LEAN_DOWNLOAD_SIZE = "\u2248800 MB download, 2.7 GB on disk";
|
|
38792
|
-
var DOWNLOAD_STALL_MS = 6e4;
|
|
38793
|
-
var LEAN_DISK_NEEDED_BYTES = 3.75 * 1024 ** 3;
|
|
38794
|
-
function freeBytes(dir) {
|
|
38795
|
-
let d = dir;
|
|
38796
|
-
for (let i2 = 0; i2 < 64; i2++) {
|
|
38797
|
-
try {
|
|
38798
|
-
const st = (0, import_node_fs63.statfsSync)(d);
|
|
38799
|
-
return Number(st.bavail) * Number(st.bsize);
|
|
38800
|
-
} catch {
|
|
38801
|
-
const up = (0, import_node_path47.join)(d, "..");
|
|
38802
|
-
if (up === d) return null;
|
|
38803
|
-
d = up;
|
|
38804
|
-
}
|
|
38805
|
-
}
|
|
38806
|
-
return null;
|
|
38807
|
-
}
|
|
38808
38805
|
var LEAN_ASSET_SHA256 = {
|
|
38809
38806
|
"v4.34.0": {
|
|
38810
38807
|
"lean-4.34.0-darwin.zip": "75a2a4b8e3d35680e8f51fae5a42c79702f463dd73ee1520fb61e5a9143e336c",
|
|
@@ -38863,32 +38860,17 @@ function unzip(zip, dest) {
|
|
|
38863
38860
|
}
|
|
38864
38861
|
return { ok: false, error: errors.join("; ") };
|
|
38865
38862
|
}
|
|
38866
|
-
async function download(url, dest, onProgress
|
|
38867
|
-
const
|
|
38868
|
-
|
|
38869
|
-
const
|
|
38870
|
-
|
|
38871
|
-
|
|
38872
|
-
|
|
38873
|
-
|
|
38874
|
-
|
|
38875
|
-
|
|
38876
|
-
|
|
38877
|
-
const total = Number(res.headers.get("content-length")) || null;
|
|
38878
|
-
let seen = 0;
|
|
38879
|
-
const stream = import_node_stream.Readable.fromWeb(res.body);
|
|
38880
|
-
stream.on("data", (chunk) => {
|
|
38881
|
-
arm();
|
|
38882
|
-
seen += chunk.length;
|
|
38883
|
-
onProgress(seen, total);
|
|
38884
|
-
});
|
|
38885
|
-
await (0, import_promises18.pipeline)(stream, (0, import_node_fs63.createWriteStream)(dest), { signal: ctrl.signal });
|
|
38886
|
-
} catch (err2) {
|
|
38887
|
-
if (ctrl.signal.aborted) throw new Error(`download stalled: nothing received for ${Math.round(stallMs / 1e3)} s`);
|
|
38888
|
-
throw err2;
|
|
38889
|
-
} finally {
|
|
38890
|
-
clearTimeout(timer);
|
|
38891
|
-
}
|
|
38863
|
+
async function download(url, dest, onProgress) {
|
|
38864
|
+
const res = await fetch(url, { redirect: "follow" });
|
|
38865
|
+
if (!res.ok || !res.body) throw new Error(`download failed: HTTP ${res.status}`);
|
|
38866
|
+
const total = Number(res.headers.get("content-length")) || null;
|
|
38867
|
+
let seen = 0;
|
|
38868
|
+
const stream = import_node_stream.Readable.fromWeb(res.body);
|
|
38869
|
+
stream.on("data", (chunk) => {
|
|
38870
|
+
seen += chunk.length;
|
|
38871
|
+
onProgress(seen, total);
|
|
38872
|
+
});
|
|
38873
|
+
await (0, import_promises18.pipeline)(stream, (0, import_node_fs63.createWriteStream)(dest));
|
|
38892
38874
|
}
|
|
38893
38875
|
function inPlaceProgress(label2, write = (s) => process.stderr.write(s)) {
|
|
38894
38876
|
let active = false;
|
|
@@ -38926,12 +38908,6 @@ async function installLean(opts = {}) {
|
|
|
38926
38908
|
const dir = pinnedVersionDir(env);
|
|
38927
38909
|
const url = `${RELEASES}/${pinnedVersion()}/${asset}`;
|
|
38928
38910
|
const home = verityLeanHome(env);
|
|
38929
|
-
const free = freeBytes(home);
|
|
38930
|
-
const needed = opts.minFreeBytes ?? LEAN_DISK_NEEDED_BYTES;
|
|
38931
|
-
if (free !== null && free < needed) {
|
|
38932
|
-
const gb = (n) => (n / 1024 ** 3).toFixed(1);
|
|
38933
|
-
return { ok: false, error: `not enough disk space for Lean: ${gb(free)} GB free where ${home} lives, needs about ${gb(needed)} GB` };
|
|
38934
|
-
}
|
|
38935
38911
|
const tmp = (0, import_node_path47.join)(home, ".tmp");
|
|
38936
38912
|
(0, import_node_fs63.rmSync)(tmp, { recursive: true, force: true });
|
|
38937
38913
|
(0, import_node_fs63.mkdirSync)(tmp, { recursive: true });
|
|
@@ -39240,10 +39216,8 @@ var INTENSITY_CHOICES = [
|
|
|
39240
39216
|
{ id: "thorough", label: "thorough", hint: "all tools, all rules (~15s)" }
|
|
39241
39217
|
];
|
|
39242
39218
|
var FORMAL_CHOICES = [
|
|
39243
|
-
{ id: "yes", label: "yes", hint: "a Lean model of the riskiest changed function; blocks only on a REPRODUCED counterexample" },
|
|
39244
|
-
|
|
39245
|
-
// 2.7 GB, and a bare Enter must never do that.
|
|
39246
|
-
{ id: "no", label: "no", hint: "enable later with: verity config formal push", recommended: true }
|
|
39219
|
+
{ id: "yes", label: "yes", hint: "a Lean model of the riskiest changed function; blocks only on a REPRODUCED counterexample", recommended: true },
|
|
39220
|
+
{ id: "no", label: "no", hint: "enable later with: verity config formal push" }
|
|
39247
39221
|
];
|
|
39248
39222
|
var MOMENT_CHOICES = [
|
|
39249
39223
|
{ id: "stop", label: "On stop", hint: "after every agent turn \u2014 fast feedback while you work", recommended: true },
|
|
@@ -39649,20 +39623,16 @@ async function offerFormalVerification(defaultsOnly, pluginMode) {
|
|
|
39649
39623
|
printWarn(` Formal verification: off \u2014 ${formalRefusalMessage(cfg.formal_refused)}`);
|
|
39650
39624
|
return;
|
|
39651
39625
|
}
|
|
39626
|
+
const toolchain = findToolchain();
|
|
39652
39627
|
if (cfg.formal === "push") {
|
|
39653
|
-
if (
|
|
39628
|
+
if (toolchain) printInfo(" Formal verification at push \u2713");
|
|
39654
39629
|
else printWarn(" Formal verification is on but Lean is missing \u2014 run: verity lean install");
|
|
39655
39630
|
return;
|
|
39656
39631
|
}
|
|
39657
|
-
if (cfg.formal === "off") {
|
|
39658
|
-
printInfo(" Formal verification: off (enable with: verity config formal push)");
|
|
39659
|
-
return;
|
|
39660
|
-
}
|
|
39661
39632
|
if (defaultsOnly || !interactive()) {
|
|
39662
39633
|
printInfo(" Formal verification (a model-based bug finder at push): off \u2014 enable with: verity config formal push");
|
|
39663
39634
|
return;
|
|
39664
39635
|
}
|
|
39665
|
-
const toolchain = findToolchain();
|
|
39666
39636
|
console.log("");
|
|
39667
39637
|
console.log(" Formal verification review \u2014 a model-based bug finder for your riskiest code.");
|
|
39668
39638
|
console.log(" At push, Verity picks the riskiest changed function, checks a small model of");
|
|
@@ -39670,10 +39640,9 @@ async function offerFormalVerification(defaultsOnly, pluginMode) {
|
|
|
39670
39640
|
console.log(" Verity for that). Only a reproduced bug can block; most pushes get no model.");
|
|
39671
39641
|
console.log(` Adds /verity-prove <worry> to check any code on demand.${toolchain ? "" : ` Needs to install Lean 4 (${LEAN_DOWNLOAD_SIZE}) on "yes".`}`);
|
|
39672
39642
|
console.log("");
|
|
39673
|
-
const wants = await promptChoice("Formal verification at push?", FORMAL_CHOICES, "
|
|
39643
|
+
const wants = await promptChoice("Formal verification at push?", FORMAL_CHOICES, "yes");
|
|
39674
39644
|
if (wants === "yes" && pluginMode) printInfo(" Plugin: the push check works now; /verity:verity-prove arrives with the plugin's next release.");
|
|
39675
39645
|
if (wants !== "yes") {
|
|
39676
|
-
writeProjectConfig({ formal: "off" });
|
|
39677
39646
|
printInfo(" Formal verification: off (enable later with: verity config formal push)");
|
|
39678
39647
|
return;
|
|
39679
39648
|
}
|
|
@@ -39932,7 +39901,7 @@ function registerInitCommand(program2) {
|
|
|
39932
39901
|
...telemetryChoice ? { telemetry: telemetryChoice } : {},
|
|
39933
39902
|
init: {
|
|
39934
39903
|
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
39935
|
-
cli_version: true ? "0.34.0-experimental.
|
|
39904
|
+
cli_version: true ? "0.34.0-experimental.675f6d2" : "dev"
|
|
39936
39905
|
}
|
|
39937
39906
|
});
|
|
39938
39907
|
} catch (err2) {
|
|
@@ -41405,8 +41374,8 @@ function registerLeanCommand(program2) {
|
|
|
41405
41374
|
}
|
|
41406
41375
|
|
|
41407
41376
|
// src/cli.ts
|
|
41408
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.34.0-experimental.
|
|
41409
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.34.0-experimental.
|
|
41377
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.34.0-experimental.675f6d2").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr").hook("preAction", async (_thisCommand, actionCommand) => {
|
|
41378
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.34.0-experimental.675f6d2");
|
|
41410
41379
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
41411
41380
|
try {
|
|
41412
41381
|
await foldLegacyLocalCredential();
|
package/package.json
CHANGED