@codacy/verity-cli 0.35.2 → 0.35.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/bin/verity.js +237 -44
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -64,6 +64,32 @@ installs are untouched.
|
|
|
64
64
|
which is the ordinary case for someone whose first Verity install *is* the
|
|
65
65
|
plugin.
|
|
66
66
|
|
|
67
|
+
## [0.35.3] — 2026-11-05
|
|
68
|
+
|
|
69
|
+
### 🔧 Fixes
|
|
70
|
+
|
|
71
|
+
- **`verity init` on a repository the Verity GitHub App cannot see gives it
|
|
72
|
+
access in the same run.** Init offers a GitHub sign-in that opens the page
|
|
73
|
+
where you add the repository to the Verity app, waits for it, and then
|
|
74
|
+
continues. Init says why a second sign-in is needed: Verity reads your
|
|
75
|
+
repository access from GitHub only when you sign in. With `--yes` or no
|
|
76
|
+
terminal, init names the one action instead.
|
|
77
|
+
- **Init states a refusal as a refusal.** When the service refuses access to
|
|
78
|
+
the repository, init writes nothing, says that Verity cannot access the
|
|
79
|
+
repository yet, names the one action, and exits 1. Before, it said the
|
|
80
|
+
service did not answer and told you to run `verity init` again.
|
|
81
|
+
- **A turn with nothing new to review no longer prints a Verity line.**
|
|
82
|
+
Before, a line such as "No files modified since last analysis" showed under
|
|
83
|
+
every message. `verity config verbose on` brings the line back. Turns that
|
|
84
|
+
wrote code still get their review, and a change that nobody reviewed is
|
|
85
|
+
still reported.
|
|
86
|
+
- **The upgrade link in a plan-limit message is clickable.** It keeps its
|
|
87
|
+
`https://`.
|
|
88
|
+
- **`verity usage` says "your plan" for the plan you own, and `verity status`
|
|
89
|
+
no longer lists that plan under "member of".** A team you belong to is still
|
|
90
|
+
listed as a team.
|
|
91
|
+
- Includes security fixes.
|
|
92
|
+
|
|
67
93
|
## [0.35.2] — 2026-10-30
|
|
68
94
|
|
|
69
95
|
### 🔧 Fixes
|
package/bin/verity.js
CHANGED
|
@@ -15325,7 +15325,7 @@ function pinRefusalMessage(verdict, targetUrl) {
|
|
|
15325
15325
|
// src/lib/cli-version.ts
|
|
15326
15326
|
function cliVersion() {
|
|
15327
15327
|
try {
|
|
15328
|
-
return true ? "0.35.
|
|
15328
|
+
return true ? "0.35.3" : "dev";
|
|
15329
15329
|
} catch {
|
|
15330
15330
|
return "dev";
|
|
15331
15331
|
}
|
|
@@ -19207,13 +19207,21 @@ function readConfigFile(path) {
|
|
|
19207
19207
|
git_moments: [...new Set(moments)],
|
|
19208
19208
|
...source2 ? { git_moments_source: source2 } : {},
|
|
19209
19209
|
...raw.formal === "push" || raw.formal === "off" ? { formal: raw.formal } : {},
|
|
19210
|
-
...raw.turn_review === "on" || raw.turn_review === "off" ? { turn_review: raw.turn_review } : {}
|
|
19210
|
+
...raw.turn_review === "on" || raw.turn_review === "off" ? { turn_review: raw.turn_review } : {},
|
|
19211
|
+
...raw.verbose === "on" || raw.verbose === "off" ? { verbose: raw.verbose } : {}
|
|
19211
19212
|
}
|
|
19212
19213
|
};
|
|
19213
19214
|
} catch {
|
|
19214
19215
|
return { cfg: DEFAULTS };
|
|
19215
19216
|
}
|
|
19216
19217
|
}
|
|
19218
|
+
function readVerbose() {
|
|
19219
|
+
try {
|
|
19220
|
+
return readProjectConfigRaw().verbose === "on";
|
|
19221
|
+
} catch {
|
|
19222
|
+
return false;
|
|
19223
|
+
}
|
|
19224
|
+
}
|
|
19217
19225
|
function configRefusalMessage(reason) {
|
|
19218
19226
|
switch (reason) {
|
|
19219
19227
|
case "link":
|
|
@@ -19285,12 +19293,13 @@ function formalRefusalMessage(reason) {
|
|
|
19285
19293
|
}
|
|
19286
19294
|
}
|
|
19287
19295
|
function writeProjectConfig(patch) {
|
|
19288
|
-
const { git_moments, git_moments_source, formal, turn_review } = readProjectConfigRaw();
|
|
19296
|
+
const { git_moments, git_moments_source, formal, turn_review, verbose } = readProjectConfigRaw();
|
|
19289
19297
|
const next = {
|
|
19290
19298
|
git_moments,
|
|
19291
19299
|
...git_moments_source ? { git_moments_source } : {},
|
|
19292
19300
|
...formal ? { formal } : {},
|
|
19293
19301
|
...turn_review ? { turn_review } : {},
|
|
19302
|
+
...verbose ? { verbose } : {},
|
|
19294
19303
|
...patch
|
|
19295
19304
|
};
|
|
19296
19305
|
writeRepoFile(PROJECT_CONFIG_FILE, JSON.stringify(next, null, 2) + "\n");
|
|
@@ -21715,6 +21724,112 @@ var LEGACY_MD_END = "<!-- gate-memory:end -->";
|
|
|
21715
21724
|
var LEGACY_PRESERVE_START = "<!-- gate-memory:preserve -->";
|
|
21716
21725
|
var LEGACY_PRESERVE_END = "<!-- /gate-memory:preserve -->";
|
|
21717
21726
|
var CLAUDE_MD_PROSE = [
|
|
21727
|
+
"## Project Memory",
|
|
21728
|
+
"",
|
|
21729
|
+
"This project has a knowledge graph maintained at `.verity/memory/`. Before starting",
|
|
21730
|
+
"non-trivial work, scan `.verity/memory/index.md` for decisions, gotchas, and patterns",
|
|
21731
|
+
"that may apply to the change you are about to make. Open specific node files via",
|
|
21732
|
+
"the Read tool when the title or scope suggests relevance.",
|
|
21733
|
+
"",
|
|
21734
|
+
"The graph is auto-maintained by Verity. Files at `.verity/memory/_archive/` are",
|
|
21735
|
+
"superseded \u2014 ignore them unless investigating history.",
|
|
21736
|
+
"",
|
|
21737
|
+
"Knowledge the organization's other repositories learned is mirrored outside the",
|
|
21738
|
+
"repo at `~/.verity/orgs/<host>/<owner>/memory/` (`verity memory org` lists it).",
|
|
21739
|
+
"Each claim says where it came from; one that is wrong here is demoted for",
|
|
21740
|
+
'everyone with `verity memory demote <id> --reason "\u2026"`.',
|
|
21741
|
+
"",
|
|
21742
|
+
"## Quality gate: accepted risks",
|
|
21743
|
+
"",
|
|
21744
|
+
"When the Verity pre-commit/pre-push gate FAILs, fix the findings \u2014 that is the",
|
|
21745
|
+
'default. Use `verity waive <pattern-id> --file <path> --reason "\u2026"` ONLY to relay',
|
|
21746
|
+
"a risk a human has explicitly accepted: a named code-review finding, an ADR, or",
|
|
21747
|
+
"the user saying so in this conversation. The --reason must cite that source.",
|
|
21748
|
+
"",
|
|
21749
|
+
"Never waive on your own judgment, to get past a block, or pre-emptively. A waive",
|
|
21750
|
+
"binds to the file's current bytes and voids automatically when the file changes,",
|
|
21751
|
+
"and every waive is recorded in the run ledger. For a pattern-level false positive",
|
|
21752
|
+
"use `verity feedback finding <run-id> <pattern-id> false_positive` instead.",
|
|
21753
|
+
"",
|
|
21754
|
+
"## Post-task reflection",
|
|
21755
|
+
"",
|
|
21756
|
+
`When a task is complete (you've created a PR, the user says "done" or "ship it",`,
|
|
21757
|
+
"or the work is clearly finished), **draft the reflection yourself** \u2014 1\u20133",
|
|
21758
|
+
"concrete things worth remembering (a decision, a gotcha, or a pattern), each",
|
|
21759
|
+
"cited with the files / PR / commands / error-signatures it came from. Skip",
|
|
21760
|
+
"entirely if nothing non-obvious happened \u2014 that judgement is the ONLY filter,",
|
|
21761
|
+
"because nothing reviews the reflection before it lands.",
|
|
21762
|
+
"",
|
|
21763
|
+
"Then record it straight away. There is no confirm step, in any environment:",
|
|
21764
|
+
"",
|
|
21765
|
+
"```bash",
|
|
21766
|
+
"verity reflect --user-input - --kind <kind> <<'VERITY_EOF_<random>'",
|
|
21767
|
+
"<your draft>",
|
|
21768
|
+
"VERITY_EOF_<random>",
|
|
21769
|
+
"```",
|
|
21770
|
+
"",
|
|
21771
|
+
'The draft goes through the quoted heredoc, never inside `"\u2026"` on the command',
|
|
21772
|
+
'line, where a `"` or `$(\u2026)` in it would run in the shell. Replace `<random>`',
|
|
21773
|
+
"with 8 random letters and digits that you pick for this call, the same at both",
|
|
21774
|
+
"ends. Text written before you picked them cannot end the heredoc early.",
|
|
21775
|
+
"",
|
|
21776
|
+
"Add `--confirmed` ONLY when the user authored or dictated the words. Without",
|
|
21777
|
+
"it the node is stored as `source: agent` \u2014 Verity thought this, nobody checked",
|
|
21778
|
+
"it. With it, `source: user` at full confidence \u2014 a person stands behind this.",
|
|
21779
|
+
"Never claim the second for your own draft, however good it is.",
|
|
21780
|
+
"",
|
|
21781
|
+
"**Name the files in the text.** Verity scopes the reflection to the paths it",
|
|
21782
|
+
"cites, and a reflection that names no file in this repo is never retrieved for",
|
|
21783
|
+
"a later review \u2014 it is recorded and then invisible. The command says so when it",
|
|
21784
|
+
"happens; `--file-globs '<path or glob>'` is the fix when the prose cannot carry",
|
|
21785
|
+
"the paths.",
|
|
21786
|
+
"",
|
|
21787
|
+
"Then tell the user, in one line, what you recorded and where: the command",
|
|
21788
|
+
"prints the node id, the path under `.verity/memory/`, and a dashboard link.",
|
|
21789
|
+
"They did not agree to it in advance, so say it happened \u2014 editing or deleting",
|
|
21790
|
+
"that file is how they correct it.",
|
|
21791
|
+
"",
|
|
21792
|
+
"> Durable, hand-curated guidance goes in the preserve region below (it survives",
|
|
21793
|
+
"> regeneration) or anywhere OUTSIDE these markers. Everything else between the",
|
|
21794
|
+
"> markers is tool-owned and overwritten on each run.",
|
|
21795
|
+
"",
|
|
21796
|
+
"## Housekeeping Turns",
|
|
21797
|
+
"",
|
|
21798
|
+
"When a turn will be pure housekeeping \u2014 pulling, installing dependencies,",
|
|
21799
|
+
"rebasing, a formatting sweep you are not authoring \u2014 declare it BEFORE doing it:",
|
|
21800
|
+
"",
|
|
21801
|
+
"```bash",
|
|
21802
|
+
'verity ignore --turn --agent --reason "pulling latest before starting"',
|
|
21803
|
+
"```",
|
|
21804
|
+
"",
|
|
21805
|
+
"This skips the review for that turn, which saves the turn Verity would",
|
|
21806
|
+
"otherwise spend saying it had nothing to say. Use `--for 30m` instead of",
|
|
21807
|
+
"`--turn` when a single piece of housekeeping spans several turns.",
|
|
21808
|
+
"",
|
|
21809
|
+
"**It is a claim about the turn, not a way to silence review.** The declaration",
|
|
21810
|
+
"is checked against what the turn actually did: if anything is authored \u2014 by you,",
|
|
21811
|
+
"by a subagent, or by a shell command that can write files \u2014 it voids, the review",
|
|
21812
|
+
"runs anyway, and the broken declaration is reported. So declare housekeeping you",
|
|
21813
|
+
"are about to do, never work you have already done, and never as a way to get past",
|
|
21814
|
+
"a finding. Declarations are budgeted per session and every one is recorded with",
|
|
21815
|
+
"its reason.",
|
|
21816
|
+
"",
|
|
21817
|
+
"## Verity settings",
|
|
21818
|
+
"",
|
|
21819
|
+
"Change these only when the user asks. Each command prints what it changed.",
|
|
21820
|
+
"",
|
|
21821
|
+
"- When Verity reviews: `verity config moments turn,commit,push`. Give any of the",
|
|
21822
|
+
" three, or `none`. With no list, it prints the current setting.",
|
|
21823
|
+
"- Formal verification at push: `verity config formal push`, or `verity config formal off`.",
|
|
21824
|
+
"- The line Verity prints when a turn has nothing new to review: `verity config verbose on`,",
|
|
21825
|
+
" or `verity config verbose off` (the default).",
|
|
21826
|
+
"- Project rules, written by Verity from this repository's history and docs:",
|
|
21827
|
+
" `verity standard generate`. It works only for a project with no Standard on the",
|
|
21828
|
+
" service. It writes `.verity/repo-profile.json` and sends nothing without consent.",
|
|
21829
|
+
" Show the user that file. Run the command again with `--yes` only after they agree.",
|
|
21830
|
+
"- The rules themselves: edit `.verity/standard.yaml`, then run `verity standard push`."
|
|
21831
|
+
].join("\n");
|
|
21832
|
+
var CLAUDE_MD_PROSE_PRE_VERBOSE = [
|
|
21718
21833
|
"## Project Memory",
|
|
21719
21834
|
"",
|
|
21720
21835
|
"This project has a knowledge graph maintained at `.verity/memory/`. Before starting",
|
|
@@ -22351,6 +22466,7 @@ function stripKnownProse(interior) {
|
|
|
22351
22466
|
const trimmed = interior.replace(/^\n+/, "");
|
|
22352
22467
|
for (const prose of [
|
|
22353
22468
|
CLAUDE_MD_PROSE,
|
|
22469
|
+
CLAUDE_MD_PROSE_PRE_VERBOSE,
|
|
22354
22470
|
CLAUDE_MD_PROSE_PRE_SETTINGS,
|
|
22355
22471
|
CLAUDE_MD_PROSE_PRE_STDIN,
|
|
22356
22472
|
CLAUDE_MD_PROSE_PRE_ORG,
|
|
@@ -26343,6 +26459,18 @@ function registerConfigCommands(program2) {
|
|
|
26343
26459
|
printInfo(state === "push" ? "Formal verification at push: on for this checkout (Lean must be installed \u2014 verity lean status)" : "Formal verification at push: off");
|
|
26344
26460
|
if (state === "push") printInfo("The phase runs with your Verity login (a push without one is skipped and says so: not-logged-in)");
|
|
26345
26461
|
});
|
|
26462
|
+
config.command("verbose [state]").description('Get or set the line Verity prints when a turn has nothing new to review: "on" or "off" (the default)').action((state) => {
|
|
26463
|
+
if (state === void 0) {
|
|
26464
|
+
process.stdout.write((readProjectConfig().verbose === "on" ? "on" : "off") + "\n");
|
|
26465
|
+
return;
|
|
26466
|
+
}
|
|
26467
|
+
if (state !== "on" && state !== "off") {
|
|
26468
|
+
printError(`Unrecognised state: ${state}. Use "on" or "off".`);
|
|
26469
|
+
process.exit(1);
|
|
26470
|
+
}
|
|
26471
|
+
writeProjectConfig({ verbose: state });
|
|
26472
|
+
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.");
|
|
26473
|
+
});
|
|
26346
26474
|
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
26475
|
const globals = program2.opts();
|
|
26348
26476
|
const tokenResult = await resolveToken(globals.token);
|
|
@@ -26818,8 +26946,8 @@ function timeAgo(isoDate) {
|
|
|
26818
26946
|
}
|
|
26819
26947
|
var PLAN_NAME = { free: "Free", pro: "Pro", fleet: "Fleet", enterprise: "Enterprise" };
|
|
26820
26948
|
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"`;
|
|
26949
|
+
const teams = accounts.filter((a) => !(a.is_owner ?? a.kind === "personal")).map((a) => `${terminalText(a.name)} (${PLAN_NAME[a.plan] ?? terminalText(a.plan)})`);
|
|
26950
|
+
return `${PLAN_NAME[plan] ?? terminalText(plan)}${teams.length ? ` \xB7 member of ${teams.join(", ")}` : ""} \u2014 limits: "verity usage"`;
|
|
26823
26951
|
}
|
|
26824
26952
|
function registerStatusCommand(program2) {
|
|
26825
26953
|
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 +27198,7 @@ function dollars(cents2) {
|
|
|
27070
27198
|
return `$${((cents2 ?? 0) / 100).toFixed(2)}`;
|
|
27071
27199
|
}
|
|
27072
27200
|
function link(l) {
|
|
27073
|
-
return (l.upgrade_url
|
|
27201
|
+
return terminalUrl(l.upgrade_url) || "https://verity.md/upgrade";
|
|
27074
27202
|
}
|
|
27075
27203
|
function detail(l, now) {
|
|
27076
27204
|
const reset = resetPhrase(l, now, true);
|
|
@@ -27081,7 +27209,8 @@ function detail(l, now) {
|
|
|
27081
27209
|
return `Extra usage reached this month's ${dollars(l.limit)} cap. ${Reset}. ${way2}`;
|
|
27082
27210
|
}
|
|
27083
27211
|
if (l.period === "week") {
|
|
27084
|
-
const
|
|
27212
|
+
const team = shared ? terminalText(l.account) : "";
|
|
27213
|
+
const who = team ? `${team} used its` : "You used your";
|
|
27085
27214
|
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
27215
|
return `${who} ${l.limit} ${METER[l.meter]} this week. ${Reset}. ${way2}`;
|
|
27087
27216
|
}
|
|
@@ -27160,8 +27289,11 @@ function windowText(w, resetsAt, now, weekly) {
|
|
|
27160
27289
|
function cents(n2) {
|
|
27161
27290
|
return n2 === null ? "\u2014" : n2 < 100 ? `${n2}\xA2` : `$${(n2 / 100).toFixed(2)}`;
|
|
27162
27291
|
}
|
|
27292
|
+
function ownsAccount(b) {
|
|
27293
|
+
return b?.account?.is_owner ?? b?.account?.kind === "personal";
|
|
27294
|
+
}
|
|
27163
27295
|
function extraOffText(b, ui) {
|
|
27164
|
-
if (b
|
|
27296
|
+
if (ownsAccount(b)) return `off \u2014 turn it on at ${ui}/account/billing`;
|
|
27165
27297
|
return "off \u2014 a team admin can turn it on";
|
|
27166
27298
|
}
|
|
27167
27299
|
function renderBudget(b, now = /* @__PURE__ */ new Date(), ui = uiBase()) {
|
|
@@ -27177,12 +27309,14 @@ function renderBudget(b, now = /* @__PURE__ */ new Date(), ui = uiBase()) {
|
|
|
27177
27309
|
return lines;
|
|
27178
27310
|
}
|
|
27179
27311
|
function budgetName(b) {
|
|
27180
|
-
|
|
27312
|
+
if (!b.account) return PLAN2[b.plan];
|
|
27313
|
+
const name2 = terminalText(b.account.name);
|
|
27314
|
+
return ownsAccount(b) ? `${PLAN2[b.plan]} \xB7 ${name2} (your plan)` : `${PLAN2[b.plan]} \xB7 ${name2}`;
|
|
27181
27315
|
}
|
|
27182
27316
|
function payerText(b) {
|
|
27183
27317
|
if (!b || !b.account) return "your Free plan";
|
|
27184
|
-
if (b
|
|
27185
|
-
return `the ${PLAN2[b.plan]} plan of ${b.account.name}`;
|
|
27318
|
+
if (ownsAccount(b)) return `your ${PLAN2[b.plan]} plan`;
|
|
27319
|
+
return `the ${PLAN2[b.plan]} plan of ${terminalText(b.account.name)}`;
|
|
27186
27320
|
}
|
|
27187
27321
|
function renderLimits(d, now = /* @__PURE__ */ new Date()) {
|
|
27188
27322
|
const ui = d.ui_url ? d.ui_url.replace(/\/+$/, "") : uiBase();
|
|
@@ -27190,10 +27324,10 @@ function renderLimits(d, now = /* @__PURE__ */ new Date()) {
|
|
|
27190
27324
|
if (!d.enforced) lines.push(d.mode === "shadow" ? "Limits are counted, not yet enforced." : "Limits are not active.");
|
|
27191
27325
|
const payer = d.budgets.find((b) => b.applies_here);
|
|
27192
27326
|
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.`);
|
|
27327
|
+
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
27328
|
}
|
|
27195
|
-
const
|
|
27196
|
-
const shown = d.budgets.filter((b) => !(
|
|
27329
|
+
const hasOwn = d.budgets.some((b) => ownsAccount(b));
|
|
27330
|
+
const shown = d.budgets.filter((b) => !(hasOwn && b.budget === "free"));
|
|
27197
27331
|
const full = payer ? shown.filter((b) => b === payer) : shown;
|
|
27198
27332
|
for (const b of full) {
|
|
27199
27333
|
lines.push("");
|
|
@@ -30244,7 +30378,13 @@ async function passAndExit(run4, reason, skip, kindOverride) {
|
|
|
30244
30378
|
const AGENT_SILENT_SKIPS = /* @__PURE__ */ new Set([]);
|
|
30245
30379
|
const agentNote = AGENT_SILENT_SKIPS.has(skip) ? null : note;
|
|
30246
30380
|
const HUMAN_SILENT_SKIPS = /* @__PURE__ */ new Set(["command-only-turn"]);
|
|
30247
|
-
const
|
|
30381
|
+
const quiet = quietSkip({
|
|
30382
|
+
skip,
|
|
30383
|
+
kind: skipKind,
|
|
30384
|
+
nothingChanged: nothingChanged(run4),
|
|
30385
|
+
verbose: readVerbose()
|
|
30386
|
+
});
|
|
30387
|
+
const humanNote = HUMAN_SILENT_SKIPS.has(skip) || quiet ? null : `Verity: ${reason}`;
|
|
30248
30388
|
printJsonCompact(
|
|
30249
30389
|
buildHookOutput(
|
|
30250
30390
|
verdict,
|
|
@@ -30257,6 +30397,22 @@ async function passAndExit(run4, reason, skip, kindOverride) {
|
|
|
30257
30397
|
);
|
|
30258
30398
|
process.exit(0);
|
|
30259
30399
|
}
|
|
30400
|
+
var NOTHING_NEW = /* @__PURE__ */ new Set(["no-delta-since-last-review", "no-analyzable-files"]);
|
|
30401
|
+
var QUIET_ON_CLEAN_TREE = /* @__PURE__ */ new Set([
|
|
30402
|
+
"debounce",
|
|
30403
|
+
"verity-command",
|
|
30404
|
+
"bare-acknowledgment",
|
|
30405
|
+
"reflection-prompt",
|
|
30406
|
+
"skip-mode",
|
|
30407
|
+
"zero-increment"
|
|
30408
|
+
]);
|
|
30409
|
+
function quietSkip(s) {
|
|
30410
|
+
if (s.verbose || s.kind !== "policy") return false;
|
|
30411
|
+
return NOTHING_NEW.has(s.skip) || QUIET_ON_CLEAN_TREE.has(s.skip) && s.nothingChanged;
|
|
30412
|
+
}
|
|
30413
|
+
function nothingChanged(run4) {
|
|
30414
|
+
return partitionVerityOwned(run4.changedUniverse).kept.length === 0;
|
|
30415
|
+
}
|
|
30260
30416
|
|
|
30261
30417
|
// src/commands/analyze/phases/02-scope.ts
|
|
30262
30418
|
async function scope(run4) {
|
|
@@ -31148,7 +31304,8 @@ async function evidence(run4) {
|
|
|
31148
31304
|
const scoped = scopeToAuthored(allForReview, actionSummary);
|
|
31149
31305
|
const canTrustNoneAuthored = scoped.signal === "none-authored" && authorshipIsObservable;
|
|
31150
31306
|
if (canTrustNoneAuthored && !hasNonEditAuthorship(actionSummary, sessionAuthoredCode)) {
|
|
31151
|
-
|
|
31307
|
+
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";
|
|
31308
|
+
await passAndExit(run4, why, "zero-increment");
|
|
31152
31309
|
}
|
|
31153
31310
|
if (scoped.signal === "none-authored" && !authorshipIsObservable) {
|
|
31154
31311
|
logEvent("none_authored_unverifiable", {
|
|
@@ -43499,13 +43656,20 @@ function sayPacks(ui, plan) {
|
|
|
43499
43656
|
}
|
|
43500
43657
|
|
|
43501
43658
|
// src/commands/init/team-standard.ts
|
|
43659
|
+
function refusalOutcome(code) {
|
|
43660
|
+
return code === "FORBIDDEN" ? "denied" : "sign-in-needed";
|
|
43661
|
+
}
|
|
43502
43662
|
async function lookUpTeamStandard(opts) {
|
|
43503
43663
|
if (!opts.adopt) return { status: "skipped", why: "no-adopt" };
|
|
43504
43664
|
const token = await resolveToken(opts.globals.token);
|
|
43505
43665
|
const url = await resolveServiceUrl(opts.globals.serviceUrl);
|
|
43506
43666
|
if (!token.ok || !url.ok) return { status: "skipped", why: "not-signed-in" };
|
|
43507
43667
|
const found = await fetchRemoteSetup({ token: token.data.token, serviceUrl: url.data, verbose: opts.globals.verbose });
|
|
43508
|
-
if (found.status === "unavailable")
|
|
43668
|
+
if (found.status === "unavailable") {
|
|
43669
|
+
const denial = authDenialRemedy(found.reason);
|
|
43670
|
+
if (denial) return { status: "denied", code: denial.code, reason: terminalText(found.reason, 300) };
|
|
43671
|
+
return { status: "unavailable", reason: terminalText(found.reason, 300) };
|
|
43672
|
+
}
|
|
43509
43673
|
if (found.status === "none") return { status: "none" };
|
|
43510
43674
|
if (opts.previous?.declinedStandardVersion === found.standard.version) {
|
|
43511
43675
|
return { status: "declined-before", version: found.standard.version, found };
|
|
@@ -43679,12 +43843,12 @@ async function standardStep(ui, ctx) {
|
|
|
43679
43843
|
return end({ source: "adopted", version: again.version, profile: profile2 });
|
|
43680
43844
|
}
|
|
43681
43845
|
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 };
|
|
43846
|
+
if (again.status === "write-failed" || again.status === "unavailable" || again.status === "denied") rail.line(terminalText(again.reason, 300));
|
|
43847
|
+
return { ...leaveTeamStandard(again.status === "write-failed" ? "write-failed" : again.status === "denied" ? refusalOutcome(again.code) : "unavailable", null), profile: profile2 };
|
|
43684
43848
|
};
|
|
43685
43849
|
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.");
|
|
43850
|
+
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.");
|
|
43851
|
+
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
43852
|
return end({ source: "none", version: null, profile: notAsked, teamInEffect: why });
|
|
43689
43853
|
};
|
|
43690
43854
|
const useTeam = async (team2) => {
|
|
@@ -43706,7 +43870,7 @@ async function standardStep(ui, ctx) {
|
|
|
43706
43870
|
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
43871
|
return end({ source: "kept", version: team2.version, profile: notAsked });
|
|
43708
43872
|
}
|
|
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.`);
|
|
43873
|
+
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
43874
|
return end({ source: "none", version: null, profile: notAsked });
|
|
43711
43875
|
};
|
|
43712
43876
|
if (ctx.standard === "new" && (0, import_node_fs77.lstatSync)(projectPath(STANDARD_FILE), { throwIfNoEntry: false })) {
|
|
@@ -43761,6 +43925,12 @@ async function standardStep(ui, ctx) {
|
|
|
43761
43925
|
rail.line(terminalText(team.reason, 300));
|
|
43762
43926
|
return leaveTeamStandard("unavailable", null);
|
|
43763
43927
|
}
|
|
43928
|
+
if (team.status === "denied") {
|
|
43929
|
+
const refused2 = refusalOutcome(team.code);
|
|
43930
|
+
rail.warn(refused2 === "denied" ? "Verity cannot access this repository yet" : "The Verity service did not accept your sign-in");
|
|
43931
|
+
rail.line(terminalText(team.reason, 300));
|
|
43932
|
+
return leaveTeamStandard(refused2, null);
|
|
43933
|
+
}
|
|
43764
43934
|
if (team.status === "skipped") return derived(notAsked);
|
|
43765
43935
|
if (!await rulesOffered(ui, ctx.globals)) return derived(notAsked);
|
|
43766
43936
|
const profile = buildRepoProfile();
|
|
@@ -43811,10 +43981,10 @@ async function standardStep(ui, ctx) {
|
|
|
43811
43981
|
sayAdopted(ui, again);
|
|
43812
43982
|
return end({ source: "adopted", version: again.version, profile: { outcome: "ok", detail: detail2 } });
|
|
43813
43983
|
}
|
|
43814
|
-
if (again.status === "unavailable" || again.status === "write-failed") {
|
|
43815
|
-
rail.warn(again.status === "
|
|
43984
|
+
if (again.status === "unavailable" || again.status === "write-failed" || again.status === "denied") {
|
|
43985
|
+
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
43986
|
rail.line(terminalText(again.reason, 300));
|
|
43817
|
-
return { ...leaveTeamStandard(again.status, null), profile: { outcome: "ok", detail: detail2 } };
|
|
43987
|
+
return { ...leaveTeamStandard(again.status === "denied" ? refusalOutcome(again.code) : again.status, null), profile: { outcome: "ok", detail: detail2 } };
|
|
43818
43988
|
}
|
|
43819
43989
|
}
|
|
43820
43990
|
return derived({ outcome: "ok", detail: detail2 });
|
|
@@ -43830,8 +44000,8 @@ async function finishRun(ui, ctx) {
|
|
|
43830
44000
|
sayChanged(ui, ctx.before);
|
|
43831
44001
|
if (ctx.teamInEffect) {
|
|
43832
44002
|
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."
|
|
44003
|
+
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.`,
|
|
44004
|
+
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
44005
|
);
|
|
43836
44006
|
return;
|
|
43837
44007
|
}
|
|
@@ -44227,13 +44397,14 @@ async function classifyExistingLogin(serviceUrl, remote, opts) {
|
|
|
44227
44397
|
if (!existing.ok) return { kind: "none" };
|
|
44228
44398
|
const who = await whoami(existing.data.token, serviceUrl, opts.verbose);
|
|
44229
44399
|
if (who.ok && who.data.logged_in) {
|
|
44400
|
+
const nudge = reverifyNudge(who.data);
|
|
44230
44401
|
return {
|
|
44231
44402
|
kind: "signed-in",
|
|
44232
44403
|
identity: terminalText(who.data.email ?? `user #${who.data.user_id}`, 120),
|
|
44233
44404
|
// Being logged in does not mean THIS repo is covered (VRT-83): grants come
|
|
44234
44405
|
// from the login sweep. grant_status is non-null only when a grant exists.
|
|
44235
44406
|
covered: remote ? who.data.grant_status != null : null,
|
|
44236
|
-
nudge:
|
|
44407
|
+
nudge: nudge && terminalText(nudge, 200)
|
|
44237
44408
|
};
|
|
44238
44409
|
}
|
|
44239
44410
|
if (!who.ok) {
|
|
@@ -44263,6 +44434,7 @@ function coverageLines(ui, repo, covered) {
|
|
|
44263
44434
|
} else {
|
|
44264
44435
|
ui.rail.line(`${repo} is not covered by your Verity access, so nothing syncs.`, "warn");
|
|
44265
44436
|
ui.rail.line("Give the Verity GitHub App access to it, then run: verity login");
|
|
44437
|
+
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
44438
|
}
|
|
44267
44439
|
}
|
|
44268
44440
|
async function signInStep(ui, resolution, opts) {
|
|
@@ -44283,6 +44455,7 @@ async function signInStep(ui, resolution, opts) {
|
|
|
44283
44455
|
const heal = await maybeHealServiceUrl(resolution, opts.verbose);
|
|
44284
44456
|
const serviceUrl = heal.serviceUrl;
|
|
44285
44457
|
const remote = gitRemote();
|
|
44458
|
+
let grantAccess = false;
|
|
44286
44459
|
if (heal.healed) {
|
|
44287
44460
|
rail.warn("The saved Verity service no longer answers");
|
|
44288
44461
|
rail.line("Sign in again to repair ~/.verity/credentials.");
|
|
@@ -44290,9 +44463,14 @@ async function signInStep(ui, resolution, opts) {
|
|
|
44290
44463
|
const state = await classifyExistingLogin(serviceUrl, remote, opts);
|
|
44291
44464
|
if (state.kind === "signed-in") {
|
|
44292
44465
|
rail.done(`Signed in as ${s.bold}${state.identity}${s.reset}`);
|
|
44293
|
-
coverageLines(ui, opts.repo, state.covered);
|
|
44294
44466
|
if (state.nudge) rail.line(state.nudge, "warn");
|
|
44295
|
-
|
|
44467
|
+
if (state.covered !== false || !ui.asking) {
|
|
44468
|
+
coverageLines(ui, opts.repo, state.covered);
|
|
44469
|
+
return end("already");
|
|
44470
|
+
}
|
|
44471
|
+
rail.line(`Verity can't see ${opts.repo} yet: the Verity GitHub App has no access to it.`, "warn");
|
|
44472
|
+
grantAccess = true;
|
|
44473
|
+
rail.settle();
|
|
44296
44474
|
}
|
|
44297
44475
|
if (state.kind === "cached") {
|
|
44298
44476
|
rail.done(state.identity ? `Signed in as ${s.bold}${state.identity}${s.reset} (cached)` : "Using your existing Verity token");
|
|
@@ -44313,16 +44491,28 @@ async function signInStep(ui, resolution, opts) {
|
|
|
44313
44491
|
sayWhatASkipCosts(ui);
|
|
44314
44492
|
return end("unattended");
|
|
44315
44493
|
}
|
|
44316
|
-
|
|
44317
|
-
|
|
44318
|
-
|
|
44494
|
+
if (grantAccess) {
|
|
44495
|
+
rail.active(`Give Verity access to ${opts.repo}`);
|
|
44496
|
+
rail.line("Verity reads your repository access from GitHub only when you sign in.");
|
|
44497
|
+
rail.line("So sign in again: Verity opens the page where you add this repository to its app, and waits.");
|
|
44498
|
+
rail.line("When the repository is added, Verity can see it, and this run continues.");
|
|
44499
|
+
} else {
|
|
44500
|
+
rail.active("Sign in with GitHub");
|
|
44501
|
+
rail.line("One sign-in covers every repository on this machine.");
|
|
44502
|
+
rail.line("Signing in does not give Verity access to the contents of your repositories.");
|
|
44503
|
+
}
|
|
44319
44504
|
rail.gap();
|
|
44320
44505
|
rail.keys([["Enter", "open the browser"], ["s", "skip"]]);
|
|
44321
44506
|
const choice = await screen.key(["enter", "s"], "s");
|
|
44322
44507
|
if (choice === "s") {
|
|
44323
44508
|
rail.collapse();
|
|
44324
|
-
rail.warn("Sign-in skipped");
|
|
44325
|
-
|
|
44509
|
+
rail.warn(grantAccess ? "Access skipped" : "Sign-in skipped");
|
|
44510
|
+
if (grantAccess) {
|
|
44511
|
+
rail.line(`Verity can't review ${opts.repo} until its GitHub App has access to it.`);
|
|
44512
|
+
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.");
|
|
44513
|
+
} else {
|
|
44514
|
+
sayWhatASkipCosts(ui);
|
|
44515
|
+
}
|
|
44326
44516
|
return end("declined");
|
|
44327
44517
|
}
|
|
44328
44518
|
const failed = (why) => {
|
|
@@ -44338,20 +44528,23 @@ async function signInStep(ui, resolution, opts) {
|
|
|
44338
44528
|
const dc = code.data;
|
|
44339
44529
|
const copied = copyToClipboard(dc.user_code);
|
|
44340
44530
|
const opened = openInBrowser(dc.verification_uri);
|
|
44341
|
-
|
|
44531
|
+
const where2 = terminalText(dc.verification_uri, 200);
|
|
44532
|
+
const userCode = terminalText(dc.user_code, 40);
|
|
44533
|
+
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
44534
|
const prefix = `${s.gray}\u2502${s.reset} `;
|
|
44343
44535
|
const polled = await screen.breathe(
|
|
44344
44536
|
prefix,
|
|
44345
|
-
() => `Waiting for you in the browser \xB7 code ${s.bold}${
|
|
44537
|
+
() => `Waiting for you in the browser \xB7 code ${s.bold}${userCode}${s.reset}${copied ? ` ${s.gray}(copied)${s.reset}` : ""}`,
|
|
44346
44538
|
pollDeviceToken(dc, { codeExpiresAt: Date.now() + dc.expires_in * 1e3, quiet: true })
|
|
44347
44539
|
);
|
|
44348
44540
|
if (!polled.ok) return failed(polled.error);
|
|
44349
44541
|
let gaveUp = null;
|
|
44350
44542
|
const appInstallUi = {
|
|
44351
44543
|
wait: async (ctx, visible) => {
|
|
44352
|
-
|
|
44353
|
-
rail.line(ctx.
|
|
44354
|
-
|
|
44544
|
+
const owner = terminalText(ctx.owner, 100);
|
|
44545
|
+
rail.line(`The Verity GitHub App cannot see ${owner}/${terminalText(ctx.repo, 100)} yet. Install it${ctx.opened ? " (opened in your browser)" : ""}:`, "warn");
|
|
44546
|
+
rail.line(terminalText(ctx.installUrl, 300), "plain");
|
|
44547
|
+
return screen.breathe(prefix, () => `Waiting for the install on ${owner}`, visible);
|
|
44355
44548
|
},
|
|
44356
44549
|
gaveUp: (message) => {
|
|
44357
44550
|
gaveUp = message;
|
|
@@ -44372,7 +44565,7 @@ async function signInStep(ui, resolution, opts) {
|
|
|
44372
44565
|
if (gaveUp) rail.line(terminalText(gaveUp, 300), "warn");
|
|
44373
44566
|
for (const line2 of report.slice(1)) {
|
|
44374
44567
|
if (line2.level === "verbose") continue;
|
|
44375
|
-
rail.line(line2.text.trim().replace(/^✓\s*/, ""), line2.level === "warn" ? "warn" : "muted");
|
|
44568
|
+
rail.line(terminalText(line2.text.trim().replace(/^✓\s*/, ""), 300), line2.level === "warn" ? "warn" : "muted");
|
|
44376
44569
|
}
|
|
44377
44570
|
return end("new");
|
|
44378
44571
|
}
|
|
@@ -44412,7 +44605,7 @@ async function recordAnswers(ui, momentIds, telemetry, completed) {
|
|
|
44412
44605
|
moments: momentIds,
|
|
44413
44606
|
...telemetry ? { telemetry } : {},
|
|
44414
44607
|
// 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.
|
|
44608
|
+
init: completed ? { completed_at: (/* @__PURE__ */ new Date()).toISOString(), cli_version: true ? "0.35.3" : "dev" } : void 0
|
|
44416
44609
|
});
|
|
44417
44610
|
} catch (err2) {
|
|
44418
44611
|
ui.rail.line(`Could not record the setup answers: ${terminalText(err2.message, 200)}`, "warn");
|
|
@@ -46335,10 +46528,10 @@ function registerLeanCommand(program2) {
|
|
|
46335
46528
|
}
|
|
46336
46529
|
|
|
46337
46530
|
// src/cli.ts
|
|
46338
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.35.
|
|
46531
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.35.3").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
46532
|
const isTelemetryHelper = actionCommand.name() === "headers" && actionCommand.parent?.name() === "telemetry";
|
|
46340
46533
|
if (!isTelemetryHelper) {
|
|
46341
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.35.
|
|
46534
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.35.3");
|
|
46342
46535
|
}
|
|
46343
46536
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
46344
46537
|
try {
|