@codacy/verity-cli 0.35.3-experimental.f980d82 → 0.35.4
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 +68 -0
- package/bin/verity.js +686 -245
- 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,8 +14732,10 @@ var SECURITY_PATTERNS = [
|
|
|
14732
14732
|
/(^|\/)pom\.xml$/,
|
|
14733
14733
|
/(^|\/)gradle\.lockfile$/
|
|
14734
14734
|
];
|
|
14735
|
-
var
|
|
14736
|
-
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`;
|
|
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";
|
|
14739
14741
|
var GITHUB_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
|
|
@@ -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.4" : "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",
|
|
@@ -19207,13 +19306,21 @@ function readConfigFile(path) {
|
|
|
19207
19306
|
git_moments: [...new Set(moments)],
|
|
19208
19307
|
...source2 ? { git_moments_source: source2 } : {},
|
|
19209
19308
|
...raw.formal === "push" || raw.formal === "off" ? { formal: raw.formal } : {},
|
|
19210
|
-
...raw.turn_review === "on" || raw.turn_review === "off" ? { turn_review: raw.turn_review } : {}
|
|
19309
|
+
...raw.turn_review === "on" || raw.turn_review === "off" ? { turn_review: raw.turn_review } : {},
|
|
19310
|
+
...raw.verbose === "on" || raw.verbose === "off" ? { verbose: raw.verbose } : {}
|
|
19211
19311
|
}
|
|
19212
19312
|
};
|
|
19213
19313
|
} catch {
|
|
19214
19314
|
return { cfg: DEFAULTS };
|
|
19215
19315
|
}
|
|
19216
19316
|
}
|
|
19317
|
+
function readVerbose() {
|
|
19318
|
+
try {
|
|
19319
|
+
return readProjectConfigRaw().verbose === "on";
|
|
19320
|
+
} catch {
|
|
19321
|
+
return false;
|
|
19322
|
+
}
|
|
19323
|
+
}
|
|
19217
19324
|
function configRefusalMessage(reason) {
|
|
19218
19325
|
switch (reason) {
|
|
19219
19326
|
case "link":
|
|
@@ -19285,12 +19392,13 @@ function formalRefusalMessage(reason) {
|
|
|
19285
19392
|
}
|
|
19286
19393
|
}
|
|
19287
19394
|
function writeProjectConfig(patch) {
|
|
19288
|
-
const { git_moments, git_moments_source, formal, turn_review } = readProjectConfigRaw();
|
|
19395
|
+
const { git_moments, git_moments_source, formal, turn_review, verbose } = readProjectConfigRaw();
|
|
19289
19396
|
const next = {
|
|
19290
19397
|
git_moments,
|
|
19291
19398
|
...git_moments_source ? { git_moments_source } : {},
|
|
19292
19399
|
...formal ? { formal } : {},
|
|
19293
19400
|
...turn_review ? { turn_review } : {},
|
|
19401
|
+
...verbose ? { verbose } : {},
|
|
19294
19402
|
...patch
|
|
19295
19403
|
};
|
|
19296
19404
|
writeRepoFile(PROJECT_CONFIG_FILE, JSON.stringify(next, null, 2) + "\n");
|
|
@@ -21085,13 +21193,15 @@ var import_node_child_process9 = require("node:child_process");
|
|
|
21085
21193
|
var import_node_fs24 = require("node:fs");
|
|
21086
21194
|
var VERITY_GITIGNORE_MARKER = "# Verity \u2014 machine-local state.";
|
|
21087
21195
|
var SETTINGS_LOCAL_IGNORE_ENTRY = ".claude/settings.local.json";
|
|
21196
|
+
var BLOCK_COMMENT = [
|
|
21197
|
+
"# Verity \u2014 machine-local state. Everything in .verity/ is ignored. The Standard",
|
|
21198
|
+
"# is held by the Verity service (verity standard pull writes it here), and the",
|
|
21199
|
+
"# knowledge graph under .verity/memory/ is rebuilt from it. Committing either",
|
|
21200
|
+
"# puts generated files in every diff and pull request."
|
|
21201
|
+
];
|
|
21088
21202
|
var VERITY_GITIGNORE_BLOCK = [
|
|
21089
|
-
|
|
21090
|
-
"# shared standard, which is meant to be committed. The knowledge graph under",
|
|
21091
|
-
"# .verity/memory/ is machine-local too: the service rebuilds it, and committing",
|
|
21092
|
-
"# it puts generated notes in every diff and pull request.",
|
|
21203
|
+
...BLOCK_COMMENT,
|
|
21093
21204
|
".verity/*",
|
|
21094
|
-
"!.verity/standard.yaml",
|
|
21095
21205
|
SETTINGS_LOCAL_IGNORE_ENTRY,
|
|
21096
21206
|
""
|
|
21097
21207
|
].join("\n");
|
|
@@ -21116,9 +21226,11 @@ var SUPERSEDED_MEMORY_LINES = /* @__PURE__ */ new Set([
|
|
|
21116
21226
|
".verity/memory/log.md",
|
|
21117
21227
|
SUPERSEDED_COMMENT
|
|
21118
21228
|
]);
|
|
21119
|
-
|
|
21229
|
+
var SUPERSEDED_STANDARD_LINE = "!.verity/standard.yaml";
|
|
21230
|
+
var OLD_COMMENT_LINES = /* @__PURE__ */ new Set([SUPERSEDED_COMMENT, ...MEMORY_COMMENT]);
|
|
21231
|
+
function isIgnored3(path, opts = {}) {
|
|
21120
21232
|
try {
|
|
21121
|
-
(0, import_node_child_process9.execSync)(`git check-ignore -q -- "${path}"`, { stdio: "pipe" });
|
|
21233
|
+
(0, import_node_child_process9.execSync)(`git check-ignore -q ${opts.noIndex ? "--no-index " : ""}-- "${path}"`, { stdio: "pipe" });
|
|
21122
21234
|
return true;
|
|
21123
21235
|
} catch (err2) {
|
|
21124
21236
|
return err2.status === 1 ? false : null;
|
|
@@ -21126,10 +21238,9 @@ function isIgnored3(path) {
|
|
|
21126
21238
|
}
|
|
21127
21239
|
function semanticsHold() {
|
|
21128
21240
|
const snapshot = isIgnored3(".verity/.snapshot/__probe__");
|
|
21129
|
-
const standard = isIgnored3(".verity/standard.yaml");
|
|
21130
21241
|
const futureState = isIgnored3(".verity/.__probe-future-state__");
|
|
21131
|
-
if (snapshot === null ||
|
|
21132
|
-
return snapshot === true && futureState === true
|
|
21242
|
+
if (snapshot === null || futureState === null) return null;
|
|
21243
|
+
return snapshot === true && futureState === true;
|
|
21133
21244
|
}
|
|
21134
21245
|
function memoryPosture() {
|
|
21135
21246
|
const ignored = isIgnored3(".verity/memory/domain/__probe__.md");
|
|
@@ -21146,6 +21257,22 @@ function committedMemoryFiles() {
|
|
|
21146
21257
|
return [];
|
|
21147
21258
|
}
|
|
21148
21259
|
}
|
|
21260
|
+
var STANDARD_PATH = ".verity/standard.yaml";
|
|
21261
|
+
function standardPosture() {
|
|
21262
|
+
const ignored = isIgnored3(STANDARD_PATH, { noIndex: true });
|
|
21263
|
+
if (ignored === null) return "unknown";
|
|
21264
|
+
return ignored ? "ignored" : "committable";
|
|
21265
|
+
}
|
|
21266
|
+
function committedStandardFile() {
|
|
21267
|
+
try {
|
|
21268
|
+
return (0, import_node_child_process9.execSync)(`git ls-files -z -- ${STANDARD_PATH}`, {
|
|
21269
|
+
encoding: "utf-8",
|
|
21270
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
21271
|
+
}).split("\0").filter(Boolean).length > 0;
|
|
21272
|
+
} catch {
|
|
21273
|
+
return false;
|
|
21274
|
+
}
|
|
21275
|
+
}
|
|
21149
21276
|
var OPT_OUT_COMMENT_LINES = /* @__PURE__ */ new Set([
|
|
21150
21277
|
MEMORY_OPT_OUT_MARKER,
|
|
21151
21278
|
'# Remove these three lines (or run "verity memory untrack") to stop tracking it.'
|
|
@@ -21163,6 +21290,19 @@ function fenceMemoryLines(lines) {
|
|
|
21163
21290
|
}
|
|
21164
21291
|
return out2;
|
|
21165
21292
|
}
|
|
21293
|
+
function fenceStandardLines(lines) {
|
|
21294
|
+
const out2 = [];
|
|
21295
|
+
for (const line2 of lines) {
|
|
21296
|
+
const trimmed = line2.trim();
|
|
21297
|
+
if (trimmed.startsWith(VERITY_GITIGNORE_MARKER) && trimmed !== BLOCK_COMMENT[0]) {
|
|
21298
|
+
out2.push(...BLOCK_COMMENT);
|
|
21299
|
+
continue;
|
|
21300
|
+
}
|
|
21301
|
+
if (trimmed === SUPERSEDED_STANDARD_LINE || OLD_COMMENT_LINES.has(trimmed)) continue;
|
|
21302
|
+
out2.push(line2);
|
|
21303
|
+
}
|
|
21304
|
+
return out2;
|
|
21305
|
+
}
|
|
21166
21306
|
function ensureVerityGitignore() {
|
|
21167
21307
|
let content = "";
|
|
21168
21308
|
try {
|
|
@@ -21174,9 +21314,11 @@ function ensureVerityGitignore() {
|
|
|
21174
21314
|
const lines = content.split("\n");
|
|
21175
21315
|
const needsRepair = lines.some((l) => BREAKING_ENTRIES.has(l.trim()));
|
|
21176
21316
|
const hasSupersededMemory = hasMarker && !optedOut && lines.some((l) => SUPERSEDED_MEMORY_LINES.has(l.trim()));
|
|
21317
|
+
const hasSupersededStandard = hasMarker && lines.some((l) => l.trim() === SUPERSEDED_STANDARD_LINE);
|
|
21177
21318
|
const memoryIsCommitted = hasSupersededMemory && committedMemoryFiles().length > 0;
|
|
21319
|
+
const standardIsCommitted = hasSupersededStandard && committedStandardFile();
|
|
21178
21320
|
const verified = (result) => semanticsHold() === false ? "conflict" : result;
|
|
21179
|
-
if (hasMarker && !needsRepair && !hasSupersededMemory) return verified("covered");
|
|
21321
|
+
if (hasMarker && !needsRepair && !hasSupersededMemory && !hasSupersededStandard) return verified("covered");
|
|
21180
21322
|
if (!hasMarker && !needsRepair) {
|
|
21181
21323
|
if (semanticsHold() === true) return "covered";
|
|
21182
21324
|
}
|
|
@@ -21185,6 +21327,9 @@ function ensureVerityGitignore() {
|
|
|
21185
21327
|
if (needsRepair) {
|
|
21186
21328
|
next = next.map((l) => BREAKING_ENTRIES.has(l.trim()) ? ".verity/*" : l);
|
|
21187
21329
|
}
|
|
21330
|
+
if (hasSupersededStandard && !standardIsCommitted) {
|
|
21331
|
+
next = fenceStandardLines(next);
|
|
21332
|
+
}
|
|
21188
21333
|
if (hasSupersededMemory && !memoryIsCommitted) {
|
|
21189
21334
|
next = fenceMemoryLines(next);
|
|
21190
21335
|
}
|
|
@@ -21195,7 +21340,7 @@ function ensureVerityGitignore() {
|
|
|
21195
21340
|
}
|
|
21196
21341
|
if (text3 !== content) (0, import_node_fs24.writeFileSync)(".gitignore", text3);
|
|
21197
21342
|
return verified(
|
|
21198
|
-
memoryIsCommitted ? "memory-tracked" : hasSupersededMemory ? "memory-fenced" : needsRepair ? "repaired" : "added"
|
|
21343
|
+
memoryIsCommitted ? "memory-tracked" : standardIsCommitted ? "standard-tracked" : hasSupersededMemory ? "memory-fenced" : hasSupersededStandard ? "standard-fenced" : needsRepair ? "repaired" : "added"
|
|
21199
21344
|
);
|
|
21200
21345
|
} catch {
|
|
21201
21346
|
return "failed";
|
|
@@ -21210,7 +21355,7 @@ function untrackMemory() {
|
|
|
21210
21355
|
return "failed";
|
|
21211
21356
|
}
|
|
21212
21357
|
}
|
|
21213
|
-
function writeFencedBlock() {
|
|
21358
|
+
function writeFencedBlock(fence) {
|
|
21214
21359
|
let content = "";
|
|
21215
21360
|
try {
|
|
21216
21361
|
content = (0, import_node_fs24.readFileSync)(".gitignore", "utf-8");
|
|
@@ -21218,7 +21363,8 @@ function writeFencedBlock() {
|
|
|
21218
21363
|
}
|
|
21219
21364
|
const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
|
|
21220
21365
|
let lines = content.split("\n").map((l) => BREAKING_ENTRIES.has(l.trim()) ? ".verity/*" : l);
|
|
21221
|
-
lines =
|
|
21366
|
+
if (fence.standard) lines = fenceStandardLines(lines);
|
|
21367
|
+
if (fence.memory) lines = fenceMemoryLines(lines);
|
|
21222
21368
|
let text3 = lines.join("\n");
|
|
21223
21369
|
if (!hasMarker) {
|
|
21224
21370
|
const sep7 = text3 === "" ? "" : text3.endsWith("\n") ? "\n" : "\n\n";
|
|
@@ -21245,7 +21391,7 @@ function fenceMemory() {
|
|
|
21245
21391
|
} catch {
|
|
21246
21392
|
}
|
|
21247
21393
|
};
|
|
21248
|
-
if (!writeFencedBlock()) return { untracked: 0, ok: false };
|
|
21394
|
+
if (!writeFencedBlock({ memory: true })) return { untracked: 0, ok: false };
|
|
21249
21395
|
if (memoryPosture() !== "ignored") {
|
|
21250
21396
|
restore();
|
|
21251
21397
|
return { untracked: 0, ok: false };
|
|
@@ -21257,6 +21403,34 @@ function fenceMemory() {
|
|
|
21257
21403
|
}
|
|
21258
21404
|
return { untracked: tracked, ok: true };
|
|
21259
21405
|
}
|
|
21406
|
+
function untrackStandard() {
|
|
21407
|
+
let original = null;
|
|
21408
|
+
try {
|
|
21409
|
+
original = (0, import_node_fs24.readFileSync)(".gitignore", "utf-8");
|
|
21410
|
+
} catch {
|
|
21411
|
+
original = null;
|
|
21412
|
+
}
|
|
21413
|
+
const restore = () => {
|
|
21414
|
+
try {
|
|
21415
|
+
if (original === null) (0, import_node_fs24.rmSync)(".gitignore", { force: true });
|
|
21416
|
+
else (0, import_node_fs24.writeFileSync)(".gitignore", original);
|
|
21417
|
+
} catch {
|
|
21418
|
+
}
|
|
21419
|
+
};
|
|
21420
|
+
if (!writeFencedBlock({ standard: true })) return { ok: false, why: "gitignore" };
|
|
21421
|
+
if (standardPosture() !== "ignored") {
|
|
21422
|
+
restore();
|
|
21423
|
+
return { ok: false, why: "still-committable" };
|
|
21424
|
+
}
|
|
21425
|
+
if (!committedStandardFile()) return { ok: true, untracked: false };
|
|
21426
|
+
try {
|
|
21427
|
+
(0, import_node_child_process9.execSync)(`git rm --cached --quiet -- ${STANDARD_PATH}`, { stdio: "pipe" });
|
|
21428
|
+
return { ok: true, untracked: true };
|
|
21429
|
+
} catch {
|
|
21430
|
+
restore();
|
|
21431
|
+
return { ok: false, why: "index" };
|
|
21432
|
+
}
|
|
21433
|
+
}
|
|
21260
21434
|
function memoryOptOut() {
|
|
21261
21435
|
try {
|
|
21262
21436
|
return (0, import_node_fs24.readFileSync)(".gitignore", "utf-8").includes(MEMORY_OPT_OUT_MARKER);
|
|
@@ -21286,18 +21460,23 @@ function committedVerityState() {
|
|
|
21286
21460
|
} catch {
|
|
21287
21461
|
return [];
|
|
21288
21462
|
}
|
|
21289
|
-
return out2.split("\0").filter(Boolean).filter((p) => p !==
|
|
21463
|
+
return out2.split("\0").filter(Boolean).filter((p) => p !== STANDARD_PATH && !p.startsWith(".verity/memory/"));
|
|
21290
21464
|
}
|
|
21291
21465
|
function untrackVerityState() {
|
|
21292
21466
|
const tracked = committedVerityState();
|
|
21293
21467
|
if (tracked.length === 0) return "none";
|
|
21468
|
+
const standardWasTracked = committedStandardFile();
|
|
21294
21469
|
try {
|
|
21295
21470
|
(0, import_node_child_process9.execSync)("git rm -r --cached --quiet -- .verity", { stdio: "pipe" });
|
|
21296
|
-
|
|
21297
|
-
if (memoryPosture() === "committable") keeps.push(".verity/memory");
|
|
21298
|
-
for (const keep of keeps) {
|
|
21471
|
+
if (standardWasTracked) {
|
|
21299
21472
|
try {
|
|
21300
|
-
(0, import_node_child_process9.execSync)(`git add --
|
|
21473
|
+
(0, import_node_child_process9.execSync)(`git add -f -- ${STANDARD_PATH}`, { stdio: "pipe" });
|
|
21474
|
+
} catch {
|
|
21475
|
+
}
|
|
21476
|
+
}
|
|
21477
|
+
if (memoryPosture() === "committable") {
|
|
21478
|
+
try {
|
|
21479
|
+
(0, import_node_child_process9.execSync)("git add -- .verity/memory", { stdio: "pipe" });
|
|
21301
21480
|
} catch {
|
|
21302
21481
|
}
|
|
21303
21482
|
}
|
|
@@ -21715,6 +21894,117 @@ var LEGACY_MD_END = "<!-- gate-memory:end -->";
|
|
|
21715
21894
|
var LEGACY_PRESERVE_START = "<!-- gate-memory:preserve -->";
|
|
21716
21895
|
var LEGACY_PRESERVE_END = "<!-- /gate-memory:preserve -->";
|
|
21717
21896
|
var CLAUDE_MD_PROSE = [
|
|
21897
|
+
"## Project Memory",
|
|
21898
|
+
"",
|
|
21899
|
+
"This project has a knowledge graph maintained at `.verity/memory/`. Before starting",
|
|
21900
|
+
"non-trivial work, scan `.verity/memory/index.md` for decisions, gotchas, and patterns",
|
|
21901
|
+
"that may apply to the change you are about to make. Open specific node files via",
|
|
21902
|
+
"the Read tool when the title or scope suggests relevance.",
|
|
21903
|
+
"",
|
|
21904
|
+
"The graph is auto-maintained by Verity. Files at `.verity/memory/_archive/` are",
|
|
21905
|
+
"superseded \u2014 ignore them unless investigating history.",
|
|
21906
|
+
"",
|
|
21907
|
+
"Knowledge the organization's other repositories learned is mirrored outside the",
|
|
21908
|
+
"repo at `~/.verity/orgs/<host>/<owner>/memory/` (`verity memory org` lists it).",
|
|
21909
|
+
"Each claim says where it came from; one that is wrong here is demoted for",
|
|
21910
|
+
'everyone with `verity memory demote <id> --reason "\u2026"`.',
|
|
21911
|
+
"",
|
|
21912
|
+
"## Quality gate: accepted risks",
|
|
21913
|
+
"",
|
|
21914
|
+
"When the Verity pre-commit/pre-push gate FAILs, fix the findings \u2014 that is the",
|
|
21915
|
+
'default. Use `verity waive <pattern-id> --file <path> --reason "\u2026"` ONLY to relay',
|
|
21916
|
+
"a risk a human has explicitly accepted: a named code-review finding, an ADR, or",
|
|
21917
|
+
"the user saying so in this conversation. The --reason must cite that source.",
|
|
21918
|
+
"",
|
|
21919
|
+
"Never waive on your own judgment, to get past a block, or pre-emptively. A waive",
|
|
21920
|
+
"binds to the file's current bytes and voids automatically when the file changes,",
|
|
21921
|
+
"and every waive is recorded in the run ledger. For a pattern-level false positive",
|
|
21922
|
+
"use `verity feedback finding <run-id> <pattern-id> false_positive` instead.",
|
|
21923
|
+
"",
|
|
21924
|
+
"## Post-task reflection",
|
|
21925
|
+
"",
|
|
21926
|
+
`When a task is complete (you've created a PR, the user says "done" or "ship it",`,
|
|
21927
|
+
"or the work is clearly finished), **draft the reflection yourself** \u2014 1\u20133",
|
|
21928
|
+
"concrete things worth remembering (a decision, a gotcha, or a pattern), each",
|
|
21929
|
+
"cited with the files / PR / commands / error-signatures it came from. Skip",
|
|
21930
|
+
"entirely if nothing non-obvious happened \u2014 that judgement is the ONLY filter,",
|
|
21931
|
+
"because nothing reviews the reflection before it lands.",
|
|
21932
|
+
"",
|
|
21933
|
+
"Then record it straight away. There is no confirm step, in any environment:",
|
|
21934
|
+
"",
|
|
21935
|
+
"```bash",
|
|
21936
|
+
"verity reflect --user-input - --kind <kind> <<'VERITY_EOF_<random>'",
|
|
21937
|
+
"<your draft>",
|
|
21938
|
+
"VERITY_EOF_<random>",
|
|
21939
|
+
"```",
|
|
21940
|
+
"",
|
|
21941
|
+
'The draft goes through the quoted heredoc, never inside `"\u2026"` on the command',
|
|
21942
|
+
'line, where a `"` or `$(\u2026)` in it would run in the shell. Replace `<random>`',
|
|
21943
|
+
"with 8 random letters and digits that you pick for this call, the same at both",
|
|
21944
|
+
"ends. Text written before you picked them cannot end the heredoc early.",
|
|
21945
|
+
"",
|
|
21946
|
+
"Add `--confirmed` ONLY when the user authored or dictated the words. Without",
|
|
21947
|
+
"it the node is stored as `source: agent` \u2014 Verity thought this, nobody checked",
|
|
21948
|
+
"it. With it, `source: user` at full confidence \u2014 a person stands behind this.",
|
|
21949
|
+
"Never claim the second for your own draft, however good it is.",
|
|
21950
|
+
"",
|
|
21951
|
+
"**Name the files in the text.** Verity scopes the reflection to the paths it",
|
|
21952
|
+
"cites, and a reflection that names no file in this repo is never retrieved for",
|
|
21953
|
+
"a later review \u2014 it is recorded and then invisible. The command says so when it",
|
|
21954
|
+
"happens; `--file-globs '<path or glob>'` is the fix when the prose cannot carry",
|
|
21955
|
+
"the paths.",
|
|
21956
|
+
"",
|
|
21957
|
+
"Then tell the user, in one line, what you recorded and where: the command",
|
|
21958
|
+
"prints the node id, the path under `.verity/memory/`, and a dashboard link.",
|
|
21959
|
+
"They did not agree to it in advance, so say it happened \u2014 editing or deleting",
|
|
21960
|
+
"that file is how they correct it.",
|
|
21961
|
+
"",
|
|
21962
|
+
"> Durable, hand-curated guidance goes in the preserve region below (it survives",
|
|
21963
|
+
"> regeneration) or anywhere OUTSIDE these markers. Everything else between the",
|
|
21964
|
+
"> markers is tool-owned and overwritten on each run.",
|
|
21965
|
+
"",
|
|
21966
|
+
"## Housekeeping Turns",
|
|
21967
|
+
"",
|
|
21968
|
+
"When a turn will be pure housekeeping \u2014 pulling, installing dependencies,",
|
|
21969
|
+
"rebasing, a formatting sweep you are not authoring \u2014 declare it BEFORE doing it:",
|
|
21970
|
+
"",
|
|
21971
|
+
"```bash",
|
|
21972
|
+
'verity ignore --turn --agent --reason "pulling latest before starting"',
|
|
21973
|
+
"```",
|
|
21974
|
+
"",
|
|
21975
|
+
"This skips the review for that turn, which saves the turn Verity would",
|
|
21976
|
+
"otherwise spend saying it had nothing to say. Use `--for 30m` instead of",
|
|
21977
|
+
"`--turn` when a single piece of housekeeping spans several turns.",
|
|
21978
|
+
"",
|
|
21979
|
+
"**It is a claim about the turn, not a way to silence review.** The declaration",
|
|
21980
|
+
"is checked against what the turn actually did: if anything is authored \u2014 by you,",
|
|
21981
|
+
"by a subagent, or by a shell command that can write files \u2014 it voids, the review",
|
|
21982
|
+
"runs anyway, and the broken declaration is reported. So declare housekeeping you",
|
|
21983
|
+
"are about to do, never work you have already done, and never as a way to get past",
|
|
21984
|
+
"a finding. Declarations are budgeted per session and every one is recorded with",
|
|
21985
|
+
"its reason.",
|
|
21986
|
+
"",
|
|
21987
|
+
"## Verity settings",
|
|
21988
|
+
"",
|
|
21989
|
+
"Change these only when the user asks. Each command prints what it changed.",
|
|
21990
|
+
"",
|
|
21991
|
+
"- When Verity reviews: `verity config moments turn,commit,push`. Give any of the",
|
|
21992
|
+
" three, or `none`. With no list, it prints the current setting.",
|
|
21993
|
+
"- Formal verification at push: `verity config formal push`, or `verity config formal off`.",
|
|
21994
|
+
"- The line Verity prints when a turn has nothing new to review: `verity config verbose on`,",
|
|
21995
|
+
" or `verity config verbose off` (the default).",
|
|
21996
|
+
"- Project rules, written by Verity from this repository's history and docs:",
|
|
21997
|
+
" `verity standard generate`. It works only for a project with no Standard on the",
|
|
21998
|
+
" service. It writes `.verity/repo-profile.json` and sends nothing without consent.",
|
|
21999
|
+
" Show the user that file. Run the command again with `--yes` only after they agree.",
|
|
22000
|
+
"- The rules themselves: run `verity standard pull` first (the file here can be behind",
|
|
22001
|
+
" the team's), edit `.verity/standard.yaml`, then run `verity standard push`."
|
|
22002
|
+
].join("\n");
|
|
22003
|
+
var CLAUDE_MD_PROSE_PRE_PULL = CLAUDE_MD_PROSE.replace(
|
|
22004
|
+
/- 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`\.$/,
|
|
22005
|
+
"- The rules themselves: edit `.verity/standard.yaml`, then run `verity standard push`."
|
|
22006
|
+
);
|
|
22007
|
+
var CLAUDE_MD_PROSE_PRE_VERBOSE = [
|
|
21718
22008
|
"## Project Memory",
|
|
21719
22009
|
"",
|
|
21720
22010
|
"This project has a knowledge graph maintained at `.verity/memory/`. Before starting",
|
|
@@ -22351,6 +22641,8 @@ function stripKnownProse(interior) {
|
|
|
22351
22641
|
const trimmed = interior.replace(/^\n+/, "");
|
|
22352
22642
|
for (const prose of [
|
|
22353
22643
|
CLAUDE_MD_PROSE,
|
|
22644
|
+
CLAUDE_MD_PROSE_PRE_PULL,
|
|
22645
|
+
CLAUDE_MD_PROSE_PRE_VERBOSE,
|
|
22354
22646
|
CLAUDE_MD_PROSE_PRE_SETTINGS,
|
|
22355
22647
|
CLAUDE_MD_PROSE_PRE_STDIN,
|
|
22356
22648
|
CLAUDE_MD_PROSE_PRE_ORG,
|
|
@@ -25415,6 +25707,8 @@ async function generateStandard(opts) {
|
|
|
25415
25707
|
} catch (err2) {
|
|
25416
25708
|
return { status: "failed", reason: `the Standard is on the service (v${version}) but could not be written here: ${terminalText(err2.message, 200)}` };
|
|
25417
25709
|
}
|
|
25710
|
+
await writeSetupState({ standardVersion: version }).catch(() => {
|
|
25711
|
+
});
|
|
25418
25712
|
return {
|
|
25419
25713
|
status: "created",
|
|
25420
25714
|
version,
|
|
@@ -25595,68 +25889,6 @@ async function runGenerate(globals, opts) {
|
|
|
25595
25889
|
var import_node_fs37 = require("node:fs");
|
|
25596
25890
|
var import_yaml6 = __toESM2(require_dist());
|
|
25597
25891
|
|
|
25598
|
-
// src/lib/setup-state.ts
|
|
25599
|
-
var SETUP_STATE_FILE = `${VERITY_DIR}/setup.json`;
|
|
25600
|
-
var MOMENTS = ["stop", "pre-commit", "pre-push"];
|
|
25601
|
-
var INTENSITIES = ["lightweight", "balanced", "thorough"];
|
|
25602
|
-
var TELEMETRY = ["enabled", "declined", "deferred"];
|
|
25603
|
-
var VERSION = /^[0-9A-Za-z.+-]{1,32}$/;
|
|
25604
|
-
var stamp = (v) => typeof v === "string" && v.length > 0 && v.length <= 64;
|
|
25605
|
-
function setupStateFrom(raw) {
|
|
25606
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
|
|
25607
|
-
const r = raw;
|
|
25608
|
-
if (r.version !== 1) return null;
|
|
25609
|
-
const out2 = { version: 1 };
|
|
25610
|
-
if (INTENSITIES.includes(r.intensity)) out2.intensity = r.intensity;
|
|
25611
|
-
if (Array.isArray(r.moments) && r.moments.every((m) => MOMENTS.includes(m))) {
|
|
25612
|
-
out2.moments = [...new Set(r.moments)];
|
|
25613
|
-
}
|
|
25614
|
-
if (TELEMETRY.includes(r.telemetry)) out2.telemetry = r.telemetry;
|
|
25615
|
-
if (Number.isSafeInteger(r.declinedStandardVersion) && r.declinedStandardVersion >= 1) {
|
|
25616
|
-
out2.declinedStandardVersion = r.declinedStandardVersion;
|
|
25617
|
-
}
|
|
25618
|
-
const init2 = r.init;
|
|
25619
|
-
if (init2 && typeof init2 === "object" && stamp(init2.completed_at) && typeof init2.cli_version === "string" && VERSION.test(init2.cli_version)) {
|
|
25620
|
-
out2.init = { completed_at: init2.completed_at, cli_version: init2.cli_version };
|
|
25621
|
-
}
|
|
25622
|
-
const plugin = r.pluginSetup;
|
|
25623
|
-
if (plugin && typeof plugin === "object" && typeof plugin.version === "string" && VERSION.test(plugin.version) && stamp(plugin.completed_at)) {
|
|
25624
|
-
out2.pluginSetup = { version: plugin.version, completed_at: plugin.completed_at };
|
|
25625
|
-
}
|
|
25626
|
-
if (r.wiring === "project") out2.wiring = "project";
|
|
25627
|
-
return out2;
|
|
25628
|
-
}
|
|
25629
|
-
var MAX_SETUP_BYTES = 64 * 1024;
|
|
25630
|
-
function readSetupText() {
|
|
25631
|
-
const read2 = readRegularFileInRoot(repoRoot(), SETUP_STATE_FILE, MAX_SETUP_BYTES);
|
|
25632
|
-
return read2.ok ? read2.content : null;
|
|
25633
|
-
}
|
|
25634
|
-
async function readSetupState() {
|
|
25635
|
-
const raw = readSetupText();
|
|
25636
|
-
if (raw === null) return null;
|
|
25637
|
-
try {
|
|
25638
|
-
return setupStateFrom(JSON.parse(raw));
|
|
25639
|
-
} catch {
|
|
25640
|
-
return null;
|
|
25641
|
-
}
|
|
25642
|
-
}
|
|
25643
|
-
async function writeSetupState(patch) {
|
|
25644
|
-
const current = await readSetupState() ?? { version: 1 };
|
|
25645
|
-
const next = { ...current, ...patch, version: 1 };
|
|
25646
|
-
const raw = readSetupText();
|
|
25647
|
-
if (raw !== null) {
|
|
25648
|
-
try {
|
|
25649
|
-
if (jsonSemanticEqual(JSON.parse(raw), next)) return next;
|
|
25650
|
-
} catch {
|
|
25651
|
-
}
|
|
25652
|
-
}
|
|
25653
|
-
const text3 = JSON.stringify(next, null, raw !== null ? detectJsonIndent(raw) : 2) + "\n";
|
|
25654
|
-
if (!replaceInRoot(projectPath(VERITY_DIR), "setup.json", text3)) {
|
|
25655
|
-
throw new Error(`Could not write ${SETUP_STATE_FILE}: it is a link, or ${VERITY_DIR} is not a folder of this repository`);
|
|
25656
|
-
}
|
|
25657
|
-
return next;
|
|
25658
|
-
}
|
|
25659
|
-
|
|
25660
25892
|
// src/commands/init/rules.ts
|
|
25661
25893
|
async function projectLabel(token, serviceUrl, verbose) {
|
|
25662
25894
|
try {
|
|
@@ -25801,6 +26033,8 @@ async function pullStandard(globals, opts = {}) {
|
|
|
25801
26033
|
} catch {
|
|
25802
26034
|
}
|
|
25803
26035
|
if (local && typeof local === "object" && !Array.isArray(local) && sameStandard(local, remote.standard.content)) {
|
|
26036
|
+
await writeSetupState({ standardVersion: version, declinedStandardVersion: void 0 }).catch(() => {
|
|
26037
|
+
});
|
|
25804
26038
|
return { status: "same", version };
|
|
25805
26039
|
}
|
|
25806
26040
|
try {
|
|
@@ -25811,7 +26045,7 @@ async function pullStandard(globals, opts = {}) {
|
|
|
25811
26045
|
}
|
|
25812
26046
|
try {
|
|
25813
26047
|
const outcome = await adoptRemoteSetup(remote, { serviceUrl: url.data, projectId, expectStandard: readBytes });
|
|
25814
|
-
await writeSetupState({ declinedStandardVersion: void 0 }).catch(() => {
|
|
26048
|
+
await writeSetupState({ standardVersion: version, declinedStandardVersion: void 0 }).catch(() => {
|
|
25815
26049
|
});
|
|
25816
26050
|
return { status: "pulled", version, backup, notes: outcome.notes };
|
|
25817
26051
|
} catch (err2) {
|
|
@@ -26030,8 +26264,13 @@ function registerStandardCommands(program2) {
|
|
|
26030
26264
|
for (const path of result.written) printInfo(` ${terminalText(path, 200)} \u2713`);
|
|
26031
26265
|
for (const note of result.notes) printWarn(` ${terminalText(note, 300)}`);
|
|
26032
26266
|
if (opts.push) {
|
|
26033
|
-
const
|
|
26267
|
+
const token = await resolveToken(globals.token);
|
|
26268
|
+
const expected = token.ok && urlResult.ok ? await expectedLatestForPush(globals, token.data.token, urlResult.data) : void 0;
|
|
26269
|
+
const pushed = await pushStandard(globals, expected !== void 0 ? { expectedLatest: expected } : {});
|
|
26034
26270
|
for (const line2 of pushed.lines) printInfo(` ${terminalText(line2, 600)}`);
|
|
26271
|
+
if (pushed.conflict) {
|
|
26272
|
+
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.`);
|
|
26273
|
+
}
|
|
26035
26274
|
if (pushed.standardVersion !== null) {
|
|
26036
26275
|
await correctVerityMdVersion({
|
|
26037
26276
|
standard: result.standard,
|
|
@@ -26045,7 +26284,7 @@ function registerStandardCommands(program2) {
|
|
|
26045
26284
|
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));
|
|
26046
26285
|
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()));
|
|
26047
26286
|
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));
|
|
26048
|
-
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) => {
|
|
26287
|
+
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) => {
|
|
26049
26288
|
const globals = program2.opts();
|
|
26050
26289
|
const tokenResult = await resolveToken(globals.token);
|
|
26051
26290
|
if (!tokenResult.ok) {
|
|
@@ -26068,19 +26307,33 @@ function registerStandardCommands(program2) {
|
|
|
26068
26307
|
process.exit(1);
|
|
26069
26308
|
}
|
|
26070
26309
|
if (upload.warning) printWarn(terminalText(upload.warning, 600));
|
|
26310
|
+
const expected = opts.force ? void 0 : await expectedLatestForPush(globals, tokenResult.data.token, urlResult.data);
|
|
26071
26311
|
const result = await apiRequest({
|
|
26072
26312
|
method: "POST",
|
|
26073
26313
|
path: "/standards",
|
|
26074
26314
|
serviceUrl: urlResult.data,
|
|
26075
26315
|
token: tokenResult.data.token,
|
|
26076
|
-
body: {
|
|
26316
|
+
body: {
|
|
26317
|
+
content: upload.content,
|
|
26318
|
+
created_by: upload.createdBy,
|
|
26319
|
+
...expected !== void 0 ? { expected_latest: expected } : {}
|
|
26320
|
+
},
|
|
26077
26321
|
verbose: globals.verbose
|
|
26078
26322
|
});
|
|
26079
26323
|
if (!result.ok) {
|
|
26324
|
+
if (expected !== void 0 && result.http_status === 409 && result.error.startsWith("STANDARD_EXISTS")) {
|
|
26325
|
+
const latest = latestFromConflict(result);
|
|
26326
|
+
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`);
|
|
26327
|
+
process.exit(1);
|
|
26328
|
+
}
|
|
26080
26329
|
printError(terminalText(result.error, 300));
|
|
26081
26330
|
process.exit(1);
|
|
26082
26331
|
}
|
|
26083
26332
|
printInfo(`Standard uploaded (version ${versionText(result.data.version)})`);
|
|
26333
|
+
if (Number.isSafeInteger(result.data.version) && result.data.version >= 1) {
|
|
26334
|
+
await writeSetupState({ standardVersion: result.data.version }).catch(() => {
|
|
26335
|
+
});
|
|
26336
|
+
}
|
|
26084
26337
|
const converted = conversionLine(result.data);
|
|
26085
26338
|
if (converted) {
|
|
26086
26339
|
printInfo(converted);
|
|
@@ -26088,6 +26341,7 @@ function registerStandardCommands(program2) {
|
|
|
26088
26341
|
}
|
|
26089
26342
|
printJson(result.data);
|
|
26090
26343
|
});
|
|
26344
|
+
standard.command("untrack").description(`Stop tracking ${STANDARD_FILE} in git: Verity keeps it on each machine, and reviews read the service`).action(() => runUntrack());
|
|
26091
26345
|
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) => {
|
|
26092
26346
|
const globals = program2.opts();
|
|
26093
26347
|
const tokenResult = await resolveToken(globals.token);
|
|
@@ -26162,6 +26416,32 @@ function registerStandardCommands(program2) {
|
|
|
26162
26416
|
function versionText(value) {
|
|
26163
26417
|
return typeof value === "number" && Number.isSafeInteger(value) ? String(value) : "?";
|
|
26164
26418
|
}
|
|
26419
|
+
async function expectedLatestForPush(globals, token, serviceUrl) {
|
|
26420
|
+
const state = await readSetupState();
|
|
26421
|
+
if (state?.standardVersion !== void 0) return state.standardVersion;
|
|
26422
|
+
const remote = await fetchRemoteSetup({ token, serviceUrl, verbose: globals.verbose });
|
|
26423
|
+
if (remote.status === "found") {
|
|
26424
|
+
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.`);
|
|
26425
|
+
return remote.standard.version;
|
|
26426
|
+
}
|
|
26427
|
+
if (remote.status === "none") return null;
|
|
26428
|
+
printWarn(`Could not read the team's Standard from the service (${terminalText(remote.reason, 200)}), so this push is not conditional on it.`);
|
|
26429
|
+
return void 0;
|
|
26430
|
+
}
|
|
26431
|
+
function runUntrack() {
|
|
26432
|
+
const wasTracked = committedStandardFile();
|
|
26433
|
+
const result = untrackStandard();
|
|
26434
|
+
if (!result.ok) {
|
|
26435
|
+
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.`);
|
|
26436
|
+
process.exit(1);
|
|
26437
|
+
}
|
|
26438
|
+
if (!wasTracked) {
|
|
26439
|
+
printInfo(`${STANDARD_FILE} is not tracked in git. Git ignores it from here on; nothing else changed.`);
|
|
26440
|
+
return;
|
|
26441
|
+
}
|
|
26442
|
+
printInfo(`Untracked ${STANDARD_FILE} (staged). The file stays on disk here. Commit to finish.`);
|
|
26443
|
+
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.");
|
|
26444
|
+
}
|
|
26165
26445
|
var UPLOAD_MAX_BYTES = 512 * 1024;
|
|
26166
26446
|
function readUploadFile(file) {
|
|
26167
26447
|
const root = realOrSelf(repoRoot());
|
|
@@ -26343,6 +26623,18 @@ function registerConfigCommands(program2) {
|
|
|
26343
26623
|
printInfo(state === "push" ? "Formal verification at push: on for this checkout (Lean must be installed \u2014 verity lean status)" : "Formal verification at push: off");
|
|
26344
26624
|
if (state === "push") printInfo("The phase runs with your Verity login (a push without one is skipped and says so: not-logged-in)");
|
|
26345
26625
|
});
|
|
26626
|
+
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) => {
|
|
26627
|
+
if (state === void 0) {
|
|
26628
|
+
process.stdout.write((readProjectConfig().verbose === "on" ? "on" : "off") + "\n");
|
|
26629
|
+
return;
|
|
26630
|
+
}
|
|
26631
|
+
if (state !== "on" && state !== "off") {
|
|
26632
|
+
printError(`Unrecognised state: ${state}. Use "on" or "off".`);
|
|
26633
|
+
process.exit(1);
|
|
26634
|
+
}
|
|
26635
|
+
writeProjectConfig({ verbose: state });
|
|
26636
|
+
printInfo(state === "on" ? "Verbose: on. A turn with nothing new to review now says so." : "Verbose: off. A turn with nothing new to review says nothing.");
|
|
26637
|
+
});
|
|
26346
26638
|
config.command("push").description("Upload .codacy/codacy.config.json to the service (not used by the gate, which runs Trivy only)").option("--file <path>", "Path to config file", CODACY_CONFIG_FILE).action(async (opts) => {
|
|
26347
26639
|
const globals = program2.opts();
|
|
26348
26640
|
const tokenResult = await resolveToken(globals.token);
|
|
@@ -26818,8 +27110,8 @@ function timeAgo(isoDate) {
|
|
|
26818
27110
|
}
|
|
26819
27111
|
var PLAN_NAME = { free: "Free", pro: "Pro", fleet: "Fleet", enterprise: "Enterprise" };
|
|
26820
27112
|
function planLine(plan, accounts) {
|
|
26821
|
-
const teams = accounts.filter((a) => a.kind
|
|
26822
|
-
return `${PLAN_NAME[plan] ?? plan}${teams.length ? ` \xB7 member of ${teams.join(", ")}` : ""} \u2014 limits: "verity usage"`;
|
|
27113
|
+
const teams = accounts.filter((a) => !(a.is_owner ?? a.kind === "personal")).map((a) => `${terminalText(a.name)} (${PLAN_NAME[a.plan] ?? terminalText(a.plan)})`);
|
|
27114
|
+
return `${PLAN_NAME[plan] ?? terminalText(plan)}${teams.length ? ` \xB7 member of ${teams.join(", ")}` : ""} \u2014 limits: "verity usage"`;
|
|
26823
27115
|
}
|
|
26824
27116
|
function registerStatusCommand(program2) {
|
|
26825
27117
|
program2.command("status").description("Show project quality status").option("--history", "Include recent run history").option("--limit <n>", "Number of history entries (1-100)", "5").option("--json", "Output raw JSON").action(async (opts) => {
|
|
@@ -27070,7 +27362,7 @@ function dollars(cents2) {
|
|
|
27070
27362
|
return `$${((cents2 ?? 0) / 100).toFixed(2)}`;
|
|
27071
27363
|
}
|
|
27072
27364
|
function link(l) {
|
|
27073
|
-
return (l.upgrade_url
|
|
27365
|
+
return terminalUrl(l.upgrade_url) || "https://verity.md/upgrade";
|
|
27074
27366
|
}
|
|
27075
27367
|
function detail(l, now) {
|
|
27076
27368
|
const reset = resetPhrase(l, now, true);
|
|
@@ -27081,7 +27373,8 @@ function detail(l, now) {
|
|
|
27081
27373
|
return `Extra usage reached this month's ${dollars(l.limit)} cap. ${Reset}. ${way2}`;
|
|
27082
27374
|
}
|
|
27083
27375
|
if (l.period === "week") {
|
|
27084
|
-
const
|
|
27376
|
+
const team = shared ? terminalText(l.account) : "";
|
|
27377
|
+
const who = team ? `${team} used its` : "You used your";
|
|
27085
27378
|
const way2 = l.budget === "free" ? `Upgrade: ${link(l)}` : shared ? `An admin can turn on extra usage, or upgrade: ${link(l)}` : `Turn on extra usage or upgrade: ${link(l)}`;
|
|
27086
27379
|
return `${who} ${l.limit} ${METER[l.meter]} this week. ${Reset}. ${way2}`;
|
|
27087
27380
|
}
|
|
@@ -27160,8 +27453,11 @@ function windowText(w, resetsAt, now, weekly) {
|
|
|
27160
27453
|
function cents(n2) {
|
|
27161
27454
|
return n2 === null ? "\u2014" : n2 < 100 ? `${n2}\xA2` : `$${(n2 / 100).toFixed(2)}`;
|
|
27162
27455
|
}
|
|
27456
|
+
function ownsAccount(b) {
|
|
27457
|
+
return b?.account?.is_owner ?? b?.account?.kind === "personal";
|
|
27458
|
+
}
|
|
27163
27459
|
function extraOffText(b, ui) {
|
|
27164
|
-
if (b
|
|
27460
|
+
if (ownsAccount(b)) return `off \u2014 turn it on at ${ui}/account/billing`;
|
|
27165
27461
|
return "off \u2014 a team admin can turn it on";
|
|
27166
27462
|
}
|
|
27167
27463
|
function renderBudget(b, now = /* @__PURE__ */ new Date(), ui = uiBase()) {
|
|
@@ -27177,12 +27473,14 @@ function renderBudget(b, now = /* @__PURE__ */ new Date(), ui = uiBase()) {
|
|
|
27177
27473
|
return lines;
|
|
27178
27474
|
}
|
|
27179
27475
|
function budgetName(b) {
|
|
27180
|
-
|
|
27476
|
+
if (!b.account) return PLAN2[b.plan];
|
|
27477
|
+
const name2 = terminalText(b.account.name);
|
|
27478
|
+
return ownsAccount(b) ? `${PLAN2[b.plan]} \xB7 ${name2} (your plan)` : `${PLAN2[b.plan]} \xB7 ${name2}`;
|
|
27181
27479
|
}
|
|
27182
27480
|
function payerText(b) {
|
|
27183
27481
|
if (!b || !b.account) return "your Free plan";
|
|
27184
|
-
if (b
|
|
27185
|
-
return `the ${PLAN2[b.plan]} plan of ${b.account.name}`;
|
|
27482
|
+
if (ownsAccount(b)) return `your ${PLAN2[b.plan]} plan`;
|
|
27483
|
+
return `the ${PLAN2[b.plan]} plan of ${terminalText(b.account.name)}`;
|
|
27186
27484
|
}
|
|
27187
27485
|
function renderLimits(d, now = /* @__PURE__ */ new Date()) {
|
|
27188
27486
|
const ui = d.ui_url ? d.ui_url.replace(/\/+$/, "") : uiBase();
|
|
@@ -27190,10 +27488,10 @@ function renderLimits(d, now = /* @__PURE__ */ new Date()) {
|
|
|
27190
27488
|
if (!d.enforced) lines.push(d.mode === "shadow" ? "Limits are counted, not yet enforced." : "Limits are not active.");
|
|
27191
27489
|
const payer = d.budgets.find((b) => b.applies_here);
|
|
27192
27490
|
if (d.team_here && !d.team_here.member) {
|
|
27193
|
-
lines.push(d.team_here.auto_join ? `${d.team_here.name} pays for Verity in this repository. Your first review here makes you a member (${d.team_here.default_plan}).` : `${d.team_here.name} pays for Verity here for its members. An admin approves new members. Until an admin adds you, ${payerText(payer)} pays for your reviews here.`);
|
|
27491
|
+
lines.push(d.team_here.auto_join ? `${terminalText(d.team_here.name)} pays for Verity in this repository. Your first review here makes you a member (${terminalText(d.team_here.default_plan)}).` : `${terminalText(d.team_here.name)} pays for Verity here for its members. An admin approves new members. Until an admin adds you, ${payerText(payer)} pays for your reviews here.`);
|
|
27194
27492
|
}
|
|
27195
|
-
const
|
|
27196
|
-
const shown = d.budgets.filter((b) => !(
|
|
27493
|
+
const hasOwn = d.budgets.some((b) => ownsAccount(b));
|
|
27494
|
+
const shown = d.budgets.filter((b) => !(hasOwn && b.budget === "free"));
|
|
27197
27495
|
const full = payer ? shown.filter((b) => b === payer) : shown;
|
|
27198
27496
|
for (const b of full) {
|
|
27199
27497
|
lines.push("");
|
|
@@ -30244,7 +30542,13 @@ async function passAndExit(run4, reason, skip, kindOverride) {
|
|
|
30244
30542
|
const AGENT_SILENT_SKIPS = /* @__PURE__ */ new Set([]);
|
|
30245
30543
|
const agentNote = AGENT_SILENT_SKIPS.has(skip) ? null : note;
|
|
30246
30544
|
const HUMAN_SILENT_SKIPS = /* @__PURE__ */ new Set(["command-only-turn"]);
|
|
30247
|
-
const
|
|
30545
|
+
const quiet = quietSkip({
|
|
30546
|
+
skip,
|
|
30547
|
+
kind: skipKind,
|
|
30548
|
+
nothingChanged: nothingChanged(run4),
|
|
30549
|
+
verbose: readVerbose()
|
|
30550
|
+
});
|
|
30551
|
+
const humanNote = HUMAN_SILENT_SKIPS.has(skip) || quiet ? null : `Verity: ${reason}`;
|
|
30248
30552
|
printJsonCompact(
|
|
30249
30553
|
buildHookOutput(
|
|
30250
30554
|
verdict,
|
|
@@ -30257,6 +30561,22 @@ async function passAndExit(run4, reason, skip, kindOverride) {
|
|
|
30257
30561
|
);
|
|
30258
30562
|
process.exit(0);
|
|
30259
30563
|
}
|
|
30564
|
+
var NOTHING_NEW = /* @__PURE__ */ new Set(["no-delta-since-last-review", "no-analyzable-files"]);
|
|
30565
|
+
var QUIET_ON_CLEAN_TREE = /* @__PURE__ */ new Set([
|
|
30566
|
+
"debounce",
|
|
30567
|
+
"verity-command",
|
|
30568
|
+
"bare-acknowledgment",
|
|
30569
|
+
"reflection-prompt",
|
|
30570
|
+
"skip-mode",
|
|
30571
|
+
"zero-increment"
|
|
30572
|
+
]);
|
|
30573
|
+
function quietSkip(s) {
|
|
30574
|
+
if (s.verbose || s.kind !== "policy") return false;
|
|
30575
|
+
return NOTHING_NEW.has(s.skip) || QUIET_ON_CLEAN_TREE.has(s.skip) && s.nothingChanged;
|
|
30576
|
+
}
|
|
30577
|
+
function nothingChanged(run4) {
|
|
30578
|
+
return partitionVerityOwned(run4.changedUniverse).kept.length === 0;
|
|
30579
|
+
}
|
|
30260
30580
|
|
|
30261
30581
|
// src/commands/analyze/phases/02-scope.ts
|
|
30262
30582
|
async function scope(run4) {
|
|
@@ -31148,7 +31468,8 @@ async function evidence(run4) {
|
|
|
31148
31468
|
const scoped = scopeToAuthored(allForReview, actionSummary);
|
|
31149
31469
|
const canTrustNoneAuthored = scoped.signal === "none-authored" && authorshipIsObservable;
|
|
31150
31470
|
if (canTrustNoneAuthored && !hasNonEditAuthorship(actionSummary, sessionAuthoredCode)) {
|
|
31151
|
-
|
|
31471
|
+
const why = nothingChanged(run4) ? "No code changed this turn" : "No agent-authored code this turn \u2014 working-tree changes were not authored by this session";
|
|
31472
|
+
await passAndExit(run4, why, "zero-increment");
|
|
31152
31473
|
}
|
|
31153
31474
|
if (scoped.signal === "none-authored" && !authorshipIsObservable) {
|
|
31154
31475
|
logEvent("none_authored_unverifiable", {
|
|
@@ -34195,15 +34516,23 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
|
|
|
34195
34516
|
].join("\n");
|
|
34196
34517
|
return fm;
|
|
34197
34518
|
}
|
|
34198
|
-
async function
|
|
34199
|
-
if (
|
|
34200
|
-
|
|
34519
|
+
async function standardForSeed(opts) {
|
|
34520
|
+
if ((0, import_node_fs53.existsSync)(STANDARD_FILE)) {
|
|
34521
|
+
const raw = readRepoFile(STANDARD_FILE);
|
|
34522
|
+
if (raw === null) return null;
|
|
34523
|
+
try {
|
|
34524
|
+
const parsed = (0, import_yaml9.parse)(raw);
|
|
34525
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
34526
|
+
} catch {
|
|
34527
|
+
return null;
|
|
34528
|
+
}
|
|
34201
34529
|
}
|
|
34202
|
-
|
|
34203
|
-
|
|
34204
|
-
|
|
34205
|
-
|
|
34206
|
-
|
|
34530
|
+
const remote = await fetchRemoteSetup({ serviceUrl: opts.serviceUrl, token: opts.token, verbose: opts.verbose });
|
|
34531
|
+
return remote.status === "found" ? remote.standard.content : null;
|
|
34532
|
+
}
|
|
34533
|
+
async function runSeed(opts) {
|
|
34534
|
+
const standardDoc = await standardForSeed(opts);
|
|
34535
|
+
if (standardDoc === null) {
|
|
34207
34536
|
return { created: 0, existing: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
34208
34537
|
}
|
|
34209
34538
|
const knowledgeSpec = standardDoc.knowledge_spec ?? {};
|
|
@@ -34330,9 +34659,8 @@ async function memoryManifest(run4) {
|
|
|
34330
34659
|
try {
|
|
34331
34660
|
await ensureMemoryDir();
|
|
34332
34661
|
const seedMarker = (0, import_node_path43.join)(VERITY_DIR, ".seeded");
|
|
34333
|
-
const hasStandard = (0, import_node_fs54.existsSync)(STANDARD_FILE);
|
|
34334
34662
|
const alreadyTried = (0, import_node_fs54.existsSync)(seedMarker);
|
|
34335
|
-
if (
|
|
34663
|
+
if (!alreadyTried) {
|
|
34336
34664
|
const preManifest = await buildManifest();
|
|
34337
34665
|
if (preManifest.nodes.length === 0) {
|
|
34338
34666
|
try {
|
|
@@ -43225,8 +43553,8 @@ async function scaffoldStep(ui, given = {}) {
|
|
|
43225
43553
|
rail.warn(".gitignore: could not write the Verity block");
|
|
43226
43554
|
rail.line("Add it by hand: .verity/ holds copies of analyzed files, including any secret the gate flagged.");
|
|
43227
43555
|
} else if (ignore === "conflict") {
|
|
43228
|
-
rail.warn(".gitignore: git
|
|
43229
|
-
rail.line("A
|
|
43556
|
+
rail.warn(".gitignore: git does not ignore the files under .verity/");
|
|
43557
|
+
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");
|
|
43230
43558
|
} else if (ignore === "memory-tracked") {
|
|
43231
43559
|
rail.warn("This project commits its knowledge graph");
|
|
43232
43560
|
}
|
|
@@ -43241,15 +43569,25 @@ async function scaffoldStep(ui, given = {}) {
|
|
|
43241
43569
|
rail.line("They show up in every diff. Stop with: verity memory untrack (or keep them on purpose: verity memory track)");
|
|
43242
43570
|
}
|
|
43243
43571
|
}
|
|
43572
|
+
if (committedStandardFile()) {
|
|
43573
|
+
if (given.untrackStandard) {
|
|
43574
|
+
const result = untrackStandard();
|
|
43575
|
+
if (result.ok) rail.line(`Untracked ${STANDARD_FILE} (staged). Commit to finish. Teammates get it back with: verity standard pull`);
|
|
43576
|
+
else rail.line(`Could not untrack ${STANDARD_FILE}. Run: verity standard untrack`, "warn");
|
|
43577
|
+
} else {
|
|
43578
|
+
rail.warn(`${STANDARD_FILE} is tracked in git`);
|
|
43579
|
+
rail.line("Verity keeps it on each machine now, and reviews read the Standard on the service. Stop tracking it with: verity standard untrack");
|
|
43580
|
+
}
|
|
43581
|
+
}
|
|
43244
43582
|
const tracked = committedVerityState();
|
|
43245
43583
|
if (tracked.length > 0) {
|
|
43246
43584
|
if (given.untrackState || ui.asking && await askUntrackState(ui, tracked)) {
|
|
43247
43585
|
const result = untrackVerityState();
|
|
43248
43586
|
if (result === "untracked") rail.line("Untracked the Verity state files (staged). Commit to finish.");
|
|
43249
|
-
else if (result === "failed") rail.line("Could not untrack them. Run:
|
|
43587
|
+
else if (result === "failed") rail.line("Could not untrack them. Run: verity init --untrack-state", "warn");
|
|
43250
43588
|
} else {
|
|
43251
43589
|
rail.warn(`${tracked.length} Verity state file(s) are tracked in git`);
|
|
43252
|
-
rail.line(`For example ${terminalText(tracked[0], 200)}. Fix:
|
|
43590
|
+
rail.line(`For example ${terminalText(tracked[0], 200)}. Fix: verity init --untrack-state`);
|
|
43253
43591
|
}
|
|
43254
43592
|
}
|
|
43255
43593
|
retireCodacyConfig(ui);
|
|
@@ -43499,13 +43837,20 @@ function sayPacks(ui, plan) {
|
|
|
43499
43837
|
}
|
|
43500
43838
|
|
|
43501
43839
|
// src/commands/init/team-standard.ts
|
|
43840
|
+
function refusalOutcome(code) {
|
|
43841
|
+
return code === "FORBIDDEN" ? "denied" : "sign-in-needed";
|
|
43842
|
+
}
|
|
43502
43843
|
async function lookUpTeamStandard(opts) {
|
|
43503
43844
|
if (!opts.adopt) return { status: "skipped", why: "no-adopt" };
|
|
43504
43845
|
const token = await resolveToken(opts.globals.token);
|
|
43505
43846
|
const url = await resolveServiceUrl(opts.globals.serviceUrl);
|
|
43506
43847
|
if (!token.ok || !url.ok) return { status: "skipped", why: "not-signed-in" };
|
|
43507
43848
|
const found = await fetchRemoteSetup({ token: token.data.token, serviceUrl: url.data, verbose: opts.globals.verbose });
|
|
43508
|
-
if (found.status === "unavailable")
|
|
43849
|
+
if (found.status === "unavailable") {
|
|
43850
|
+
const denial = authDenialRemedy(found.reason);
|
|
43851
|
+
if (denial) return { status: "denied", code: denial.code, reason: terminalText(found.reason, 300) };
|
|
43852
|
+
return { status: "unavailable", reason: terminalText(found.reason, 300) };
|
|
43853
|
+
}
|
|
43509
43854
|
if (found.status === "none") return { status: "none" };
|
|
43510
43855
|
if (opts.previous?.declinedStandardVersion === found.standard.version) {
|
|
43511
43856
|
return { status: "declined-before", version: found.standard.version, found };
|
|
@@ -43522,10 +43867,8 @@ async function writeTeamStandard(team, opts) {
|
|
|
43522
43867
|
serviceUrl: url.data,
|
|
43523
43868
|
projectId: await projectLabel(token.data.token, url.data, opts.globals.verbose)
|
|
43524
43869
|
});
|
|
43525
|
-
|
|
43526
|
-
|
|
43527
|
-
});
|
|
43528
|
-
}
|
|
43870
|
+
await writeSetupState({ standardVersion: found.standard.version, declinedStandardVersion: void 0 }).catch(() => {
|
|
43871
|
+
});
|
|
43529
43872
|
return { status: "adopted", version: found.standard.version, summary: describeRemote(found), notes: outcome.notes };
|
|
43530
43873
|
} catch (err2) {
|
|
43531
43874
|
return { status: "write-failed", reason: terminalText(err2.message, 300) };
|
|
@@ -43546,6 +43889,17 @@ async function askTeamChoice(ui, team) {
|
|
|
43546
43889
|
rail.collapse();
|
|
43547
43890
|
return k === "n" ? "new" : "use";
|
|
43548
43891
|
}
|
|
43892
|
+
async function askKeepOrPull(ui, team) {
|
|
43893
|
+
const { rail, screen } = ui;
|
|
43894
|
+
rail.active(`${STANDARD_FILE} differs from your team's Standard`);
|
|
43895
|
+
rail.line(`On the service: ${describeRemote(team.found)}. Reviews use that one.`);
|
|
43896
|
+
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`);
|
|
43897
|
+
rail.gap();
|
|
43898
|
+
rail.keys([["Enter", "use the team's"], ["k", "keep yours"]]);
|
|
43899
|
+
const k = await screen.key(["enter", "k"], "enter", { freshMs: 300 });
|
|
43900
|
+
rail.collapse();
|
|
43901
|
+
return k === "k" ? "keep" : "use";
|
|
43902
|
+
}
|
|
43549
43903
|
function sayAdopted(ui, team) {
|
|
43550
43904
|
ui.rail.done(`Using your team's Standard v${team.version}`);
|
|
43551
43905
|
ui.rail.line(terminalText(team.summary, 300));
|
|
@@ -43614,19 +43968,19 @@ async function deriveFromCatalogue(ui, globals, plan, expectedLatest) {
|
|
|
43614
43968
|
return { ok: false, version: null };
|
|
43615
43969
|
}
|
|
43616
43970
|
}
|
|
43617
|
-
function
|
|
43971
|
+
function localStandard() {
|
|
43618
43972
|
const raw = readRepoFile(STANDARD_FILE);
|
|
43619
|
-
if (raw === null) return `${STANDARD_FILE} is a link, not a regular file, or larger than 512 KB
|
|
43973
|
+
if (raw === null) return { ok: false, problem: `${STANDARD_FILE} is a link, not a regular file, or larger than 512 KB.` };
|
|
43620
43974
|
let parsed;
|
|
43621
43975
|
try {
|
|
43622
43976
|
parsed = (0, import_yaml10.parse)(raw);
|
|
43623
43977
|
} catch (err2) {
|
|
43624
|
-
return `${STANDARD_FILE} is not valid YAML: ${terminalText(err2 instanceof Error ? err2.message : String(err2), 200)}
|
|
43978
|
+
return { ok: false, problem: `${STANDARD_FILE} is not valid YAML: ${terminalText(err2 instanceof Error ? err2.message : String(err2), 200)}` };
|
|
43625
43979
|
}
|
|
43626
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return `${STANDARD_FILE} holds no Standard
|
|
43980
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return { ok: false, problem: `${STANDARD_FILE} holds no Standard.` };
|
|
43627
43981
|
const valid = validateStandardContent(parsed);
|
|
43628
|
-
if (!valid.ok) return `${STANDARD_FILE} is not a Standard the service accepts: ${terminalText(valid.error, 200)}
|
|
43629
|
-
return
|
|
43982
|
+
if (!valid.ok) return { ok: false, problem: `${STANDARD_FILE} is not a Standard the service accepts: ${terminalText(valid.error, 200)}` };
|
|
43983
|
+
return { ok: true, content: parsed };
|
|
43630
43984
|
}
|
|
43631
43985
|
function removeLocalStandard() {
|
|
43632
43986
|
const path = projectPath(STANDARD_FILE);
|
|
@@ -43679,12 +44033,12 @@ async function standardStep(ui, ctx) {
|
|
|
43679
44033
|
return end({ source: "adopted", version: again.version, profile: profile2 });
|
|
43680
44034
|
}
|
|
43681
44035
|
removeLocalStandard();
|
|
43682
|
-
if (again.status === "write-failed" || again.status === "unavailable") rail.line(terminalText(again.reason, 300));
|
|
43683
|
-
return { ...leaveTeamStandard(again.status === "write-failed" ? "write-failed" : "unavailable", null), profile: profile2 };
|
|
44036
|
+
if (again.status === "write-failed" || again.status === "unavailable" || again.status === "denied") rail.line(terminalText(again.reason, 300));
|
|
44037
|
+
return { ...leaveTeamStandard(again.status === "write-failed" ? "write-failed" : again.status === "denied" ? refusalOutcome(again.code) : "unavailable", null), profile: profile2 };
|
|
43684
44038
|
};
|
|
43685
44039
|
const leaveTeamStandard = (why, version) => {
|
|
43686
|
-
rail.line(why === "write-failed" ? `The team's Standard${version !== null ? ` v${version}` : ""} stays in effect for reviews. Nothing was sent to the service.` : "If the team has a Standard on the service, it stays in effect for reviews. Nothing was written here or to the service.");
|
|
43687
|
-
rail.line(why === "unavailable" ? "Run verity init again once the Verity service answers." : "Fix the cause above, then run verity init again.");
|
|
44040
|
+
rail.line(why === "write-failed" ? `The team's Standard${version !== null ? ` v${version}` : ""} stays in effect for reviews. Nothing was sent to the service.` : why === "denied" ? "Verity has no access to this repository, so nothing was read or written here or on the service." : why === "sign-in-needed" ? "The Verity service did not accept your sign-in, so nothing was read or written here or on the service." : "If the team has a Standard on the service, it stays in effect for reviews. Nothing was written here or to the service.");
|
|
44041
|
+
rail.line(why === "unavailable" ? "Run verity init again once the Verity service answers." : why === "denied" ? "Give the Verity GitHub App access to this repository (the line above says how), then run: verity login, and verity init. Verity reads your repository access from GitHub only when you sign in." : why === "sign-in-needed" ? "Sign in again: run verity login, then verity init." : "Fix the cause above, then run verity init again.");
|
|
43688
44042
|
return end({ source: "none", version: null, profile: notAsked, teamInEffect: why });
|
|
43689
44043
|
};
|
|
43690
44044
|
const useTeam = async (team2) => {
|
|
@@ -43706,7 +44060,7 @@ async function standardStep(ui, ctx) {
|
|
|
43706
44060
|
rail.line(`Reviews use the team's Standard v${team2.version} on the service. Fix ${STANDARD_FILE}, or replace it with the team's: verity standard pull`);
|
|
43707
44061
|
return end({ source: "kept", version: team2.version, profile: notAsked });
|
|
43708
44062
|
}
|
|
43709
|
-
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.` : `No Standard on the service was looked up. Fix ${STANDARD_FILE}, or sign in, then run verity init again.`);
|
|
44063
|
+
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.`);
|
|
43710
44064
|
return end({ source: "none", version: null, profile: notAsked });
|
|
43711
44065
|
};
|
|
43712
44066
|
if (ctx.standard === "new" && (0, import_node_fs77.lstatSync)(projectPath(STANDARD_FILE), { throwIfNoEntry: false })) {
|
|
@@ -43719,26 +44073,77 @@ async function standardStep(ui, ctx) {
|
|
|
43719
44073
|
}
|
|
43720
44074
|
rail.done(`Set your Standard aside ${s.gray}\xB7 a copy is in ${aside.path}${s.reset}`);
|
|
43721
44075
|
}
|
|
43722
|
-
|
|
43723
|
-
const problem = localStandardProblem();
|
|
43724
|
-
if (problem !== null) return unusableHere(problem);
|
|
43725
|
-
const sync = await pushLocalStandardIfMissing(ctx.globals);
|
|
43726
|
-
rail.done("Kept your Standard");
|
|
43727
|
-
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`);
|
|
44076
|
+
const keptHints = async () => {
|
|
43728
44077
|
if (!usesReviewPacks()) {
|
|
43729
44078
|
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");
|
|
43730
44079
|
}
|
|
43731
|
-
if (
|
|
43732
|
-
rail.line(
|
|
43733
|
-
|
|
44080
|
+
if (!hasProjectRules() && await rulesOn(ctx.globals)) {
|
|
44081
|
+
rail.line("It has no project rules yet. Add them from a repo profile: verity standard generate");
|
|
44082
|
+
}
|
|
44083
|
+
};
|
|
44084
|
+
const keptHere = async (local) => {
|
|
44085
|
+
const team2 = await lookUpTeamStandard(ctx);
|
|
44086
|
+
if (team2.status === "found" || team2.status === "declined-before") {
|
|
44087
|
+
if (sameStandard(local, team2.found.standard.content)) {
|
|
44088
|
+
rail.done(`Kept your Standard ${s.gray}\xB7 it is the team's v${team2.version}${s.reset}`);
|
|
44089
|
+
rail.line(`Edit it in ${STANDARD_FILE}, then share the change: verity standard push`);
|
|
44090
|
+
await writeSetupState({ standardVersion: team2.version }).catch(() => {
|
|
44091
|
+
});
|
|
44092
|
+
await keptHints();
|
|
44093
|
+
return end({ source: "kept", version: team2.version, profile: notAsked });
|
|
44094
|
+
}
|
|
44095
|
+
const choice = ctx.standard === "use" ? "use" : team2.status === "declined-before" ? "keep" : ui.asking ? await askKeepOrPull(ui, team2) : "use";
|
|
44096
|
+
if (choice === "use") {
|
|
44097
|
+
const pulled = await pullStandard(ctx.globals);
|
|
44098
|
+
if (pulled.status === "pulled" || pulled.status === "same") {
|
|
44099
|
+
rail.done(`Using your team's Standard v${pulled.version}`);
|
|
44100
|
+
rail.line(terminalText(describeRemote(team2.found), 300));
|
|
44101
|
+
if (pulled.status === "pulled" && pulled.backup) rail.line(`Your file is kept as ${pulled.backup}`, "muted");
|
|
44102
|
+
rail.line(`Edit it in ${STANDARD_FILE}, then share the change: verity standard push`);
|
|
44103
|
+
if (pulled.status === "pulled") for (const note of pulled.notes) rail.line(terminalText(note, 300), "warn");
|
|
44104
|
+
return end({ source: "adopted", version: pulled.version, profile: notAsked });
|
|
44105
|
+
}
|
|
44106
|
+
rail.warn("Could not write the team's Standard here");
|
|
44107
|
+
rail.line(pulled.status === "failed" ? terminalText(pulled.message, 300) : `${STANDARD_FILE} changed while this ran.`);
|
|
44108
|
+
rail.line(`Reviews use the team's Standard v${team2.version} on the service. To write it here: verity standard pull`);
|
|
44109
|
+
return end({ source: "kept", version: team2.version, profile: notAsked });
|
|
44110
|
+
}
|
|
44111
|
+
rail.done(`Kept your Standard ${s.gray}\xB7 it differs from the team's v${team2.version}${s.reset}`);
|
|
44112
|
+
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.");
|
|
44113
|
+
rail.line(`To share yours over the team's: verity standard push. To use the team's here: verity standard pull`);
|
|
44114
|
+
await writeSetupState({ standardVersion: team2.version }).catch(() => {
|
|
44115
|
+
});
|
|
44116
|
+
await keptHints();
|
|
44117
|
+
return end({ source: "kept", version: team2.version, profile: notAsked });
|
|
44118
|
+
}
|
|
44119
|
+
rail.done("Kept your Standard");
|
|
44120
|
+
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`);
|
|
44121
|
+
let version = null;
|
|
44122
|
+
if (team2.status === "none") {
|
|
44123
|
+
const pushed = await pushStandard(ctx.globals, { expectedLatest: null });
|
|
44124
|
+
if (pushed.conflict) {
|
|
44125
|
+
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");
|
|
44126
|
+
} else if (pushed.standardVersion !== null) {
|
|
44127
|
+
version = pushed.standardVersion;
|
|
44128
|
+
rail.line(`It was only on this machine. It is shared now as v${version}.`, "muted");
|
|
44129
|
+
} else {
|
|
44130
|
+
rail.line("It is only on this machine:", "warn");
|
|
44131
|
+
}
|
|
44132
|
+
for (const line2 of pushed.lines) if (!line2.startsWith("Standard pushed")) rail.line(terminalText(line2, 600), "warn");
|
|
43734
44133
|
}
|
|
43735
|
-
if (
|
|
44134
|
+
if (team2.status === "unavailable") {
|
|
43736
44135
|
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");
|
|
43737
44136
|
}
|
|
43738
|
-
if (
|
|
43739
|
-
rail.line(
|
|
44137
|
+
if (team2.status === "denied") {
|
|
44138
|
+
rail.line(`It could not be compared with the team's: ${terminalText(team2.reason, 300)}`, "warn");
|
|
43740
44139
|
}
|
|
43741
|
-
|
|
44140
|
+
await keptHints();
|
|
44141
|
+
return end({ source: "kept", version, profile: notAsked });
|
|
44142
|
+
};
|
|
44143
|
+
if ((0, import_node_fs77.existsSync)(projectPath(STANDARD_FILE))) {
|
|
44144
|
+
const local = localStandard();
|
|
44145
|
+
if (!local.ok) return unusableHere(local.problem);
|
|
44146
|
+
return keptHere(local.content);
|
|
43742
44147
|
}
|
|
43743
44148
|
const team = await lookUpTeamStandard(ctx);
|
|
43744
44149
|
let replaces;
|
|
@@ -43761,6 +44166,12 @@ async function standardStep(ui, ctx) {
|
|
|
43761
44166
|
rail.line(terminalText(team.reason, 300));
|
|
43762
44167
|
return leaveTeamStandard("unavailable", null);
|
|
43763
44168
|
}
|
|
44169
|
+
if (team.status === "denied") {
|
|
44170
|
+
const refused2 = refusalOutcome(team.code);
|
|
44171
|
+
rail.warn(refused2 === "denied" ? "Verity cannot access this repository yet" : "The Verity service did not accept your sign-in");
|
|
44172
|
+
rail.line(terminalText(team.reason, 300));
|
|
44173
|
+
return leaveTeamStandard(refused2, null);
|
|
44174
|
+
}
|
|
43764
44175
|
if (team.status === "skipped") return derived(notAsked);
|
|
43765
44176
|
if (!await rulesOffered(ui, ctx.globals)) return derived(notAsked);
|
|
43766
44177
|
const profile = buildRepoProfile();
|
|
@@ -43811,10 +44222,10 @@ async function standardStep(ui, ctx) {
|
|
|
43811
44222
|
sayAdopted(ui, again);
|
|
43812
44223
|
return end({ source: "adopted", version: again.version, profile: { outcome: "ok", detail: detail2 } });
|
|
43813
44224
|
}
|
|
43814
|
-
if (again.status === "unavailable" || again.status === "write-failed") {
|
|
43815
|
-
rail.warn(again.status === "
|
|
44225
|
+
if (again.status === "unavailable" || again.status === "write-failed" || again.status === "denied") {
|
|
44226
|
+
rail.warn(again.status === "write-failed" ? "Could not write the team's Standard here" : "Could not read the team's new Standard from the Verity service");
|
|
43816
44227
|
rail.line(terminalText(again.reason, 300));
|
|
43817
|
-
return { ...leaveTeamStandard(again.status, null), profile: { outcome: "ok", detail: detail2 } };
|
|
44228
|
+
return { ...leaveTeamStandard(again.status === "denied" ? refusalOutcome(again.code) : again.status, null), profile: { outcome: "ok", detail: detail2 } };
|
|
43818
44229
|
}
|
|
43819
44230
|
}
|
|
43820
44231
|
return derived({ outcome: "ok", detail: detail2 });
|
|
@@ -43830,8 +44241,8 @@ async function finishRun(ui, ctx) {
|
|
|
43830
44241
|
sayChanged(ui, ctx.before);
|
|
43831
44242
|
if (ctx.teamInEffect) {
|
|
43832
44243
|
rail.end(
|
|
43833
|
-
ctx.teamInEffect === "unavailable" ? `${s.yellow}Not finished:${s.reset} the Verity service did not answer, so this machine has no Standard yet.` : `${s.yellow}Not finished:${s.reset} the team's Standard could not be written on this machine. Reviews still use it on the service.`,
|
|
43834
|
-
ctx.teamInEffect === "unavailable" ? "Run verity init again once the Verity service answers." : "Fix the error above, then run verity init again."
|
|
44244
|
+
ctx.teamInEffect === "unavailable" ? `${s.yellow}Not finished:${s.reset} the Verity service did not answer, so this machine has no Standard yet.` : ctx.teamInEffect === "denied" ? `${s.yellow}Not finished:${s.reset} Verity has no access to this repository yet, so it cannot review it.` : ctx.teamInEffect === "sign-in-needed" ? `${s.yellow}Not finished:${s.reset} the Verity service did not accept your sign-in, so this machine has no Standard yet.` : `${s.yellow}Not finished:${s.reset} the team's Standard could not be written on this machine. Reviews still use it on the service.`,
|
|
44245
|
+
ctx.teamInEffect === "unavailable" ? "Run verity init again once the Verity service answers." : ctx.teamInEffect === "denied" ? "Give the Verity GitHub App access to this repository, then run: verity login, and verity init. Verity reads your repository access from GitHub only when you sign in." : ctx.teamInEffect === "sign-in-needed" ? "Sign in again: run verity login, then verity init." : "Fix the error above, then run verity init again."
|
|
43835
44246
|
);
|
|
43836
44247
|
return;
|
|
43837
44248
|
}
|
|
@@ -44227,13 +44638,14 @@ async function classifyExistingLogin(serviceUrl, remote, opts) {
|
|
|
44227
44638
|
if (!existing.ok) return { kind: "none" };
|
|
44228
44639
|
const who = await whoami(existing.data.token, serviceUrl, opts.verbose);
|
|
44229
44640
|
if (who.ok && who.data.logged_in) {
|
|
44641
|
+
const nudge = reverifyNudge(who.data);
|
|
44230
44642
|
return {
|
|
44231
44643
|
kind: "signed-in",
|
|
44232
44644
|
identity: terminalText(who.data.email ?? `user #${who.data.user_id}`, 120),
|
|
44233
44645
|
// Being logged in does not mean THIS repo is covered (VRT-83): grants come
|
|
44234
44646
|
// from the login sweep. grant_status is non-null only when a grant exists.
|
|
44235
44647
|
covered: remote ? who.data.grant_status != null : null,
|
|
44236
|
-
nudge:
|
|
44648
|
+
nudge: nudge && terminalText(nudge, 200)
|
|
44237
44649
|
};
|
|
44238
44650
|
}
|
|
44239
44651
|
if (!who.ok) {
|
|
@@ -44263,6 +44675,7 @@ function coverageLines(ui, repo, covered) {
|
|
|
44263
44675
|
} else {
|
|
44264
44676
|
ui.rail.line(`${repo} is not covered by your Verity access, so nothing syncs.`, "warn");
|
|
44265
44677
|
ui.rail.line("Give the Verity GitHub App access to it, then run: verity login");
|
|
44678
|
+
ui.rail.line("Verity reads your repository access from GitHub only when you sign in. The new sign-in is how Verity sees the repository.", "muted");
|
|
44266
44679
|
}
|
|
44267
44680
|
}
|
|
44268
44681
|
async function signInStep(ui, resolution, opts) {
|
|
@@ -44283,6 +44696,7 @@ async function signInStep(ui, resolution, opts) {
|
|
|
44283
44696
|
const heal = await maybeHealServiceUrl(resolution, opts.verbose);
|
|
44284
44697
|
const serviceUrl = heal.serviceUrl;
|
|
44285
44698
|
const remote = gitRemote();
|
|
44699
|
+
let grantAccess = false;
|
|
44286
44700
|
if (heal.healed) {
|
|
44287
44701
|
rail.warn("The saved Verity service no longer answers");
|
|
44288
44702
|
rail.line("Sign in again to repair ~/.verity/credentials.");
|
|
@@ -44290,9 +44704,14 @@ async function signInStep(ui, resolution, opts) {
|
|
|
44290
44704
|
const state = await classifyExistingLogin(serviceUrl, remote, opts);
|
|
44291
44705
|
if (state.kind === "signed-in") {
|
|
44292
44706
|
rail.done(`Signed in as ${s.bold}${state.identity}${s.reset}`);
|
|
44293
|
-
coverageLines(ui, opts.repo, state.covered);
|
|
44294
44707
|
if (state.nudge) rail.line(state.nudge, "warn");
|
|
44295
|
-
|
|
44708
|
+
if (state.covered !== false || !ui.asking) {
|
|
44709
|
+
coverageLines(ui, opts.repo, state.covered);
|
|
44710
|
+
return end("already");
|
|
44711
|
+
}
|
|
44712
|
+
rail.line(`Verity can't see ${opts.repo} yet: the Verity GitHub App has no access to it.`, "warn");
|
|
44713
|
+
grantAccess = true;
|
|
44714
|
+
rail.settle();
|
|
44296
44715
|
}
|
|
44297
44716
|
if (state.kind === "cached") {
|
|
44298
44717
|
rail.done(state.identity ? `Signed in as ${s.bold}${state.identity}${s.reset} (cached)` : "Using your existing Verity token");
|
|
@@ -44313,16 +44732,28 @@ async function signInStep(ui, resolution, opts) {
|
|
|
44313
44732
|
sayWhatASkipCosts(ui);
|
|
44314
44733
|
return end("unattended");
|
|
44315
44734
|
}
|
|
44316
|
-
|
|
44317
|
-
|
|
44318
|
-
|
|
44735
|
+
if (grantAccess) {
|
|
44736
|
+
rail.active(`Give Verity access to ${opts.repo}`);
|
|
44737
|
+
rail.line("Verity reads your repository access from GitHub only when you sign in.");
|
|
44738
|
+
rail.line("So sign in again: Verity opens the page where you add this repository to its app, and waits.");
|
|
44739
|
+
rail.line("When the repository is added, Verity can see it, and this run continues.");
|
|
44740
|
+
} else {
|
|
44741
|
+
rail.active("Sign in with GitHub");
|
|
44742
|
+
rail.line("One sign-in covers every repository on this machine.");
|
|
44743
|
+
rail.line("Signing in does not give Verity access to the contents of your repositories.");
|
|
44744
|
+
}
|
|
44319
44745
|
rail.gap();
|
|
44320
44746
|
rail.keys([["Enter", "open the browser"], ["s", "skip"]]);
|
|
44321
44747
|
const choice = await screen.key(["enter", "s"], "s");
|
|
44322
44748
|
if (choice === "s") {
|
|
44323
44749
|
rail.collapse();
|
|
44324
|
-
rail.warn("Sign-in skipped");
|
|
44325
|
-
|
|
44750
|
+
rail.warn(grantAccess ? "Access skipped" : "Sign-in skipped");
|
|
44751
|
+
if (grantAccess) {
|
|
44752
|
+
rail.line(`Verity can't review ${opts.repo} until its GitHub App has access to it.`);
|
|
44753
|
+
rail.line("Later: add the repository to the Verity app, then run verity login. Verity reads your repository access from GitHub only when you sign in.");
|
|
44754
|
+
} else {
|
|
44755
|
+
sayWhatASkipCosts(ui);
|
|
44756
|
+
}
|
|
44326
44757
|
return end("declined");
|
|
44327
44758
|
}
|
|
44328
44759
|
const failed = (why) => {
|
|
@@ -44338,20 +44769,23 @@ async function signInStep(ui, resolution, opts) {
|
|
|
44338
44769
|
const dc = code.data;
|
|
44339
44770
|
const copied = copyToClipboard(dc.user_code);
|
|
44340
44771
|
const opened = openInBrowser(dc.verification_uri);
|
|
44341
|
-
|
|
44772
|
+
const where2 = terminalText(dc.verification_uri, 200);
|
|
44773
|
+
const userCode = terminalText(dc.user_code, 40);
|
|
44774
|
+
rail.line(opened ? `Opened ${where2} in your browser. If no window appeared, open it and enter the code.` : `Open ${where2} and enter the code.`, opened ? "muted" : "plain");
|
|
44342
44775
|
const prefix = `${s.gray}\u2502${s.reset} `;
|
|
44343
44776
|
const polled = await screen.breathe(
|
|
44344
44777
|
prefix,
|
|
44345
|
-
() => `Waiting for you in the browser \xB7 code ${s.bold}${
|
|
44778
|
+
() => `Waiting for you in the browser \xB7 code ${s.bold}${userCode}${s.reset}${copied ? ` ${s.gray}(copied)${s.reset}` : ""}`,
|
|
44346
44779
|
pollDeviceToken(dc, { codeExpiresAt: Date.now() + dc.expires_in * 1e3, quiet: true })
|
|
44347
44780
|
);
|
|
44348
44781
|
if (!polled.ok) return failed(polled.error);
|
|
44349
44782
|
let gaveUp = null;
|
|
44350
44783
|
const appInstallUi = {
|
|
44351
44784
|
wait: async (ctx, visible) => {
|
|
44352
|
-
|
|
44353
|
-
rail.line(ctx.
|
|
44354
|
-
|
|
44785
|
+
const owner = terminalText(ctx.owner, 100);
|
|
44786
|
+
rail.line(`The Verity GitHub App cannot see ${owner}/${terminalText(ctx.repo, 100)} yet. Install it${ctx.opened ? " (opened in your browser)" : ""}:`, "warn");
|
|
44787
|
+
rail.line(terminalText(ctx.installUrl, 300), "plain");
|
|
44788
|
+
return screen.breathe(prefix, () => `Waiting for the install on ${owner}`, visible);
|
|
44355
44789
|
},
|
|
44356
44790
|
gaveUp: (message) => {
|
|
44357
44791
|
gaveUp = message;
|
|
@@ -44372,7 +44806,7 @@ async function signInStep(ui, resolution, opts) {
|
|
|
44372
44806
|
if (gaveUp) rail.line(terminalText(gaveUp, 300), "warn");
|
|
44373
44807
|
for (const line2 of report.slice(1)) {
|
|
44374
44808
|
if (line2.level === "verbose") continue;
|
|
44375
|
-
rail.line(line2.text.trim().replace(/^✓\s*/, ""), line2.level === "warn" ? "warn" : "muted");
|
|
44809
|
+
rail.line(terminalText(line2.text.trim().replace(/^✓\s*/, ""), 300), line2.level === "warn" ? "warn" : "muted");
|
|
44376
44810
|
}
|
|
44377
44811
|
return end("new");
|
|
44378
44812
|
}
|
|
@@ -44412,7 +44846,7 @@ async function recordAnswers(ui, momentIds, telemetry, completed) {
|
|
|
44412
44846
|
moments: momentIds,
|
|
44413
44847
|
...telemetry ? { telemetry } : {},
|
|
44414
44848
|
// A failed run also clears an earlier stamp: "done" describes this checkout now.
|
|
44415
|
-
init: completed ? { completed_at: (/* @__PURE__ */ new Date()).toISOString(), cli_version: true ? "0.35.
|
|
44849
|
+
init: completed ? { completed_at: (/* @__PURE__ */ new Date()).toISOString(), cli_version: true ? "0.35.4" : "dev" } : void 0
|
|
44416
44850
|
});
|
|
44417
44851
|
} catch (err2) {
|
|
44418
44852
|
ui.rail.line(`Could not record the setup answers: ${terminalText(err2.message, 200)}`, "warn");
|
|
@@ -44491,7 +44925,7 @@ async function runInit(program2, opts) {
|
|
|
44491
44925
|
process.exit(1);
|
|
44492
44926
|
}
|
|
44493
44927
|
trace.mark("prerequisites", "ok");
|
|
44494
|
-
await scaffoldStep(ui, { untrackMemory: opts.untrackMemory === true, untrackState: opts.untrackState === true });
|
|
44928
|
+
await scaffoldStep(ui, { untrackMemory: opts.untrackMemory === true, untrackStandard: opts.untrackStandard === true, untrackState: opts.untrackState === true });
|
|
44495
44929
|
trace.mark("scaffold", "ok");
|
|
44496
44930
|
await (0, import_promises17.mkdir)((0, import_node_path68.join)((0, import_node_os15.homedir)(), ".verity"), { recursive: true });
|
|
44497
44931
|
await repoStep(ui, detectProject());
|
|
@@ -44542,7 +44976,7 @@ async function runInit(program2, opts) {
|
|
|
44542
44976
|
}
|
|
44543
44977
|
}
|
|
44544
44978
|
function registerInitCommand(program2) {
|
|
44545
|
-
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));
|
|
44979
|
+
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));
|
|
44546
44980
|
}
|
|
44547
44981
|
|
|
44548
44982
|
// src/commands/doctor.ts
|
|
@@ -44571,17 +45005,23 @@ async function buildReport() {
|
|
|
44571
45005
|
if (legacyOnly) {
|
|
44572
45006
|
next.push(`Run "verity init" \u2014 it moves the old GATE.md install, with its Standard (${LEGACY_STANDARD_FILE}), to .verity/.`);
|
|
44573
45007
|
}
|
|
45008
|
+
const standard = { tracked: committedStandardFile(), version: state?.standardVersion ?? null };
|
|
44574
45009
|
const missing = [
|
|
44575
45010
|
!artifacts.standard && !legacyOnly && ".verity/standard.yaml",
|
|
44576
45011
|
!artifacts.verityMd && !legacyOnly && "VERITY.md"
|
|
44577
45012
|
].filter((x) => !!x);
|
|
44578
|
-
if (
|
|
44579
|
-
next.push(
|
|
45013
|
+
if (!artifacts.standard && !legacyOnly) {
|
|
45014
|
+
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.`);
|
|
44580
45015
|
} else if (missing.length > 0) {
|
|
44581
45016
|
next.push(
|
|
44582
45017
|
`Missing ${missing.join(" and ")}. Run "verity standard synthesize --force" to regenerate \u2014 note that replaces the Standard.`
|
|
44583
45018
|
);
|
|
44584
45019
|
}
|
|
45020
|
+
if (standard.tracked) {
|
|
45021
|
+
next.push(
|
|
45022
|
+
'.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").'
|
|
45023
|
+
);
|
|
45024
|
+
}
|
|
44585
45025
|
const noAnalysisMoment = !hooks.stop && hooks.guardOn.length === 0;
|
|
44586
45026
|
const configRead = readProjectConfig();
|
|
44587
45027
|
if (configRead.refused) next.push(configRefusalMessage(configRead.refused));
|
|
@@ -44659,6 +45099,7 @@ async function buildReport() {
|
|
|
44659
45099
|
artifacts,
|
|
44660
45100
|
memory: memory2,
|
|
44661
45101
|
trackedState,
|
|
45102
|
+
standard,
|
|
44662
45103
|
next
|
|
44663
45104
|
};
|
|
44664
45105
|
}
|
|
@@ -44706,7 +45147,7 @@ function registerDoctorCommand(program2) {
|
|
|
44706
45147
|
if (process.platform === "win32") printWarn(WINDOWS_STATIC_NOTE);
|
|
44707
45148
|
else printInfo("Static analysis: Trivy (dependencies, malicious packages, secrets)");
|
|
44708
45149
|
printInfo("Artifacts:");
|
|
44709
|
-
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"}`);
|
|
45150
|
+
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"}`);
|
|
44710
45151
|
printInfo(` VERITY.md: ${report.artifacts.verityMd ? "\u2713" : "missing"}`);
|
|
44711
45152
|
printInfo(
|
|
44712
45153
|
` .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"}`
|
|
@@ -46335,10 +46776,10 @@ function registerLeanCommand(program2) {
|
|
|
46335
46776
|
}
|
|
46336
46777
|
|
|
46337
46778
|
// src/cli.ts
|
|
46338
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.35.
|
|
46779
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.35.4").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) => {
|
|
46339
46780
|
const isTelemetryHelper = actionCommand.name() === "headers" && actionCommand.parent?.name() === "telemetry";
|
|
46340
46781
|
if (!isTelemetryHelper) {
|
|
46341
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.35.
|
|
46782
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.35.4");
|
|
46342
46783
|
}
|
|
46343
46784
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
46344
46785
|
try {
|