@codacy/verity-cli 0.35.3 → 0.35.5
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 +71 -0
- package/README.md +22 -10
- package/bin/verity.js +880 -464
- package/data/skills/verity-init/SKILL.md +23 -8
- package/data/skills/verity-setup/SKILL.md +12 -5
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -14732,7 +14732,9 @@ var SECURITY_PATTERNS = [
|
|
|
14732
14732
|
/(^|\/)pom\.xml$/,
|
|
14733
14733
|
/(^|\/)gradle\.lockfile$/
|
|
14734
14734
|
];
|
|
14735
|
-
var
|
|
14735
|
+
var PROD_SERVICE_ORIGIN = "https://server.verity.md";
|
|
14736
|
+
var LEGACY_PROD_SERVICE_ORIGIN = "https://ofcamwrjwrkazqvdchko.supabase.co";
|
|
14737
|
+
var PROD_SERVICE_URL = `${PROD_SERVICE_ORIGIN}/functions/v1`;
|
|
14736
14738
|
var DEFAULT_SERVICE_URL = "".length > 0 ? "" : PROD_SERVICE_URL;
|
|
14737
14739
|
var GITHUB_CLIENT_ID = "Iv23li88HxAi3ZrbYzWh";
|
|
14738
14740
|
var GITHUB_DEVICE_CODE_URL = "https://github.com/login/device/code";
|
|
@@ -14823,6 +14825,36 @@ function rotateIfNeeded(file) {
|
|
|
14823
14825
|
var import_promises = require("node:fs/promises");
|
|
14824
14826
|
var import_node_path3 = require("node:path");
|
|
14825
14827
|
var import_node_child_process2 = require("node:child_process");
|
|
14828
|
+
|
|
14829
|
+
// src/lib/service-origin.ts
|
|
14830
|
+
var LEGACY = new URL(LEGACY_PROD_SERVICE_ORIGIN);
|
|
14831
|
+
function canonicalServiceUrl(raw) {
|
|
14832
|
+
const trimmed = raw.trim();
|
|
14833
|
+
let u;
|
|
14834
|
+
try {
|
|
14835
|
+
u = new URL(trimmed);
|
|
14836
|
+
} catch {
|
|
14837
|
+
return raw;
|
|
14838
|
+
}
|
|
14839
|
+
if (u.protocol !== LEGACY.protocol || u.host.toLowerCase() !== LEGACY.host || u.username !== "" || u.password !== "") {
|
|
14840
|
+
return raw;
|
|
14841
|
+
}
|
|
14842
|
+
return trimmed.replace(/^https:\/\/[^/?#]+/i, PROD_SERVICE_ORIGIN);
|
|
14843
|
+
}
|
|
14844
|
+
function normalizeServiceUrl(raw) {
|
|
14845
|
+
const trimmed = canonicalServiceUrl(raw).trim().replace(/\/+$/, "");
|
|
14846
|
+
try {
|
|
14847
|
+
const u = new URL(trimmed);
|
|
14848
|
+
return `${u.protocol}//${u.host.toLowerCase()}${u.pathname.replace(/\/+$/, "")}`;
|
|
14849
|
+
} catch {
|
|
14850
|
+
return trimmed.toLowerCase();
|
|
14851
|
+
}
|
|
14852
|
+
}
|
|
14853
|
+
function sameServiceUrl(a, b) {
|
|
14854
|
+
return normalizeServiceUrl(a) === normalizeServiceUrl(b);
|
|
14855
|
+
}
|
|
14856
|
+
|
|
14857
|
+
// src/lib/credentials.ts
|
|
14826
14858
|
function globalCredentialsPath() {
|
|
14827
14859
|
return `${process.env.HOME}/.verity/credentials`;
|
|
14828
14860
|
}
|
|
@@ -14843,7 +14875,8 @@ function parseCredentialLine(line2) {
|
|
|
14843
14875
|
const rest = idx === -1 ? line2 : line2.slice(idx);
|
|
14844
14876
|
const tokenMatch = rest.match(TOKEN_RE);
|
|
14845
14877
|
if (!tokenMatch) return null;
|
|
14846
|
-
const
|
|
14878
|
+
const serviceUrlRaw = rest.match(/service_url:\s*(https?:\/\/\S+)/)?.[1];
|
|
14879
|
+
const serviceUrl = serviceUrlRaw != null ? canonicalServiceUrl(serviceUrlRaw) : void 0;
|
|
14847
14880
|
const userIdRaw = rest.match(/user_id:\s*(\d+)/)?.[1];
|
|
14848
14881
|
const email = rest.match(/email:\s*(\S+)/)?.[1];
|
|
14849
14882
|
return {
|
|
@@ -14865,7 +14898,7 @@ function encodeRemoteKey(remote) {
|
|
|
14865
14898
|
function serializeCredential(remote, rec) {
|
|
14866
14899
|
const key = encodeRemoteKey(remote);
|
|
14867
14900
|
const out2 = [key ? `${key} token: ${rec.token}` : `token: ${rec.token}`];
|
|
14868
|
-
if (rec.serviceUrl) out2.push(`service_url: ${rec.serviceUrl}`);
|
|
14901
|
+
if (rec.serviceUrl) out2.push(`service_url: ${canonicalServiceUrl(rec.serviceUrl)}`);
|
|
14869
14902
|
if (rec.userId != null) out2.push(`user_id: ${rec.userId}`);
|
|
14870
14903
|
if (rec.email) out2.push(`email: ${rec.email}`);
|
|
14871
14904
|
return out2.join(" ");
|
|
@@ -14938,7 +14971,7 @@ async function removeSupersededUserCredentials(loginServiceUrl, loginUserId) {
|
|
|
14938
14971
|
let removed = 0;
|
|
14939
14972
|
for (const line2 of content.split("\n")) {
|
|
14940
14973
|
const parsed = parseCredentialLine(line2);
|
|
14941
|
-
const superseded = parsed !== null && parsed.remote !== "" && parsed.rec.userId === loginUserId && (!parsed.rec.serviceUrl || parsed.rec.serviceUrl
|
|
14974
|
+
const superseded = parsed !== null && parsed.remote !== "" && parsed.rec.userId === loginUserId && (!parsed.rec.serviceUrl || sameServiceUrl(parsed.rec.serviceUrl, loginServiceUrl));
|
|
14942
14975
|
if (superseded) {
|
|
14943
14976
|
removed++;
|
|
14944
14977
|
continue;
|
|
@@ -14990,9 +15023,10 @@ function parseLocalCredentialFile(content) {
|
|
|
14990
15023
|
const tokenMatch = content.match(/token:\s*((?:gate_|verity_)[a-f0-9]+)/);
|
|
14991
15024
|
if (!tokenMatch) return null;
|
|
14992
15025
|
const userIdMatch = content.match(/^user_id:\s*(\d+)/m);
|
|
15026
|
+
const serviceUrl = content.match(/service_url:\s*(https?:\/\/\S+)/)?.[1];
|
|
14993
15027
|
return {
|
|
14994
15028
|
token: tokenMatch[1],
|
|
14995
|
-
serviceUrl:
|
|
15029
|
+
serviceUrl: serviceUrl != null ? canonicalServiceUrl(serviceUrl) : void 0,
|
|
14996
15030
|
userId: userIdMatch ? Number(userIdMatch[1]) : void 0,
|
|
14997
15031
|
email: content.match(/^email:\s*(\S+)/m)?.[1]
|
|
14998
15032
|
};
|
|
@@ -15306,15 +15340,7 @@ async function checkTokenPin(token, targetUrl) {
|
|
|
15306
15340
|
if (!stored.serviceUrl) return { attach: false, reason: "unpinnable" };
|
|
15307
15341
|
return normalizeUrl(stored.serviceUrl) === normalizeUrl(targetUrl) ? { attach: true } : { attach: false, reason: "mismatch", mintedFor: stored.serviceUrl };
|
|
15308
15342
|
}
|
|
15309
|
-
|
|
15310
|
-
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
15311
|
-
try {
|
|
15312
|
-
const u = new URL(trimmed);
|
|
15313
|
-
return `${u.protocol}//${u.host.toLowerCase()}${u.pathname.replace(/\/+$/, "")}`;
|
|
15314
|
-
} catch {
|
|
15315
|
-
return trimmed.toLowerCase();
|
|
15316
|
-
}
|
|
15317
|
-
}
|
|
15343
|
+
var normalizeUrl = normalizeServiceUrl;
|
|
15318
15344
|
function pinRefusalMessage(verdict, targetUrl) {
|
|
15319
15345
|
if (verdict.reason === "unpinnable") {
|
|
15320
15346
|
return `Refusing to send your Verity login to ${targetUrl}: this machine's credential does not record which service issued it, so it cannot be verified. Run "verity login" to re-issue it.`;
|
|
@@ -15325,7 +15351,7 @@ function pinRefusalMessage(verdict, targetUrl) {
|
|
|
15325
15351
|
// src/lib/cli-version.ts
|
|
15326
15352
|
function cliVersion() {
|
|
15327
15353
|
try {
|
|
15328
|
-
return true ? "0.35.
|
|
15354
|
+
return true ? "0.35.5" : "dev";
|
|
15329
15355
|
} catch {
|
|
15330
15356
|
return "dev";
|
|
15331
15357
|
}
|
|
@@ -15530,7 +15556,7 @@ async function serviceUrlFromVerityMd() {
|
|
|
15530
15556
|
const line2 = content.split("\n").find((l) => /\*{0,2}(?:url|service)\*{0,2}\s*:/i.test(l));
|
|
15531
15557
|
if (line2) {
|
|
15532
15558
|
const urlMatch = line2.match(/https:\/\/[^\s]+/);
|
|
15533
|
-
if (urlMatch) return urlMatch[0];
|
|
15559
|
+
if (urlMatch) return canonicalServiceUrl(urlMatch[0]);
|
|
15534
15560
|
}
|
|
15535
15561
|
} catch {
|
|
15536
15562
|
}
|
|
@@ -18048,6 +18074,124 @@ function describeRemote(found) {
|
|
|
18048
18074
|
return `version ${found.standard.version}, pushed${who} on ${when}${also}`;
|
|
18049
18075
|
}
|
|
18050
18076
|
|
|
18077
|
+
// src/lib/json-file.ts
|
|
18078
|
+
var import_promises3 = require("node:fs/promises");
|
|
18079
|
+
var import_node_path12 = require("node:path");
|
|
18080
|
+
function jsonSemanticEqual(a, b) {
|
|
18081
|
+
if (a === b) return true;
|
|
18082
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
|
|
18083
|
+
return a === b;
|
|
18084
|
+
}
|
|
18085
|
+
const aIsArr = Array.isArray(a);
|
|
18086
|
+
const bIsArr = Array.isArray(b);
|
|
18087
|
+
if (aIsArr || bIsArr) {
|
|
18088
|
+
if (!aIsArr || !bIsArr || a.length !== b.length) return false;
|
|
18089
|
+
for (let i2 = 0; i2 < a.length; i2++) {
|
|
18090
|
+
if (!jsonSemanticEqual(a[i2], b[i2])) return false;
|
|
18091
|
+
}
|
|
18092
|
+
return true;
|
|
18093
|
+
}
|
|
18094
|
+
const ao = a;
|
|
18095
|
+
const bo = b;
|
|
18096
|
+
const aKeys = Object.keys(ao).filter((k) => ao[k] !== void 0);
|
|
18097
|
+
const bKeys = Object.keys(bo).filter((k) => bo[k] !== void 0);
|
|
18098
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
18099
|
+
for (const k of aKeys) {
|
|
18100
|
+
if (bo[k] === void 0) return false;
|
|
18101
|
+
if (!jsonSemanticEqual(ao[k], bo[k])) return false;
|
|
18102
|
+
}
|
|
18103
|
+
return true;
|
|
18104
|
+
}
|
|
18105
|
+
function detectJsonIndent(raw) {
|
|
18106
|
+
const m = raw.match(/\n([ \t]+)\S/);
|
|
18107
|
+
return m ? m[1] : 2;
|
|
18108
|
+
}
|
|
18109
|
+
async function writeJsonFilePreservingStyle(file, value) {
|
|
18110
|
+
let currentRaw = null;
|
|
18111
|
+
try {
|
|
18112
|
+
currentRaw = await (0, import_promises3.readFile)(file, "utf-8");
|
|
18113
|
+
} catch {
|
|
18114
|
+
currentRaw = null;
|
|
18115
|
+
}
|
|
18116
|
+
if (currentRaw !== null) {
|
|
18117
|
+
try {
|
|
18118
|
+
if (jsonSemanticEqual(JSON.parse(currentRaw), value)) return false;
|
|
18119
|
+
} catch {
|
|
18120
|
+
}
|
|
18121
|
+
}
|
|
18122
|
+
const indent = currentRaw !== null ? detectJsonIndent(currentRaw) : 2;
|
|
18123
|
+
const next = JSON.stringify(value, null, indent) + "\n";
|
|
18124
|
+
if (next === currentRaw) return false;
|
|
18125
|
+
await (0, import_promises3.mkdir)((0, import_node_path12.dirname)(file), { recursive: true });
|
|
18126
|
+
await (0, import_promises3.writeFile)(file, next);
|
|
18127
|
+
return true;
|
|
18128
|
+
}
|
|
18129
|
+
|
|
18130
|
+
// src/lib/setup-state.ts
|
|
18131
|
+
var SETUP_STATE_FILE = `${VERITY_DIR}/setup.json`;
|
|
18132
|
+
var MOMENTS = ["stop", "pre-commit", "pre-push"];
|
|
18133
|
+
var INTENSITIES = ["lightweight", "balanced", "thorough"];
|
|
18134
|
+
var TELEMETRY = ["enabled", "declined", "deferred"];
|
|
18135
|
+
var VERSION = /^[0-9A-Za-z.+-]{1,32}$/;
|
|
18136
|
+
var stamp = (v) => typeof v === "string" && v.length > 0 && v.length <= 64;
|
|
18137
|
+
function setupStateFrom(raw) {
|
|
18138
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
|
|
18139
|
+
const r = raw;
|
|
18140
|
+
if (r.version !== 1) return null;
|
|
18141
|
+
const out2 = { version: 1 };
|
|
18142
|
+
if (INTENSITIES.includes(r.intensity)) out2.intensity = r.intensity;
|
|
18143
|
+
if (Array.isArray(r.moments) && r.moments.every((m) => MOMENTS.includes(m))) {
|
|
18144
|
+
out2.moments = [...new Set(r.moments)];
|
|
18145
|
+
}
|
|
18146
|
+
if (TELEMETRY.includes(r.telemetry)) out2.telemetry = r.telemetry;
|
|
18147
|
+
if (Number.isSafeInteger(r.declinedStandardVersion) && r.declinedStandardVersion >= 1) {
|
|
18148
|
+
out2.declinedStandardVersion = r.declinedStandardVersion;
|
|
18149
|
+
}
|
|
18150
|
+
if (Number.isSafeInteger(r.standardVersion) && r.standardVersion >= 1) {
|
|
18151
|
+
out2.standardVersion = r.standardVersion;
|
|
18152
|
+
}
|
|
18153
|
+
const init2 = r.init;
|
|
18154
|
+
if (init2 && typeof init2 === "object" && stamp(init2.completed_at) && typeof init2.cli_version === "string" && VERSION.test(init2.cli_version)) {
|
|
18155
|
+
out2.init = { completed_at: init2.completed_at, cli_version: init2.cli_version };
|
|
18156
|
+
}
|
|
18157
|
+
const plugin = r.pluginSetup;
|
|
18158
|
+
if (plugin && typeof plugin === "object" && typeof plugin.version === "string" && VERSION.test(plugin.version) && stamp(plugin.completed_at)) {
|
|
18159
|
+
out2.pluginSetup = { version: plugin.version, completed_at: plugin.completed_at };
|
|
18160
|
+
}
|
|
18161
|
+
if (r.wiring === "project") out2.wiring = "project";
|
|
18162
|
+
return out2;
|
|
18163
|
+
}
|
|
18164
|
+
var MAX_SETUP_BYTES = 64 * 1024;
|
|
18165
|
+
function readSetupText() {
|
|
18166
|
+
const read2 = readRegularFileInRoot(repoRoot(), SETUP_STATE_FILE, MAX_SETUP_BYTES);
|
|
18167
|
+
return read2.ok ? read2.content : null;
|
|
18168
|
+
}
|
|
18169
|
+
async function readSetupState() {
|
|
18170
|
+
const raw = readSetupText();
|
|
18171
|
+
if (raw === null) return null;
|
|
18172
|
+
try {
|
|
18173
|
+
return setupStateFrom(JSON.parse(raw));
|
|
18174
|
+
} catch {
|
|
18175
|
+
return null;
|
|
18176
|
+
}
|
|
18177
|
+
}
|
|
18178
|
+
async function writeSetupState(patch) {
|
|
18179
|
+
const current = await readSetupState() ?? { version: 1 };
|
|
18180
|
+
const next = { ...current, ...patch, version: 1 };
|
|
18181
|
+
const raw = readSetupText();
|
|
18182
|
+
if (raw !== null) {
|
|
18183
|
+
try {
|
|
18184
|
+
if (jsonSemanticEqual(JSON.parse(raw), next)) return next;
|
|
18185
|
+
} catch {
|
|
18186
|
+
}
|
|
18187
|
+
}
|
|
18188
|
+
const text3 = JSON.stringify(next, null, raw !== null ? detectJsonIndent(raw) : 2) + "\n";
|
|
18189
|
+
if (!replaceInRoot(projectPath(VERITY_DIR), "setup.json", text3)) {
|
|
18190
|
+
throw new Error(`Could not write ${SETUP_STATE_FILE}: it is a link, or ${VERITY_DIR} is not a folder of this repository`);
|
|
18191
|
+
}
|
|
18192
|
+
return next;
|
|
18193
|
+
}
|
|
18194
|
+
|
|
18051
18195
|
// src/lib/catalogue-conversion.ts
|
|
18052
18196
|
var PACK_ID2 = /^[a-z][a-z0-9-]{0,39}$/;
|
|
18053
18197
|
var MAX_PACKS2 = 12;
|
|
@@ -18078,6 +18222,12 @@ function count(v) {
|
|
|
18078
18222
|
}
|
|
18079
18223
|
|
|
18080
18224
|
// src/lib/push-setup.ts
|
|
18225
|
+
function latestFromConflict(result) {
|
|
18226
|
+
const err2 = result.errorBody?.error;
|
|
18227
|
+
const raw = err2 && typeof err2 === "object" ? err2.latest_version : void 0;
|
|
18228
|
+
const n2 = typeof raw === "string" && /^[1-9][0-9]*$/.test(raw) ? Number(raw) : typeof raw === "number" ? raw : NaN;
|
|
18229
|
+
return Number.isSafeInteger(n2) && n2 >= 1 ? n2 : null;
|
|
18230
|
+
}
|
|
18081
18231
|
async function pushStandard(globals, opts = {}) {
|
|
18082
18232
|
const lines = [];
|
|
18083
18233
|
const token = await resolveToken(globals.token);
|
|
@@ -18113,11 +18263,15 @@ async function pushStandard(globals, opts = {}) {
|
|
|
18113
18263
|
if (result.ok) {
|
|
18114
18264
|
standardVersion = result.data.version;
|
|
18115
18265
|
lines.push(`Standard pushed to Verity (v${result.data.version}) \u2713`);
|
|
18266
|
+
if (Number.isSafeInteger(standardVersion) && standardVersion >= 1) {
|
|
18267
|
+
await writeSetupState({ standardVersion }).catch(() => {
|
|
18268
|
+
});
|
|
18269
|
+
}
|
|
18116
18270
|
const converted = conversionLine(result.data);
|
|
18117
18271
|
if (converted) lines.push(converted);
|
|
18118
18272
|
} else if (opts.expectedLatest !== void 0 && result.http_status === 409 && result.error.startsWith("STANDARD_EXISTS")) {
|
|
18119
18273
|
lines.push("The service has a Standard now that this run did not see, so nothing was pushed over it.");
|
|
18120
|
-
return { lines, standardVersion: null, conflict: true };
|
|
18274
|
+
return { lines, standardVersion: null, conflict: true, latest: latestFromConflict(result) };
|
|
18121
18275
|
} else {
|
|
18122
18276
|
lines.push(`Could not push the Standard: ${terminalText(result.error, 300)} \u2014 run "verity standard push" later.`);
|
|
18123
18277
|
}
|
|
@@ -18285,7 +18439,7 @@ async function finishSplitLogin(opts) {
|
|
|
18285
18439
|
if (read2.status === "invalid") fail2("invalid", `the pending sign-in is unusable (${read2.reason}) \u2014 run "verity login --start" again`, true);
|
|
18286
18440
|
if (read2.status === "expired") fail2("expired", 'the code expired before it was approved \u2014 run "verity login --start" again', true);
|
|
18287
18441
|
const pending = read2.record;
|
|
18288
|
-
if (pending.service_url
|
|
18442
|
+
if (!sameServiceUrl(pending.service_url, opts.serviceUrl)) {
|
|
18289
18443
|
fail2(
|
|
18290
18444
|
"service_changed",
|
|
18291
18445
|
`the sign-in was started for ${pending.service_url}, but this machine now resolves ${opts.serviceUrl} \u2014 run "verity login --start" again`,
|
|
@@ -18646,61 +18800,6 @@ function registerLogoutCommand(program2) {
|
|
|
18646
18800
|
// src/lib/hooks.ts
|
|
18647
18801
|
var import_promises4 = require("node:fs/promises");
|
|
18648
18802
|
var import_node_path13 = require("node:path");
|
|
18649
|
-
|
|
18650
|
-
// src/lib/json-file.ts
|
|
18651
|
-
var import_promises3 = require("node:fs/promises");
|
|
18652
|
-
var import_node_path12 = require("node:path");
|
|
18653
|
-
function jsonSemanticEqual(a, b) {
|
|
18654
|
-
if (a === b) return true;
|
|
18655
|
-
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
|
|
18656
|
-
return a === b;
|
|
18657
|
-
}
|
|
18658
|
-
const aIsArr = Array.isArray(a);
|
|
18659
|
-
const bIsArr = Array.isArray(b);
|
|
18660
|
-
if (aIsArr || bIsArr) {
|
|
18661
|
-
if (!aIsArr || !bIsArr || a.length !== b.length) return false;
|
|
18662
|
-
for (let i2 = 0; i2 < a.length; i2++) {
|
|
18663
|
-
if (!jsonSemanticEqual(a[i2], b[i2])) return false;
|
|
18664
|
-
}
|
|
18665
|
-
return true;
|
|
18666
|
-
}
|
|
18667
|
-
const ao = a;
|
|
18668
|
-
const bo = b;
|
|
18669
|
-
const aKeys = Object.keys(ao).filter((k) => ao[k] !== void 0);
|
|
18670
|
-
const bKeys = Object.keys(bo).filter((k) => bo[k] !== void 0);
|
|
18671
|
-
if (aKeys.length !== bKeys.length) return false;
|
|
18672
|
-
for (const k of aKeys) {
|
|
18673
|
-
if (bo[k] === void 0) return false;
|
|
18674
|
-
if (!jsonSemanticEqual(ao[k], bo[k])) return false;
|
|
18675
|
-
}
|
|
18676
|
-
return true;
|
|
18677
|
-
}
|
|
18678
|
-
function detectJsonIndent(raw) {
|
|
18679
|
-
const m = raw.match(/\n([ \t]+)\S/);
|
|
18680
|
-
return m ? m[1] : 2;
|
|
18681
|
-
}
|
|
18682
|
-
async function writeJsonFilePreservingStyle(file, value) {
|
|
18683
|
-
let currentRaw = null;
|
|
18684
|
-
try {
|
|
18685
|
-
currentRaw = await (0, import_promises3.readFile)(file, "utf-8");
|
|
18686
|
-
} catch {
|
|
18687
|
-
currentRaw = null;
|
|
18688
|
-
}
|
|
18689
|
-
if (currentRaw !== null) {
|
|
18690
|
-
try {
|
|
18691
|
-
if (jsonSemanticEqual(JSON.parse(currentRaw), value)) return false;
|
|
18692
|
-
} catch {
|
|
18693
|
-
}
|
|
18694
|
-
}
|
|
18695
|
-
const indent = currentRaw !== null ? detectJsonIndent(currentRaw) : 2;
|
|
18696
|
-
const next = JSON.stringify(value, null, indent) + "\n";
|
|
18697
|
-
if (next === currentRaw) return false;
|
|
18698
|
-
await (0, import_promises3.mkdir)((0, import_node_path12.dirname)(file), { recursive: true });
|
|
18699
|
-
await (0, import_promises3.writeFile)(file, next);
|
|
18700
|
-
return true;
|
|
18701
|
-
}
|
|
18702
|
-
|
|
18703
|
-
// src/lib/hooks.ts
|
|
18704
18803
|
var VERITY_STOP_HOOK = {
|
|
18705
18804
|
type: "command",
|
|
18706
18805
|
command: "verity analyze",
|
|
@@ -19270,26 +19369,43 @@ function readProjectConfig() {
|
|
|
19270
19369
|
cfg = { ...rest, turn_review_refused: refused2 };
|
|
19271
19370
|
}
|
|
19272
19371
|
}
|
|
19372
|
+
if (cfg.formal === "off" && cfg.path) {
|
|
19373
|
+
const refused2 = repoControlledRefusal(cfg.path);
|
|
19374
|
+
if (refused2 === "unverified") {
|
|
19375
|
+
cfg = { ...cfg, formal_off_unverified: true };
|
|
19376
|
+
} else if (refused2) {
|
|
19377
|
+
const { formal: _dropped, ...rest } = cfg;
|
|
19378
|
+
cfg = { ...rest, formal_off_refused: refused2 };
|
|
19379
|
+
}
|
|
19380
|
+
}
|
|
19273
19381
|
return cfg;
|
|
19274
19382
|
}
|
|
19275
|
-
function
|
|
19383
|
+
function formalOffUnverifiedNote() {
|
|
19384
|
+
return 'off-unverified: .verity/config.json says "off" and git could not confirm that the repository does not control it, so the "off" is kept and the formal check does not run';
|
|
19385
|
+
}
|
|
19386
|
+
function formalOffRefusalMessage(reason) {
|
|
19276
19387
|
switch (reason) {
|
|
19277
19388
|
case "tracked":
|
|
19278
|
-
return '.verity/config.json is tracked in git, so its
|
|
19389
|
+
return '.verity/config.json is tracked in git, so its formal "off" is ignored (a repository cannot switch formal verification off). To make your "off" count, untrack the file: git rm --cached .verity/config.json';
|
|
19279
19390
|
case "symlink":
|
|
19280
|
-
return '.verity/config.json is reached through a symlink, so its
|
|
19281
|
-
case "unverified":
|
|
19282
|
-
return 'could not confirm with git that .verity/config.json is untracked, so its turn_review "off" is ignored';
|
|
19391
|
+
return '.verity/config.json is reached through a symlink, so its formal "off" is ignored';
|
|
19283
19392
|
}
|
|
19284
19393
|
}
|
|
19285
|
-
function
|
|
19394
|
+
function formalSetting(cfg, env = process.env) {
|
|
19395
|
+
const fromEnv = env.VERITY_GIT_MOMENT_FORMAL;
|
|
19396
|
+
if (fromEnv === "off" || fromEnv === "push") return { state: fromEnv, source: "env" };
|
|
19397
|
+
if (cfg.formal === "off") return { state: "off", source: "config" };
|
|
19398
|
+
if (cfg.formal === "push") return { state: "push", source: "config" };
|
|
19399
|
+
return { state: "push", source: "default" };
|
|
19400
|
+
}
|
|
19401
|
+
function turnReviewRefusalMessage(reason) {
|
|
19286
19402
|
switch (reason) {
|
|
19287
19403
|
case "tracked":
|
|
19288
|
-
return
|
|
19404
|
+
return '.verity/config.json is tracked in git, so its turn_review "off" is ignored (a repository cannot switch the review off) \u2014 untrack it with: git rm --cached .verity/config.json';
|
|
19289
19405
|
case "symlink":
|
|
19290
|
-
return
|
|
19406
|
+
return '.verity/config.json is reached through a symlink, so its turn_review "off" is ignored';
|
|
19291
19407
|
case "unverified":
|
|
19292
|
-
return
|
|
19408
|
+
return 'could not confirm with git that .verity/config.json is untracked, so its turn_review "off" is ignored';
|
|
19293
19409
|
}
|
|
19294
19410
|
}
|
|
19295
19411
|
function writeProjectConfig(patch) {
|
|
@@ -21094,13 +21210,15 @@ var import_node_child_process9 = require("node:child_process");
|
|
|
21094
21210
|
var import_node_fs24 = require("node:fs");
|
|
21095
21211
|
var VERITY_GITIGNORE_MARKER = "# Verity \u2014 machine-local state.";
|
|
21096
21212
|
var SETTINGS_LOCAL_IGNORE_ENTRY = ".claude/settings.local.json";
|
|
21213
|
+
var BLOCK_COMMENT = [
|
|
21214
|
+
"# Verity \u2014 machine-local state. Everything in .verity/ is ignored. The Standard",
|
|
21215
|
+
"# is held by the Verity service (verity standard pull writes it here), and the",
|
|
21216
|
+
"# knowledge graph under .verity/memory/ is rebuilt from it. Committing either",
|
|
21217
|
+
"# puts generated files in every diff and pull request."
|
|
21218
|
+
];
|
|
21097
21219
|
var VERITY_GITIGNORE_BLOCK = [
|
|
21098
|
-
|
|
21099
|
-
"# shared standard, which is meant to be committed. The knowledge graph under",
|
|
21100
|
-
"# .verity/memory/ is machine-local too: the service rebuilds it, and committing",
|
|
21101
|
-
"# it puts generated notes in every diff and pull request.",
|
|
21220
|
+
...BLOCK_COMMENT,
|
|
21102
21221
|
".verity/*",
|
|
21103
|
-
"!.verity/standard.yaml",
|
|
21104
21222
|
SETTINGS_LOCAL_IGNORE_ENTRY,
|
|
21105
21223
|
""
|
|
21106
21224
|
].join("\n");
|
|
@@ -21125,9 +21243,11 @@ var SUPERSEDED_MEMORY_LINES = /* @__PURE__ */ new Set([
|
|
|
21125
21243
|
".verity/memory/log.md",
|
|
21126
21244
|
SUPERSEDED_COMMENT
|
|
21127
21245
|
]);
|
|
21128
|
-
|
|
21246
|
+
var SUPERSEDED_STANDARD_LINE = "!.verity/standard.yaml";
|
|
21247
|
+
var OLD_COMMENT_LINES = /* @__PURE__ */ new Set([SUPERSEDED_COMMENT, ...MEMORY_COMMENT]);
|
|
21248
|
+
function isIgnored3(path, opts = {}) {
|
|
21129
21249
|
try {
|
|
21130
|
-
(0, import_node_child_process9.execSync)(`git check-ignore -q -- "${path}"`, { stdio: "pipe" });
|
|
21250
|
+
(0, import_node_child_process9.execSync)(`git check-ignore -q ${opts.noIndex ? "--no-index " : ""}-- "${path}"`, { stdio: "pipe" });
|
|
21131
21251
|
return true;
|
|
21132
21252
|
} catch (err2) {
|
|
21133
21253
|
return err2.status === 1 ? false : null;
|
|
@@ -21135,10 +21255,9 @@ function isIgnored3(path) {
|
|
|
21135
21255
|
}
|
|
21136
21256
|
function semanticsHold() {
|
|
21137
21257
|
const snapshot = isIgnored3(".verity/.snapshot/__probe__");
|
|
21138
|
-
const standard = isIgnored3(".verity/standard.yaml");
|
|
21139
21258
|
const futureState = isIgnored3(".verity/.__probe-future-state__");
|
|
21140
|
-
if (snapshot === null ||
|
|
21141
|
-
return snapshot === true && futureState === true
|
|
21259
|
+
if (snapshot === null || futureState === null) return null;
|
|
21260
|
+
return snapshot === true && futureState === true;
|
|
21142
21261
|
}
|
|
21143
21262
|
function memoryPosture() {
|
|
21144
21263
|
const ignored = isIgnored3(".verity/memory/domain/__probe__.md");
|
|
@@ -21155,6 +21274,22 @@ function committedMemoryFiles() {
|
|
|
21155
21274
|
return [];
|
|
21156
21275
|
}
|
|
21157
21276
|
}
|
|
21277
|
+
var STANDARD_PATH = ".verity/standard.yaml";
|
|
21278
|
+
function standardPosture() {
|
|
21279
|
+
const ignored = isIgnored3(STANDARD_PATH, { noIndex: true });
|
|
21280
|
+
if (ignored === null) return "unknown";
|
|
21281
|
+
return ignored ? "ignored" : "committable";
|
|
21282
|
+
}
|
|
21283
|
+
function committedStandardFile() {
|
|
21284
|
+
try {
|
|
21285
|
+
return (0, import_node_child_process9.execSync)(`git ls-files -z -- ${STANDARD_PATH}`, {
|
|
21286
|
+
encoding: "utf-8",
|
|
21287
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
21288
|
+
}).split("\0").filter(Boolean).length > 0;
|
|
21289
|
+
} catch {
|
|
21290
|
+
return false;
|
|
21291
|
+
}
|
|
21292
|
+
}
|
|
21158
21293
|
var OPT_OUT_COMMENT_LINES = /* @__PURE__ */ new Set([
|
|
21159
21294
|
MEMORY_OPT_OUT_MARKER,
|
|
21160
21295
|
'# Remove these three lines (or run "verity memory untrack") to stop tracking it.'
|
|
@@ -21172,6 +21307,19 @@ function fenceMemoryLines(lines) {
|
|
|
21172
21307
|
}
|
|
21173
21308
|
return out2;
|
|
21174
21309
|
}
|
|
21310
|
+
function fenceStandardLines(lines) {
|
|
21311
|
+
const out2 = [];
|
|
21312
|
+
for (const line2 of lines) {
|
|
21313
|
+
const trimmed = line2.trim();
|
|
21314
|
+
if (trimmed.startsWith(VERITY_GITIGNORE_MARKER) && trimmed !== BLOCK_COMMENT[0]) {
|
|
21315
|
+
out2.push(...BLOCK_COMMENT);
|
|
21316
|
+
continue;
|
|
21317
|
+
}
|
|
21318
|
+
if (trimmed === SUPERSEDED_STANDARD_LINE || OLD_COMMENT_LINES.has(trimmed)) continue;
|
|
21319
|
+
out2.push(line2);
|
|
21320
|
+
}
|
|
21321
|
+
return out2;
|
|
21322
|
+
}
|
|
21175
21323
|
function ensureVerityGitignore() {
|
|
21176
21324
|
let content = "";
|
|
21177
21325
|
try {
|
|
@@ -21183,9 +21331,11 @@ function ensureVerityGitignore() {
|
|
|
21183
21331
|
const lines = content.split("\n");
|
|
21184
21332
|
const needsRepair = lines.some((l) => BREAKING_ENTRIES.has(l.trim()));
|
|
21185
21333
|
const hasSupersededMemory = hasMarker && !optedOut && lines.some((l) => SUPERSEDED_MEMORY_LINES.has(l.trim()));
|
|
21334
|
+
const hasSupersededStandard = hasMarker && lines.some((l) => l.trim() === SUPERSEDED_STANDARD_LINE);
|
|
21186
21335
|
const memoryIsCommitted = hasSupersededMemory && committedMemoryFiles().length > 0;
|
|
21336
|
+
const standardIsCommitted = hasSupersededStandard && committedStandardFile();
|
|
21187
21337
|
const verified = (result) => semanticsHold() === false ? "conflict" : result;
|
|
21188
|
-
if (hasMarker && !needsRepair && !hasSupersededMemory) return verified("covered");
|
|
21338
|
+
if (hasMarker && !needsRepair && !hasSupersededMemory && !hasSupersededStandard) return verified("covered");
|
|
21189
21339
|
if (!hasMarker && !needsRepair) {
|
|
21190
21340
|
if (semanticsHold() === true) return "covered";
|
|
21191
21341
|
}
|
|
@@ -21194,6 +21344,9 @@ function ensureVerityGitignore() {
|
|
|
21194
21344
|
if (needsRepair) {
|
|
21195
21345
|
next = next.map((l) => BREAKING_ENTRIES.has(l.trim()) ? ".verity/*" : l);
|
|
21196
21346
|
}
|
|
21347
|
+
if (hasSupersededStandard && !standardIsCommitted) {
|
|
21348
|
+
next = fenceStandardLines(next);
|
|
21349
|
+
}
|
|
21197
21350
|
if (hasSupersededMemory && !memoryIsCommitted) {
|
|
21198
21351
|
next = fenceMemoryLines(next);
|
|
21199
21352
|
}
|
|
@@ -21204,7 +21357,7 @@ function ensureVerityGitignore() {
|
|
|
21204
21357
|
}
|
|
21205
21358
|
if (text3 !== content) (0, import_node_fs24.writeFileSync)(".gitignore", text3);
|
|
21206
21359
|
return verified(
|
|
21207
|
-
memoryIsCommitted ? "memory-tracked" : hasSupersededMemory ? "memory-fenced" : needsRepair ? "repaired" : "added"
|
|
21360
|
+
memoryIsCommitted ? "memory-tracked" : standardIsCommitted ? "standard-tracked" : hasSupersededMemory ? "memory-fenced" : hasSupersededStandard ? "standard-fenced" : needsRepair ? "repaired" : "added"
|
|
21208
21361
|
);
|
|
21209
21362
|
} catch {
|
|
21210
21363
|
return "failed";
|
|
@@ -21219,7 +21372,7 @@ function untrackMemory() {
|
|
|
21219
21372
|
return "failed";
|
|
21220
21373
|
}
|
|
21221
21374
|
}
|
|
21222
|
-
function writeFencedBlock() {
|
|
21375
|
+
function writeFencedBlock(fence) {
|
|
21223
21376
|
let content = "";
|
|
21224
21377
|
try {
|
|
21225
21378
|
content = (0, import_node_fs24.readFileSync)(".gitignore", "utf-8");
|
|
@@ -21227,7 +21380,8 @@ function writeFencedBlock() {
|
|
|
21227
21380
|
}
|
|
21228
21381
|
const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
|
|
21229
21382
|
let lines = content.split("\n").map((l) => BREAKING_ENTRIES.has(l.trim()) ? ".verity/*" : l);
|
|
21230
|
-
lines =
|
|
21383
|
+
if (fence.standard) lines = fenceStandardLines(lines);
|
|
21384
|
+
if (fence.memory) lines = fenceMemoryLines(lines);
|
|
21231
21385
|
let text3 = lines.join("\n");
|
|
21232
21386
|
if (!hasMarker) {
|
|
21233
21387
|
const sep7 = text3 === "" ? "" : text3.endsWith("\n") ? "\n" : "\n\n";
|
|
@@ -21254,7 +21408,7 @@ function fenceMemory() {
|
|
|
21254
21408
|
} catch {
|
|
21255
21409
|
}
|
|
21256
21410
|
};
|
|
21257
|
-
if (!writeFencedBlock()) return { untracked: 0, ok: false };
|
|
21411
|
+
if (!writeFencedBlock({ memory: true })) return { untracked: 0, ok: false };
|
|
21258
21412
|
if (memoryPosture() !== "ignored") {
|
|
21259
21413
|
restore();
|
|
21260
21414
|
return { untracked: 0, ok: false };
|
|
@@ -21266,6 +21420,34 @@ function fenceMemory() {
|
|
|
21266
21420
|
}
|
|
21267
21421
|
return { untracked: tracked, ok: true };
|
|
21268
21422
|
}
|
|
21423
|
+
function untrackStandard() {
|
|
21424
|
+
let original = null;
|
|
21425
|
+
try {
|
|
21426
|
+
original = (0, import_node_fs24.readFileSync)(".gitignore", "utf-8");
|
|
21427
|
+
} catch {
|
|
21428
|
+
original = null;
|
|
21429
|
+
}
|
|
21430
|
+
const restore = () => {
|
|
21431
|
+
try {
|
|
21432
|
+
if (original === null) (0, import_node_fs24.rmSync)(".gitignore", { force: true });
|
|
21433
|
+
else (0, import_node_fs24.writeFileSync)(".gitignore", original);
|
|
21434
|
+
} catch {
|
|
21435
|
+
}
|
|
21436
|
+
};
|
|
21437
|
+
if (!writeFencedBlock({ standard: true })) return { ok: false, why: "gitignore" };
|
|
21438
|
+
if (standardPosture() !== "ignored") {
|
|
21439
|
+
restore();
|
|
21440
|
+
return { ok: false, why: "still-committable" };
|
|
21441
|
+
}
|
|
21442
|
+
if (!committedStandardFile()) return { ok: true, untracked: false };
|
|
21443
|
+
try {
|
|
21444
|
+
(0, import_node_child_process9.execSync)(`git rm --cached --quiet -- ${STANDARD_PATH}`, { stdio: "pipe" });
|
|
21445
|
+
return { ok: true, untracked: true };
|
|
21446
|
+
} catch {
|
|
21447
|
+
restore();
|
|
21448
|
+
return { ok: false, why: "index" };
|
|
21449
|
+
}
|
|
21450
|
+
}
|
|
21269
21451
|
function memoryOptOut() {
|
|
21270
21452
|
try {
|
|
21271
21453
|
return (0, import_node_fs24.readFileSync)(".gitignore", "utf-8").includes(MEMORY_OPT_OUT_MARKER);
|
|
@@ -21295,18 +21477,23 @@ function committedVerityState() {
|
|
|
21295
21477
|
} catch {
|
|
21296
21478
|
return [];
|
|
21297
21479
|
}
|
|
21298
|
-
return out2.split("\0").filter(Boolean).filter((p) => p !==
|
|
21480
|
+
return out2.split("\0").filter(Boolean).filter((p) => p !== STANDARD_PATH && !p.startsWith(".verity/memory/"));
|
|
21299
21481
|
}
|
|
21300
21482
|
function untrackVerityState() {
|
|
21301
21483
|
const tracked = committedVerityState();
|
|
21302
21484
|
if (tracked.length === 0) return "none";
|
|
21485
|
+
const standardWasTracked = committedStandardFile();
|
|
21303
21486
|
try {
|
|
21304
21487
|
(0, import_node_child_process9.execSync)("git rm -r --cached --quiet -- .verity", { stdio: "pipe" });
|
|
21305
|
-
|
|
21306
|
-
|
|
21307
|
-
|
|
21488
|
+
if (standardWasTracked) {
|
|
21489
|
+
try {
|
|
21490
|
+
(0, import_node_child_process9.execSync)(`git add -f -- ${STANDARD_PATH}`, { stdio: "pipe" });
|
|
21491
|
+
} catch {
|
|
21492
|
+
}
|
|
21493
|
+
}
|
|
21494
|
+
if (memoryPosture() === "committable") {
|
|
21308
21495
|
try {
|
|
21309
|
-
(0, import_node_child_process9.execSync)(
|
|
21496
|
+
(0, import_node_child_process9.execSync)("git add -- .verity/memory", { stdio: "pipe" });
|
|
21310
21497
|
} catch {
|
|
21311
21498
|
}
|
|
21312
21499
|
}
|
|
@@ -21827,8 +22014,13 @@ var CLAUDE_MD_PROSE = [
|
|
|
21827
22014
|
" `verity standard generate`. It works only for a project with no Standard on the",
|
|
21828
22015
|
" service. It writes `.verity/repo-profile.json` and sends nothing without consent.",
|
|
21829
22016
|
" Show the user that file. Run the command again with `--yes` only after they agree.",
|
|
21830
|
-
"- The rules themselves:
|
|
22017
|
+
"- The rules themselves: run `verity standard pull` first (the file here can be behind",
|
|
22018
|
+
" the team's), edit `.verity/standard.yaml`, then run `verity standard push`."
|
|
21831
22019
|
].join("\n");
|
|
22020
|
+
var CLAUDE_MD_PROSE_PRE_PULL = CLAUDE_MD_PROSE.replace(
|
|
22021
|
+
/- The rules themselves: run `verity standard pull` first \(the file here can be behind\n the team's\), edit `\.verity\/standard\.yaml`, then run `verity standard push`\.$/,
|
|
22022
|
+
"- The rules themselves: edit `.verity/standard.yaml`, then run `verity standard push`."
|
|
22023
|
+
);
|
|
21832
22024
|
var CLAUDE_MD_PROSE_PRE_VERBOSE = [
|
|
21833
22025
|
"## Project Memory",
|
|
21834
22026
|
"",
|
|
@@ -22466,6 +22658,7 @@ function stripKnownProse(interior) {
|
|
|
22466
22658
|
const trimmed = interior.replace(/^\n+/, "");
|
|
22467
22659
|
for (const prose of [
|
|
22468
22660
|
CLAUDE_MD_PROSE,
|
|
22661
|
+
CLAUDE_MD_PROSE_PRE_PULL,
|
|
22469
22662
|
CLAUDE_MD_PROSE_PRE_VERBOSE,
|
|
22470
22663
|
CLAUDE_MD_PROSE_PRE_SETTINGS,
|
|
22471
22664
|
CLAUDE_MD_PROSE_PRE_STDIN,
|
|
@@ -25531,6 +25724,8 @@ async function generateStandard(opts) {
|
|
|
25531
25724
|
} catch (err2) {
|
|
25532
25725
|
return { status: "failed", reason: `the Standard is on the service (v${version}) but could not be written here: ${terminalText(err2.message, 200)}` };
|
|
25533
25726
|
}
|
|
25727
|
+
await writeSetupState({ standardVersion: version }).catch(() => {
|
|
25728
|
+
});
|
|
25534
25729
|
return {
|
|
25535
25730
|
status: "created",
|
|
25536
25731
|
version,
|
|
@@ -25711,68 +25906,6 @@ async function runGenerate(globals, opts) {
|
|
|
25711
25906
|
var import_node_fs37 = require("node:fs");
|
|
25712
25907
|
var import_yaml6 = __toESM2(require_dist());
|
|
25713
25908
|
|
|
25714
|
-
// src/lib/setup-state.ts
|
|
25715
|
-
var SETUP_STATE_FILE = `${VERITY_DIR}/setup.json`;
|
|
25716
|
-
var MOMENTS = ["stop", "pre-commit", "pre-push"];
|
|
25717
|
-
var INTENSITIES = ["lightweight", "balanced", "thorough"];
|
|
25718
|
-
var TELEMETRY = ["enabled", "declined", "deferred"];
|
|
25719
|
-
var VERSION = /^[0-9A-Za-z.+-]{1,32}$/;
|
|
25720
|
-
var stamp = (v) => typeof v === "string" && v.length > 0 && v.length <= 64;
|
|
25721
|
-
function setupStateFrom(raw) {
|
|
25722
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
|
|
25723
|
-
const r = raw;
|
|
25724
|
-
if (r.version !== 1) return null;
|
|
25725
|
-
const out2 = { version: 1 };
|
|
25726
|
-
if (INTENSITIES.includes(r.intensity)) out2.intensity = r.intensity;
|
|
25727
|
-
if (Array.isArray(r.moments) && r.moments.every((m) => MOMENTS.includes(m))) {
|
|
25728
|
-
out2.moments = [...new Set(r.moments)];
|
|
25729
|
-
}
|
|
25730
|
-
if (TELEMETRY.includes(r.telemetry)) out2.telemetry = r.telemetry;
|
|
25731
|
-
if (Number.isSafeInteger(r.declinedStandardVersion) && r.declinedStandardVersion >= 1) {
|
|
25732
|
-
out2.declinedStandardVersion = r.declinedStandardVersion;
|
|
25733
|
-
}
|
|
25734
|
-
const init2 = r.init;
|
|
25735
|
-
if (init2 && typeof init2 === "object" && stamp(init2.completed_at) && typeof init2.cli_version === "string" && VERSION.test(init2.cli_version)) {
|
|
25736
|
-
out2.init = { completed_at: init2.completed_at, cli_version: init2.cli_version };
|
|
25737
|
-
}
|
|
25738
|
-
const plugin = r.pluginSetup;
|
|
25739
|
-
if (plugin && typeof plugin === "object" && typeof plugin.version === "string" && VERSION.test(plugin.version) && stamp(plugin.completed_at)) {
|
|
25740
|
-
out2.pluginSetup = { version: plugin.version, completed_at: plugin.completed_at };
|
|
25741
|
-
}
|
|
25742
|
-
if (r.wiring === "project") out2.wiring = "project";
|
|
25743
|
-
return out2;
|
|
25744
|
-
}
|
|
25745
|
-
var MAX_SETUP_BYTES = 64 * 1024;
|
|
25746
|
-
function readSetupText() {
|
|
25747
|
-
const read2 = readRegularFileInRoot(repoRoot(), SETUP_STATE_FILE, MAX_SETUP_BYTES);
|
|
25748
|
-
return read2.ok ? read2.content : null;
|
|
25749
|
-
}
|
|
25750
|
-
async function readSetupState() {
|
|
25751
|
-
const raw = readSetupText();
|
|
25752
|
-
if (raw === null) return null;
|
|
25753
|
-
try {
|
|
25754
|
-
return setupStateFrom(JSON.parse(raw));
|
|
25755
|
-
} catch {
|
|
25756
|
-
return null;
|
|
25757
|
-
}
|
|
25758
|
-
}
|
|
25759
|
-
async function writeSetupState(patch) {
|
|
25760
|
-
const current = await readSetupState() ?? { version: 1 };
|
|
25761
|
-
const next = { ...current, ...patch, version: 1 };
|
|
25762
|
-
const raw = readSetupText();
|
|
25763
|
-
if (raw !== null) {
|
|
25764
|
-
try {
|
|
25765
|
-
if (jsonSemanticEqual(JSON.parse(raw), next)) return next;
|
|
25766
|
-
} catch {
|
|
25767
|
-
}
|
|
25768
|
-
}
|
|
25769
|
-
const text3 = JSON.stringify(next, null, raw !== null ? detectJsonIndent(raw) : 2) + "\n";
|
|
25770
|
-
if (!replaceInRoot(projectPath(VERITY_DIR), "setup.json", text3)) {
|
|
25771
|
-
throw new Error(`Could not write ${SETUP_STATE_FILE}: it is a link, or ${VERITY_DIR} is not a folder of this repository`);
|
|
25772
|
-
}
|
|
25773
|
-
return next;
|
|
25774
|
-
}
|
|
25775
|
-
|
|
25776
25909
|
// src/commands/init/rules.ts
|
|
25777
25910
|
async function projectLabel(token, serviceUrl, verbose) {
|
|
25778
25911
|
try {
|
|
@@ -25917,6 +26050,8 @@ async function pullStandard(globals, opts = {}) {
|
|
|
25917
26050
|
} catch {
|
|
25918
26051
|
}
|
|
25919
26052
|
if (local && typeof local === "object" && !Array.isArray(local) && sameStandard(local, remote.standard.content)) {
|
|
26053
|
+
await writeSetupState({ standardVersion: version, declinedStandardVersion: void 0 }).catch(() => {
|
|
26054
|
+
});
|
|
25920
26055
|
return { status: "same", version };
|
|
25921
26056
|
}
|
|
25922
26057
|
try {
|
|
@@ -25927,7 +26062,7 @@ async function pullStandard(globals, opts = {}) {
|
|
|
25927
26062
|
}
|
|
25928
26063
|
try {
|
|
25929
26064
|
const outcome = await adoptRemoteSetup(remote, { serviceUrl: url.data, projectId, expectStandard: readBytes });
|
|
25930
|
-
await writeSetupState({ declinedStandardVersion: void 0 }).catch(() => {
|
|
26065
|
+
await writeSetupState({ standardVersion: version, declinedStandardVersion: void 0 }).catch(() => {
|
|
25931
26066
|
});
|
|
25932
26067
|
return { status: "pulled", version, backup, notes: outcome.notes };
|
|
25933
26068
|
} catch (err2) {
|
|
@@ -26146,8 +26281,13 @@ function registerStandardCommands(program2) {
|
|
|
26146
26281
|
for (const path of result.written) printInfo(` ${terminalText(path, 200)} \u2713`);
|
|
26147
26282
|
for (const note of result.notes) printWarn(` ${terminalText(note, 300)}`);
|
|
26148
26283
|
if (opts.push) {
|
|
26149
|
-
const
|
|
26284
|
+
const token = await resolveToken(globals.token);
|
|
26285
|
+
const expected = token.ok && urlResult.ok ? await expectedLatestForPush(globals, token.data.token, urlResult.data) : void 0;
|
|
26286
|
+
const pushed = await pushStandard(globals, expected !== void 0 ? { expectedLatest: expected } : {});
|
|
26150
26287
|
for (const line2 of pushed.lines) printInfo(` ${terminalText(line2, 600)}`);
|
|
26288
|
+
if (pushed.conflict) {
|
|
26289
|
+
printWarn(` The team's Standard is v${pushed.latest ?? "?"} now. Run verity standard pull to use it here, or verity standard push --force to replace it with this file.`);
|
|
26290
|
+
}
|
|
26151
26291
|
if (pushed.standardVersion !== null) {
|
|
26152
26292
|
await correctVerityMdVersion({
|
|
26153
26293
|
standard: result.standard,
|
|
@@ -26161,7 +26301,7 @@ function registerStandardCommands(program2) {
|
|
|
26161
26301
|
standard.command("generate").description("Have Verity write project-specific rules from a profile of this repository (asks before sending it)").option("--yes", `Send the profile without asking (you have read ${PROFILE_FILE})`).option("--status", "Print whether the service writes project rules for this project: on, off, unsupported or unknown. Sends nothing.").action((opts) => runGenerate(program2.opts(), opts));
|
|
26162
26302
|
standard.command("pull").description("Write the team's Standard on the service into .verity/standard.yaml (keeps a copy of yours)").action(() => runPull(program2.opts()));
|
|
26163
26303
|
standard.command("catalogue [pack]").description("What each review pack holds: every pack, or the rules of one (core, api, data, \u2026)").option("--json", "Print the catalogue as JSON").action((pack, opts) => runCatalogue(program2.opts(), pack, opts));
|
|
26164
|
-
standard.command("push").description("Upload the project Standard to the service").option("--file <path>", "Path to standard YAML file", STANDARD_FILE).option("--created-by <name>", "Who created this version", "claude-code").action(async (opts) => {
|
|
26304
|
+
standard.command("push").description("Upload the project Standard to the service, as the next version after the one this machine last saw").option("--file <path>", "Path to standard YAML file", STANDARD_FILE).option("--created-by <name>", "Who created this version", "claude-code").option("--force", "Upload even when the team's Standard moved since this machine last pulled or pushed it").action(async (opts) => {
|
|
26165
26305
|
const globals = program2.opts();
|
|
26166
26306
|
const tokenResult = await resolveToken(globals.token);
|
|
26167
26307
|
if (!tokenResult.ok) {
|
|
@@ -26184,19 +26324,33 @@ function registerStandardCommands(program2) {
|
|
|
26184
26324
|
process.exit(1);
|
|
26185
26325
|
}
|
|
26186
26326
|
if (upload.warning) printWarn(terminalText(upload.warning, 600));
|
|
26327
|
+
const expected = opts.force ? void 0 : await expectedLatestForPush(globals, tokenResult.data.token, urlResult.data);
|
|
26187
26328
|
const result = await apiRequest({
|
|
26188
26329
|
method: "POST",
|
|
26189
26330
|
path: "/standards",
|
|
26190
26331
|
serviceUrl: urlResult.data,
|
|
26191
26332
|
token: tokenResult.data.token,
|
|
26192
|
-
body: {
|
|
26333
|
+
body: {
|
|
26334
|
+
content: upload.content,
|
|
26335
|
+
created_by: upload.createdBy,
|
|
26336
|
+
...expected !== void 0 ? { expected_latest: expected } : {}
|
|
26337
|
+
},
|
|
26193
26338
|
verbose: globals.verbose
|
|
26194
26339
|
});
|
|
26195
26340
|
if (!result.ok) {
|
|
26341
|
+
if (expected !== void 0 && result.http_status === 409 && result.error.startsWith("STANDARD_EXISTS")) {
|
|
26342
|
+
const latest = latestFromConflict(result);
|
|
26343
|
+
printError(latest !== null ? `The team's Standard is v${latest} now${expected !== null ? `, and this machine last saw v${expected}` : ", and this machine saw none"}. Nothing was pushed. Run "verity standard pull" first (it keeps a copy of your file), put your changes into the pulled file, then push again. To replace v${latest} with this file as it is: verity standard push --force` : `The service has no Standard for this project, but this machine last saw v${expected}. Nothing was pushed. To share this file as v1: verity standard push --force`);
|
|
26344
|
+
process.exit(1);
|
|
26345
|
+
}
|
|
26196
26346
|
printError(terminalText(result.error, 300));
|
|
26197
26347
|
process.exit(1);
|
|
26198
26348
|
}
|
|
26199
26349
|
printInfo(`Standard uploaded (version ${versionText(result.data.version)})`);
|
|
26350
|
+
if (Number.isSafeInteger(result.data.version) && result.data.version >= 1) {
|
|
26351
|
+
await writeSetupState({ standardVersion: result.data.version }).catch(() => {
|
|
26352
|
+
});
|
|
26353
|
+
}
|
|
26200
26354
|
const converted = conversionLine(result.data);
|
|
26201
26355
|
if (converted) {
|
|
26202
26356
|
printInfo(converted);
|
|
@@ -26204,6 +26358,7 @@ function registerStandardCommands(program2) {
|
|
|
26204
26358
|
}
|
|
26205
26359
|
printJson(result.data);
|
|
26206
26360
|
});
|
|
26361
|
+
standard.command("untrack").description(`Stop tracking ${STANDARD_FILE} in git: Verity keeps it on each machine, and reviews read the service`).action(() => runUntrack());
|
|
26207
26362
|
standard.command("get").description("Get the current Standard from the service").option("--version <n>", "Specific version number").option("--resolved", "Show it as a review reads it: the catalogue packs in `extends` expanded into patterns").action(async (opts) => {
|
|
26208
26363
|
const globals = program2.opts();
|
|
26209
26364
|
const tokenResult = await resolveToken(globals.token);
|
|
@@ -26278,6 +26433,32 @@ function registerStandardCommands(program2) {
|
|
|
26278
26433
|
function versionText(value) {
|
|
26279
26434
|
return typeof value === "number" && Number.isSafeInteger(value) ? String(value) : "?";
|
|
26280
26435
|
}
|
|
26436
|
+
async function expectedLatestForPush(globals, token, serviceUrl) {
|
|
26437
|
+
const state = await readSetupState();
|
|
26438
|
+
if (state?.standardVersion !== void 0) return state.standardVersion;
|
|
26439
|
+
const remote = await fetchRemoteSetup({ token, serviceUrl, verbose: globals.verbose });
|
|
26440
|
+
if (remote.status === "found") {
|
|
26441
|
+
printInfo(`This machine had no record of the team's Standard. It is v${remote.standard.version} on the service, and this push replaces it.`);
|
|
26442
|
+
return remote.standard.version;
|
|
26443
|
+
}
|
|
26444
|
+
if (remote.status === "none") return null;
|
|
26445
|
+
printWarn(`Could not read the team's Standard from the service (${terminalText(remote.reason, 200)}), so this push is not conditional on it.`);
|
|
26446
|
+
return void 0;
|
|
26447
|
+
}
|
|
26448
|
+
function runUntrack() {
|
|
26449
|
+
const wasTracked = committedStandardFile();
|
|
26450
|
+
const result = untrackStandard();
|
|
26451
|
+
if (!result.ok) {
|
|
26452
|
+
printError(result.why === "gitignore" ? "Could not write .gitignore. Nothing changed." : result.why === "still-committable" ? `Git still lets ${STANDARD_FILE} be committed after the .gitignore change, so nothing was untracked and .gitignore is as it was. A nested .gitignore re-includes it: check with git check-ignore -v --no-index ${STANDARD_FILE}` : `Could not remove ${STANDARD_FILE} from the git index. .gitignore is as it was.`);
|
|
26453
|
+
process.exit(1);
|
|
26454
|
+
}
|
|
26455
|
+
if (!wasTracked) {
|
|
26456
|
+
printInfo(`${STANDARD_FILE} is not tracked in git. Git ignores it from here on; nothing else changed.`);
|
|
26457
|
+
return;
|
|
26458
|
+
}
|
|
26459
|
+
printInfo(`Untracked ${STANDARD_FILE} (staged). The file stays on disk here. Commit to finish.`);
|
|
26460
|
+
printInfo("Teammates lose the file on their next pull: `verity standard pull` (or `verity init`) writes the team's Standard back for them. Reviews read the Standard on the service, so none is affected.");
|
|
26461
|
+
}
|
|
26281
26462
|
var UPLOAD_MAX_BYTES = 512 * 1024;
|
|
26282
26463
|
function readUploadFile(file) {
|
|
26283
26464
|
const root = realOrSelf(repoRoot());
|
|
@@ -26439,11 +26620,15 @@ function registerConfigCommands(program2) {
|
|
|
26439
26620
|
}
|
|
26440
26621
|
printInfo(pluginMode ? "It applies from the next turn." : "It applies from the next Claude Code session (Claude Code reads hooks when a session starts).");
|
|
26441
26622
|
});
|
|
26442
|
-
config.command("formal [state]").description('Get or set formal verification at push: "push" or "off" (needs Lean \u2014 verity lean status)').action((state) => {
|
|
26623
|
+
config.command("formal [state]").description('Get or set formal verification at push: "push" (the default) or "off" (needs Lean \u2014 verity lean status)').action((state) => {
|
|
26443
26624
|
if (state === void 0) {
|
|
26444
26625
|
const cfg = readProjectConfig();
|
|
26445
|
-
|
|
26446
|
-
|
|
26626
|
+
const setting = formalSetting(cfg);
|
|
26627
|
+
process.stdout.write(setting.state + "\n");
|
|
26628
|
+
if (cfg.formal_off_refused && setting.source === "default") printWarn(formalOffRefusalMessage(cfg.formal_off_refused));
|
|
26629
|
+
else if (setting.source === "default") printInfo("On by default. To turn it off for this checkout, run: verity config formal off");
|
|
26630
|
+
if (setting.source === "env") printInfo("Set by VERITY_GIT_MOMENT_FORMAL in this environment");
|
|
26631
|
+
if (cfg.formal_off_unverified && setting.source === "config") printWarn(formalOffUnverifiedNote());
|
|
26447
26632
|
return;
|
|
26448
26633
|
}
|
|
26449
26634
|
if (state !== "push" && state !== "off") {
|
|
@@ -26451,13 +26636,18 @@ function registerConfigCommands(program2) {
|
|
|
26451
26636
|
process.exit(1);
|
|
26452
26637
|
}
|
|
26453
26638
|
writeProjectConfig({ formal: state === "push" ? "push" : "off" });
|
|
26454
|
-
const
|
|
26455
|
-
|
|
26456
|
-
|
|
26639
|
+
const after = readProjectConfig();
|
|
26640
|
+
const offRefused = state === "off" && formalSetting(after).state === "push" ? after.formal_off_refused : void 0;
|
|
26641
|
+
if (offRefused) {
|
|
26642
|
+
printWarn(`Formal verification at push: still on \u2014 ${formalOffRefusalMessage(offRefused)}`);
|
|
26457
26643
|
return;
|
|
26458
26644
|
}
|
|
26459
|
-
printInfo(state === "push" ? "Formal verification at push: on for this checkout (Lean must be installed \u2014 verity lean status)" : "Formal verification at push: off");
|
|
26645
|
+
printInfo(state === "push" ? "Formal verification at push: on for this checkout (Lean must be installed \u2014 verity lean status)" : "Formal verification at push: off for this checkout");
|
|
26460
26646
|
if (state === "push") printInfo("The phase runs with your Verity login (a push without one is skipped and says so: not-logged-in)");
|
|
26647
|
+
const env = process.env.VERITY_GIT_MOMENT_FORMAL;
|
|
26648
|
+
if ((env === "off" || env === "push") && env !== state) {
|
|
26649
|
+
printWarn(`VERITY_GIT_MOMENT_FORMAL=${env} in this environment overrides the file while it is set`);
|
|
26650
|
+
}
|
|
26461
26651
|
});
|
|
26462
26652
|
config.command("verbose [state]").description('Get or set the line Verity prints when a turn has nothing new to review: "on" or "off" (the default)').action((state) => {
|
|
26463
26653
|
if (state === void 0) {
|
|
@@ -29616,11 +29806,11 @@ async function readStopHookStdin() {
|
|
|
29616
29806
|
return new Promise((resolve10) => {
|
|
29617
29807
|
const chunks = [];
|
|
29618
29808
|
let size = 0;
|
|
29619
|
-
let
|
|
29809
|
+
let settled2 = false;
|
|
29620
29810
|
let timer;
|
|
29621
29811
|
const settle = (result) => {
|
|
29622
|
-
if (
|
|
29623
|
-
|
|
29812
|
+
if (settled2) return;
|
|
29813
|
+
settled2 = true;
|
|
29624
29814
|
if (timer) clearTimeout(timer);
|
|
29625
29815
|
process.stdin.off("data", onData);
|
|
29626
29816
|
process.stdin.off("end", onEnd);
|
|
@@ -34352,15 +34542,23 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
|
|
|
34352
34542
|
].join("\n");
|
|
34353
34543
|
return fm;
|
|
34354
34544
|
}
|
|
34355
|
-
async function
|
|
34356
|
-
if (
|
|
34357
|
-
|
|
34545
|
+
async function standardForSeed(opts) {
|
|
34546
|
+
if ((0, import_node_fs53.existsSync)(STANDARD_FILE)) {
|
|
34547
|
+
const raw = readRepoFile(STANDARD_FILE);
|
|
34548
|
+
if (raw === null) return null;
|
|
34549
|
+
try {
|
|
34550
|
+
const parsed = (0, import_yaml9.parse)(raw);
|
|
34551
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
34552
|
+
} catch {
|
|
34553
|
+
return null;
|
|
34554
|
+
}
|
|
34358
34555
|
}
|
|
34359
|
-
|
|
34360
|
-
|
|
34361
|
-
|
|
34362
|
-
|
|
34363
|
-
|
|
34556
|
+
const remote = await fetchRemoteSetup({ serviceUrl: opts.serviceUrl, token: opts.token, verbose: opts.verbose });
|
|
34557
|
+
return remote.status === "found" ? remote.standard.content : null;
|
|
34558
|
+
}
|
|
34559
|
+
async function runSeed(opts) {
|
|
34560
|
+
const standardDoc = await standardForSeed(opts);
|
|
34561
|
+
if (standardDoc === null) {
|
|
34364
34562
|
return { created: 0, existing: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
34365
34563
|
}
|
|
34366
34564
|
const knowledgeSpec = standardDoc.knowledge_spec ?? {};
|
|
@@ -34487,9 +34685,8 @@ async function memoryManifest(run4) {
|
|
|
34487
34685
|
try {
|
|
34488
34686
|
await ensureMemoryDir();
|
|
34489
34687
|
const seedMarker = (0, import_node_path43.join)(VERITY_DIR, ".seeded");
|
|
34490
|
-
const hasStandard = (0, import_node_fs54.existsSync)(STANDARD_FILE);
|
|
34491
34688
|
const alreadyTried = (0, import_node_fs54.existsSync)(seedMarker);
|
|
34492
|
-
if (
|
|
34689
|
+
if (!alreadyTried) {
|
|
34493
34690
|
const preManifest = await buildManifest();
|
|
34494
34691
|
if (preManifest.nodes.length === 0) {
|
|
34495
34692
|
try {
|
|
@@ -36958,7 +37155,7 @@ function runAsync(tc, cwd, args2, timeoutMs) {
|
|
|
36958
37155
|
let stdout = "";
|
|
36959
37156
|
let stderr = "";
|
|
36960
37157
|
let timedOut = false;
|
|
36961
|
-
let
|
|
37158
|
+
let settled2 = false;
|
|
36962
37159
|
const kill = () => {
|
|
36963
37160
|
try {
|
|
36964
37161
|
if (posix && child.pid) process.kill(-child.pid, "SIGKILL");
|
|
@@ -36977,8 +37174,8 @@ function runAsync(tc, cwd, args2, timeoutMs) {
|
|
|
36977
37174
|
if (stderr.length < MAX) stderr += d.toString("utf-8");
|
|
36978
37175
|
});
|
|
36979
37176
|
const finish = (ok, message) => {
|
|
36980
|
-
if (
|
|
36981
|
-
|
|
37177
|
+
if (settled2) return;
|
|
37178
|
+
settled2 = true;
|
|
36982
37179
|
clearTimeout(timer);
|
|
36983
37180
|
if (ok) resolve10({ ok: true, stdout, stderr: "", durationMs: Date.now() - started, timedOut: false });
|
|
36984
37181
|
else resolve10({ ok: false, stdout, stderr: stderr || message || "", durationMs: Date.now() - started, timedOut });
|
|
@@ -37487,16 +37684,138 @@ function resumeInterruptedInstall(opts) {
|
|
|
37487
37684
|
return shouldStartBackgroundInstall({ formal: opts.formal, env, free: opts.free }).start && startBackgroundInstall({ cli: opts.cli, env, run: opts.run });
|
|
37488
37685
|
}
|
|
37489
37686
|
|
|
37687
|
+
// src/lib/prove/formal-default.ts
|
|
37688
|
+
var import_node_fs64 = require("node:fs");
|
|
37689
|
+
var import_node_path52 = require("node:path");
|
|
37690
|
+
var NOTICE_MARKER = ".formal-default-notice";
|
|
37691
|
+
var LEAN_MARKER = ".formal-lean-checked";
|
|
37692
|
+
function markerPath3(name2) {
|
|
37693
|
+
return (0, import_node_path52.join)(verityHome(), name2);
|
|
37694
|
+
}
|
|
37695
|
+
function writeMarker(name2, now) {
|
|
37696
|
+
try {
|
|
37697
|
+
(0, import_node_fs64.mkdirSync)(verityHome(), { recursive: true, mode: 448 });
|
|
37698
|
+
(0, import_node_fs64.writeFileSync)(markerPath3(name2), now.toISOString() + "\n");
|
|
37699
|
+
} catch {
|
|
37700
|
+
}
|
|
37701
|
+
}
|
|
37702
|
+
function formalDefaultNoticeDue() {
|
|
37703
|
+
return !(0, import_node_fs64.existsSync)(markerPath3(NOTICE_MARKER));
|
|
37704
|
+
}
|
|
37705
|
+
function recordFormalDefaultNotice(now = /* @__PURE__ */ new Date()) {
|
|
37706
|
+
writeMarker(NOTICE_MARKER, now);
|
|
37707
|
+
}
|
|
37708
|
+
var BLOCKED_LINES = {
|
|
37709
|
+
"opted-out": () => "VERITY_NO_LEAN=1 is set, so Verity does not download Lean 4. Without Lean 4, a push skips the formal check.",
|
|
37710
|
+
ci: () => "This is a CI environment, so Verity does not download Lean 4 (VERITY_LEAN=1 allows it). Without Lean 4, a push skips the formal check.",
|
|
37711
|
+
disk: (detail2) => `Lean 4 needs more disk space${detail2 ? ` (${detail2})` : ""}. Until Lean 4 is installed, a push skips the formal check. Free some space, then run: verity lean install`,
|
|
37712
|
+
"no-release": () => "Lean 4 has no release for this machine, so a push skips the formal check."
|
|
37713
|
+
};
|
|
37714
|
+
function leanLine(lean) {
|
|
37715
|
+
switch (lean.kind) {
|
|
37716
|
+
case "started":
|
|
37717
|
+
return "Lean 4 (about 800 MB) is downloading in the background. To see the progress, run: verity lean status";
|
|
37718
|
+
case "downloading":
|
|
37719
|
+
return "Lean 4 is downloading in the background. To see the progress, run: verity lean status";
|
|
37720
|
+
case "failed":
|
|
37721
|
+
return "The Lean 4 download could not start. Until Lean 4 is installed, a push skips the formal check. To install it, run: verity lean install";
|
|
37722
|
+
case "previous-failed":
|
|
37723
|
+
return "The last Lean 4 download failed. Until Lean 4 is installed, a push skips the formal check. To try again, run: verity lean install";
|
|
37724
|
+
case "blocked":
|
|
37725
|
+
return BLOCKED_LINES[lean.why](lean.detail);
|
|
37726
|
+
case "installed":
|
|
37727
|
+
case "unknown":
|
|
37728
|
+
return null;
|
|
37729
|
+
}
|
|
37730
|
+
}
|
|
37731
|
+
function formalDefaultUserMessage(lean, offRefused) {
|
|
37732
|
+
const aboutLean = leanLine(lean);
|
|
37733
|
+
return [
|
|
37734
|
+
...offRefused ? [`Verity: ${formalOffRefusalMessage(offRefused)}`] : [],
|
|
37735
|
+
"Verity: formal verification at push is now on by default.",
|
|
37736
|
+
"At a push, Verity can check a small Lean model of the riskiest changed function and replay a counterexample on the real code. For the replay, the source of that function goes to the Verity service.",
|
|
37737
|
+
"Only a reproduced bug can block a push.",
|
|
37738
|
+
...aboutLean ? [aboutLean] : [],
|
|
37739
|
+
"To turn it off for this project, run: verity config formal off"
|
|
37740
|
+
].join("\n");
|
|
37741
|
+
}
|
|
37742
|
+
var AGENT_LINE = "Formal verification at push is on by default in this project. At a push, Verity can model one changed function in Lean, so a push can take longer. A block from it means that the counterexample was reproduced on the real code. If the user wants it off, the command is `verity config formal off`.";
|
|
37743
|
+
function settled(lean) {
|
|
37744
|
+
return lean.kind === "installed" || lean.kind === "blocked" && lean.why === "no-release";
|
|
37745
|
+
}
|
|
37746
|
+
var LEAN_RECHECK_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
37747
|
+
function settledRecently(now) {
|
|
37748
|
+
try {
|
|
37749
|
+
const at = Date.parse((0, import_node_fs64.readFileSync)(markerPath3(LEAN_MARKER), "utf-8").trim());
|
|
37750
|
+
return Number.isFinite(at) && now.getTime() - at >= 0 && now.getTime() - at < LEAN_RECHECK_MS;
|
|
37751
|
+
} catch {
|
|
37752
|
+
return false;
|
|
37753
|
+
}
|
|
37754
|
+
}
|
|
37755
|
+
function leanAtStart(opts, now, probeAgain) {
|
|
37756
|
+
const { env } = opts;
|
|
37757
|
+
if (env.VERITY_NO_LEAN === "1") return { kind: "blocked", why: "opted-out" };
|
|
37758
|
+
if (env.CI && env.VERITY_LEAN !== "1") return { kind: "blocked", why: "ci" };
|
|
37759
|
+
const state = readInstallState(env);
|
|
37760
|
+
if (state?.state === "failed") return { kind: "previous-failed" };
|
|
37761
|
+
if (state?.state === "done") return { kind: "installed" };
|
|
37762
|
+
if (state?.state === "running") return installRunning(env) ? { kind: "downloading" } : { kind: "unknown" };
|
|
37763
|
+
if (!probeAgain && settledRecently(now)) return { kind: "unknown" };
|
|
37764
|
+
const lean = probeAndStart(opts);
|
|
37765
|
+
if (settled(lean)) writeMarker(LEAN_MARKER, now);
|
|
37766
|
+
return lean;
|
|
37767
|
+
}
|
|
37768
|
+
function probeAndStart(opts) {
|
|
37769
|
+
const { env } = opts;
|
|
37770
|
+
const d = shouldStartBackgroundInstall({ formal: "push", env, free: opts.free });
|
|
37771
|
+
if (d.start) {
|
|
37772
|
+
const started = startBackgroundInstall({ cli: opts.cli, env, ...opts.run ? { run: opts.run } : {} });
|
|
37773
|
+
return started ? { kind: "started" } : { kind: "failed" };
|
|
37774
|
+
}
|
|
37775
|
+
switch (d.why) {
|
|
37776
|
+
case "installed":
|
|
37777
|
+
return { kind: "installed" };
|
|
37778
|
+
case "running":
|
|
37779
|
+
return { kind: "downloading" };
|
|
37780
|
+
case "opted-out":
|
|
37781
|
+
case "ci":
|
|
37782
|
+
case "no-release":
|
|
37783
|
+
return { kind: "blocked", why: d.why };
|
|
37784
|
+
case "disk":
|
|
37785
|
+
return { kind: "blocked", why: "disk", ...d.detail ? { detail: d.detail } : {} };
|
|
37786
|
+
case "formal-off":
|
|
37787
|
+
return { kind: "unknown" };
|
|
37788
|
+
}
|
|
37789
|
+
}
|
|
37790
|
+
function formalAtSessionStart(opts) {
|
|
37791
|
+
const env = opts.env ?? process.env;
|
|
37792
|
+
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
37793
|
+
const none = { userMsg: null, agentLine: null, leanStarted: false };
|
|
37794
|
+
const setting = formalSetting(opts.cfg, env);
|
|
37795
|
+
if (setting.state !== "push") return none;
|
|
37796
|
+
const noticeDue = setting.source === "default" && formalDefaultNoticeDue();
|
|
37797
|
+
let lean;
|
|
37798
|
+
try {
|
|
37799
|
+
lean = leanAtStart({ cli: opts.cli, env, ...opts.free !== void 0 ? { free: opts.free } : {}, ...opts.run ? { run: opts.run } : {} }, now, noticeDue);
|
|
37800
|
+
} catch (err2) {
|
|
37801
|
+
lean = { kind: "failed" };
|
|
37802
|
+
logEvent("formal_default_lean_failed", { error: String(err2?.message ?? err2).slice(0, 200) });
|
|
37803
|
+
}
|
|
37804
|
+
const leanStarted = lean.kind === "started";
|
|
37805
|
+
if (!noticeDue) return { ...none, leanStarted };
|
|
37806
|
+
return { userMsg: formalDefaultUserMessage(lean, opts.cfg.formal_off_refused), agentLine: AGENT_LINE, leanStarted };
|
|
37807
|
+
}
|
|
37808
|
+
|
|
37490
37809
|
// src/commands/baseline.ts
|
|
37491
|
-
var
|
|
37492
|
-
var
|
|
37810
|
+
var import_node_fs67 = require("node:fs");
|
|
37811
|
+
var import_node_path55 = require("node:path");
|
|
37493
37812
|
|
|
37494
37813
|
// src/lib/skew-notice.ts
|
|
37495
|
-
var
|
|
37496
|
-
var
|
|
37814
|
+
var import_node_fs65 = require("node:fs");
|
|
37815
|
+
var import_node_path53 = require("node:path");
|
|
37497
37816
|
var MARKER2 = ".skew-notice.json";
|
|
37498
|
-
function
|
|
37499
|
-
return (0,
|
|
37817
|
+
function markerPath4() {
|
|
37818
|
+
return (0, import_node_path53.join)(verityHome(), MARKER2);
|
|
37500
37819
|
}
|
|
37501
37820
|
function today(now) {
|
|
37502
37821
|
const y = now.getFullYear();
|
|
@@ -37506,7 +37825,7 @@ function today(now) {
|
|
|
37506
37825
|
}
|
|
37507
37826
|
function skewNoticeDue(skew, now = /* @__PURE__ */ new Date()) {
|
|
37508
37827
|
try {
|
|
37509
|
-
const seen = JSON.parse((0,
|
|
37828
|
+
const seen = JSON.parse((0, import_node_fs65.readFileSync)(markerPath4(), "utf-8"));
|
|
37510
37829
|
return !(seen.global === skew.global && seen.hooks === skew.hooks && seen.day === today(now));
|
|
37511
37830
|
} catch {
|
|
37512
37831
|
return true;
|
|
@@ -37514,15 +37833,15 @@ function skewNoticeDue(skew, now = /* @__PURE__ */ new Date()) {
|
|
|
37514
37833
|
}
|
|
37515
37834
|
function recordSkewNotice(skew, now = /* @__PURE__ */ new Date()) {
|
|
37516
37835
|
try {
|
|
37517
|
-
(0,
|
|
37518
|
-
(0,
|
|
37836
|
+
(0, import_node_fs65.mkdirSync)(verityHome(), { recursive: true, mode: 448 });
|
|
37837
|
+
(0, import_node_fs65.writeFileSync)(markerPath4(), JSON.stringify({ global: skew.global, hooks: skew.hooks, day: today(now) }) + "\n");
|
|
37519
37838
|
} catch {
|
|
37520
37839
|
}
|
|
37521
37840
|
}
|
|
37522
37841
|
|
|
37523
37842
|
// src/lib/project-skills.ts
|
|
37524
|
-
var
|
|
37525
|
-
var
|
|
37843
|
+
var import_node_fs66 = require("node:fs");
|
|
37844
|
+
var import_node_path54 = require("node:path");
|
|
37526
37845
|
var PROJECT_SKILL_NAMES = [
|
|
37527
37846
|
"verity-setup",
|
|
37528
37847
|
"verity-analyze",
|
|
@@ -37548,14 +37867,14 @@ var LEGACY_SKILL_NAMES = [
|
|
|
37548
37867
|
var ALL = [...PROJECT_SKILL_NAMES, ...LEGACY_SKILL_NAMES];
|
|
37549
37868
|
function staleProjectSkills() {
|
|
37550
37869
|
const root = projectPath(".claude/skills");
|
|
37551
|
-
if (!(0,
|
|
37552
|
-
return ALL.filter((name2) => (0,
|
|
37870
|
+
if (!(0, import_node_fs66.existsSync)(root)) return [];
|
|
37871
|
+
return ALL.filter((name2) => (0, import_node_fs66.existsSync)((0, import_node_path54.join)(root, name2)));
|
|
37553
37872
|
}
|
|
37554
37873
|
function removeProjectSkills() {
|
|
37555
37874
|
const root = projectPath(".claude/skills");
|
|
37556
37875
|
const removed = [];
|
|
37557
37876
|
for (const name2 of staleProjectSkills()) {
|
|
37558
|
-
(0,
|
|
37877
|
+
(0, import_node_fs66.rmSync)((0, import_node_path54.join)(root, name2), { recursive: true, force: true });
|
|
37559
37878
|
removed.push(name2);
|
|
37560
37879
|
}
|
|
37561
37880
|
return removed;
|
|
@@ -37590,7 +37909,7 @@ function registerBaselineCommands(program2) {
|
|
|
37590
37909
|
const loginWarning = "Until they have, do not send them to run `verity login` in a terminal: that runs the global one, which can sign this machine in to a different server.";
|
|
37591
37910
|
const skewNote = !skew ? null : skewLoud ? `Before anything else, including /verity:init's questions, tell the user their global \`verity\` is ${skew.global}, the hooks run ${skew.hooks}, and \`${skew.remedy}\` fixes it. ${loginWarning}` : `The user's global \`verity\` is ${skew.global} and the hooks run ${skew.hooks}; \`${skew.remedy}\` fixes it. They were already told today, so do not repeat it unprompted \u2014 mention it only where it matters, such as before suggesting a \`verity\` command for their terminal. ${loginWarning}`;
|
|
37592
37911
|
if (!verityConfigured()) {
|
|
37593
|
-
if (isMachineStore((0,
|
|
37912
|
+
if (isMachineStore((0, import_node_path55.join)(repoRoot(), VERITY_DIR))) process.exit(0);
|
|
37594
37913
|
const how = isPluginInvocation() ? "Tell the user to run /verity:init \u2014 they type it; you cannot invoke it." : "Tell the user to run `verity init` in their terminal.";
|
|
37595
37914
|
const lines = [
|
|
37596
37915
|
`Verity is installed but this project is not set up yet, so the quality gate will not review anything here. ${how}`
|
|
@@ -37624,17 +37943,20 @@ function registerBaselineCommands(program2) {
|
|
|
37624
37943
|
let memoryMsg = null;
|
|
37625
37944
|
let memoryAgentLine = null;
|
|
37626
37945
|
const memoryNotice = projectPath(`${VERITY_DIR}/.memory-fence-notice`);
|
|
37627
|
-
if (realStart && !(0,
|
|
37946
|
+
if (realStart && !(0, import_node_fs67.existsSync)(memoryNotice)) {
|
|
37628
37947
|
const trackedGraph = memoryOptOut() ? 0 : committedMemoryFiles().length;
|
|
37629
37948
|
if (trackedGraph > 0) {
|
|
37630
37949
|
memoryMsg = `Verity: this project commits its knowledge base (${trackedGraph} files under .verity/memory/), so Verity's generated notes show up in every diff and pull request. Run \`verity memory untrack\` to keep them on disk but out of git, or \`verity memory track\` to keep committing them on purpose.`;
|
|
37631
37950
|
memoryAgentLine = `This project has ${trackedGraph} knowledge-graph files tracked in git under .verity/memory/. As of Verity 0.32.6 the graph is machine-local by default \u2014 it is rebuilt from the service, and committing it puts generated notes in every pull request. If the user wants that stopped, run \`verity memory untrack\` for them: it keeps every file on disk and stages their removal from the index, so they only need to commit \u2014 and their teammates' working copies will vanish on the next pull and re-sync from the service, which is expected. If they would rather keep committing it, \`verity memory track\` records that and nothing will offer again.`;
|
|
37632
37951
|
try {
|
|
37633
|
-
(0,
|
|
37952
|
+
(0, import_node_fs67.writeFileSync)(memoryNotice, (/* @__PURE__ */ new Date()).toISOString() + "\n");
|
|
37634
37953
|
} catch {
|
|
37635
37954
|
}
|
|
37636
37955
|
}
|
|
37637
37956
|
}
|
|
37957
|
+
const formalStart = realStart ? formalAtSessionStart({ cli: process.argv[1], cfg: readProjectConfig() }) : null;
|
|
37958
|
+
const formalMsg = formalStart?.userMsg ?? null;
|
|
37959
|
+
const formalAgentLine = formalStart?.agentLine ?? null;
|
|
37638
37960
|
if (isPluginInvocation() && realStart) {
|
|
37639
37961
|
const installed2 = activePluginVersion();
|
|
37640
37962
|
const state = await readSetupState().catch(() => null);
|
|
@@ -37658,10 +37980,11 @@ function registerBaselineCommands(program2) {
|
|
|
37658
37980
|
}
|
|
37659
37981
|
}
|
|
37660
37982
|
if (memoryAgentLine) notices.push(memoryAgentLine);
|
|
37983
|
+
if (formalAgentLine) notices.push(formalAgentLine);
|
|
37661
37984
|
if (notices.length > 0 || skewMsg) {
|
|
37662
37985
|
process.stdout.write(
|
|
37663
37986
|
JSON.stringify({
|
|
37664
|
-
...userMsg || skewMsg || memoryMsg ? { systemMessage: [skewMsg, userMsg, memoryMsg].filter(Boolean).join("\n") } : {},
|
|
37987
|
+
...userMsg || skewMsg || memoryMsg || formalMsg ? { systemMessage: [skewMsg, userMsg, memoryMsg, formalMsg].filter(Boolean).join("\n") } : {},
|
|
37665
37988
|
hookSpecificOutput: {
|
|
37666
37989
|
hookEventName: "SessionStart",
|
|
37667
37990
|
additionalContext: notices.join("\n")
|
|
@@ -37669,17 +37992,20 @@ function registerBaselineCommands(program2) {
|
|
|
37669
37992
|
}) + "\n"
|
|
37670
37993
|
);
|
|
37671
37994
|
if (skew && skewMsg) recordSkewNotice(skew);
|
|
37995
|
+
if (formalMsg) recordFormalDefaultNotice();
|
|
37672
37996
|
}
|
|
37673
|
-
} else if (memoryMsg) {
|
|
37997
|
+
} else if (memoryMsg || formalMsg) {
|
|
37998
|
+
const agentLines = [memoryAgentLine, formalAgentLine].filter(Boolean).join("\n");
|
|
37674
37999
|
process.stdout.write(
|
|
37675
38000
|
JSON.stringify({
|
|
37676
|
-
systemMessage: memoryMsg,
|
|
38001
|
+
systemMessage: [memoryMsg, formalMsg].filter(Boolean).join("\n"),
|
|
37677
38002
|
hookSpecificOutput: {
|
|
37678
38003
|
hookEventName: "SessionStart",
|
|
37679
|
-
...
|
|
38004
|
+
...agentLines ? { additionalContext: agentLines } : {}
|
|
37680
38005
|
}
|
|
37681
38006
|
}) + "\n"
|
|
37682
38007
|
);
|
|
38008
|
+
if (formalMsg) recordFormalDefaultNotice();
|
|
37683
38009
|
}
|
|
37684
38010
|
if (deferredToPlugin("baseline capture", session ?? null)) {
|
|
37685
38011
|
process.exit(0);
|
|
@@ -37687,7 +38013,7 @@ function registerBaselineCommands(program2) {
|
|
|
37687
38013
|
const authForScope = await resolveToken(program2.opts().token);
|
|
37688
38014
|
const scopeToken = authForScope.ok ? authForScope.data.token : void 0;
|
|
37689
38015
|
if (authForScope.ok && pullsAtSessionStart(authForScope.data, source2)) spawnBackgroundPull();
|
|
37690
|
-
if (source2 !== "compact") resumeInterruptedInstall({ cli: process.argv[1], formal: readProjectConfig().
|
|
38016
|
+
if (source2 !== "compact") resumeInterruptedInstall({ cli: process.argv[1], formal: formalSetting(readProjectConfig()).state });
|
|
37691
38017
|
const scopeSession = session;
|
|
37692
38018
|
const result = captureBaseline({ sessionId: sessionScopeKey(scopeToken, scopeSession), source: source2 });
|
|
37693
38019
|
logEvent("baseline_capture", {
|
|
@@ -37733,31 +38059,31 @@ function hookSource(value) {
|
|
|
37733
38059
|
}
|
|
37734
38060
|
|
|
37735
38061
|
// src/commands/review.ts
|
|
37736
|
-
var
|
|
37737
|
-
var
|
|
38062
|
+
var import_node_fs68 = require("node:fs");
|
|
38063
|
+
var import_node_path56 = require("node:path");
|
|
37738
38064
|
function containReviewPaths(paths, base) {
|
|
37739
38065
|
const kept = [];
|
|
37740
38066
|
const refused2 = [];
|
|
37741
38067
|
for (const raw of paths) {
|
|
37742
|
-
const candidate = (0,
|
|
38068
|
+
const candidate = (0, import_node_path56.isAbsolute)(raw) ? relativeForm(base, raw) : raw;
|
|
37743
38069
|
if (candidate === "" || resolveInside(base, candidate) === null) refused2.push(raw);
|
|
37744
38070
|
else kept.push(candidate);
|
|
37745
38071
|
}
|
|
37746
38072
|
return { kept, refused: refused2 };
|
|
37747
38073
|
}
|
|
37748
38074
|
function relativeForm(base, abs) {
|
|
37749
|
-
const lexical = (0,
|
|
37750
|
-
if (!(lexical === ".." || lexical.startsWith(`..${
|
|
38075
|
+
const lexical = (0, import_node_path56.relative)(base, abs);
|
|
38076
|
+
if (!(lexical === ".." || lexical.startsWith(`..${import_node_path56.sep}`) || (0, import_node_path56.isAbsolute)(lexical))) return lexical;
|
|
37751
38077
|
try {
|
|
37752
|
-
let dir = (0,
|
|
37753
|
-
let rest = (0,
|
|
37754
|
-
while (!(0,
|
|
37755
|
-
const up = (0,
|
|
38078
|
+
let dir = (0, import_node_path56.dirname)(abs);
|
|
38079
|
+
let rest = (0, import_node_path56.basename)(abs);
|
|
38080
|
+
while (!(0, import_node_fs68.existsSync)(dir)) {
|
|
38081
|
+
const up = (0, import_node_path56.dirname)(dir);
|
|
37756
38082
|
if (up === dir) return lexical;
|
|
37757
|
-
rest = (0,
|
|
38083
|
+
rest = (0, import_node_path56.join)((0, import_node_path56.basename)(dir), rest);
|
|
37758
38084
|
dir = up;
|
|
37759
38085
|
}
|
|
37760
|
-
return (0,
|
|
38086
|
+
return (0, import_node_path56.relative)((0, import_node_fs68.realpathSync)(base), (0, import_node_path56.join)((0, import_node_fs68.realpathSync)(dir), rest));
|
|
37761
38087
|
} catch {
|
|
37762
38088
|
return lexical;
|
|
37763
38089
|
}
|
|
@@ -37796,7 +38122,7 @@ async function runReview(opts, globals) {
|
|
|
37796
38122
|
const changedFiles = changed.kept;
|
|
37797
38123
|
const analyzable = filterAnalyzable(allFiles);
|
|
37798
38124
|
const securityFiles = filterSecurity(allFiles);
|
|
37799
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0,
|
|
38125
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs68.existsSync)(f) || resolveFile(f) !== null);
|
|
37800
38126
|
const staticResults = runCodacyAnalysisIfAvailable(scannable);
|
|
37801
38127
|
const codeDelta = collectCodeDelta(allFiles);
|
|
37802
38128
|
const tokenResult = await resolveToken(globals.token);
|
|
@@ -37867,12 +38193,12 @@ async function runReview(opts, globals) {
|
|
|
37867
38193
|
}
|
|
37868
38194
|
|
|
37869
38195
|
// src/commands/guard.ts
|
|
37870
|
-
var
|
|
37871
|
-
var
|
|
38196
|
+
var import_node_fs70 = require("node:fs");
|
|
38197
|
+
var import_node_path59 = require("node:path");
|
|
37872
38198
|
|
|
37873
38199
|
// src/lib/vendored.ts
|
|
37874
|
-
var
|
|
37875
|
-
var
|
|
38200
|
+
var import_node_fs69 = require("node:fs");
|
|
38201
|
+
var import_node_path57 = require("node:path");
|
|
37876
38202
|
var INSTALLED_SKILL = /^\.claude\/skills\/(verity-[a-z0-9-]+)\/(.+)$/;
|
|
37877
38203
|
function dataDirOrNull() {
|
|
37878
38204
|
try {
|
|
@@ -37887,7 +38213,7 @@ function shippedSkillFile(path, dataDir = dataDirOrNull()) {
|
|
|
37887
38213
|
const [, skill, rel] = m;
|
|
37888
38214
|
if (rel.split("/").some((seg) => seg === ".." || seg === ".")) return null;
|
|
37889
38215
|
try {
|
|
37890
|
-
return (0,
|
|
38216
|
+
return (0, import_node_fs69.readFileSync)((0, import_node_path57.join)(dataDir, "skills", skill, rel), "utf8");
|
|
37891
38217
|
} catch {
|
|
37892
38218
|
return null;
|
|
37893
38219
|
}
|
|
@@ -37926,10 +38252,10 @@ function summarizeFindings(response) {
|
|
|
37926
38252
|
return out2;
|
|
37927
38253
|
});
|
|
37928
38254
|
}
|
|
37929
|
-
function finishOneShot(
|
|
37930
|
-
if (!
|
|
37931
|
-
if (!
|
|
37932
|
-
const r =
|
|
38255
|
+
function finishOneShot(settled2) {
|
|
38256
|
+
if (!settled2) return { status: "pending" };
|
|
38257
|
+
if (!settled2.ok) return { status: "failed" };
|
|
38258
|
+
const r = settled2.response;
|
|
37933
38259
|
return {
|
|
37934
38260
|
status: "arrived",
|
|
37935
38261
|
...typeof r.agent_attestation === "string" ? { attestation: r.agent_attestation } : {},
|
|
@@ -37940,13 +38266,13 @@ function finishOneShot(settled) {
|
|
|
37940
38266
|
async function runAgentReview(options) {
|
|
37941
38267
|
const now = options.now ?? Date.now;
|
|
37942
38268
|
const remaining = () => options.deadlineMs - (now() - options.startedAt);
|
|
37943
|
-
let
|
|
38269
|
+
let settled2 = null;
|
|
37944
38270
|
const oneShotDone = options.oneShot.then(
|
|
37945
38271
|
(outcome) => {
|
|
37946
|
-
|
|
38272
|
+
settled2 = outcome;
|
|
37947
38273
|
},
|
|
37948
38274
|
() => {
|
|
37949
|
-
|
|
38275
|
+
settled2 = { ok: false };
|
|
37950
38276
|
}
|
|
37951
38277
|
);
|
|
37952
38278
|
if (remaining() < MIN_AGENT_START_MS) return { kind: "skipped", reason: "not enough time left after prep" };
|
|
@@ -37968,7 +38294,7 @@ async function runAgentReview(options) {
|
|
|
37968
38294
|
if (turn >= MAX_TURNS || remaining() < MIN_TURN_MS) break;
|
|
37969
38295
|
const results = await options.executeTools(calls);
|
|
37970
38296
|
let oneShot;
|
|
37971
|
-
const current =
|
|
38297
|
+
const current = settled2;
|
|
37972
38298
|
if (current && sentOneShot === "pending") {
|
|
37973
38299
|
oneShot = current.ok ? { status: "arrived", findings: summarizeFindings(current.response) } : { status: "failed" };
|
|
37974
38300
|
sentOneShot = oneShot.status;
|
|
@@ -37983,13 +38309,13 @@ async function runAgentReview(options) {
|
|
|
37983
38309
|
calls = next.data.calls ?? [];
|
|
37984
38310
|
done = next.data.done;
|
|
37985
38311
|
}
|
|
37986
|
-
if (!
|
|
38312
|
+
if (!settled2) {
|
|
37987
38313
|
const wait = Math.max(0, remaining() - FINISH_TIMEOUT_MS);
|
|
37988
38314
|
await Promise.race([oneShotDone, new Promise((resolve10) => setTimeout(resolve10, wait))]);
|
|
37989
38315
|
}
|
|
37990
38316
|
const finished = await options.http.post(
|
|
37991
38317
|
"/agent-review/finish",
|
|
37992
|
-
{ state, session_id: options.sessionId, one_shot: finishOneShot(
|
|
38318
|
+
{ state, session_id: options.sessionId, one_shot: finishOneShot(settled2) },
|
|
37993
38319
|
FINISH_TIMEOUT_MS
|
|
37994
38320
|
);
|
|
37995
38321
|
if (!finished.ok) {
|
|
@@ -38016,7 +38342,7 @@ function effortProfile(root, env = process.env) {
|
|
|
38016
38342
|
}
|
|
38017
38343
|
|
|
38018
38344
|
// src/lib/prove/auto.ts
|
|
38019
|
-
var
|
|
38345
|
+
var import_node_path58 = require("node:path");
|
|
38020
38346
|
var import_node_crypto21 = require("node:crypto");
|
|
38021
38347
|
|
|
38022
38348
|
// src/lib/prove/grounding.ts
|
|
@@ -40244,7 +40570,7 @@ async function runFormalPhase(input) {
|
|
|
40244
40570
|
modelName = gen.name;
|
|
40245
40571
|
const rel = `${AUTO_MODELS_DIR}/${gen.name}.lean`;
|
|
40246
40572
|
writeFileInRootNoFollow(root, rel, gen.source);
|
|
40247
|
-
const abs = resolveModelFile(root, rel) ?? (0,
|
|
40573
|
+
const abs = resolveModelFile(root, rel) ?? (0, import_node_path58.join)(root, rel);
|
|
40248
40574
|
progress.model = { name: gen.name, file: rel, rounds: round };
|
|
40249
40575
|
progress.step = "check";
|
|
40250
40576
|
report = await deps.check(root, abs);
|
|
@@ -40393,7 +40719,7 @@ async function runFormalPhase(input) {
|
|
|
40393
40719
|
return done({
|
|
40394
40720
|
status: "checked",
|
|
40395
40721
|
target,
|
|
40396
|
-
model: { name: modelName, file: (0,
|
|
40722
|
+
model: { name: modelName, file: (0, import_node_path58.relative)(root, (0, import_node_path58.join)(root, modelFile)), rounds },
|
|
40397
40723
|
properties: report.properties,
|
|
40398
40724
|
findings
|
|
40399
40725
|
});
|
|
@@ -40470,7 +40796,7 @@ async function generateAndCheck(root, req, opts) {
|
|
|
40470
40796
|
}
|
|
40471
40797
|
const rel = `${dir}/${gen.name}.lean`;
|
|
40472
40798
|
writeFileInRootNoFollow(root, rel, gen.source);
|
|
40473
|
-
const abs = resolveModelFile(root, rel) ?? (0,
|
|
40799
|
+
const abs = resolveModelFile(root, rel) ?? (0, import_node_path58.join)(root, rel);
|
|
40474
40800
|
const report = await opts.deps.check(root, abs);
|
|
40475
40801
|
const abstracts = report.header?.abstracts ?? [];
|
|
40476
40802
|
const stray = abstracts.find((a) => !headerFiles.has(a.file)) ?? (abstracts[0] && abstracts[0].file !== req.file ? abstracts[0] : void 0);
|
|
@@ -40879,7 +41205,7 @@ var WRITERS_BUDGET_MS = 1500;
|
|
|
40879
41205
|
var EXCERPT_MAX_LINES2 = 30;
|
|
40880
41206
|
var VENDORED_READ_MAX_BYTES = 256 * 1024;
|
|
40881
41207
|
var GUARD_BLOCK_CAP = 2;
|
|
40882
|
-
var GUARD_ITER_FILE = (0,
|
|
41208
|
+
var GUARD_ITER_FILE = (0, import_node_path59.join)(VERITY_DIR, ".guard-iteration");
|
|
40883
41209
|
function readPreToolUseStdin() {
|
|
40884
41210
|
const empty = { command: "", cwd: null, sessionId: null };
|
|
40885
41211
|
return new Promise((resolve10) => {
|
|
@@ -40887,11 +41213,11 @@ function readPreToolUseStdin() {
|
|
|
40887
41213
|
if (process.stdin.isTTY) return resolve10(empty);
|
|
40888
41214
|
const chunks = [];
|
|
40889
41215
|
let timer;
|
|
40890
|
-
let
|
|
41216
|
+
let settled2 = false;
|
|
40891
41217
|
const onData = (c) => chunks.push(c);
|
|
40892
41218
|
const settle = (value) => {
|
|
40893
|
-
if (
|
|
40894
|
-
|
|
41219
|
+
if (settled2) return;
|
|
41220
|
+
settled2 = true;
|
|
40895
41221
|
if (timer) clearTimeout(timer);
|
|
40896
41222
|
process.stdin.removeListener("data", onData);
|
|
40897
41223
|
process.stdin.removeListener("end", onEnd);
|
|
@@ -40924,7 +41250,7 @@ function readPreToolUseStdin() {
|
|
|
40924
41250
|
}
|
|
40925
41251
|
function readIterMap() {
|
|
40926
41252
|
try {
|
|
40927
|
-
const raw = JSON.parse((0,
|
|
41253
|
+
const raw = JSON.parse((0, import_node_fs70.readFileSync)(GUARD_ITER_FILE, "utf-8"));
|
|
40928
41254
|
if (raw && typeof raw === "object") {
|
|
40929
41255
|
if (typeof raw.moment === "string" && typeof raw.count === "number") {
|
|
40930
41256
|
return { [raw.moment]: raw.count };
|
|
@@ -40944,10 +41270,10 @@ function readIter(moment) {
|
|
|
40944
41270
|
}
|
|
40945
41271
|
function writeIter(moment, count2) {
|
|
40946
41272
|
try {
|
|
40947
|
-
(0,
|
|
41273
|
+
(0, import_node_fs70.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
40948
41274
|
const map = readIterMap();
|
|
40949
41275
|
map[moment] = count2;
|
|
40950
|
-
(0,
|
|
41276
|
+
(0, import_node_fs70.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
40951
41277
|
} catch {
|
|
40952
41278
|
}
|
|
40953
41279
|
}
|
|
@@ -40957,10 +41283,10 @@ function resetIter(moment) {
|
|
|
40957
41283
|
if (!(moment in map)) return;
|
|
40958
41284
|
delete map[moment];
|
|
40959
41285
|
if (Object.keys(map).length === 0) {
|
|
40960
|
-
if ((0,
|
|
41286
|
+
if ((0, import_node_fs70.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs70.unlinkSync)(GUARD_ITER_FILE);
|
|
40961
41287
|
} else {
|
|
40962
|
-
(0,
|
|
40963
|
-
(0,
|
|
41288
|
+
(0, import_node_fs70.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
41289
|
+
(0, import_node_fs70.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
40964
41290
|
}
|
|
40965
41291
|
} catch {
|
|
40966
41292
|
}
|
|
@@ -41037,7 +41363,7 @@ function ofThisChange(response, sentFiles) {
|
|
|
41037
41363
|
function buildGuardRequest(moment, files, codeDelta, iter, sessionId, statedIntent, coverageTelemetry) {
|
|
41038
41364
|
const analyzable = filterAnalyzable(files);
|
|
41039
41365
|
const securityFiles = filterSecurity(files);
|
|
41040
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0,
|
|
41366
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs70.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
|
|
41041
41367
|
const staticResults = runCodacyAnalysisIfAvailable(scannable);
|
|
41042
41368
|
const trigger = moment === "pre-commit" ? "hook:pre-commit" : "hook:pre-push";
|
|
41043
41369
|
const requestBody2 = {
|
|
@@ -41210,11 +41536,14 @@ function startAgentReview(input) {
|
|
|
41210
41536
|
};
|
|
41211
41537
|
return run4().catch((err2) => ({ kind: "failed", reason: String(err2?.message ?? err2) }));
|
|
41212
41538
|
}
|
|
41539
|
+
function formalOffUnverifiedLine(moment, config) {
|
|
41540
|
+
if (moment !== "pre-push" || !config.formal_off_unverified) return "";
|
|
41541
|
+
const setting = formalSetting(config);
|
|
41542
|
+
return setting.state === "off" && setting.source === "config" ? `formal: skipped (${formalOffUnverifiedNote()})` : "";
|
|
41543
|
+
}
|
|
41213
41544
|
function startFormalPhase(input) {
|
|
41214
41545
|
if (input.moment !== "pre-push") return null;
|
|
41215
|
-
|
|
41216
|
-
if (env === "off") return null;
|
|
41217
|
-
if (env !== "push" && readProjectConfig().formal !== "push") return null;
|
|
41546
|
+
if (formalSetting(input.config).state !== "push") return null;
|
|
41218
41547
|
const profile = effortProfile(input.root);
|
|
41219
41548
|
const deadlineAt = input.hookStartedAt + profile.pushDeadlineMs - 1e4;
|
|
41220
41549
|
const ig = loadVerityIgnore();
|
|
@@ -41420,7 +41749,8 @@ async function runGuard(opts, globals) {
|
|
|
41420
41749
|
requestBody: requestBody2,
|
|
41421
41750
|
oneShot
|
|
41422
41751
|
});
|
|
41423
|
-
const
|
|
41752
|
+
const projectConfig = moment === "pre-push" ? readProjectConfig() : null;
|
|
41753
|
+
const formal = projectConfig ? startFormalPhase({ moment, files, root: frame.worktreeRoot, hookStartedAt, frame, range, auth: { serviceUrl: urlResult.data, token: tokenResult.data.token }, config: projectConfig }) : null;
|
|
41424
41754
|
const result = await oneShot;
|
|
41425
41755
|
const agentOutcome = agent ? await agent : null;
|
|
41426
41756
|
const formalOutcome = formal ? await formal : null;
|
|
@@ -41472,7 +41802,7 @@ async function runGuard(opts, globals) {
|
|
|
41472
41802
|
const link2 = viewUrl ? ` \u2014 ${viewUrl}` : "";
|
|
41473
41803
|
const covLine = `${coverageSummary(coverage)} in ${reviewSecs}s`;
|
|
41474
41804
|
const agentLine = describeAgentOutcome(agentOutcome);
|
|
41475
|
-
const formalLine = describeFormalOutcome(formalOutcome);
|
|
41805
|
+
const formalLine = describeFormalOutcome(formalOutcome) || (projectConfig ? formalOffUnverifiedLine(moment, projectConfig) : "");
|
|
41476
41806
|
const covDetail = [coverageBlock(coverage), agentLine, formalLine].filter(Boolean).join("\n ");
|
|
41477
41807
|
const witnessed = [...codeDelta.files.map((f) => f.path), ...agentVerdict?.witnessed_files ?? []];
|
|
41478
41808
|
mergeFormalFindings(response, formalOutcome, files);
|
|
@@ -41713,7 +42043,7 @@ function registerIgnoreCommand(program2) {
|
|
|
41713
42043
|
|
|
41714
42044
|
// src/commands/waive.ts
|
|
41715
42045
|
var import_node_crypto23 = require("node:crypto");
|
|
41716
|
-
var
|
|
42046
|
+
var import_node_fs71 = require("node:fs");
|
|
41717
42047
|
function registerWaiveCommand(program2) {
|
|
41718
42048
|
program2.command("waive <pattern-id>").description("Record an accepted-risk disposition for an open finding (voids when the file changes)").option("--file <path>", "File the finding is anchored to, REPO-RELATIVE (recommended \u2014 narrows the waive)").requiredOption("--reason <text>", "The human disposition this records (reviewer finding, ADR, \u2026)").action(async (patternId, opts) => {
|
|
41719
42049
|
const globals = program2.opts();
|
|
@@ -41742,7 +42072,7 @@ function registerWaiveCommand(program2) {
|
|
|
41742
42072
|
if (opts.file) {
|
|
41743
42073
|
body2.file = opts.file;
|
|
41744
42074
|
try {
|
|
41745
|
-
body2.file_sha256 = (0, import_node_crypto23.createHash)("sha256").update((0,
|
|
42075
|
+
body2.file_sha256 = (0, import_node_crypto23.createHash)("sha256").update((0, import_node_fs71.readFileSync)(opts.file)).digest("hex");
|
|
41746
42076
|
} catch {
|
|
41747
42077
|
printError(`Cannot read ${opts.file} \u2014 run from the repo root, or omit --file to waive by pattern.`);
|
|
41748
42078
|
process.exit(1);
|
|
@@ -41768,15 +42098,15 @@ function registerWaiveCommand(program2) {
|
|
|
41768
42098
|
|
|
41769
42099
|
// src/commands/init/index.ts
|
|
41770
42100
|
var import_node_os15 = require("node:os");
|
|
41771
|
-
var
|
|
42101
|
+
var import_node_fs80 = require("node:fs");
|
|
41772
42102
|
var import_promises17 = require("node:fs/promises");
|
|
41773
|
-
var
|
|
42103
|
+
var import_node_path69 = require("node:path");
|
|
41774
42104
|
|
|
41775
42105
|
// src/lib/init-changes.ts
|
|
41776
42106
|
var import_node_crypto24 = require("node:crypto");
|
|
41777
|
-
var
|
|
42107
|
+
var import_node_fs72 = require("node:fs");
|
|
41778
42108
|
var import_node_os12 = require("node:os");
|
|
41779
|
-
var
|
|
42109
|
+
var import_node_path60 = require("node:path");
|
|
41780
42110
|
var REPO_FILES = [
|
|
41781
42111
|
".gitignore",
|
|
41782
42112
|
"CLAUDE.md",
|
|
@@ -41791,7 +42121,7 @@ var SKILLS_DIR = ".claude/skills";
|
|
|
41791
42121
|
var MAX_HASH_BYTES = 2 * 1024 * 1024;
|
|
41792
42122
|
var MAX_TREE_ENTRIES = 2e3;
|
|
41793
42123
|
function userSettingsDir(env) {
|
|
41794
|
-
return env.CLAUDE_CONFIG_DIR || (0,
|
|
42124
|
+
return env.CLAUDE_CONFIG_DIR || (0, import_node_path60.join)(env.HOME || (0, import_node_os12.homedir)(), ".claude");
|
|
41795
42125
|
}
|
|
41796
42126
|
function fingerprint(root, rel) {
|
|
41797
42127
|
const opened = openRegularInRoot(root, rel);
|
|
@@ -41799,7 +42129,7 @@ function fingerprint(root, rel) {
|
|
|
41799
42129
|
if (opened.reason === "missing") return null;
|
|
41800
42130
|
if (opened.reason === "symlink") {
|
|
41801
42131
|
try {
|
|
41802
|
-
return `link:${(0,
|
|
42132
|
+
return `link:${(0, import_node_fs72.readlinkSync)((0, import_node_path60.join)(root, rel))}`;
|
|
41803
42133
|
} catch {
|
|
41804
42134
|
return "link";
|
|
41805
42135
|
}
|
|
@@ -41818,7 +42148,7 @@ function fingerprint(root, rel) {
|
|
|
41818
42148
|
}
|
|
41819
42149
|
function treeFingerprint(root, dirRel) {
|
|
41820
42150
|
try {
|
|
41821
|
-
if (!(0,
|
|
42151
|
+
if (!(0, import_node_fs72.lstatSync)((0, import_node_path60.join)(root, dirRel)).isDirectory()) return fingerprint(root, dirRel);
|
|
41822
42152
|
} catch {
|
|
41823
42153
|
return null;
|
|
41824
42154
|
}
|
|
@@ -41826,7 +42156,7 @@ function treeFingerprint(root, dirRel) {
|
|
|
41826
42156
|
const walk2 = (rel) => {
|
|
41827
42157
|
let names2;
|
|
41828
42158
|
try {
|
|
41829
|
-
names2 = (0,
|
|
42159
|
+
names2 = (0, import_node_fs72.readdirSync)((0, import_node_path60.join)(root, rel)).sort();
|
|
41830
42160
|
} catch {
|
|
41831
42161
|
return;
|
|
41832
42162
|
}
|
|
@@ -41835,7 +42165,7 @@ function treeFingerprint(root, dirRel) {
|
|
|
41835
42165
|
const relPath = `${rel}/${name2}`;
|
|
41836
42166
|
let st;
|
|
41837
42167
|
try {
|
|
41838
|
-
st = (0,
|
|
42168
|
+
st = (0, import_node_fs72.lstatSync)((0, import_node_path60.join)(root, relPath));
|
|
41839
42169
|
} catch {
|
|
41840
42170
|
continue;
|
|
41841
42171
|
}
|
|
@@ -41859,8 +42189,8 @@ function changedSince(before, after) {
|
|
|
41859
42189
|
|
|
41860
42190
|
// src/lib/init-trace.ts
|
|
41861
42191
|
var import_node_crypto25 = require("node:crypto");
|
|
41862
|
-
var
|
|
41863
|
-
var
|
|
42192
|
+
var import_node_fs73 = require("node:fs");
|
|
42193
|
+
var import_node_path61 = require("node:path");
|
|
41864
42194
|
var INIT_STEPS = [
|
|
41865
42195
|
"started",
|
|
41866
42196
|
"prerequisites",
|
|
@@ -41906,9 +42236,9 @@ function traceDisabled(env = process.env) {
|
|
|
41906
42236
|
}
|
|
41907
42237
|
var PENDING_NAME = "init-trace.json";
|
|
41908
42238
|
var MAX_PENDING_BYTES = 64 * 1024;
|
|
41909
|
-
var verityHome2 = () => (0,
|
|
42239
|
+
var verityHome2 = () => (0, import_node_path61.join)(process.env.HOME ?? "", ".verity");
|
|
41910
42240
|
function pendingTracePath() {
|
|
41911
|
-
return (0,
|
|
42241
|
+
return (0, import_node_path61.join)(verityHome2(), PENDING_NAME);
|
|
41912
42242
|
}
|
|
41913
42243
|
var RUN_ID = /^[0-9a-f]{16}$/;
|
|
41914
42244
|
var CLI_VERSION = /^[0-9A-Za-z.+-]{1,40}$/;
|
|
@@ -41966,10 +42296,10 @@ function writePending(runs) {
|
|
|
41966
42296
|
try {
|
|
41967
42297
|
const kept = runs.filter((r) => r.events.length > 0).slice(-MAX_PENDING_RUNS);
|
|
41968
42298
|
if (kept.length === 0) {
|
|
41969
|
-
(0,
|
|
42299
|
+
(0, import_node_fs73.rmSync)(pendingTracePath(), { force: true });
|
|
41970
42300
|
return;
|
|
41971
42301
|
}
|
|
41972
|
-
(0,
|
|
42302
|
+
(0, import_node_fs73.mkdirSync)(verityHome2(), { recursive: true });
|
|
41973
42303
|
if (!replaceInRoot(verityHome2(), PENDING_NAME, JSON.stringify(kept))) {
|
|
41974
42304
|
logEvent("init_trace_save_refused", {});
|
|
41975
42305
|
}
|
|
@@ -42681,8 +43011,8 @@ var Rail = class {
|
|
|
42681
43011
|
};
|
|
42682
43012
|
|
|
42683
43013
|
// src/commands/init/ui.ts
|
|
42684
|
-
var
|
|
42685
|
-
var
|
|
43014
|
+
var import_node_fs74 = require("node:fs");
|
|
43015
|
+
var import_node_path62 = require("node:path");
|
|
42686
43016
|
var import_node_os13 = require("node:os");
|
|
42687
43017
|
var import_node_child_process18 = require("node:child_process");
|
|
42688
43018
|
function createInitUi(opts) {
|
|
@@ -42702,10 +43032,10 @@ function installInterrupt(ui) {
|
|
|
42702
43032
|
}
|
|
42703
43033
|
var SEEN_FILE = ".init-seen";
|
|
42704
43034
|
function firstInitOnMachine(home = process.env.HOME || (0, import_node_os13.homedir)()) {
|
|
42705
|
-
return !(0,
|
|
43035
|
+
return !(0, import_node_fs74.existsSync)((0, import_node_path62.join)(home, ".verity", SEEN_FILE));
|
|
42706
43036
|
}
|
|
42707
43037
|
function markInitSeen(home = process.env.HOME || (0, import_node_os13.homedir)()) {
|
|
42708
|
-
replaceInRoot((0,
|
|
43038
|
+
replaceInRoot((0, import_node_path62.join)(home, ".verity"), SEEN_FILE, `${(/* @__PURE__ */ new Date()).toISOString()}
|
|
42709
43039
|
`);
|
|
42710
43040
|
}
|
|
42711
43041
|
function repoLabel() {
|
|
@@ -42715,12 +43045,12 @@ function repoLabel() {
|
|
|
42715
43045
|
if (parsed) return terminalText(`${parsed.owner}/${parsed.repo}`, 120);
|
|
42716
43046
|
} catch {
|
|
42717
43047
|
}
|
|
42718
|
-
return terminalText((0,
|
|
43048
|
+
return terminalText((0, import_node_path62.basename)(repoRoot()), 120);
|
|
42719
43049
|
}
|
|
42720
43050
|
|
|
42721
43051
|
// src/lib/prereqs.ts
|
|
42722
43052
|
var import_node_child_process19 = require("node:child_process");
|
|
42723
|
-
var
|
|
43053
|
+
var import_node_fs75 = require("node:fs");
|
|
42724
43054
|
var MIN_NODE_MAJOR = 20;
|
|
42725
43055
|
function which(bin) {
|
|
42726
43056
|
return whichSync(bin, { real: false });
|
|
@@ -42788,7 +43118,7 @@ function checkAnalysisCli(opts = {}) {
|
|
|
42788
43118
|
}
|
|
42789
43119
|
function sameFile(a, b) {
|
|
42790
43120
|
try {
|
|
42791
|
-
return (0,
|
|
43121
|
+
return (0, import_node_fs75.realpathSync)(a) === (0, import_node_fs75.realpathSync)(b);
|
|
42792
43122
|
} catch {
|
|
42793
43123
|
return false;
|
|
42794
43124
|
}
|
|
@@ -42848,12 +43178,12 @@ async function checkPrereqs(opts = {}) {
|
|
|
42848
43178
|
}
|
|
42849
43179
|
|
|
42850
43180
|
// src/lib/telemetry-local.ts
|
|
42851
|
-
var
|
|
43181
|
+
var import_node_path64 = require("node:path");
|
|
42852
43182
|
|
|
42853
43183
|
// src/lib/telemetry-settings.ts
|
|
42854
43184
|
var import_promises14 = require("node:fs/promises");
|
|
42855
43185
|
var import_node_os14 = require("node:os");
|
|
42856
|
-
var
|
|
43186
|
+
var import_node_path63 = require("node:path");
|
|
42857
43187
|
var SETTINGS_LOCAL_FILE2 = ".claude/settings.local.json";
|
|
42858
43188
|
var OTEL_HEADERS_HELPER_CMD = "verity telemetry headers";
|
|
42859
43189
|
var LEGACY_HEADER_KEY = "OTEL_EXPORTER_OTLP_HEADERS";
|
|
@@ -42864,10 +43194,10 @@ var OTLP_ENDPOINT_KEYS = [
|
|
|
42864
43194
|
"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"
|
|
42865
43195
|
];
|
|
42866
43196
|
function claudeConfigDir2() {
|
|
42867
|
-
return process.env.CLAUDE_CONFIG_DIR || (0,
|
|
43197
|
+
return process.env.CLAUDE_CONFIG_DIR || (0, import_node_path63.join)((0, import_node_os14.homedir)(), ".claude");
|
|
42868
43198
|
}
|
|
42869
43199
|
function userSettingsPath() {
|
|
42870
|
-
return (0,
|
|
43200
|
+
return (0, import_node_path63.join)(claudeConfigDir2(), "settings.json");
|
|
42871
43201
|
}
|
|
42872
43202
|
function deriveOtlpEndpoint(serviceUrl) {
|
|
42873
43203
|
return serviceUrl.replace(/\/+$/, "").replace(/\/v1$/, "") + "/v1/otlp";
|
|
@@ -42988,7 +43318,7 @@ async function healLocalTelemetry(root = repoRoot()) {
|
|
|
42988
43318
|
if (settings.env && Object.keys(env).length === 0) delete settings.env;
|
|
42989
43319
|
if (plan.helper) delete settings.otelHeadersHelper;
|
|
42990
43320
|
const next = nextLocalBytes(local.raw, settings);
|
|
42991
|
-
if (next !== null && !replaceInRoot((0,
|
|
43321
|
+
if (next !== null && !replaceInRoot((0, import_node_path64.join)(root, ".claude"), "settings.local.json", next)) {
|
|
42992
43322
|
return { removed: [] };
|
|
42993
43323
|
}
|
|
42994
43324
|
return { removed: [...plan.envKeys, ...plan.helper ? ["otelHeadersHelper"] : []] };
|
|
@@ -42996,8 +43326,8 @@ async function healLocalTelemetry(root = repoRoot()) {
|
|
|
42996
43326
|
|
|
42997
43327
|
// src/lib/telemetry-gate.ts
|
|
42998
43328
|
var import_node_child_process20 = require("node:child_process");
|
|
42999
|
-
var
|
|
43000
|
-
var
|
|
43329
|
+
var import_node_fs76 = require("node:fs");
|
|
43330
|
+
var import_node_path65 = require("node:path");
|
|
43001
43331
|
var PROJECT_MARKERS = ["setup.json", "config.json"];
|
|
43002
43332
|
function writtenOnThisMachine(root, rel) {
|
|
43003
43333
|
const r = (0, import_node_child_process20.spawnSync)("git", hardenedGitArgv(["ls-files", "--error-unmatch", "--", rel]), {
|
|
@@ -43014,10 +43344,10 @@ function writtenOnThisMachine(root, rel) {
|
|
|
43014
43344
|
function isTelemetryProject() {
|
|
43015
43345
|
for (const root of [repoRoot(), mainWorktreeRoot()]) {
|
|
43016
43346
|
if (!root) continue;
|
|
43017
|
-
const dir = (0,
|
|
43347
|
+
const dir = (0, import_node_path65.join)(root, VERITY_DIR);
|
|
43018
43348
|
if (isMachineStore(dir)) continue;
|
|
43019
43349
|
for (const marker of PROJECT_MARKERS) {
|
|
43020
|
-
if ((0,
|
|
43350
|
+
if ((0, import_node_fs76.existsSync)((0, import_node_path65.join)(dir, marker)) && writtenOnThisMachine(root, `${VERITY_DIR}/${marker}`)) return true;
|
|
43021
43351
|
}
|
|
43022
43352
|
}
|
|
43023
43353
|
return false;
|
|
@@ -43282,7 +43612,7 @@ function signInDetail(outcome) {
|
|
|
43282
43612
|
}
|
|
43283
43613
|
function formalDefault(previous, opts = {}) {
|
|
43284
43614
|
const cfg = readProjectConfig();
|
|
43285
|
-
if (previous?.init?.completed_at || opts.setUpBefore || cfg.formal !== void 0 || cfg.formal_refused) return false;
|
|
43615
|
+
if (previous?.init?.completed_at || opts.setUpBefore || cfg.formal !== void 0 || cfg.formal_refused || cfg.formal_off_refused) return false;
|
|
43286
43616
|
writeProjectConfig({ formal: "push" });
|
|
43287
43617
|
return true;
|
|
43288
43618
|
}
|
|
@@ -43293,9 +43623,13 @@ function sayFormalOn(ui) {
|
|
|
43293
43623
|
}
|
|
43294
43624
|
function backgroundStep(ui, opts) {
|
|
43295
43625
|
const { rail } = ui;
|
|
43296
|
-
const
|
|
43297
|
-
const
|
|
43298
|
-
|
|
43626
|
+
const setting = formalSetting(readProjectConfig());
|
|
43627
|
+
const formal = setting.state;
|
|
43628
|
+
const said = formal === "push" && (opts.formalNew === true || setting.source === "default" && formalDefaultNoticeDue());
|
|
43629
|
+
if (said) {
|
|
43630
|
+
sayFormalOn(ui);
|
|
43631
|
+
recordFormalDefaultNotice();
|
|
43632
|
+
}
|
|
43299
43633
|
const lean = shouldStartBackgroundInstall({ formal });
|
|
43300
43634
|
const leanStarted = lean.start && startBackgroundInstall({ cli: opts.cli });
|
|
43301
43635
|
const trivy = startTrivyPrewarm();
|
|
@@ -43382,8 +43716,8 @@ async function scaffoldStep(ui, given = {}) {
|
|
|
43382
43716
|
rail.warn(".gitignore: could not write the Verity block");
|
|
43383
43717
|
rail.line("Add it by hand: .verity/ holds copies of analyzed files, including any secret the gate flagged.");
|
|
43384
43718
|
} else if (ignore === "conflict") {
|
|
43385
|
-
rail.warn(".gitignore: git
|
|
43386
|
-
rail.line("A
|
|
43719
|
+
rail.warn(".gitignore: git does not ignore the files under .verity/");
|
|
43720
|
+
rail.line("A nested .gitignore re-includes them, so copies of analyzed files, including any secret the gate flagged, can be committed. Check: git check-ignore -v .verity/.snapshot/x");
|
|
43387
43721
|
} else if (ignore === "memory-tracked") {
|
|
43388
43722
|
rail.warn("This project commits its knowledge graph");
|
|
43389
43723
|
}
|
|
@@ -43398,15 +43732,25 @@ async function scaffoldStep(ui, given = {}) {
|
|
|
43398
43732
|
rail.line("They show up in every diff. Stop with: verity memory untrack (or keep them on purpose: verity memory track)");
|
|
43399
43733
|
}
|
|
43400
43734
|
}
|
|
43735
|
+
if (committedStandardFile()) {
|
|
43736
|
+
if (given.untrackStandard) {
|
|
43737
|
+
const result = untrackStandard();
|
|
43738
|
+
if (result.ok) rail.line(`Untracked ${STANDARD_FILE} (staged). Commit to finish. Teammates get it back with: verity standard pull`);
|
|
43739
|
+
else rail.line(`Could not untrack ${STANDARD_FILE}. Run: verity standard untrack`, "warn");
|
|
43740
|
+
} else {
|
|
43741
|
+
rail.warn(`${STANDARD_FILE} is tracked in git`);
|
|
43742
|
+
rail.line("Verity keeps it on each machine now, and reviews read the Standard on the service. Stop tracking it with: verity standard untrack");
|
|
43743
|
+
}
|
|
43744
|
+
}
|
|
43401
43745
|
const tracked = committedVerityState();
|
|
43402
43746
|
if (tracked.length > 0) {
|
|
43403
43747
|
if (given.untrackState || ui.asking && await askUntrackState(ui, tracked)) {
|
|
43404
43748
|
const result = untrackVerityState();
|
|
43405
43749
|
if (result === "untracked") rail.line("Untracked the Verity state files (staged). Commit to finish.");
|
|
43406
|
-
else if (result === "failed") rail.line("Could not untrack them. Run:
|
|
43750
|
+
else if (result === "failed") rail.line("Could not untrack them. Run: verity init --untrack-state", "warn");
|
|
43407
43751
|
} else {
|
|
43408
43752
|
rail.warn(`${tracked.length} Verity state file(s) are tracked in git`);
|
|
43409
|
-
rail.line(`For example ${terminalText(tracked[0], 200)}. Fix:
|
|
43753
|
+
rail.line(`For example ${terminalText(tracked[0], 200)}. Fix: verity init --untrack-state`);
|
|
43410
43754
|
}
|
|
43411
43755
|
}
|
|
43412
43756
|
retireCodacyConfig(ui);
|
|
@@ -43416,7 +43760,9 @@ async function scaffoldStep(ui, given = {}) {
|
|
|
43416
43760
|
rail.line(`Could not update CLAUDE.md: ${terminalText(err2.message, 300)}`, "warn");
|
|
43417
43761
|
}
|
|
43418
43762
|
const cfg = readProjectConfig();
|
|
43419
|
-
if (cfg.
|
|
43763
|
+
if (cfg.formal_off_refused && formalSetting(cfg).state === "push") {
|
|
43764
|
+
rail.line(`Formal verification: on \u2014 ${formalOffRefusalMessage(cfg.formal_off_refused)}`, "warn");
|
|
43765
|
+
}
|
|
43420
43766
|
rail.settle();
|
|
43421
43767
|
}
|
|
43422
43768
|
async function askUntrackState(ui, tracked) {
|
|
@@ -43454,9 +43800,9 @@ function retireCodacyConfig(ui) {
|
|
|
43454
43800
|
}
|
|
43455
43801
|
|
|
43456
43802
|
// src/commands/init/wiring.ts
|
|
43457
|
-
var
|
|
43803
|
+
var import_node_fs77 = require("node:fs");
|
|
43458
43804
|
var import_promises16 = require("node:fs/promises");
|
|
43459
|
-
var
|
|
43805
|
+
var import_node_path66 = require("node:path");
|
|
43460
43806
|
var DEFAULT_MOMENTS = ["stop", "pre-commit", "pre-push"];
|
|
43461
43807
|
async function momentsFromInstalledHooks() {
|
|
43462
43808
|
const status = await checkAllVerityHooks();
|
|
@@ -43529,12 +43875,12 @@ var SKILLS = [
|
|
|
43529
43875
|
];
|
|
43530
43876
|
function resolveDataDir2() {
|
|
43531
43877
|
const candidates2 = [
|
|
43532
|
-
(0,
|
|
43533
|
-
(0,
|
|
43534
|
-
(0,
|
|
43878
|
+
(0, import_node_path66.join)(__dirname, "..", "data"),
|
|
43879
|
+
(0, import_node_path66.join)(__dirname, "..", "..", "data"),
|
|
43880
|
+
(0, import_node_path66.join)(process.cwd(), "cli", "data")
|
|
43535
43881
|
];
|
|
43536
43882
|
for (const candidate of candidates2) {
|
|
43537
|
-
if ((0,
|
|
43883
|
+
if ((0, import_node_fs77.existsSync)((0, import_node_path66.join)(candidate, "skills"))) return candidate;
|
|
43538
43884
|
}
|
|
43539
43885
|
throw new Error("Could not find Verity skill data. Reinstall: npm install -g @codacy/verity-cli");
|
|
43540
43886
|
}
|
|
@@ -43542,9 +43888,9 @@ async function skillIsCurrent(src, dest) {
|
|
|
43542
43888
|
const list2 = (dir) => {
|
|
43543
43889
|
const out2 = [];
|
|
43544
43890
|
const walk2 = (d, prefix) => {
|
|
43545
|
-
for (const e of (0,
|
|
43891
|
+
for (const e of (0, import_node_fs77.readdirSync)(d, { withFileTypes: true })) {
|
|
43546
43892
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
43547
|
-
if (e.isDirectory()) walk2((0,
|
|
43893
|
+
if (e.isDirectory()) walk2((0, import_node_path66.join)(d, e.name), rel);
|
|
43548
43894
|
else if (e.isFile()) out2.push(rel);
|
|
43549
43895
|
}
|
|
43550
43896
|
};
|
|
@@ -43555,7 +43901,7 @@ async function skillIsCurrent(src, dest) {
|
|
|
43555
43901
|
const shipped = list2(src);
|
|
43556
43902
|
if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
|
|
43557
43903
|
for (const rel of shipped) {
|
|
43558
|
-
if (await (0, import_promises16.readFile)((0,
|
|
43904
|
+
if (await (0, import_promises16.readFile)((0, import_node_path66.join)(src, rel), "utf-8") !== await (0, import_promises16.readFile)((0, import_node_path66.join)(dest, rel), "utf-8")) return false;
|
|
43559
43905
|
}
|
|
43560
43906
|
return true;
|
|
43561
43907
|
} catch {
|
|
@@ -43563,16 +43909,16 @@ async function skillIsCurrent(src, dest) {
|
|
|
43563
43909
|
}
|
|
43564
43910
|
}
|
|
43565
43911
|
async function installSkills(force) {
|
|
43566
|
-
const source2 = (0,
|
|
43912
|
+
const source2 = (0, import_node_path66.join)(resolveDataDir2(), "skills");
|
|
43567
43913
|
const missing = [];
|
|
43568
43914
|
for (const skill of SKILLS) {
|
|
43569
|
-
const src = (0,
|
|
43570
|
-
const dest = (0,
|
|
43571
|
-
if (!(0,
|
|
43915
|
+
const src = (0, import_node_path66.join)(source2, skill);
|
|
43916
|
+
const dest = (0, import_node_path66.join)(".claude/skills", skill);
|
|
43917
|
+
if (!(0, import_node_fs77.existsSync)(src)) {
|
|
43572
43918
|
missing.push(skill);
|
|
43573
43919
|
continue;
|
|
43574
43920
|
}
|
|
43575
|
-
if ((0,
|
|
43921
|
+
if ((0, import_node_fs77.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) continue;
|
|
43576
43922
|
await (0, import_promises16.mkdir)(dest, { recursive: true });
|
|
43577
43923
|
await (0, import_promises16.cp)(src, dest, { recursive: true, force: true });
|
|
43578
43924
|
}
|
|
@@ -43612,8 +43958,8 @@ async function hooksStep(ui, ctx) {
|
|
|
43612
43958
|
}
|
|
43613
43959
|
|
|
43614
43960
|
// src/commands/init/standard.ts
|
|
43615
|
-
var
|
|
43616
|
-
var
|
|
43961
|
+
var import_node_fs78 = require("node:fs");
|
|
43962
|
+
var import_node_path67 = require("node:path");
|
|
43617
43963
|
var import_yaml10 = __toESM2(require_dist());
|
|
43618
43964
|
|
|
43619
43965
|
// src/lib/catalogue-client.ts
|
|
@@ -43686,10 +44032,8 @@ async function writeTeamStandard(team, opts) {
|
|
|
43686
44032
|
serviceUrl: url.data,
|
|
43687
44033
|
projectId: await projectLabel(token.data.token, url.data, opts.globals.verbose)
|
|
43688
44034
|
});
|
|
43689
|
-
|
|
43690
|
-
|
|
43691
|
-
});
|
|
43692
|
-
}
|
|
44035
|
+
await writeSetupState({ standardVersion: found.standard.version, declinedStandardVersion: void 0 }).catch(() => {
|
|
44036
|
+
});
|
|
43693
44037
|
return { status: "adopted", version: found.standard.version, summary: describeRemote(found), notes: outcome.notes };
|
|
43694
44038
|
} catch (err2) {
|
|
43695
44039
|
return { status: "write-failed", reason: terminalText(err2.message, 300) };
|
|
@@ -43710,6 +44054,17 @@ async function askTeamChoice(ui, team) {
|
|
|
43710
44054
|
rail.collapse();
|
|
43711
44055
|
return k === "n" ? "new" : "use";
|
|
43712
44056
|
}
|
|
44057
|
+
async function askKeepOrPull(ui, team) {
|
|
44058
|
+
const { rail, screen } = ui;
|
|
44059
|
+
rail.active(`${STANDARD_FILE} differs from your team's Standard`);
|
|
44060
|
+
rail.line(`On the service: ${describeRemote(team.found)}. Reviews use that one.`);
|
|
44061
|
+
rail.line(`Use it here too (a copy of your file is kept), or keep your file and share it over the team's later: verity standard push`);
|
|
44062
|
+
rail.gap();
|
|
44063
|
+
rail.keys([["Enter", "use the team's"], ["k", "keep yours"]]);
|
|
44064
|
+
const k = await screen.key(["enter", "k"], "enter", { freshMs: 300 });
|
|
44065
|
+
rail.collapse();
|
|
44066
|
+
return k === "k" ? "keep" : "use";
|
|
44067
|
+
}
|
|
43713
44068
|
function sayAdopted(ui, team) {
|
|
43714
44069
|
ui.rail.done(`Using your team's Standard v${team.version}`);
|
|
43715
44070
|
ui.rail.line(terminalText(team.summary, 300));
|
|
@@ -43778,26 +44133,26 @@ async function deriveFromCatalogue(ui, globals, plan, expectedLatest) {
|
|
|
43778
44133
|
return { ok: false, version: null };
|
|
43779
44134
|
}
|
|
43780
44135
|
}
|
|
43781
|
-
function
|
|
44136
|
+
function localStandard() {
|
|
43782
44137
|
const raw = readRepoFile(STANDARD_FILE);
|
|
43783
|
-
if (raw === null) return `${STANDARD_FILE} is a link, not a regular file, or larger than 512 KB
|
|
44138
|
+
if (raw === null) return { ok: false, problem: `${STANDARD_FILE} is a link, not a regular file, or larger than 512 KB.` };
|
|
43784
44139
|
let parsed;
|
|
43785
44140
|
try {
|
|
43786
44141
|
parsed = (0, import_yaml10.parse)(raw);
|
|
43787
44142
|
} catch (err2) {
|
|
43788
|
-
return `${STANDARD_FILE} is not valid YAML: ${terminalText(err2 instanceof Error ? err2.message : String(err2), 200)}
|
|
44143
|
+
return { ok: false, problem: `${STANDARD_FILE} is not valid YAML: ${terminalText(err2 instanceof Error ? err2.message : String(err2), 200)}` };
|
|
43789
44144
|
}
|
|
43790
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return `${STANDARD_FILE} holds no Standard
|
|
44145
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return { ok: false, problem: `${STANDARD_FILE} holds no Standard.` };
|
|
43791
44146
|
const valid = validateStandardContent(parsed);
|
|
43792
|
-
if (!valid.ok) return `${STANDARD_FILE} is not a Standard the service accepts: ${terminalText(valid.error, 200)}
|
|
43793
|
-
return
|
|
44147
|
+
if (!valid.ok) return { ok: false, problem: `${STANDARD_FILE} is not a Standard the service accepts: ${terminalText(valid.error, 200)}` };
|
|
44148
|
+
return { ok: true, content: parsed };
|
|
43794
44149
|
}
|
|
43795
44150
|
function removeLocalStandard() {
|
|
43796
44151
|
const path = projectPath(STANDARD_FILE);
|
|
43797
44152
|
try {
|
|
43798
|
-
const folder = (0,
|
|
44153
|
+
const folder = (0, import_node_fs78.lstatSync)((0, import_node_path67.dirname)(path));
|
|
43799
44154
|
if (!folder.isDirectory() || folder.isSymbolicLink()) return;
|
|
43800
|
-
if ((0,
|
|
44155
|
+
if ((0, import_node_fs78.lstatSync)(path).isFile()) (0, import_node_fs78.unlinkSync)(path);
|
|
43801
44156
|
} catch {
|
|
43802
44157
|
}
|
|
43803
44158
|
}
|
|
@@ -43811,7 +44166,7 @@ function setLocalStandardAside(now = /* @__PURE__ */ new Date(), remove = remove
|
|
|
43811
44166
|
return { ok: false, message: `Could not keep a copy of ${STANDARD_FILE} (${terminalText(err2 instanceof Error ? err2.message : String(err2), 200)}), so it was not set aside.` };
|
|
43812
44167
|
}
|
|
43813
44168
|
remove();
|
|
43814
|
-
if ((0,
|
|
44169
|
+
if ((0, import_node_fs78.existsSync)(projectPath(STANDARD_FILE))) return { ok: false, message: `Could not remove ${STANDARD_FILE} after copying it to ${path}.` };
|
|
43815
44170
|
return { ok: true, path };
|
|
43816
44171
|
}
|
|
43817
44172
|
async function standardStep(ui, ctx) {
|
|
@@ -43873,7 +44228,7 @@ async function standardStep(ui, ctx) {
|
|
|
43873
44228
|
rail.line(team2.status === "none" ? `There is no Standard on the service either, so reviews have no rules. Fix ${STANDARD_FILE}, or delete it, then run verity init again.` : team2.status === "unavailable" ? `The Verity service did not answer (${terminalText(team2.reason, 200)}), so no Standard is confirmed. Fix ${STANDARD_FILE}, then run verity init again.` : team2.status === "denied" && refusalOutcome(team2.code) === "denied" ? `Verity has no access to this repository (${terminalText(team2.reason, 200)}). Fix ${STANDARD_FILE}, give the Verity GitHub App access, then run verity login and verity init.` : team2.status === "denied" ? `The Verity service did not accept your sign-in (${terminalText(team2.reason, 200)}). Fix ${STANDARD_FILE}, then run verity login and verity init.` : `No Standard on the service was looked up. Fix ${STANDARD_FILE}, or sign in, then run verity init again.`);
|
|
43874
44229
|
return end({ source: "none", version: null, profile: notAsked });
|
|
43875
44230
|
};
|
|
43876
|
-
if (ctx.standard === "new" && (0,
|
|
44231
|
+
if (ctx.standard === "new" && (0, import_node_fs78.lstatSync)(projectPath(STANDARD_FILE), { throwIfNoEntry: false })) {
|
|
43877
44232
|
const aside = setLocalStandardAside();
|
|
43878
44233
|
if (!aside.ok) {
|
|
43879
44234
|
rail.warn("Could not set your Standard aside for a new one");
|
|
@@ -43883,26 +44238,77 @@ async function standardStep(ui, ctx) {
|
|
|
43883
44238
|
}
|
|
43884
44239
|
rail.done(`Set your Standard aside ${s.gray}\xB7 a copy is in ${aside.path}${s.reset}`);
|
|
43885
44240
|
}
|
|
43886
|
-
|
|
43887
|
-
const problem = localStandardProblem();
|
|
43888
|
-
if (problem !== null) return unusableHere(problem);
|
|
43889
|
-
const sync = await pushLocalStandardIfMissing(ctx.globals);
|
|
43890
|
-
rail.done("Kept your Standard");
|
|
43891
|
-
rail.line(`${STANDARD_FILE} is already here, so this run leaves it as it is. Edit it there, then share the change: verity standard push`);
|
|
44241
|
+
const keptHints = async () => {
|
|
43892
44242
|
if (!usesReviewPacks()) {
|
|
43893
44243
|
rail.line("It does not use review packs. To move it to packs and keep your rules: verity standard push. To build a new one: verity init --standard new", "muted");
|
|
43894
44244
|
}
|
|
43895
|
-
if (
|
|
43896
|
-
rail.line(
|
|
43897
|
-
|
|
44245
|
+
if (!hasProjectRules() && await rulesOn(ctx.globals)) {
|
|
44246
|
+
rail.line("It has no project rules yet. Add them from a repo profile: verity standard generate");
|
|
44247
|
+
}
|
|
44248
|
+
};
|
|
44249
|
+
const keptHere = async (local) => {
|
|
44250
|
+
const team2 = await lookUpTeamStandard(ctx);
|
|
44251
|
+
if (team2.status === "found" || team2.status === "declined-before") {
|
|
44252
|
+
if (sameStandard(local, team2.found.standard.content)) {
|
|
44253
|
+
rail.done(`Kept your Standard ${s.gray}\xB7 it is the team's v${team2.version}${s.reset}`);
|
|
44254
|
+
rail.line(`Edit it in ${STANDARD_FILE}, then share the change: verity standard push`);
|
|
44255
|
+
await writeSetupState({ standardVersion: team2.version }).catch(() => {
|
|
44256
|
+
});
|
|
44257
|
+
await keptHints();
|
|
44258
|
+
return end({ source: "kept", version: team2.version, profile: notAsked });
|
|
44259
|
+
}
|
|
44260
|
+
const choice = ctx.standard === "use" ? "use" : team2.status === "declined-before" ? "keep" : ui.asking ? await askKeepOrPull(ui, team2) : "use";
|
|
44261
|
+
if (choice === "use") {
|
|
44262
|
+
const pulled = await pullStandard(ctx.globals);
|
|
44263
|
+
if (pulled.status === "pulled" || pulled.status === "same") {
|
|
44264
|
+
rail.done(`Using your team's Standard v${pulled.version}`);
|
|
44265
|
+
rail.line(terminalText(describeRemote(team2.found), 300));
|
|
44266
|
+
if (pulled.status === "pulled" && pulled.backup) rail.line(`Your file is kept as ${pulled.backup}`, "muted");
|
|
44267
|
+
rail.line(`Edit it in ${STANDARD_FILE}, then share the change: verity standard push`);
|
|
44268
|
+
if (pulled.status === "pulled") for (const note of pulled.notes) rail.line(terminalText(note, 300), "warn");
|
|
44269
|
+
return end({ source: "adopted", version: pulled.version, profile: notAsked });
|
|
44270
|
+
}
|
|
44271
|
+
rail.warn("Could not write the team's Standard here");
|
|
44272
|
+
rail.line(pulled.status === "failed" ? terminalText(pulled.message, 300) : `${STANDARD_FILE} changed while this ran.`);
|
|
44273
|
+
rail.line(`Reviews use the team's Standard v${team2.version} on the service. To write it here: verity standard pull`);
|
|
44274
|
+
return end({ source: "kept", version: team2.version, profile: notAsked });
|
|
44275
|
+
}
|
|
44276
|
+
rail.done(`Kept your Standard ${s.gray}\xB7 it differs from the team's v${team2.version}${s.reset}`);
|
|
44277
|
+
rail.line(team2.status === "declined-before" ? `This project turned down the team's Standard v${team2.version} before, so this run keeps yours. Reviews use the team's.` : "Reviews use the team's Standard on the service.");
|
|
44278
|
+
rail.line(`To share yours over the team's: verity standard push. To use the team's here: verity standard pull`);
|
|
44279
|
+
await writeSetupState({ standardVersion: team2.version }).catch(() => {
|
|
44280
|
+
});
|
|
44281
|
+
await keptHints();
|
|
44282
|
+
return end({ source: "kept", version: team2.version, profile: notAsked });
|
|
44283
|
+
}
|
|
44284
|
+
rail.done("Kept your Standard");
|
|
44285
|
+
rail.line(`${STANDARD_FILE} is already here, so this run leaves it as it is. Edit it there, then share the change: verity standard push`);
|
|
44286
|
+
let version = null;
|
|
44287
|
+
if (team2.status === "none") {
|
|
44288
|
+
const pushed = await pushStandard(ctx.globals, { expectedLatest: null });
|
|
44289
|
+
if (pushed.conflict) {
|
|
44290
|
+
rail.line("Someone shared a Standard for this repository while this ran. Reviews use theirs; to compare with yours, run verity init again, or verity standard pull.", "warn");
|
|
44291
|
+
} else if (pushed.standardVersion !== null) {
|
|
44292
|
+
version = pushed.standardVersion;
|
|
44293
|
+
rail.line(`It was only on this machine. It is shared now as v${version}.`, "muted");
|
|
44294
|
+
} else {
|
|
44295
|
+
rail.line("It is only on this machine:", "warn");
|
|
44296
|
+
}
|
|
44297
|
+
for (const line2 of pushed.lines) if (!line2.startsWith("Standard pushed")) rail.line(terminalText(line2, 600), "warn");
|
|
43898
44298
|
}
|
|
43899
|
-
if (
|
|
44299
|
+
if (team2.status === "unavailable") {
|
|
43900
44300
|
rail.line(`It could not be shared: the Verity service did not answer. It is shared at the first review once the service answers, or now with: verity standard push`, "warn");
|
|
43901
44301
|
}
|
|
43902
|
-
if (
|
|
43903
|
-
rail.line(
|
|
44302
|
+
if (team2.status === "denied") {
|
|
44303
|
+
rail.line(`It could not be compared with the team's: ${terminalText(team2.reason, 300)}`, "warn");
|
|
43904
44304
|
}
|
|
43905
|
-
|
|
44305
|
+
await keptHints();
|
|
44306
|
+
return end({ source: "kept", version, profile: notAsked });
|
|
44307
|
+
};
|
|
44308
|
+
if ((0, import_node_fs78.existsSync)(projectPath(STANDARD_FILE))) {
|
|
44309
|
+
const local = localStandard();
|
|
44310
|
+
if (!local.ok) return unusableHere(local.problem);
|
|
44311
|
+
return keptHere(local.content);
|
|
43906
44312
|
}
|
|
43907
44313
|
const team = await lookUpTeamStandard(ctx);
|
|
43908
44314
|
let replaces;
|
|
@@ -44025,8 +44431,8 @@ function sayChanged(ui, before) {
|
|
|
44025
44431
|
}
|
|
44026
44432
|
|
|
44027
44433
|
// src/commands/migrate.ts
|
|
44028
|
-
var
|
|
44029
|
-
var
|
|
44434
|
+
var import_node_fs79 = require("node:fs");
|
|
44435
|
+
var import_node_path68 = require("node:path");
|
|
44030
44436
|
var import_node_child_process22 = require("node:child_process");
|
|
44031
44437
|
var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
|
|
44032
44438
|
function defaultNpmRemover(pkg) {
|
|
@@ -44090,12 +44496,12 @@ async function runMigration(opts = {}) {
|
|
|
44090
44496
|
return { actions, migrated: actions.length > 0 };
|
|
44091
44497
|
}
|
|
44092
44498
|
function migrateProjectDir(root, actions) {
|
|
44093
|
-
const gateDir = (0,
|
|
44094
|
-
const verityDir = (0,
|
|
44095
|
-
if ((0,
|
|
44499
|
+
const gateDir = (0, import_node_path68.join)(root, ".gate");
|
|
44500
|
+
const verityDir = (0, import_node_path68.join)(root, ".verity");
|
|
44501
|
+
if ((0, import_node_fs79.existsSync)(gateDir) && !(0, import_node_fs79.existsSync)(verityDir)) {
|
|
44096
44502
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
44097
44503
|
}
|
|
44098
|
-
if ((0,
|
|
44504
|
+
if ((0, import_node_fs79.existsSync)(gateDir) && (0, import_node_fs79.existsSync)(verityDir)) {
|
|
44099
44505
|
return migrateProjectDirCarry(gateDir, verityDir, actions);
|
|
44100
44506
|
}
|
|
44101
44507
|
return false;
|
|
@@ -44116,13 +44522,13 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
|
|
|
44116
44522
|
}
|
|
44117
44523
|
}
|
|
44118
44524
|
if (moved) {
|
|
44119
|
-
if ((0,
|
|
44525
|
+
if ((0, import_node_fs79.existsSync)(gateDir)) {
|
|
44120
44526
|
const carried = carryLegacyContents(gateDir, verityDir);
|
|
44121
44527
|
if (carried > 0) {
|
|
44122
44528
|
actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
|
|
44123
44529
|
}
|
|
44124
44530
|
try {
|
|
44125
|
-
(0,
|
|
44531
|
+
(0, import_node_fs79.rmSync)(gateDir, { recursive: true, force: true });
|
|
44126
44532
|
} catch {
|
|
44127
44533
|
}
|
|
44128
44534
|
}
|
|
@@ -44138,18 +44544,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
44138
44544
|
actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
|
|
44139
44545
|
}
|
|
44140
44546
|
try {
|
|
44141
|
-
(0,
|
|
44547
|
+
(0, import_node_fs79.rmSync)(gateDir, { recursive: true, force: true });
|
|
44142
44548
|
} catch {
|
|
44143
44549
|
}
|
|
44144
44550
|
return carried > 0;
|
|
44145
44551
|
}
|
|
44146
44552
|
function migrateGlobalCredentials(home, actions) {
|
|
44147
44553
|
if (!home) return;
|
|
44148
|
-
const gateCreds = (0,
|
|
44149
|
-
const verityCreds = (0,
|
|
44150
|
-
if (!(0,
|
|
44151
|
-
if (!(0,
|
|
44152
|
-
(0,
|
|
44554
|
+
const gateCreds = (0, import_node_path68.join)(home, ".gate", "credentials");
|
|
44555
|
+
const verityCreds = (0, import_node_path68.join)(home, ".verity", "credentials");
|
|
44556
|
+
if (!(0, import_node_fs79.existsSync)(gateCreds)) return;
|
|
44557
|
+
if (!(0, import_node_fs79.existsSync)(verityCreds)) {
|
|
44558
|
+
(0, import_node_fs79.mkdirSync)((0, import_node_path68.join)(home, ".verity"), { recursive: true });
|
|
44153
44559
|
moveFile(gateCreds, verityCreds);
|
|
44154
44560
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
44155
44561
|
return;
|
|
@@ -44171,8 +44577,8 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
44171
44577
|
}
|
|
44172
44578
|
}
|
|
44173
44579
|
async function migrateClaudeMd(root, actions) {
|
|
44174
|
-
const claudeMd = (0,
|
|
44175
|
-
const hadLegacyBlock = (0,
|
|
44580
|
+
const claudeMd = (0, import_node_path68.join)(root, "CLAUDE.md");
|
|
44581
|
+
const hadLegacyBlock = (0, import_node_fs79.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
|
|
44176
44582
|
if (!hadLegacyBlock) return;
|
|
44177
44583
|
try {
|
|
44178
44584
|
await ensureClaudeMdPointer(root);
|
|
@@ -44182,9 +44588,9 @@ async function migrateClaudeMd(root, actions) {
|
|
|
44182
44588
|
}
|
|
44183
44589
|
}
|
|
44184
44590
|
function migrateStandardFile(root, actions) {
|
|
44185
|
-
const gateMd = (0,
|
|
44186
|
-
const verityMd = (0,
|
|
44187
|
-
if (!(0,
|
|
44591
|
+
const gateMd = (0, import_node_path68.join)(root, "GATE.md");
|
|
44592
|
+
const verityMd = (0, import_node_path68.join)(root, "VERITY.md");
|
|
44593
|
+
if (!(0, import_node_fs79.existsSync)(gateMd) || (0, import_node_fs79.existsSync)(verityMd)) return;
|
|
44188
44594
|
let moved = false;
|
|
44189
44595
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
44190
44596
|
try {
|
|
@@ -44196,7 +44602,7 @@ function migrateStandardFile(root, actions) {
|
|
|
44196
44602
|
if (!moved) moveFile(gateMd, verityMd);
|
|
44197
44603
|
const content = readFileSyncSafe(verityMd);
|
|
44198
44604
|
const refreshed = content.split("GATE.md").join("VERITY.md");
|
|
44199
|
-
if (refreshed !== content) (0,
|
|
44605
|
+
if (refreshed !== content) (0, import_node_fs79.writeFileSync)(verityMd, refreshed);
|
|
44200
44606
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
44201
44607
|
}
|
|
44202
44608
|
async function migrateLocalTelemetry(root, actions) {
|
|
@@ -44240,14 +44646,14 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
44240
44646
|
}
|
|
44241
44647
|
if (toAppend.length > 0) {
|
|
44242
44648
|
const sep7 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
44243
|
-
(0,
|
|
44649
|
+
(0, import_node_fs79.writeFileSync)(verityCreds, verityContent + sep7 + toAppend.join("\n") + "\n");
|
|
44244
44650
|
}
|
|
44245
|
-
(0,
|
|
44651
|
+
(0, import_node_fs79.rmSync)(gateCreds, { force: true });
|
|
44246
44652
|
return toAppend.length;
|
|
44247
44653
|
}
|
|
44248
44654
|
function readFileSyncSafe(path) {
|
|
44249
44655
|
try {
|
|
44250
|
-
return (0,
|
|
44656
|
+
return (0, import_node_fs79.readFileSync)(path, "utf-8");
|
|
44251
44657
|
} catch {
|
|
44252
44658
|
return "";
|
|
44253
44659
|
}
|
|
@@ -44262,20 +44668,20 @@ function hasStagedChanges(root) {
|
|
|
44262
44668
|
}
|
|
44263
44669
|
function moveDir(from, to) {
|
|
44264
44670
|
try {
|
|
44265
|
-
(0,
|
|
44671
|
+
(0, import_node_fs79.renameSync)(from, to);
|
|
44266
44672
|
} catch (err2) {
|
|
44267
44673
|
if (err2.code !== "EXDEV") throw err2;
|
|
44268
|
-
(0,
|
|
44269
|
-
(0,
|
|
44674
|
+
(0, import_node_fs79.cpSync)(from, to, { recursive: true });
|
|
44675
|
+
(0, import_node_fs79.rmSync)(from, { recursive: true, force: true });
|
|
44270
44676
|
}
|
|
44271
44677
|
}
|
|
44272
44678
|
function moveFile(from, to) {
|
|
44273
44679
|
try {
|
|
44274
|
-
(0,
|
|
44680
|
+
(0, import_node_fs79.renameSync)(from, to);
|
|
44275
44681
|
} catch (err2) {
|
|
44276
44682
|
if (err2.code !== "EXDEV") throw err2;
|
|
44277
|
-
(0,
|
|
44278
|
-
(0,
|
|
44683
|
+
(0, import_node_fs79.cpSync)(from, to);
|
|
44684
|
+
(0, import_node_fs79.rmSync)(from, { force: true });
|
|
44279
44685
|
}
|
|
44280
44686
|
}
|
|
44281
44687
|
function carryLegacyContents(gateDir, verityDir) {
|
|
@@ -44284,12 +44690,12 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
44284
44690
|
const walk2 = (relDir) => {
|
|
44285
44691
|
let entries;
|
|
44286
44692
|
try {
|
|
44287
|
-
entries = (0,
|
|
44693
|
+
entries = (0, import_node_fs79.readdirSync)((0, import_node_path68.join)(gateDir, relDir), { withFileTypes: true });
|
|
44288
44694
|
} catch {
|
|
44289
44695
|
return;
|
|
44290
44696
|
}
|
|
44291
44697
|
for (const entry of entries) {
|
|
44292
|
-
const rel = relDir ? (0,
|
|
44698
|
+
const rel = relDir ? (0, import_node_path68.join)(relDir, entry.name) : entry.name;
|
|
44293
44699
|
if (entry.isSymbolicLink()) continue;
|
|
44294
44700
|
if (entry.isDirectory()) {
|
|
44295
44701
|
walk2(rel);
|
|
@@ -44299,7 +44705,7 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
44299
44705
|
const opened = openRegularInRoot(gateDir, rel);
|
|
44300
44706
|
if (!opened.ok) continue;
|
|
44301
44707
|
try {
|
|
44302
|
-
(0,
|
|
44708
|
+
(0, import_node_fs79.writeFileSync)((0, import_node_path68.join)(verityDir, rel), readOpened(opened.fd, opened.size), { flag: "wx", mode: 384 });
|
|
44303
44709
|
copied++;
|
|
44304
44710
|
} catch {
|
|
44305
44711
|
}
|
|
@@ -44309,19 +44715,19 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
44309
44715
|
return copied;
|
|
44310
44716
|
}
|
|
44311
44717
|
function hasLegacyStandard(root = repoRoot()) {
|
|
44312
|
-
if (!isRealDir((0,
|
|
44718
|
+
if (!isRealDir((0, import_node_path68.join)(root, ".gate"))) return false;
|
|
44313
44719
|
try {
|
|
44314
|
-
if (!(0,
|
|
44720
|
+
if (!(0, import_node_fs79.lstatSync)((0, import_node_path68.join)(root, ".gate", "standard.yaml")).isFile()) return false;
|
|
44315
44721
|
} catch {
|
|
44316
44722
|
return false;
|
|
44317
44723
|
}
|
|
44318
|
-
const verityDir = (0,
|
|
44724
|
+
const verityDir = (0, import_node_path68.join)(root, ".verity");
|
|
44319
44725
|
if (pathEntryExists(verityDir) && !isRealDir(verityDir)) return false;
|
|
44320
|
-
return !pathEntryExists((0,
|
|
44726
|
+
return !pathEntryExists((0, import_node_path68.join)(verityDir, "standard.yaml"));
|
|
44321
44727
|
}
|
|
44322
44728
|
function pathEntryExists(path) {
|
|
44323
44729
|
try {
|
|
44324
|
-
(0,
|
|
44730
|
+
(0, import_node_fs79.lstatSync)(path);
|
|
44325
44731
|
return true;
|
|
44326
44732
|
} catch {
|
|
44327
44733
|
return false;
|
|
@@ -44329,7 +44735,7 @@ function pathEntryExists(path) {
|
|
|
44329
44735
|
}
|
|
44330
44736
|
function isRealDir(path) {
|
|
44331
44737
|
try {
|
|
44332
|
-
const st = (0,
|
|
44738
|
+
const st = (0, import_node_fs79.lstatSync)(path);
|
|
44333
44739
|
return st.isDirectory() && !st.isSymbolicLink();
|
|
44334
44740
|
} catch {
|
|
44335
44741
|
return false;
|
|
@@ -44338,9 +44744,9 @@ function isRealDir(path) {
|
|
|
44338
44744
|
function ensureRealDirs(root, relDir) {
|
|
44339
44745
|
let current = root;
|
|
44340
44746
|
for (const segment of relDir.split(/[\\/]/).filter(Boolean)) {
|
|
44341
|
-
current = (0,
|
|
44747
|
+
current = (0, import_node_path68.join)(current, segment);
|
|
44342
44748
|
try {
|
|
44343
|
-
(0,
|
|
44749
|
+
(0, import_node_fs79.mkdirSync)(current);
|
|
44344
44750
|
} catch (e) {
|
|
44345
44751
|
if (e.code !== "EEXIST") return false;
|
|
44346
44752
|
}
|
|
@@ -44349,23 +44755,23 @@ function ensureRealDirs(root, relDir) {
|
|
|
44349
44755
|
return true;
|
|
44350
44756
|
}
|
|
44351
44757
|
async function needsMigration(root = repoRoot()) {
|
|
44352
|
-
const gateDir = (0,
|
|
44353
|
-
const verityDir = (0,
|
|
44354
|
-
if ((0,
|
|
44355
|
-
if ((0,
|
|
44356
|
-
if ((0,
|
|
44758
|
+
const gateDir = (0, import_node_path68.join)(root, ".gate");
|
|
44759
|
+
const verityDir = (0, import_node_path68.join)(root, ".verity");
|
|
44760
|
+
if ((0, import_node_fs79.existsSync)(gateDir) && !(0, import_node_fs79.existsSync)(verityDir)) return true;
|
|
44761
|
+
if ((0, import_node_fs79.existsSync)(gateDir) && (0, import_node_fs79.existsSync)(verityDir)) {
|
|
44762
|
+
if ((0, import_node_fs79.existsSync)((0, import_node_path68.join)(gateDir, "credentials")) && !(0, import_node_fs79.existsSync)((0, import_node_path68.join)(verityDir, "credentials"))) {
|
|
44357
44763
|
return true;
|
|
44358
44764
|
}
|
|
44359
|
-
if ((0,
|
|
44765
|
+
if ((0, import_node_fs79.existsSync)((0, import_node_path68.join)(gateDir, "memory")) && !(0, import_node_fs79.existsSync)((0, import_node_path68.join)(verityDir, "memory"))) {
|
|
44360
44766
|
return true;
|
|
44361
44767
|
}
|
|
44362
44768
|
if (hasLegacyStandard(root)) return true;
|
|
44363
44769
|
}
|
|
44364
|
-
const claudeMd = (0,
|
|
44365
|
-
if ((0,
|
|
44770
|
+
const claudeMd = (0, import_node_path68.join)(root, "CLAUDE.md");
|
|
44771
|
+
if ((0, import_node_fs79.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
44366
44772
|
return true;
|
|
44367
44773
|
}
|
|
44368
|
-
if ((0,
|
|
44774
|
+
if ((0, import_node_fs79.existsSync)((0, import_node_path68.join)(root, "GATE.md")) && !(0, import_node_fs79.existsSync)((0, import_node_path68.join)(root, "VERITY.md"))) {
|
|
44369
44775
|
return true;
|
|
44370
44776
|
}
|
|
44371
44777
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -44605,7 +45011,7 @@ async function recordAnswers(ui, momentIds, telemetry, completed) {
|
|
|
44605
45011
|
moments: momentIds,
|
|
44606
45012
|
...telemetry ? { telemetry } : {},
|
|
44607
45013
|
// A failed run also clears an earlier stamp: "done" describes this checkout now.
|
|
44608
|
-
init: completed ? { completed_at: (/* @__PURE__ */ new Date()).toISOString(), cli_version: true ? "0.35.
|
|
45014
|
+
init: completed ? { completed_at: (/* @__PURE__ */ new Date()).toISOString(), cli_version: true ? "0.35.5" : "dev" } : void 0
|
|
44609
45015
|
});
|
|
44610
45016
|
} catch (err2) {
|
|
44611
45017
|
ui.rail.line(`Could not record the setup answers: ${terminalText(err2.message, 200)}`, "warn");
|
|
@@ -44658,7 +45064,7 @@ async function runInit(program2, opts) {
|
|
|
44658
45064
|
const defaultsOnly = (opts.yes ?? false) || !interactive();
|
|
44659
45065
|
const { givenMoments, givenTelemetry, profileAnswer, standardAnswer } = parseInitFlags(opts);
|
|
44660
45066
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
44661
|
-
if (!projectMarkers.some((m) => (0,
|
|
45067
|
+
if (!projectMarkers.some((m) => (0, import_node_fs80.existsSync)(m))) {
|
|
44662
45068
|
printError('No project detected in the current directory. Run "verity init" from your project root.');
|
|
44663
45069
|
process.exit(1);
|
|
44664
45070
|
}
|
|
@@ -44684,12 +45090,12 @@ async function runInit(program2, opts) {
|
|
|
44684
45090
|
process.exit(1);
|
|
44685
45091
|
}
|
|
44686
45092
|
trace.mark("prerequisites", "ok");
|
|
44687
|
-
await scaffoldStep(ui, { untrackMemory: opts.untrackMemory === true, untrackState: opts.untrackState === true });
|
|
45093
|
+
await scaffoldStep(ui, { untrackMemory: opts.untrackMemory === true, untrackStandard: opts.untrackStandard === true, untrackState: opts.untrackState === true });
|
|
44688
45094
|
trace.mark("scaffold", "ok");
|
|
44689
|
-
await (0, import_promises17.mkdir)((0,
|
|
45095
|
+
await (0, import_promises17.mkdir)((0, import_node_path69.join)((0, import_node_os15.homedir)(), ".verity"), { recursive: true });
|
|
44690
45096
|
await repoStep(ui, detectProject());
|
|
44691
45097
|
const previous = await readSetupState();
|
|
44692
|
-
const setUpBefore = (0,
|
|
45098
|
+
const setUpBefore = (0, import_node_fs80.existsSync)(projectPath(STANDARD_FILE));
|
|
44693
45099
|
const answers = await askSetupQuestions(defaultsOnly, previous, { moments: givenMoments, telemetry: givenTelemetry });
|
|
44694
45100
|
trace.mark("questions", "ok", givenMoments || givenTelemetry !== void 0 || profileAnswer || standardAnswer ? "asked" : "defaults");
|
|
44695
45101
|
const plan = planMoments(answers.moments, { given: givenMoments !== void 0, defaultsOnly });
|
|
@@ -44735,11 +45141,11 @@ async function runInit(program2, opts) {
|
|
|
44735
45141
|
}
|
|
44736
45142
|
}
|
|
44737
45143
|
function registerInitCommand(program2) {
|
|
44738
|
-
program2.command("init").alias("setup").description("Set up Verity in this project: sign in, telemetry, and the Standard; every other choice is a stated default").option("--force", "Reinstall the skills even when they are up to date (hooks are always reconciled)").option("-y, --yes", "Ask nothing: skip sign-in unless already signed in, and send the profile only with --profile send").option("--profile <send|skip>", "Answer the repo-profile question without asking (the plugin asks in the session)").option("--standard <use|new>", "When the team already has a Standard: use it, or create a new one (the plugin asks in the session; unattended runs use it)").option("--no-setup", "Ignored: init no longer hands off to /verity-setup (kept for old scripts)").option("--plugin-mode", "The Claude Code plugin owns the skills and hooks: install neither, and remove any this project already has").option("--no-plugin", "Ignore any Claude Code plugin here and wire this project's own skills and hooks").option("--no-adopt", "Don't use this repository's Standard from the service; build a new one").option("--moments <list>", 'Set when Verity reviews without the default: stop,pre-commit,pre-push \u2014 or "none"').option("--intensity <level>", "Ignored: static analysis is Trivy only (kept so older plugin skills keep working)").option("--telemetry <on|off>", "Answer the telemetry question without asking: send cost & usage from this machine, or not").option("--untrack-memory", "Stop tracking the knowledge graph in git (init does not ask)").option("--untrack-state", "Untrack committed Verity state without asking (a terminal run asks when it finds some)").action((opts) => runInit(program2, opts));
|
|
45144
|
+
program2.command("init").alias("setup").description("Set up Verity in this project: sign in, telemetry, and the Standard; every other choice is a stated default").option("--force", "Reinstall the skills even when they are up to date (hooks are always reconciled)").option("-y, --yes", "Ask nothing: skip sign-in unless already signed in, and send the profile only with --profile send").option("--profile <send|skip>", "Answer the repo-profile question without asking (the plugin asks in the session)").option("--standard <use|new>", "When the team already has a Standard: use it, or create a new one (the plugin asks in the session; unattended runs use it)").option("--no-setup", "Ignored: init no longer hands off to /verity-setup (kept for old scripts)").option("--plugin-mode", "The Claude Code plugin owns the skills and hooks: install neither, and remove any this project already has").option("--no-plugin", "Ignore any Claude Code plugin here and wire this project's own skills and hooks").option("--no-adopt", "Don't use this repository's Standard from the service; build a new one").option("--moments <list>", 'Set when Verity reviews without the default: stop,pre-commit,pre-push \u2014 or "none"').option("--intensity <level>", "Ignored: static analysis is Trivy only (kept so older plugin skills keep working)").option("--telemetry <on|off>", "Answer the telemetry question without asking: send cost & usage from this machine, or not").option("--untrack-memory", "Stop tracking the knowledge graph in git (init does not ask)").option("--untrack-standard", "Stop tracking .verity/standard.yaml in git: Verity keeps it on each machine (init does not ask)").option("--untrack-state", "Untrack committed Verity state without asking (a terminal run asks when it finds some)").action((opts) => runInit(program2, opts));
|
|
44739
45145
|
}
|
|
44740
45146
|
|
|
44741
45147
|
// src/commands/doctor.ts
|
|
44742
|
-
var
|
|
45148
|
+
var import_node_fs81 = require("node:fs");
|
|
44743
45149
|
var LEGACY_STANDARD_FILE = ".gate/standard.yaml";
|
|
44744
45150
|
async function buildReport() {
|
|
44745
45151
|
const prereqs = await checkPrereqs({ install: false });
|
|
@@ -44749,11 +45155,11 @@ async function buildReport() {
|
|
|
44749
45155
|
const provenance = cliProvenance();
|
|
44750
45156
|
const telemetry = await checkTelemetry();
|
|
44751
45157
|
const artifacts = {
|
|
44752
|
-
standard: (0,
|
|
45158
|
+
standard: (0, import_node_fs81.existsSync)(projectPath(STANDARD_FILE)),
|
|
44753
45159
|
// The migration's own answer, not a bare existsSync: /verity:init skips a
|
|
44754
45160
|
// question on this, so it must be true only when init will carry the file.
|
|
44755
45161
|
legacyStandard: hasLegacyStandard(repoRoot()),
|
|
44756
|
-
verityMd: (0,
|
|
45162
|
+
verityMd: (0, import_node_fs81.existsSync)(projectPath(VERITY_MD_FILE))
|
|
44757
45163
|
};
|
|
44758
45164
|
const next = [];
|
|
44759
45165
|
for (const c of prereqs.checks) {
|
|
@@ -44764,17 +45170,23 @@ async function buildReport() {
|
|
|
44764
45170
|
if (legacyOnly) {
|
|
44765
45171
|
next.push(`Run "verity init" \u2014 it moves the old GATE.md install, with its Standard (${LEGACY_STANDARD_FILE}), to .verity/.`);
|
|
44766
45172
|
}
|
|
45173
|
+
const standard = { tracked: committedStandardFile(), version: state?.standardVersion ?? null };
|
|
44767
45174
|
const missing = [
|
|
44768
45175
|
!artifacts.standard && !legacyOnly && ".verity/standard.yaml",
|
|
44769
45176
|
!artifacts.verityMd && !legacyOnly && "VERITY.md"
|
|
44770
45177
|
].filter((x) => !!x);
|
|
44771
|
-
if (
|
|
44772
|
-
next.push(
|
|
45178
|
+
if (!artifacts.standard && !legacyOnly) {
|
|
45179
|
+
next.push(standard.version !== null ? `Run "verity standard pull" \u2014 the team's Standard (v${standard.version}) is on the service, and this machine has no copy of it.` : `Run "verity init" \u2014 it writes the team's Standard from the service, or builds one when the team has none.`);
|
|
44773
45180
|
} else if (missing.length > 0) {
|
|
44774
45181
|
next.push(
|
|
44775
45182
|
`Missing ${missing.join(" and ")}. Run "verity standard synthesize --force" to regenerate \u2014 note that replaces the Standard.`
|
|
44776
45183
|
);
|
|
44777
45184
|
}
|
|
45185
|
+
if (standard.tracked) {
|
|
45186
|
+
next.push(
|
|
45187
|
+
'.verity/standard.yaml is tracked in git. Verity keeps it on each machine now, and reviews read the Standard on the service. Run "verity standard untrack" to stop tracking it (the file stays on disk; teammates get it back with "verity standard pull").'
|
|
45188
|
+
);
|
|
45189
|
+
}
|
|
44778
45190
|
const noAnalysisMoment = !hooks.stop && hooks.guardOn.length === 0;
|
|
44779
45191
|
const configRead = readProjectConfig();
|
|
44780
45192
|
if (configRead.refused) next.push(configRefusalMessage(configRead.refused));
|
|
@@ -44852,6 +45264,7 @@ async function buildReport() {
|
|
|
44852
45264
|
artifacts,
|
|
44853
45265
|
memory: memory2,
|
|
44854
45266
|
trackedState,
|
|
45267
|
+
standard,
|
|
44855
45268
|
next
|
|
44856
45269
|
};
|
|
44857
45270
|
}
|
|
@@ -44886,11 +45299,14 @@ function registerDoctorCommand(program2) {
|
|
|
44886
45299
|
printInfo(` Git-moment gate: ${report.hooks.guardOn.length ? report.hooks.guardOn.join(", ") : "off"}`);
|
|
44887
45300
|
{
|
|
44888
45301
|
const cfg = readProjectConfig();
|
|
44889
|
-
const
|
|
45302
|
+
const setting = formalSetting(cfg);
|
|
45303
|
+
const formal = setting.state === "push";
|
|
44890
45304
|
const tc = formal ? findToolchain() : null;
|
|
44891
45305
|
const lean = tc ? "\u2713" : installProgressLine() ?? "MISSING \u2014 verity lean install";
|
|
44892
|
-
|
|
44893
|
-
|
|
45306
|
+
const how = setting.source === "default" ? " by default" : setting.source === "env" ? " (VERITY_GIT_MOMENT_FORMAL)" : "";
|
|
45307
|
+
printInfo(` Formal verification (push): ${formal ? `on${how}, Lean ${lean} (ranking, model writing and replay run on the Verity service with your login)` : `off${how}`}`);
|
|
45308
|
+
if (cfg.formal_off_refused && formal) printWarn(` ${formalOffRefusalMessage(cfg.formal_off_refused)}`);
|
|
45309
|
+
if (cfg.formal_off_unverified && !formal && setting.source === "config") printWarn(` ${formalOffUnverifiedNote()}`);
|
|
44894
45310
|
}
|
|
44895
45311
|
printInfo(` Infra (intent/baseline/compact/session-end): ${[report.hooks.intent, report.hooks.baseline, report.hooks.compact, report.hooks.sessionEnd].filter(Boolean).length}/4`);
|
|
44896
45312
|
printInfo(
|
|
@@ -44899,7 +45315,7 @@ function registerDoctorCommand(program2) {
|
|
|
44899
45315
|
if (process.platform === "win32") printWarn(WINDOWS_STATIC_NOTE);
|
|
44900
45316
|
else printInfo("Static analysis: Trivy (dependencies, malicious packages, secrets)");
|
|
44901
45317
|
printInfo("Artifacts:");
|
|
44902
|
-
printInfo(` .verity/standard.yaml: ${report.artifacts.standard ? "\u2713" : report.artifacts.legacyStandard ? `not yet (an old GATE.md Standard is at ${LEGACY_STANDARD_FILE}; verity init moves it)` : "missing"}`);
|
|
45318
|
+
printInfo(` .verity/standard.yaml: ${report.artifacts.standard ? report.standard.tracked ? "\u2713 (tracked in git \u2014 Verity keeps it machine-local now: verity standard untrack)" : "\u2713" : report.artifacts.legacyStandard ? `not yet (an old GATE.md Standard is at ${LEGACY_STANDARD_FILE}; verity init moves it)` : report.standard.version !== null ? `not on this machine (the team's v${report.standard.version} is on the service: verity standard pull)` : "missing"}`);
|
|
44903
45319
|
printInfo(` VERITY.md: ${report.artifacts.verityMd ? "\u2713" : "missing"}`);
|
|
44904
45320
|
printInfo(
|
|
44905
45321
|
` .verity/memory/: ${report.memory.trackedFiles > 0 ? `${report.memory.trackedFiles} file(s) tracked in git \u2014 they appear in every diff` : report.memory.posture === "ignored" ? "machine-local \u2713" : "not tracked"}`
|
|
@@ -44916,8 +45332,8 @@ function registerDoctorCommand(program2) {
|
|
|
44916
45332
|
}
|
|
44917
45333
|
|
|
44918
45334
|
// src/commands/uninstall.ts
|
|
44919
|
-
var
|
|
44920
|
-
var
|
|
45335
|
+
var import_node_fs82 = require("node:fs");
|
|
45336
|
+
var import_node_path70 = require("node:path");
|
|
44921
45337
|
function registerUninstallCommand(program2) {
|
|
44922
45338
|
program2.command("uninstall").description("Remove Verity from this project (skills, hooks, .verity/, VERITY.md)").option("--dry-run", "Show what would be removed without doing it").option("--purge-global", "Also remove ~/.verity/ (deletes saved tokens \u2014 reconnect requires re-registration)").option("--keep-verity-md", "Keep the project root VERITY.md file").action(async (opts) => {
|
|
44923
45339
|
const dryRun = opts.dryRun ?? false;
|
|
@@ -44926,11 +45342,11 @@ function registerUninstallCommand(program2) {
|
|
|
44926
45342
|
const actions = [];
|
|
44927
45343
|
const skillsRoot = projectPath(".claude/skills");
|
|
44928
45344
|
for (const name2 of PROJECT_SKILL_NAMES) {
|
|
44929
|
-
const dir = (0,
|
|
44930
|
-
if ((0,
|
|
45345
|
+
const dir = (0, import_node_path70.join)(skillsRoot, name2);
|
|
45346
|
+
if ((0, import_node_fs82.existsSync)(dir)) {
|
|
44931
45347
|
actions.push({
|
|
44932
45348
|
label: `Remove .claude/skills/${name2}/`,
|
|
44933
|
-
apply: () => (0,
|
|
45349
|
+
apply: () => (0, import_node_fs82.rmSync)(dir, { recursive: true, force: true })
|
|
44934
45350
|
});
|
|
44935
45351
|
}
|
|
44936
45352
|
}
|
|
@@ -44944,24 +45360,24 @@ function registerUninstallCommand(program2) {
|
|
|
44944
45360
|
});
|
|
44945
45361
|
}
|
|
44946
45362
|
const verityDir = projectPath(VERITY_DIR);
|
|
44947
|
-
if ((0,
|
|
45363
|
+
if ((0, import_node_fs82.existsSync)(verityDir)) {
|
|
44948
45364
|
actions.push({
|
|
44949
45365
|
label: `Remove ${VERITY_DIR}/`,
|
|
44950
|
-
apply: () => (0,
|
|
45366
|
+
apply: () => (0, import_node_fs82.rmSync)(verityDir, { recursive: true, force: true })
|
|
44951
45367
|
});
|
|
44952
45368
|
}
|
|
44953
45369
|
if (!keepVerityMd) {
|
|
44954
45370
|
const verityMd = projectPath(VERITY_MD_FILE);
|
|
44955
|
-
if ((0,
|
|
45371
|
+
if ((0, import_node_fs82.existsSync)(verityMd)) {
|
|
44956
45372
|
actions.push({
|
|
44957
45373
|
label: `Remove ${VERITY_MD_FILE}`,
|
|
44958
|
-
apply: () => (0,
|
|
45374
|
+
apply: () => (0, import_node_fs82.rmSync)(verityMd, { force: true })
|
|
44959
45375
|
});
|
|
44960
45376
|
}
|
|
44961
45377
|
}
|
|
44962
45378
|
const cleanupEmptyDir = (path) => {
|
|
44963
|
-
if ((0,
|
|
44964
|
-
(0,
|
|
45379
|
+
if ((0, import_node_fs82.existsSync)(path) && (0, import_node_fs82.statSync)(path).isDirectory() && (0, import_node_fs82.readdirSync)(path).length === 0) {
|
|
45380
|
+
(0, import_node_fs82.rmdirSync)(path);
|
|
44965
45381
|
}
|
|
44966
45382
|
};
|
|
44967
45383
|
actions.push({
|
|
@@ -44972,11 +45388,11 @@ function registerUninstallCommand(program2) {
|
|
|
44972
45388
|
}
|
|
44973
45389
|
});
|
|
44974
45390
|
const home = process.env.HOME ?? "";
|
|
44975
|
-
const globalVerityDir = (0,
|
|
44976
|
-
if (purgeGlobal && (0,
|
|
45391
|
+
const globalVerityDir = (0, import_node_path70.join)(home, ".verity");
|
|
45392
|
+
if (purgeGlobal && (0, import_node_fs82.existsSync)(globalVerityDir)) {
|
|
44977
45393
|
actions.push({
|
|
44978
45394
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
44979
|
-
apply: () => (0,
|
|
45395
|
+
apply: () => (0, import_node_fs82.rmSync)(globalVerityDir, { recursive: true, force: true })
|
|
44980
45396
|
});
|
|
44981
45397
|
}
|
|
44982
45398
|
if (actions.length === 0) {
|
|
@@ -45195,8 +45611,8 @@ function registerTaskCommands(program2) {
|
|
|
45195
45611
|
}
|
|
45196
45612
|
|
|
45197
45613
|
// src/commands/reset.ts
|
|
45198
|
-
var
|
|
45199
|
-
var
|
|
45614
|
+
var import_node_fs83 = require("node:fs");
|
|
45615
|
+
var import_node_path71 = require("node:path");
|
|
45200
45616
|
function registerResetCommand(program2) {
|
|
45201
45617
|
program2.command("reset").description("Close the current task and clear transient state").option("--keep-task", "Only purge caches; leave the current task open").option("--all", "Also purge diagnostic logs (.verity/.logs/)").action(async (opts) => {
|
|
45202
45618
|
const globals = program2.opts();
|
|
@@ -45236,18 +45652,18 @@ function registerResetCommand(program2) {
|
|
|
45236
45652
|
} catch {
|
|
45237
45653
|
}
|
|
45238
45654
|
}
|
|
45239
|
-
const purged = purgeVerityDir((0,
|
|
45655
|
+
const purged = purgeVerityDir((0, import_node_path71.basename)(CACHE_DIR), (name2) => name2.startsWith("pending-"));
|
|
45240
45656
|
if (purged === null) printError(`Did not purge ${CACHE_DIR}: it is not a directory inside ${VERITY_DIR}.`);
|
|
45241
45657
|
const stateDir2 = projectPath(VERITY_DIR);
|
|
45242
45658
|
const filesToClear = [
|
|
45243
|
-
(0,
|
|
45244
|
-
(0,
|
|
45245
|
-
(0,
|
|
45659
|
+
(0, import_node_path71.basename)(INTENT_FILE),
|
|
45660
|
+
(0, import_node_path71.basename)(HASH_FILE),
|
|
45661
|
+
(0, import_node_path71.basename)(BASELINE_SHA_FILE),
|
|
45246
45662
|
".iteration-count",
|
|
45247
45663
|
".last-analysis"
|
|
45248
45664
|
];
|
|
45249
45665
|
for (const name2 of filesToClear) {
|
|
45250
|
-
if (lstatOrNull((0,
|
|
45666
|
+
if (lstatOrNull((0, import_node_path71.join)(stateDir2, name2)) && !replaceInRoot(stateDir2, name2, "")) {
|
|
45251
45667
|
printError(`Did not clear ${VERITY_DIR}/${name2}: it is not a regular file inside ${VERITY_DIR}.`);
|
|
45252
45668
|
}
|
|
45253
45669
|
}
|
|
@@ -45262,29 +45678,29 @@ function registerResetCommand(program2) {
|
|
|
45262
45678
|
}
|
|
45263
45679
|
function lstatOrNull(path) {
|
|
45264
45680
|
try {
|
|
45265
|
-
return (0,
|
|
45681
|
+
return (0, import_node_fs83.lstatSync)(path);
|
|
45266
45682
|
} catch {
|
|
45267
45683
|
return null;
|
|
45268
45684
|
}
|
|
45269
45685
|
}
|
|
45270
45686
|
function purgeVerityDir(child, select) {
|
|
45271
45687
|
const verityDir = projectPath(VERITY_DIR);
|
|
45272
|
-
const dir = (0,
|
|
45688
|
+
const dir = (0, import_node_path71.join)(verityDir, child);
|
|
45273
45689
|
const parent = lstatOrNull(verityDir);
|
|
45274
45690
|
const st = lstatOrNull(dir);
|
|
45275
45691
|
if (!st) return 0;
|
|
45276
45692
|
if (!parent || parent.isSymbolicLink() || !parent.isDirectory()) return null;
|
|
45277
45693
|
if (st.isSymbolicLink() || !st.isDirectory()) return null;
|
|
45278
45694
|
try {
|
|
45279
|
-
if ((0,
|
|
45695
|
+
if ((0, import_node_fs83.realpathSync)(dir) !== (0, import_node_path71.join)((0, import_node_fs83.realpathSync)(verityDir), child)) return null;
|
|
45280
45696
|
} catch {
|
|
45281
45697
|
return null;
|
|
45282
45698
|
}
|
|
45283
45699
|
let removed = 0;
|
|
45284
|
-
for (const entry of (0,
|
|
45700
|
+
for (const entry of (0, import_node_fs83.readdirSync)(dir, { withFileTypes: true })) {
|
|
45285
45701
|
if (entry.isDirectory() || !select(entry.name)) continue;
|
|
45286
45702
|
try {
|
|
45287
|
-
(0,
|
|
45703
|
+
(0, import_node_fs83.unlinkSync)((0, import_node_path71.join)(dir, entry.name));
|
|
45288
45704
|
removed++;
|
|
45289
45705
|
} catch {
|
|
45290
45706
|
}
|
|
@@ -45293,7 +45709,7 @@ function purgeVerityDir(child, select) {
|
|
|
45293
45709
|
}
|
|
45294
45710
|
|
|
45295
45711
|
// src/commands/reflect.ts
|
|
45296
|
-
var
|
|
45712
|
+
var import_node_fs84 = require("node:fs");
|
|
45297
45713
|
|
|
45298
45714
|
// src/lib/reflection-globs.ts
|
|
45299
45715
|
var MAX_GLOBS = 6;
|
|
@@ -45331,7 +45747,7 @@ async function writeNodeToDisk(args2) {
|
|
|
45331
45747
|
{ treePaths: listTrackedFiles(), recordBaseline: false }
|
|
45332
45748
|
);
|
|
45333
45749
|
if (written === 0) return false;
|
|
45334
|
-
return (0,
|
|
45750
|
+
return (0, import_node_fs84.existsSync)(projectPath(`${VERITY_DIR}/memory/${args2.filePath}`));
|
|
45335
45751
|
} catch {
|
|
45336
45752
|
return false;
|
|
45337
45753
|
}
|
|
@@ -45768,7 +46184,7 @@ function registerRunCommand(program2) {
|
|
|
45768
46184
|
}
|
|
45769
46185
|
|
|
45770
46186
|
// src/commands/telemetry.ts
|
|
45771
|
-
var
|
|
46187
|
+
var import_node_fs85 = require("node:fs");
|
|
45772
46188
|
var SCOPE = "every Claude Code session on this machine";
|
|
45773
46189
|
function declineHeaders(why) {
|
|
45774
46190
|
process.stderr.write(`Verity telemetry is off here: ${why} Nothing is exported from this session.
|
|
@@ -45776,7 +46192,7 @@ function declineHeaders(why) {
|
|
|
45776
46192
|
process.exitCode = 1;
|
|
45777
46193
|
}
|
|
45778
46194
|
async function recordTelemetryChoice(choice) {
|
|
45779
|
-
if (!(0,
|
|
46195
|
+
if (!(0, import_node_fs85.existsSync)(projectPath(SETUP_STATE_FILE))) return;
|
|
45780
46196
|
try {
|
|
45781
46197
|
if ((await readSetupState())?.telemetry === choice) return;
|
|
45782
46198
|
await writeSetupState({ telemetry: choice });
|
|
@@ -45884,12 +46300,12 @@ function registerTelemetryCommands(program2) {
|
|
|
45884
46300
|
}
|
|
45885
46301
|
|
|
45886
46302
|
// src/commands/prove.ts
|
|
45887
|
-
var
|
|
45888
|
-
var
|
|
46303
|
+
var import_node_fs87 = require("node:fs");
|
|
46304
|
+
var import_node_path73 = require("node:path");
|
|
45889
46305
|
|
|
45890
46306
|
// src/lib/prove/on-demand-run.ts
|
|
45891
|
-
var
|
|
45892
|
-
var
|
|
46307
|
+
var import_node_fs86 = require("node:fs");
|
|
46308
|
+
var import_node_path72 = require("node:path");
|
|
45893
46309
|
var ON_DEMAND_RUN = `${PROOFS_DIR}/.results/.formal-run.json`;
|
|
45894
46310
|
var ON_DEMAND_RUN_REUSE_MS = 18 * 6e4;
|
|
45895
46311
|
function isLocalState2(root) {
|
|
@@ -45911,7 +46327,7 @@ function forgetOnDemandRun(root) {
|
|
|
45911
46327
|
setFormalRun(null);
|
|
45912
46328
|
if (!isLocalState2(root)) return;
|
|
45913
46329
|
try {
|
|
45914
|
-
(0,
|
|
46330
|
+
(0, import_node_fs86.unlinkSync)((0, import_node_path72.join)(root, ON_DEMAND_RUN));
|
|
45915
46331
|
} catch {
|
|
45916
46332
|
}
|
|
45917
46333
|
}
|
|
@@ -46088,7 +46504,7 @@ function registerProveCommand(program2) {
|
|
|
46088
46504
|
process.exit(2);
|
|
46089
46505
|
}
|
|
46090
46506
|
const limit = Math.max(1, Math.min(50, Number(opts.limit) || 10));
|
|
46091
|
-
let signals = collectRiskSignals(root, { since: opts.since, limit, paths: paths.map((p) => (0,
|
|
46507
|
+
let signals = collectRiskSignals(root, { since: opts.since, limit, paths: paths.map((p) => (0, import_node_path73.relative)(root, (0, import_node_path73.resolve)(p)) || ".") });
|
|
46092
46508
|
if (opts.hint && paths.length === 0) {
|
|
46093
46509
|
const hit = hintMatches(root, opts.hint);
|
|
46094
46510
|
if (hit.files.length > 0) {
|
|
@@ -46142,7 +46558,7 @@ function registerProveCommand(program2) {
|
|
|
46142
46558
|
});
|
|
46143
46559
|
prove.command("check [model]").description("Elaborate a model (or every model) with the local Lean toolchain and report each property").option("--timeout <ms>", "Per-model timeout in ms", "120000").option("--json", "Machine-readable output").action((model, opts) => {
|
|
46144
46560
|
const root = repoRoot();
|
|
46145
|
-
if (!(0,
|
|
46561
|
+
if (!(0, import_node_fs87.existsSync)((0, import_node_path73.join)(root, PROOFS_DIR, "lakefile.toml"))) {
|
|
46146
46562
|
printError(`No ${PROOFS_DIR}/ project here. Run \`verity prove init\` first.`);
|
|
46147
46563
|
process.exit(2);
|
|
46148
46564
|
}
|
|
@@ -46166,7 +46582,7 @@ ${build.stderr.split("\n").filter((l) => !l.startsWith("trace:")).slice(0, 20).j
|
|
|
46166
46582
|
const reports = [];
|
|
46167
46583
|
for (const f of files) {
|
|
46168
46584
|
const report = checkModel(tc, root, f, { timeoutMs: Math.max(1e3, Number(opts.timeout) || 12e4) });
|
|
46169
|
-
report.file = (0,
|
|
46585
|
+
report.file = (0, import_node_path73.relative)(root, f);
|
|
46170
46586
|
reports.push(report);
|
|
46171
46587
|
try {
|
|
46172
46588
|
writeResult(root, report);
|
|
@@ -46204,7 +46620,7 @@ ${build.stderr.split("\n").filter((l) => !l.startsWith("trace:")).slice(0, 20).j
|
|
|
46204
46620
|
printError("Not logged in \u2014 replays run on the Verity service. Run `verity login` first.");
|
|
46205
46621
|
process.exit(2);
|
|
46206
46622
|
}
|
|
46207
|
-
if (!(0,
|
|
46623
|
+
if (!(0, import_node_fs87.existsSync)((0, import_node_path73.join)(root, PROOFS_DIR, "lakefile.toml"))) {
|
|
46208
46624
|
printError(`No ${PROOFS_DIR}/ project here. Run \`verity prove init\` first.`);
|
|
46209
46625
|
process.exit(2);
|
|
46210
46626
|
}
|
|
@@ -46243,7 +46659,7 @@ ${report.error ?? ""}`);
|
|
|
46243
46659
|
process.exit(2);
|
|
46244
46660
|
}
|
|
46245
46661
|
}
|
|
46246
|
-
const modelSource = readRegularFileInRoot(root, (0,
|
|
46662
|
+
const modelSource = readRegularFileInRoot(root, (0, import_node_path73.relative)(root, file), 512 * 1024);
|
|
46247
46663
|
if (!opts.json) printInfo(`replaying ${targets.length} counterexample(s) of ${model} in network-less containers (${Math.min(targets.length, REPLAY_CONCURRENCY)} at a time)\u2026`);
|
|
46248
46664
|
const outcomes = await mapPool(targets, REPLAY_CONCURRENCY, async (p) => {
|
|
46249
46665
|
const brief = buildReplayBrief(root, report, p, modelSource.ok ? modelSource.content : "");
|
|
@@ -46264,7 +46680,7 @@ ${report.error ?? ""}`);
|
|
|
46264
46680
|
});
|
|
46265
46681
|
prove.command("auto [files...]").description("The formal phase the pre-push guard runs: select one risky symbol among changed files, generate a model, check it, replay counterexamples (default files: the commits ahead of upstream)").option("--deadline <ms>", "Budget for the whole phase", "170000").option("--json", "Machine-readable output").action(async (paths, opts) => {
|
|
46266
46682
|
const root = repoRoot();
|
|
46267
|
-
let files = paths.map((p) => (0,
|
|
46683
|
+
let files = paths.map((p) => (0, import_node_path73.relative)(root, (0, import_node_path73.resolve)(p)));
|
|
46268
46684
|
if (files.length === 0) {
|
|
46269
46685
|
const ahead = runGitSync(root, ["diff", "--name-only", "@{upstream}...HEAD"]);
|
|
46270
46686
|
const fallback = ahead.ok ? ahead : runGitSync(root, ["diff", "--name-only", "HEAD~1..HEAD"]);
|
|
@@ -46338,7 +46754,7 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
|
|
|
46338
46754
|
let revise;
|
|
46339
46755
|
if (opts.revise) {
|
|
46340
46756
|
const existing = resolveModelFile(root, opts.revise);
|
|
46341
|
-
const src = existing ? readRegularFileInRoot(root, (0,
|
|
46757
|
+
const src = existing ? readRegularFileInRoot(root, (0, import_node_path73.relative)(root, existing), 64 * 1024) : null;
|
|
46342
46758
|
if (!src || !src.ok || !opts.note) {
|
|
46343
46759
|
printError("--revise needs an existing model under Models/ and --note - with what the replay showed on stdin");
|
|
46344
46760
|
process.exit(2);
|
|
@@ -46387,8 +46803,8 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
|
|
|
46387
46803
|
});
|
|
46388
46804
|
prove.command("waive <file>").description("Dismiss the remembered formal finding(s) on a file for its current bytes \u2014 the accepted-risk path for a formal block").requiredOption("--reason <text>", "The human disposition this records (reviewer finding, ADR, \u2026)").action((file, opts) => {
|
|
46389
46805
|
const root = repoRoot();
|
|
46390
|
-
const rel0 = (0,
|
|
46391
|
-
const rel = rel0.startsWith("..") || (0,
|
|
46806
|
+
const rel0 = (0, import_node_path73.relative)(root, (0, import_node_path73.isAbsolute)(file) ? file : (0, import_node_path73.join)(root, file)).replace(/\\/g, "/");
|
|
46807
|
+
const rel = rel0.startsWith("..") || (0, import_node_path73.isAbsolute)(rel0) ? null : rel0;
|
|
46392
46808
|
if (!rel) {
|
|
46393
46809
|
printError(`${file} is not inside this repository`);
|
|
46394
46810
|
process.exit(2);
|
|
@@ -46404,8 +46820,8 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
|
|
|
46404
46820
|
});
|
|
46405
46821
|
prove.command("hash <file>").description("Print the sha256 of a file, for a model header (Verity.model \u2026 sha256). Path is REPO-relative, as in the header").action((file) => {
|
|
46406
46822
|
const root = repoRoot();
|
|
46407
|
-
const rel = (0,
|
|
46408
|
-
const digest = rel.startsWith("..") || (0,
|
|
46823
|
+
const rel = (0, import_node_path73.relative)(root, (0, import_node_path73.isAbsolute)(file) ? file : (0, import_node_path73.join)(root, file));
|
|
46824
|
+
const digest = rel.startsWith("..") || (0, import_node_path73.isAbsolute)(rel) ? null : sha256InRoot(root, rel);
|
|
46409
46825
|
if (!digest) {
|
|
46410
46826
|
printError(`Cannot hash ${file}: it must be a regular file inside this repository (not a symlink)`);
|
|
46411
46827
|
process.exit(2);
|
|
@@ -46439,10 +46855,10 @@ function refreshScaffold(root) {
|
|
|
46439
46855
|
}
|
|
46440
46856
|
|
|
46441
46857
|
// src/commands/lean.ts
|
|
46442
|
-
var
|
|
46858
|
+
var import_node_fs88 = require("node:fs");
|
|
46443
46859
|
var import_node_child_process24 = require("node:child_process");
|
|
46444
46860
|
var import_node_os16 = require("node:os");
|
|
46445
|
-
var
|
|
46861
|
+
var import_node_path74 = require("node:path");
|
|
46446
46862
|
function registerLeanCommand(program2) {
|
|
46447
46863
|
const lean = program2.command("lean").description("The Lean 4 toolchain formal verification needs (managed download, pinned by this CLI)");
|
|
46448
46864
|
lean.command("status").option("--json", "Machine-readable output").description("Which toolchain would run, and whether it matches the pinned version").action((opts) => {
|
|
@@ -46461,7 +46877,7 @@ function registerLeanCommand(program2) {
|
|
|
46461
46877
|
const bg = readInstallState();
|
|
46462
46878
|
const background = bg ? { ...bg, running: bg.state === "running" && installRunning() } : null;
|
|
46463
46879
|
if (opts.json) {
|
|
46464
|
-
printJson({ pinned: LEAN_TOOLCHAIN, found: tc?.lake ?? null, version, matches_pin: matches, managed_dir: managed, managed_installed: (0,
|
|
46880
|
+
printJson({ pinned: LEAN_TOOLCHAIN, found: tc?.lake ?? null, version, matches_pin: matches, managed_dir: managed, managed_installed: (0, import_node_fs88.existsSync)((0, import_node_path74.join)(managed, "bin")), asset: leanAssetName(), background });
|
|
46465
46881
|
return;
|
|
46466
46882
|
}
|
|
46467
46883
|
printInfo(`pinned: ${LEAN_TOOLCHAIN}`);
|
|
@@ -46482,7 +46898,7 @@ function registerLeanCommand(program2) {
|
|
|
46482
46898
|
process.exit(2);
|
|
46483
46899
|
}
|
|
46484
46900
|
const dir = pinnedVersionDir();
|
|
46485
|
-
if ((0,
|
|
46901
|
+
if ((0, import_node_fs88.existsSync)((0, import_node_path74.join)(dir, "bin", "lake")) && !opts.force) {
|
|
46486
46902
|
printInfo(`already installed at ${dir}`);
|
|
46487
46903
|
return;
|
|
46488
46904
|
}
|
|
@@ -46518,20 +46934,20 @@ function registerLeanCommand(program2) {
|
|
|
46518
46934
|
});
|
|
46519
46935
|
lean.command("remove").description("Delete the Verity-managed toolchain for the pinned version").action(() => {
|
|
46520
46936
|
const dir = pinnedVersionDir();
|
|
46521
|
-
if (!(0,
|
|
46937
|
+
if (!(0, import_node_fs88.existsSync)(dir)) {
|
|
46522
46938
|
printInfo("nothing to remove");
|
|
46523
46939
|
return;
|
|
46524
46940
|
}
|
|
46525
|
-
(0,
|
|
46941
|
+
(0, import_node_fs88.rmSync)(dir, { recursive: true, force: true });
|
|
46526
46942
|
printInfo(`removed ${dir}`);
|
|
46527
46943
|
});
|
|
46528
46944
|
}
|
|
46529
46945
|
|
|
46530
46946
|
// src/cli.ts
|
|
46531
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.35.
|
|
46947
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.35.5").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) => {
|
|
46532
46948
|
const isTelemetryHelper = actionCommand.name() === "headers" && actionCommand.parent?.name() === "telemetry";
|
|
46533
46949
|
if (!isTelemetryHelper) {
|
|
46534
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.35.
|
|
46950
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.35.5");
|
|
46535
46951
|
}
|
|
46536
46952
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
46537
46953
|
try {
|