@codacy/verity-cli 0.35.4 → 0.35.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/verity.js CHANGED
@@ -15351,7 +15351,7 @@ function pinRefusalMessage(verdict, targetUrl) {
15351
15351
  // src/lib/cli-version.ts
15352
15352
  function cliVersion() {
15353
15353
  try {
15354
- return true ? "0.35.4" : "dev";
15354
+ return true ? "0.35.5" : "dev";
15355
15355
  } catch {
15356
15356
  return "dev";
15357
15357
  }
@@ -19369,26 +19369,43 @@ function readProjectConfig() {
19369
19369
  cfg = { ...rest, turn_review_refused: refused2 };
19370
19370
  }
19371
19371
  }
19372
+ if (cfg.formal === "off" && cfg.path) {
19373
+ const refused2 = repoControlledRefusal(cfg.path);
19374
+ if (refused2 === "unverified") {
19375
+ cfg = { ...cfg, formal_off_unverified: true };
19376
+ } else if (refused2) {
19377
+ const { formal: _dropped, ...rest } = cfg;
19378
+ cfg = { ...rest, formal_off_refused: refused2 };
19379
+ }
19380
+ }
19372
19381
  return cfg;
19373
19382
  }
19374
- function turnReviewRefusalMessage(reason) {
19383
+ function formalOffUnverifiedNote() {
19384
+ return 'off-unverified: .verity/config.json says "off" and git could not confirm that the repository does not control it, so the "off" is kept and the formal check does not run';
19385
+ }
19386
+ function formalOffRefusalMessage(reason) {
19375
19387
  switch (reason) {
19376
19388
  case "tracked":
19377
- return '.verity/config.json is tracked in git, so its turn_review "off" is ignored (a repository cannot switch the review off) \u2014 untrack it with: git rm --cached .verity/config.json';
19389
+ return '.verity/config.json is tracked in git, so its formal "off" is ignored (a repository cannot switch formal verification off). To make your "off" count, untrack the file: git rm --cached .verity/config.json';
19378
19390
  case "symlink":
19379
- return '.verity/config.json is reached through a symlink, so its turn_review "off" is ignored';
19380
- case "unverified":
19381
- return 'could not confirm with git that .verity/config.json is untracked, so its turn_review "off" is ignored';
19391
+ return '.verity/config.json is reached through a symlink, so its formal "off" is ignored';
19382
19392
  }
19383
19393
  }
19384
- function formalRefusalMessage(reason) {
19394
+ function formalSetting(cfg, env = process.env) {
19395
+ const fromEnv = env.VERITY_GIT_MOMENT_FORMAL;
19396
+ if (fromEnv === "off" || fromEnv === "push") return { state: fromEnv, source: "env" };
19397
+ if (cfg.formal === "off") return { state: "off", source: "config" };
19398
+ if (cfg.formal === "push") return { state: "push", source: "config" };
19399
+ return { state: "push", source: "default" };
19400
+ }
19401
+ function turnReviewRefusalMessage(reason) {
19385
19402
  switch (reason) {
19386
19403
  case "tracked":
19387
- return ".verity/config.json is tracked in git, so its formal setting is ignored (a repository cannot switch formal verification on) \u2014 untrack it with: git rm --cached .verity/config.json";
19404
+ return '.verity/config.json is tracked in git, so its turn_review "off" is ignored (a repository cannot switch the review off) \u2014 untrack it with: git rm --cached .verity/config.json';
19388
19405
  case "symlink":
19389
- return ".verity/config.json is reached through a symlink, so its formal setting is ignored";
19406
+ return '.verity/config.json is reached through a symlink, so its turn_review "off" is ignored';
19390
19407
  case "unverified":
19391
- return "could not confirm with git that .verity/config.json is untracked, so its formal setting is ignored";
19408
+ return 'could not confirm with git that .verity/config.json is untracked, so its turn_review "off" is ignored';
19392
19409
  }
19393
19410
  }
19394
19411
  function writeProjectConfig(patch) {
@@ -26603,11 +26620,15 @@ function registerConfigCommands(program2) {
26603
26620
  }
26604
26621
  printInfo(pluginMode ? "It applies from the next turn." : "It applies from the next Claude Code session (Claude Code reads hooks when a session starts).");
26605
26622
  });
26606
- config.command("formal [state]").description('Get or set formal verification at push: "push" or "off" (needs Lean \u2014 verity lean status)').action((state) => {
26623
+ config.command("formal [state]").description('Get or set formal verification at push: "push" (the default) or "off" (needs Lean \u2014 verity lean status)').action((state) => {
26607
26624
  if (state === void 0) {
26608
26625
  const cfg = readProjectConfig();
26609
- process.stdout.write((cfg.formal === "push" ? "push" : "off") + "\n");
26610
- if (cfg.formal_refused) printWarn(formalRefusalMessage(cfg.formal_refused));
26626
+ const setting = formalSetting(cfg);
26627
+ process.stdout.write(setting.state + "\n");
26628
+ if (cfg.formal_off_refused && setting.source === "default") printWarn(formalOffRefusalMessage(cfg.formal_off_refused));
26629
+ else if (setting.source === "default") printInfo("On by default. To turn it off for this checkout, run: verity config formal off");
26630
+ if (setting.source === "env") printInfo("Set by VERITY_GIT_MOMENT_FORMAL in this environment");
26631
+ if (cfg.formal_off_unverified && setting.source === "config") printWarn(formalOffUnverifiedNote());
26611
26632
  return;
26612
26633
  }
26613
26634
  if (state !== "push" && state !== "off") {
@@ -26615,13 +26636,18 @@ function registerConfigCommands(program2) {
26615
26636
  process.exit(1);
26616
26637
  }
26617
26638
  writeProjectConfig({ formal: state === "push" ? "push" : "off" });
26618
- const refused2 = state === "push" ? readProjectConfig().formal_refused : void 0;
26619
- if (refused2) {
26620
- printWarn(`Formal verification at push: still off \u2014 ${formalRefusalMessage(refused2)}`);
26639
+ const after = readProjectConfig();
26640
+ const offRefused = state === "off" && formalSetting(after).state === "push" ? after.formal_off_refused : void 0;
26641
+ if (offRefused) {
26642
+ printWarn(`Formal verification at push: still on \u2014 ${formalOffRefusalMessage(offRefused)}`);
26621
26643
  return;
26622
26644
  }
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");
26645
+ printInfo(state === "push" ? "Formal verification at push: on for this checkout (Lean must be installed \u2014 verity lean status)" : "Formal verification at push: off for this checkout");
26624
26646
  if (state === "push") printInfo("The phase runs with your Verity login (a push without one is skipped and says so: not-logged-in)");
26647
+ const env = process.env.VERITY_GIT_MOMENT_FORMAL;
26648
+ if ((env === "off" || env === "push") && env !== state) {
26649
+ printWarn(`VERITY_GIT_MOMENT_FORMAL=${env} in this environment overrides the file while it is set`);
26650
+ }
26625
26651
  });
26626
26652
  config.command("verbose [state]").description('Get or set the line Verity prints when a turn has nothing new to review: "on" or "off" (the default)').action((state) => {
26627
26653
  if (state === void 0) {
@@ -29780,11 +29806,11 @@ async function readStopHookStdin() {
29780
29806
  return new Promise((resolve10) => {
29781
29807
  const chunks = [];
29782
29808
  let size = 0;
29783
- let settled = false;
29809
+ let settled2 = false;
29784
29810
  let timer;
29785
29811
  const settle = (result) => {
29786
- if (settled) return;
29787
- settled = true;
29812
+ if (settled2) return;
29813
+ settled2 = true;
29788
29814
  if (timer) clearTimeout(timer);
29789
29815
  process.stdin.off("data", onData);
29790
29816
  process.stdin.off("end", onEnd);
@@ -37129,7 +37155,7 @@ function runAsync(tc, cwd, args2, timeoutMs) {
37129
37155
  let stdout = "";
37130
37156
  let stderr = "";
37131
37157
  let timedOut = false;
37132
- let settled = false;
37158
+ let settled2 = false;
37133
37159
  const kill = () => {
37134
37160
  try {
37135
37161
  if (posix && child.pid) process.kill(-child.pid, "SIGKILL");
@@ -37148,8 +37174,8 @@ function runAsync(tc, cwd, args2, timeoutMs) {
37148
37174
  if (stderr.length < MAX) stderr += d.toString("utf-8");
37149
37175
  });
37150
37176
  const finish = (ok, message) => {
37151
- if (settled) return;
37152
- settled = true;
37177
+ if (settled2) return;
37178
+ settled2 = true;
37153
37179
  clearTimeout(timer);
37154
37180
  if (ok) resolve10({ ok: true, stdout, stderr: "", durationMs: Date.now() - started, timedOut: false });
37155
37181
  else resolve10({ ok: false, stdout, stderr: stderr || message || "", durationMs: Date.now() - started, timedOut });
@@ -37658,16 +37684,138 @@ function resumeInterruptedInstall(opts) {
37658
37684
  return shouldStartBackgroundInstall({ formal: opts.formal, env, free: opts.free }).start && startBackgroundInstall({ cli: opts.cli, env, run: opts.run });
37659
37685
  }
37660
37686
 
37687
+ // src/lib/prove/formal-default.ts
37688
+ var import_node_fs64 = require("node:fs");
37689
+ var import_node_path52 = require("node:path");
37690
+ var NOTICE_MARKER = ".formal-default-notice";
37691
+ var LEAN_MARKER = ".formal-lean-checked";
37692
+ function markerPath3(name2) {
37693
+ return (0, import_node_path52.join)(verityHome(), name2);
37694
+ }
37695
+ function writeMarker(name2, now) {
37696
+ try {
37697
+ (0, import_node_fs64.mkdirSync)(verityHome(), { recursive: true, mode: 448 });
37698
+ (0, import_node_fs64.writeFileSync)(markerPath3(name2), now.toISOString() + "\n");
37699
+ } catch {
37700
+ }
37701
+ }
37702
+ function formalDefaultNoticeDue() {
37703
+ return !(0, import_node_fs64.existsSync)(markerPath3(NOTICE_MARKER));
37704
+ }
37705
+ function recordFormalDefaultNotice(now = /* @__PURE__ */ new Date()) {
37706
+ writeMarker(NOTICE_MARKER, now);
37707
+ }
37708
+ var BLOCKED_LINES = {
37709
+ "opted-out": () => "VERITY_NO_LEAN=1 is set, so Verity does not download Lean 4. Without Lean 4, a push skips the formal check.",
37710
+ ci: () => "This is a CI environment, so Verity does not download Lean 4 (VERITY_LEAN=1 allows it). Without Lean 4, a push skips the formal check.",
37711
+ disk: (detail2) => `Lean 4 needs more disk space${detail2 ? ` (${detail2})` : ""}. Until Lean 4 is installed, a push skips the formal check. Free some space, then run: verity lean install`,
37712
+ "no-release": () => "Lean 4 has no release for this machine, so a push skips the formal check."
37713
+ };
37714
+ function leanLine(lean) {
37715
+ switch (lean.kind) {
37716
+ case "started":
37717
+ return "Lean 4 (about 800 MB) is downloading in the background. To see the progress, run: verity lean status";
37718
+ case "downloading":
37719
+ return "Lean 4 is downloading in the background. To see the progress, run: verity lean status";
37720
+ case "failed":
37721
+ return "The Lean 4 download could not start. Until Lean 4 is installed, a push skips the formal check. To install it, run: verity lean install";
37722
+ case "previous-failed":
37723
+ return "The last Lean 4 download failed. Until Lean 4 is installed, a push skips the formal check. To try again, run: verity lean install";
37724
+ case "blocked":
37725
+ return BLOCKED_LINES[lean.why](lean.detail);
37726
+ case "installed":
37727
+ case "unknown":
37728
+ return null;
37729
+ }
37730
+ }
37731
+ function formalDefaultUserMessage(lean, offRefused) {
37732
+ const aboutLean = leanLine(lean);
37733
+ return [
37734
+ ...offRefused ? [`Verity: ${formalOffRefusalMessage(offRefused)}`] : [],
37735
+ "Verity: formal verification at push is now on by default.",
37736
+ "At a push, Verity can check a small Lean model of the riskiest changed function and replay a counterexample on the real code. For the replay, the source of that function goes to the Verity service.",
37737
+ "Only a reproduced bug can block a push.",
37738
+ ...aboutLean ? [aboutLean] : [],
37739
+ "To turn it off for this project, run: verity config formal off"
37740
+ ].join("\n");
37741
+ }
37742
+ var AGENT_LINE = "Formal verification at push is on by default in this project. At a push, Verity can model one changed function in Lean, so a push can take longer. A block from it means that the counterexample was reproduced on the real code. If the user wants it off, the command is `verity config formal off`.";
37743
+ function settled(lean) {
37744
+ return lean.kind === "installed" || lean.kind === "blocked" && lean.why === "no-release";
37745
+ }
37746
+ var LEAN_RECHECK_MS = 7 * 24 * 60 * 60 * 1e3;
37747
+ function settledRecently(now) {
37748
+ try {
37749
+ const at = Date.parse((0, import_node_fs64.readFileSync)(markerPath3(LEAN_MARKER), "utf-8").trim());
37750
+ return Number.isFinite(at) && now.getTime() - at >= 0 && now.getTime() - at < LEAN_RECHECK_MS;
37751
+ } catch {
37752
+ return false;
37753
+ }
37754
+ }
37755
+ function leanAtStart(opts, now, probeAgain) {
37756
+ const { env } = opts;
37757
+ if (env.VERITY_NO_LEAN === "1") return { kind: "blocked", why: "opted-out" };
37758
+ if (env.CI && env.VERITY_LEAN !== "1") return { kind: "blocked", why: "ci" };
37759
+ const state = readInstallState(env);
37760
+ if (state?.state === "failed") return { kind: "previous-failed" };
37761
+ if (state?.state === "done") return { kind: "installed" };
37762
+ if (state?.state === "running") return installRunning(env) ? { kind: "downloading" } : { kind: "unknown" };
37763
+ if (!probeAgain && settledRecently(now)) return { kind: "unknown" };
37764
+ const lean = probeAndStart(opts);
37765
+ if (settled(lean)) writeMarker(LEAN_MARKER, now);
37766
+ return lean;
37767
+ }
37768
+ function probeAndStart(opts) {
37769
+ const { env } = opts;
37770
+ const d = shouldStartBackgroundInstall({ formal: "push", env, free: opts.free });
37771
+ if (d.start) {
37772
+ const started = startBackgroundInstall({ cli: opts.cli, env, ...opts.run ? { run: opts.run } : {} });
37773
+ return started ? { kind: "started" } : { kind: "failed" };
37774
+ }
37775
+ switch (d.why) {
37776
+ case "installed":
37777
+ return { kind: "installed" };
37778
+ case "running":
37779
+ return { kind: "downloading" };
37780
+ case "opted-out":
37781
+ case "ci":
37782
+ case "no-release":
37783
+ return { kind: "blocked", why: d.why };
37784
+ case "disk":
37785
+ return { kind: "blocked", why: "disk", ...d.detail ? { detail: d.detail } : {} };
37786
+ case "formal-off":
37787
+ return { kind: "unknown" };
37788
+ }
37789
+ }
37790
+ function formalAtSessionStart(opts) {
37791
+ const env = opts.env ?? process.env;
37792
+ const now = opts.now ?? /* @__PURE__ */ new Date();
37793
+ const none = { userMsg: null, agentLine: null, leanStarted: false };
37794
+ const setting = formalSetting(opts.cfg, env);
37795
+ if (setting.state !== "push") return none;
37796
+ const noticeDue = setting.source === "default" && formalDefaultNoticeDue();
37797
+ let lean;
37798
+ try {
37799
+ lean = leanAtStart({ cli: opts.cli, env, ...opts.free !== void 0 ? { free: opts.free } : {}, ...opts.run ? { run: opts.run } : {} }, now, noticeDue);
37800
+ } catch (err2) {
37801
+ lean = { kind: "failed" };
37802
+ logEvent("formal_default_lean_failed", { error: String(err2?.message ?? err2).slice(0, 200) });
37803
+ }
37804
+ const leanStarted = lean.kind === "started";
37805
+ if (!noticeDue) return { ...none, leanStarted };
37806
+ return { userMsg: formalDefaultUserMessage(lean, opts.cfg.formal_off_refused), agentLine: AGENT_LINE, leanStarted };
37807
+ }
37808
+
37661
37809
  // src/commands/baseline.ts
37662
- var import_node_fs66 = require("node:fs");
37663
- var import_node_path54 = require("node:path");
37810
+ var import_node_fs67 = require("node:fs");
37811
+ var import_node_path55 = require("node:path");
37664
37812
 
37665
37813
  // src/lib/skew-notice.ts
37666
- var import_node_fs64 = require("node:fs");
37667
- var import_node_path52 = require("node:path");
37814
+ var import_node_fs65 = require("node:fs");
37815
+ var import_node_path53 = require("node:path");
37668
37816
  var MARKER2 = ".skew-notice.json";
37669
- function markerPath3() {
37670
- return (0, import_node_path52.join)(verityHome(), MARKER2);
37817
+ function markerPath4() {
37818
+ return (0, import_node_path53.join)(verityHome(), MARKER2);
37671
37819
  }
37672
37820
  function today(now) {
37673
37821
  const y = now.getFullYear();
@@ -37677,7 +37825,7 @@ function today(now) {
37677
37825
  }
37678
37826
  function skewNoticeDue(skew, now = /* @__PURE__ */ new Date()) {
37679
37827
  try {
37680
- const seen = JSON.parse((0, import_node_fs64.readFileSync)(markerPath3(), "utf-8"));
37828
+ const seen = JSON.parse((0, import_node_fs65.readFileSync)(markerPath4(), "utf-8"));
37681
37829
  return !(seen.global === skew.global && seen.hooks === skew.hooks && seen.day === today(now));
37682
37830
  } catch {
37683
37831
  return true;
@@ -37685,15 +37833,15 @@ function skewNoticeDue(skew, now = /* @__PURE__ */ new Date()) {
37685
37833
  }
37686
37834
  function recordSkewNotice(skew, now = /* @__PURE__ */ new Date()) {
37687
37835
  try {
37688
- (0, import_node_fs64.mkdirSync)(verityHome(), { recursive: true, mode: 448 });
37689
- (0, import_node_fs64.writeFileSync)(markerPath3(), JSON.stringify({ global: skew.global, hooks: skew.hooks, day: today(now) }) + "\n");
37836
+ (0, import_node_fs65.mkdirSync)(verityHome(), { recursive: true, mode: 448 });
37837
+ (0, import_node_fs65.writeFileSync)(markerPath4(), JSON.stringify({ global: skew.global, hooks: skew.hooks, day: today(now) }) + "\n");
37690
37838
  } catch {
37691
37839
  }
37692
37840
  }
37693
37841
 
37694
37842
  // src/lib/project-skills.ts
37695
- var import_node_fs65 = require("node:fs");
37696
- var import_node_path53 = require("node:path");
37843
+ var import_node_fs66 = require("node:fs");
37844
+ var import_node_path54 = require("node:path");
37697
37845
  var PROJECT_SKILL_NAMES = [
37698
37846
  "verity-setup",
37699
37847
  "verity-analyze",
@@ -37719,14 +37867,14 @@ var LEGACY_SKILL_NAMES = [
37719
37867
  var ALL = [...PROJECT_SKILL_NAMES, ...LEGACY_SKILL_NAMES];
37720
37868
  function staleProjectSkills() {
37721
37869
  const root = projectPath(".claude/skills");
37722
- if (!(0, import_node_fs65.existsSync)(root)) return [];
37723
- return ALL.filter((name2) => (0, import_node_fs65.existsSync)((0, import_node_path53.join)(root, name2)));
37870
+ if (!(0, import_node_fs66.existsSync)(root)) return [];
37871
+ return ALL.filter((name2) => (0, import_node_fs66.existsSync)((0, import_node_path54.join)(root, name2)));
37724
37872
  }
37725
37873
  function removeProjectSkills() {
37726
37874
  const root = projectPath(".claude/skills");
37727
37875
  const removed = [];
37728
37876
  for (const name2 of staleProjectSkills()) {
37729
- (0, import_node_fs65.rmSync)((0, import_node_path53.join)(root, name2), { recursive: true, force: true });
37877
+ (0, import_node_fs66.rmSync)((0, import_node_path54.join)(root, name2), { recursive: true, force: true });
37730
37878
  removed.push(name2);
37731
37879
  }
37732
37880
  return removed;
@@ -37761,7 +37909,7 @@ function registerBaselineCommands(program2) {
37761
37909
  const loginWarning = "Until they have, do not send them to run `verity login` in a terminal: that runs the global one, which can sign this machine in to a different server.";
37762
37910
  const skewNote = !skew ? null : skewLoud ? `Before anything else, including /verity:init's questions, tell the user their global \`verity\` is ${skew.global}, the hooks run ${skew.hooks}, and \`${skew.remedy}\` fixes it. ${loginWarning}` : `The user's global \`verity\` is ${skew.global} and the hooks run ${skew.hooks}; \`${skew.remedy}\` fixes it. They were already told today, so do not repeat it unprompted \u2014 mention it only where it matters, such as before suggesting a \`verity\` command for their terminal. ${loginWarning}`;
37763
37911
  if (!verityConfigured()) {
37764
- if (isMachineStore((0, import_node_path54.join)(repoRoot(), VERITY_DIR))) process.exit(0);
37912
+ if (isMachineStore((0, import_node_path55.join)(repoRoot(), VERITY_DIR))) process.exit(0);
37765
37913
  const how = isPluginInvocation() ? "Tell the user to run /verity:init \u2014 they type it; you cannot invoke it." : "Tell the user to run `verity init` in their terminal.";
37766
37914
  const lines = [
37767
37915
  `Verity is installed but this project is not set up yet, so the quality gate will not review anything here. ${how}`
@@ -37795,17 +37943,20 @@ function registerBaselineCommands(program2) {
37795
37943
  let memoryMsg = null;
37796
37944
  let memoryAgentLine = null;
37797
37945
  const memoryNotice = projectPath(`${VERITY_DIR}/.memory-fence-notice`);
37798
- if (realStart && !(0, import_node_fs66.existsSync)(memoryNotice)) {
37946
+ if (realStart && !(0, import_node_fs67.existsSync)(memoryNotice)) {
37799
37947
  const trackedGraph = memoryOptOut() ? 0 : committedMemoryFiles().length;
37800
37948
  if (trackedGraph > 0) {
37801
37949
  memoryMsg = `Verity: this project commits its knowledge base (${trackedGraph} files under .verity/memory/), so Verity's generated notes show up in every diff and pull request. Run \`verity memory untrack\` to keep them on disk but out of git, or \`verity memory track\` to keep committing them on purpose.`;
37802
37950
  memoryAgentLine = `This project has ${trackedGraph} knowledge-graph files tracked in git under .verity/memory/. As of Verity 0.32.6 the graph is machine-local by default \u2014 it is rebuilt from the service, and committing it puts generated notes in every pull request. If the user wants that stopped, run \`verity memory untrack\` for them: it keeps every file on disk and stages their removal from the index, so they only need to commit \u2014 and their teammates' working copies will vanish on the next pull and re-sync from the service, which is expected. If they would rather keep committing it, \`verity memory track\` records that and nothing will offer again.`;
37803
37951
  try {
37804
- (0, import_node_fs66.writeFileSync)(memoryNotice, (/* @__PURE__ */ new Date()).toISOString() + "\n");
37952
+ (0, import_node_fs67.writeFileSync)(memoryNotice, (/* @__PURE__ */ new Date()).toISOString() + "\n");
37805
37953
  } catch {
37806
37954
  }
37807
37955
  }
37808
37956
  }
37957
+ const formalStart = realStart ? formalAtSessionStart({ cli: process.argv[1], cfg: readProjectConfig() }) : null;
37958
+ const formalMsg = formalStart?.userMsg ?? null;
37959
+ const formalAgentLine = formalStart?.agentLine ?? null;
37809
37960
  if (isPluginInvocation() && realStart) {
37810
37961
  const installed2 = activePluginVersion();
37811
37962
  const state = await readSetupState().catch(() => null);
@@ -37829,10 +37980,11 @@ function registerBaselineCommands(program2) {
37829
37980
  }
37830
37981
  }
37831
37982
  if (memoryAgentLine) notices.push(memoryAgentLine);
37983
+ if (formalAgentLine) notices.push(formalAgentLine);
37832
37984
  if (notices.length > 0 || skewMsg) {
37833
37985
  process.stdout.write(
37834
37986
  JSON.stringify({
37835
- ...userMsg || skewMsg || memoryMsg ? { systemMessage: [skewMsg, userMsg, memoryMsg].filter(Boolean).join("\n") } : {},
37987
+ ...userMsg || skewMsg || memoryMsg || formalMsg ? { systemMessage: [skewMsg, userMsg, memoryMsg, formalMsg].filter(Boolean).join("\n") } : {},
37836
37988
  hookSpecificOutput: {
37837
37989
  hookEventName: "SessionStart",
37838
37990
  additionalContext: notices.join("\n")
@@ -37840,17 +37992,20 @@ function registerBaselineCommands(program2) {
37840
37992
  }) + "\n"
37841
37993
  );
37842
37994
  if (skew && skewMsg) recordSkewNotice(skew);
37995
+ if (formalMsg) recordFormalDefaultNotice();
37843
37996
  }
37844
- } else if (memoryMsg) {
37997
+ } else if (memoryMsg || formalMsg) {
37998
+ const agentLines = [memoryAgentLine, formalAgentLine].filter(Boolean).join("\n");
37845
37999
  process.stdout.write(
37846
38000
  JSON.stringify({
37847
- systemMessage: memoryMsg,
38001
+ systemMessage: [memoryMsg, formalMsg].filter(Boolean).join("\n"),
37848
38002
  hookSpecificOutput: {
37849
38003
  hookEventName: "SessionStart",
37850
- ...memoryAgentLine ? { additionalContext: memoryAgentLine } : {}
38004
+ ...agentLines ? { additionalContext: agentLines } : {}
37851
38005
  }
37852
38006
  }) + "\n"
37853
38007
  );
38008
+ if (formalMsg) recordFormalDefaultNotice();
37854
38009
  }
37855
38010
  if (deferredToPlugin("baseline capture", session ?? null)) {
37856
38011
  process.exit(0);
@@ -37858,7 +38013,7 @@ function registerBaselineCommands(program2) {
37858
38013
  const authForScope = await resolveToken(program2.opts().token);
37859
38014
  const scopeToken = authForScope.ok ? authForScope.data.token : void 0;
37860
38015
  if (authForScope.ok && pullsAtSessionStart(authForScope.data, source2)) spawnBackgroundPull();
37861
- if (source2 !== "compact") resumeInterruptedInstall({ cli: process.argv[1], formal: readProjectConfig().formal });
38016
+ if (source2 !== "compact") resumeInterruptedInstall({ cli: process.argv[1], formal: formalSetting(readProjectConfig()).state });
37862
38017
  const scopeSession = session;
37863
38018
  const result = captureBaseline({ sessionId: sessionScopeKey(scopeToken, scopeSession), source: source2 });
37864
38019
  logEvent("baseline_capture", {
@@ -37904,31 +38059,31 @@ function hookSource(value) {
37904
38059
  }
37905
38060
 
37906
38061
  // src/commands/review.ts
37907
- var import_node_fs67 = require("node:fs");
37908
- var import_node_path55 = require("node:path");
38062
+ var import_node_fs68 = require("node:fs");
38063
+ var import_node_path56 = require("node:path");
37909
38064
  function containReviewPaths(paths, base) {
37910
38065
  const kept = [];
37911
38066
  const refused2 = [];
37912
38067
  for (const raw of paths) {
37913
- const candidate = (0, import_node_path55.isAbsolute)(raw) ? relativeForm(base, raw) : raw;
38068
+ const candidate = (0, import_node_path56.isAbsolute)(raw) ? relativeForm(base, raw) : raw;
37914
38069
  if (candidate === "" || resolveInside(base, candidate) === null) refused2.push(raw);
37915
38070
  else kept.push(candidate);
37916
38071
  }
37917
38072
  return { kept, refused: refused2 };
37918
38073
  }
37919
38074
  function relativeForm(base, abs) {
37920
- const lexical = (0, import_node_path55.relative)(base, abs);
37921
- if (!(lexical === ".." || lexical.startsWith(`..${import_node_path55.sep}`) || (0, import_node_path55.isAbsolute)(lexical))) return lexical;
38075
+ const lexical = (0, import_node_path56.relative)(base, abs);
38076
+ if (!(lexical === ".." || lexical.startsWith(`..${import_node_path56.sep}`) || (0, import_node_path56.isAbsolute)(lexical))) return lexical;
37922
38077
  try {
37923
- let dir = (0, import_node_path55.dirname)(abs);
37924
- let rest = (0, import_node_path55.basename)(abs);
37925
- while (!(0, import_node_fs67.existsSync)(dir)) {
37926
- const up = (0, import_node_path55.dirname)(dir);
38078
+ let dir = (0, import_node_path56.dirname)(abs);
38079
+ let rest = (0, import_node_path56.basename)(abs);
38080
+ while (!(0, import_node_fs68.existsSync)(dir)) {
38081
+ const up = (0, import_node_path56.dirname)(dir);
37927
38082
  if (up === dir) return lexical;
37928
- rest = (0, import_node_path55.join)((0, import_node_path55.basename)(dir), rest);
38083
+ rest = (0, import_node_path56.join)((0, import_node_path56.basename)(dir), rest);
37929
38084
  dir = up;
37930
38085
  }
37931
- return (0, import_node_path55.relative)((0, import_node_fs67.realpathSync)(base), (0, import_node_path55.join)((0, import_node_fs67.realpathSync)(dir), rest));
38086
+ return (0, import_node_path56.relative)((0, import_node_fs68.realpathSync)(base), (0, import_node_path56.join)((0, import_node_fs68.realpathSync)(dir), rest));
37932
38087
  } catch {
37933
38088
  return lexical;
37934
38089
  }
@@ -37967,7 +38122,7 @@ async function runReview(opts, globals) {
37967
38122
  const changedFiles = changed.kept;
37968
38123
  const analyzable = filterAnalyzable(allFiles);
37969
38124
  const securityFiles = filterSecurity(allFiles);
37970
- const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs67.existsSync)(f) || resolveFile(f) !== null);
38125
+ const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs68.existsSync)(f) || resolveFile(f) !== null);
37971
38126
  const staticResults = runCodacyAnalysisIfAvailable(scannable);
37972
38127
  const codeDelta = collectCodeDelta(allFiles);
37973
38128
  const tokenResult = await resolveToken(globals.token);
@@ -38038,12 +38193,12 @@ async function runReview(opts, globals) {
38038
38193
  }
38039
38194
 
38040
38195
  // src/commands/guard.ts
38041
- var import_node_fs69 = require("node:fs");
38042
- var import_node_path58 = require("node:path");
38196
+ var import_node_fs70 = require("node:fs");
38197
+ var import_node_path59 = require("node:path");
38043
38198
 
38044
38199
  // src/lib/vendored.ts
38045
- var import_node_fs68 = require("node:fs");
38046
- var import_node_path56 = require("node:path");
38200
+ var import_node_fs69 = require("node:fs");
38201
+ var import_node_path57 = require("node:path");
38047
38202
  var INSTALLED_SKILL = /^\.claude\/skills\/(verity-[a-z0-9-]+)\/(.+)$/;
38048
38203
  function dataDirOrNull() {
38049
38204
  try {
@@ -38058,7 +38213,7 @@ function shippedSkillFile(path, dataDir = dataDirOrNull()) {
38058
38213
  const [, skill, rel] = m;
38059
38214
  if (rel.split("/").some((seg) => seg === ".." || seg === ".")) return null;
38060
38215
  try {
38061
- return (0, import_node_fs68.readFileSync)((0, import_node_path56.join)(dataDir, "skills", skill, rel), "utf8");
38216
+ return (0, import_node_fs69.readFileSync)((0, import_node_path57.join)(dataDir, "skills", skill, rel), "utf8");
38062
38217
  } catch {
38063
38218
  return null;
38064
38219
  }
@@ -38097,10 +38252,10 @@ function summarizeFindings(response) {
38097
38252
  return out2;
38098
38253
  });
38099
38254
  }
38100
- function finishOneShot(settled) {
38101
- if (!settled) return { status: "pending" };
38102
- if (!settled.ok) return { status: "failed" };
38103
- const r = settled.response;
38255
+ function finishOneShot(settled2) {
38256
+ if (!settled2) return { status: "pending" };
38257
+ if (!settled2.ok) return { status: "failed" };
38258
+ const r = settled2.response;
38104
38259
  return {
38105
38260
  status: "arrived",
38106
38261
  ...typeof r.agent_attestation === "string" ? { attestation: r.agent_attestation } : {},
@@ -38111,13 +38266,13 @@ function finishOneShot(settled) {
38111
38266
  async function runAgentReview(options) {
38112
38267
  const now = options.now ?? Date.now;
38113
38268
  const remaining = () => options.deadlineMs - (now() - options.startedAt);
38114
- let settled = null;
38269
+ let settled2 = null;
38115
38270
  const oneShotDone = options.oneShot.then(
38116
38271
  (outcome) => {
38117
- settled = outcome;
38272
+ settled2 = outcome;
38118
38273
  },
38119
38274
  () => {
38120
- settled = { ok: false };
38275
+ settled2 = { ok: false };
38121
38276
  }
38122
38277
  );
38123
38278
  if (remaining() < MIN_AGENT_START_MS) return { kind: "skipped", reason: "not enough time left after prep" };
@@ -38139,7 +38294,7 @@ async function runAgentReview(options) {
38139
38294
  if (turn >= MAX_TURNS || remaining() < MIN_TURN_MS) break;
38140
38295
  const results = await options.executeTools(calls);
38141
38296
  let oneShot;
38142
- const current = settled;
38297
+ const current = settled2;
38143
38298
  if (current && sentOneShot === "pending") {
38144
38299
  oneShot = current.ok ? { status: "arrived", findings: summarizeFindings(current.response) } : { status: "failed" };
38145
38300
  sentOneShot = oneShot.status;
@@ -38154,13 +38309,13 @@ async function runAgentReview(options) {
38154
38309
  calls = next.data.calls ?? [];
38155
38310
  done = next.data.done;
38156
38311
  }
38157
- if (!settled) {
38312
+ if (!settled2) {
38158
38313
  const wait = Math.max(0, remaining() - FINISH_TIMEOUT_MS);
38159
38314
  await Promise.race([oneShotDone, new Promise((resolve10) => setTimeout(resolve10, wait))]);
38160
38315
  }
38161
38316
  const finished = await options.http.post(
38162
38317
  "/agent-review/finish",
38163
- { state, session_id: options.sessionId, one_shot: finishOneShot(settled) },
38318
+ { state, session_id: options.sessionId, one_shot: finishOneShot(settled2) },
38164
38319
  FINISH_TIMEOUT_MS
38165
38320
  );
38166
38321
  if (!finished.ok) {
@@ -38187,7 +38342,7 @@ function effortProfile(root, env = process.env) {
38187
38342
  }
38188
38343
 
38189
38344
  // src/lib/prove/auto.ts
38190
- var import_node_path57 = require("node:path");
38345
+ var import_node_path58 = require("node:path");
38191
38346
  var import_node_crypto21 = require("node:crypto");
38192
38347
 
38193
38348
  // src/lib/prove/grounding.ts
@@ -40415,7 +40570,7 @@ async function runFormalPhase(input) {
40415
40570
  modelName = gen.name;
40416
40571
  const rel = `${AUTO_MODELS_DIR}/${gen.name}.lean`;
40417
40572
  writeFileInRootNoFollow(root, rel, gen.source);
40418
- const abs = resolveModelFile(root, rel) ?? (0, import_node_path57.join)(root, rel);
40573
+ const abs = resolveModelFile(root, rel) ?? (0, import_node_path58.join)(root, rel);
40419
40574
  progress.model = { name: gen.name, file: rel, rounds: round };
40420
40575
  progress.step = "check";
40421
40576
  report = await deps.check(root, abs);
@@ -40564,7 +40719,7 @@ async function runFormalPhase(input) {
40564
40719
  return done({
40565
40720
  status: "checked",
40566
40721
  target,
40567
- model: { name: modelName, file: (0, import_node_path57.relative)(root, (0, import_node_path57.join)(root, modelFile)), rounds },
40722
+ model: { name: modelName, file: (0, import_node_path58.relative)(root, (0, import_node_path58.join)(root, modelFile)), rounds },
40568
40723
  properties: report.properties,
40569
40724
  findings
40570
40725
  });
@@ -40641,7 +40796,7 @@ async function generateAndCheck(root, req, opts) {
40641
40796
  }
40642
40797
  const rel = `${dir}/${gen.name}.lean`;
40643
40798
  writeFileInRootNoFollow(root, rel, gen.source);
40644
- const abs = resolveModelFile(root, rel) ?? (0, import_node_path57.join)(root, rel);
40799
+ const abs = resolveModelFile(root, rel) ?? (0, import_node_path58.join)(root, rel);
40645
40800
  const report = await opts.deps.check(root, abs);
40646
40801
  const abstracts = report.header?.abstracts ?? [];
40647
40802
  const stray = abstracts.find((a) => !headerFiles.has(a.file)) ?? (abstracts[0] && abstracts[0].file !== req.file ? abstracts[0] : void 0);
@@ -41050,7 +41205,7 @@ var WRITERS_BUDGET_MS = 1500;
41050
41205
  var EXCERPT_MAX_LINES2 = 30;
41051
41206
  var VENDORED_READ_MAX_BYTES = 256 * 1024;
41052
41207
  var GUARD_BLOCK_CAP = 2;
41053
- var GUARD_ITER_FILE = (0, import_node_path58.join)(VERITY_DIR, ".guard-iteration");
41208
+ var GUARD_ITER_FILE = (0, import_node_path59.join)(VERITY_DIR, ".guard-iteration");
41054
41209
  function readPreToolUseStdin() {
41055
41210
  const empty = { command: "", cwd: null, sessionId: null };
41056
41211
  return new Promise((resolve10) => {
@@ -41058,11 +41213,11 @@ function readPreToolUseStdin() {
41058
41213
  if (process.stdin.isTTY) return resolve10(empty);
41059
41214
  const chunks = [];
41060
41215
  let timer;
41061
- let settled = false;
41216
+ let settled2 = false;
41062
41217
  const onData = (c) => chunks.push(c);
41063
41218
  const settle = (value) => {
41064
- if (settled) return;
41065
- settled = true;
41219
+ if (settled2) return;
41220
+ settled2 = true;
41066
41221
  if (timer) clearTimeout(timer);
41067
41222
  process.stdin.removeListener("data", onData);
41068
41223
  process.stdin.removeListener("end", onEnd);
@@ -41095,7 +41250,7 @@ function readPreToolUseStdin() {
41095
41250
  }
41096
41251
  function readIterMap() {
41097
41252
  try {
41098
- const raw = JSON.parse((0, import_node_fs69.readFileSync)(GUARD_ITER_FILE, "utf-8"));
41253
+ const raw = JSON.parse((0, import_node_fs70.readFileSync)(GUARD_ITER_FILE, "utf-8"));
41099
41254
  if (raw && typeof raw === "object") {
41100
41255
  if (typeof raw.moment === "string" && typeof raw.count === "number") {
41101
41256
  return { [raw.moment]: raw.count };
@@ -41115,10 +41270,10 @@ function readIter(moment) {
41115
41270
  }
41116
41271
  function writeIter(moment, count2) {
41117
41272
  try {
41118
- (0, import_node_fs69.mkdirSync)(VERITY_DIR, { recursive: true });
41273
+ (0, import_node_fs70.mkdirSync)(VERITY_DIR, { recursive: true });
41119
41274
  const map = readIterMap();
41120
41275
  map[moment] = count2;
41121
- (0, import_node_fs69.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
41276
+ (0, import_node_fs70.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
41122
41277
  } catch {
41123
41278
  }
41124
41279
  }
@@ -41128,10 +41283,10 @@ function resetIter(moment) {
41128
41283
  if (!(moment in map)) return;
41129
41284
  delete map[moment];
41130
41285
  if (Object.keys(map).length === 0) {
41131
- if ((0, import_node_fs69.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs69.unlinkSync)(GUARD_ITER_FILE);
41286
+ if ((0, import_node_fs70.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs70.unlinkSync)(GUARD_ITER_FILE);
41132
41287
  } else {
41133
- (0, import_node_fs69.mkdirSync)(VERITY_DIR, { recursive: true });
41134
- (0, import_node_fs69.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
41288
+ (0, import_node_fs70.mkdirSync)(VERITY_DIR, { recursive: true });
41289
+ (0, import_node_fs70.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
41135
41290
  }
41136
41291
  } catch {
41137
41292
  }
@@ -41208,7 +41363,7 @@ function ofThisChange(response, sentFiles) {
41208
41363
  function buildGuardRequest(moment, files, codeDelta, iter, sessionId, statedIntent, coverageTelemetry) {
41209
41364
  const analyzable = filterAnalyzable(files);
41210
41365
  const securityFiles = filterSecurity(files);
41211
- const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs69.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
41366
+ const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs70.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
41212
41367
  const staticResults = runCodacyAnalysisIfAvailable(scannable);
41213
41368
  const trigger = moment === "pre-commit" ? "hook:pre-commit" : "hook:pre-push";
41214
41369
  const requestBody2 = {
@@ -41381,11 +41536,14 @@ function startAgentReview(input) {
41381
41536
  };
41382
41537
  return run4().catch((err2) => ({ kind: "failed", reason: String(err2?.message ?? err2) }));
41383
41538
  }
41539
+ function formalOffUnverifiedLine(moment, config) {
41540
+ if (moment !== "pre-push" || !config.formal_off_unverified) return "";
41541
+ const setting = formalSetting(config);
41542
+ return setting.state === "off" && setting.source === "config" ? `formal: skipped (${formalOffUnverifiedNote()})` : "";
41543
+ }
41384
41544
  function startFormalPhase(input) {
41385
41545
  if (input.moment !== "pre-push") return null;
41386
- const env = process.env.VERITY_GIT_MOMENT_FORMAL;
41387
- if (env === "off") return null;
41388
- if (env !== "push" && readProjectConfig().formal !== "push") return null;
41546
+ if (formalSetting(input.config).state !== "push") return null;
41389
41547
  const profile = effortProfile(input.root);
41390
41548
  const deadlineAt = input.hookStartedAt + profile.pushDeadlineMs - 1e4;
41391
41549
  const ig = loadVerityIgnore();
@@ -41591,7 +41749,8 @@ async function runGuard(opts, globals) {
41591
41749
  requestBody: requestBody2,
41592
41750
  oneShot
41593
41751
  });
41594
- const formal = startFormalPhase({ moment, files, root: frame.worktreeRoot, hookStartedAt, frame, range, auth: { serviceUrl: urlResult.data, token: tokenResult.data.token } });
41752
+ const projectConfig = moment === "pre-push" ? readProjectConfig() : null;
41753
+ const formal = projectConfig ? startFormalPhase({ moment, files, root: frame.worktreeRoot, hookStartedAt, frame, range, auth: { serviceUrl: urlResult.data, token: tokenResult.data.token }, config: projectConfig }) : null;
41595
41754
  const result = await oneShot;
41596
41755
  const agentOutcome = agent ? await agent : null;
41597
41756
  const formalOutcome = formal ? await formal : null;
@@ -41643,7 +41802,7 @@ async function runGuard(opts, globals) {
41643
41802
  const link2 = viewUrl ? ` \u2014 ${viewUrl}` : "";
41644
41803
  const covLine = `${coverageSummary(coverage)} in ${reviewSecs}s`;
41645
41804
  const agentLine = describeAgentOutcome(agentOutcome);
41646
- const formalLine = describeFormalOutcome(formalOutcome);
41805
+ const formalLine = describeFormalOutcome(formalOutcome) || (projectConfig ? formalOffUnverifiedLine(moment, projectConfig) : "");
41647
41806
  const covDetail = [coverageBlock(coverage), agentLine, formalLine].filter(Boolean).join("\n ");
41648
41807
  const witnessed = [...codeDelta.files.map((f) => f.path), ...agentVerdict?.witnessed_files ?? []];
41649
41808
  mergeFormalFindings(response, formalOutcome, files);
@@ -41884,7 +42043,7 @@ function registerIgnoreCommand(program2) {
41884
42043
 
41885
42044
  // src/commands/waive.ts
41886
42045
  var import_node_crypto23 = require("node:crypto");
41887
- var import_node_fs70 = require("node:fs");
42046
+ var import_node_fs71 = require("node:fs");
41888
42047
  function registerWaiveCommand(program2) {
41889
42048
  program2.command("waive <pattern-id>").description("Record an accepted-risk disposition for an open finding (voids when the file changes)").option("--file <path>", "File the finding is anchored to, REPO-RELATIVE (recommended \u2014 narrows the waive)").requiredOption("--reason <text>", "The human disposition this records (reviewer finding, ADR, \u2026)").action(async (patternId, opts) => {
41890
42049
  const globals = program2.opts();
@@ -41913,7 +42072,7 @@ function registerWaiveCommand(program2) {
41913
42072
  if (opts.file) {
41914
42073
  body2.file = opts.file;
41915
42074
  try {
41916
- body2.file_sha256 = (0, import_node_crypto23.createHash)("sha256").update((0, import_node_fs70.readFileSync)(opts.file)).digest("hex");
42075
+ body2.file_sha256 = (0, import_node_crypto23.createHash)("sha256").update((0, import_node_fs71.readFileSync)(opts.file)).digest("hex");
41917
42076
  } catch {
41918
42077
  printError(`Cannot read ${opts.file} \u2014 run from the repo root, or omit --file to waive by pattern.`);
41919
42078
  process.exit(1);
@@ -41939,15 +42098,15 @@ function registerWaiveCommand(program2) {
41939
42098
 
41940
42099
  // src/commands/init/index.ts
41941
42100
  var import_node_os15 = require("node:os");
41942
- var import_node_fs79 = require("node:fs");
42101
+ var import_node_fs80 = require("node:fs");
41943
42102
  var import_promises17 = require("node:fs/promises");
41944
- var import_node_path68 = require("node:path");
42103
+ var import_node_path69 = require("node:path");
41945
42104
 
41946
42105
  // src/lib/init-changes.ts
41947
42106
  var import_node_crypto24 = require("node:crypto");
41948
- var import_node_fs71 = require("node:fs");
42107
+ var import_node_fs72 = require("node:fs");
41949
42108
  var import_node_os12 = require("node:os");
41950
- var import_node_path59 = require("node:path");
42109
+ var import_node_path60 = require("node:path");
41951
42110
  var REPO_FILES = [
41952
42111
  ".gitignore",
41953
42112
  "CLAUDE.md",
@@ -41962,7 +42121,7 @@ var SKILLS_DIR = ".claude/skills";
41962
42121
  var MAX_HASH_BYTES = 2 * 1024 * 1024;
41963
42122
  var MAX_TREE_ENTRIES = 2e3;
41964
42123
  function userSettingsDir(env) {
41965
- return env.CLAUDE_CONFIG_DIR || (0, import_node_path59.join)(env.HOME || (0, import_node_os12.homedir)(), ".claude");
42124
+ return env.CLAUDE_CONFIG_DIR || (0, import_node_path60.join)(env.HOME || (0, import_node_os12.homedir)(), ".claude");
41966
42125
  }
41967
42126
  function fingerprint(root, rel) {
41968
42127
  const opened = openRegularInRoot(root, rel);
@@ -41970,7 +42129,7 @@ function fingerprint(root, rel) {
41970
42129
  if (opened.reason === "missing") return null;
41971
42130
  if (opened.reason === "symlink") {
41972
42131
  try {
41973
- return `link:${(0, import_node_fs71.readlinkSync)((0, import_node_path59.join)(root, rel))}`;
42132
+ return `link:${(0, import_node_fs72.readlinkSync)((0, import_node_path60.join)(root, rel))}`;
41974
42133
  } catch {
41975
42134
  return "link";
41976
42135
  }
@@ -41989,7 +42148,7 @@ function fingerprint(root, rel) {
41989
42148
  }
41990
42149
  function treeFingerprint(root, dirRel) {
41991
42150
  try {
41992
- if (!(0, import_node_fs71.lstatSync)((0, import_node_path59.join)(root, dirRel)).isDirectory()) return fingerprint(root, dirRel);
42151
+ if (!(0, import_node_fs72.lstatSync)((0, import_node_path60.join)(root, dirRel)).isDirectory()) return fingerprint(root, dirRel);
41993
42152
  } catch {
41994
42153
  return null;
41995
42154
  }
@@ -41997,7 +42156,7 @@ function treeFingerprint(root, dirRel) {
41997
42156
  const walk2 = (rel) => {
41998
42157
  let names2;
41999
42158
  try {
42000
- names2 = (0, import_node_fs71.readdirSync)((0, import_node_path59.join)(root, rel)).sort();
42159
+ names2 = (0, import_node_fs72.readdirSync)((0, import_node_path60.join)(root, rel)).sort();
42001
42160
  } catch {
42002
42161
  return;
42003
42162
  }
@@ -42006,7 +42165,7 @@ function treeFingerprint(root, dirRel) {
42006
42165
  const relPath = `${rel}/${name2}`;
42007
42166
  let st;
42008
42167
  try {
42009
- st = (0, import_node_fs71.lstatSync)((0, import_node_path59.join)(root, relPath));
42168
+ st = (0, import_node_fs72.lstatSync)((0, import_node_path60.join)(root, relPath));
42010
42169
  } catch {
42011
42170
  continue;
42012
42171
  }
@@ -42030,8 +42189,8 @@ function changedSince(before, after) {
42030
42189
 
42031
42190
  // src/lib/init-trace.ts
42032
42191
  var import_node_crypto25 = require("node:crypto");
42033
- var import_node_fs72 = require("node:fs");
42034
- var import_node_path60 = require("node:path");
42192
+ var import_node_fs73 = require("node:fs");
42193
+ var import_node_path61 = require("node:path");
42035
42194
  var INIT_STEPS = [
42036
42195
  "started",
42037
42196
  "prerequisites",
@@ -42077,9 +42236,9 @@ function traceDisabled(env = process.env) {
42077
42236
  }
42078
42237
  var PENDING_NAME = "init-trace.json";
42079
42238
  var MAX_PENDING_BYTES = 64 * 1024;
42080
- var verityHome2 = () => (0, import_node_path60.join)(process.env.HOME ?? "", ".verity");
42239
+ var verityHome2 = () => (0, import_node_path61.join)(process.env.HOME ?? "", ".verity");
42081
42240
  function pendingTracePath() {
42082
- return (0, import_node_path60.join)(verityHome2(), PENDING_NAME);
42241
+ return (0, import_node_path61.join)(verityHome2(), PENDING_NAME);
42083
42242
  }
42084
42243
  var RUN_ID = /^[0-9a-f]{16}$/;
42085
42244
  var CLI_VERSION = /^[0-9A-Za-z.+-]{1,40}$/;
@@ -42137,10 +42296,10 @@ function writePending(runs) {
42137
42296
  try {
42138
42297
  const kept = runs.filter((r) => r.events.length > 0).slice(-MAX_PENDING_RUNS);
42139
42298
  if (kept.length === 0) {
42140
- (0, import_node_fs72.rmSync)(pendingTracePath(), { force: true });
42299
+ (0, import_node_fs73.rmSync)(pendingTracePath(), { force: true });
42141
42300
  return;
42142
42301
  }
42143
- (0, import_node_fs72.mkdirSync)(verityHome2(), { recursive: true });
42302
+ (0, import_node_fs73.mkdirSync)(verityHome2(), { recursive: true });
42144
42303
  if (!replaceInRoot(verityHome2(), PENDING_NAME, JSON.stringify(kept))) {
42145
42304
  logEvent("init_trace_save_refused", {});
42146
42305
  }
@@ -42852,8 +43011,8 @@ var Rail = class {
42852
43011
  };
42853
43012
 
42854
43013
  // src/commands/init/ui.ts
42855
- var import_node_fs73 = require("node:fs");
42856
- var import_node_path61 = require("node:path");
43014
+ var import_node_fs74 = require("node:fs");
43015
+ var import_node_path62 = require("node:path");
42857
43016
  var import_node_os13 = require("node:os");
42858
43017
  var import_node_child_process18 = require("node:child_process");
42859
43018
  function createInitUi(opts) {
@@ -42873,10 +43032,10 @@ function installInterrupt(ui) {
42873
43032
  }
42874
43033
  var SEEN_FILE = ".init-seen";
42875
43034
  function firstInitOnMachine(home = process.env.HOME || (0, import_node_os13.homedir)()) {
42876
- return !(0, import_node_fs73.existsSync)((0, import_node_path61.join)(home, ".verity", SEEN_FILE));
43035
+ return !(0, import_node_fs74.existsSync)((0, import_node_path62.join)(home, ".verity", SEEN_FILE));
42877
43036
  }
42878
43037
  function markInitSeen(home = process.env.HOME || (0, import_node_os13.homedir)()) {
42879
- replaceInRoot((0, import_node_path61.join)(home, ".verity"), SEEN_FILE, `${(/* @__PURE__ */ new Date()).toISOString()}
43038
+ replaceInRoot((0, import_node_path62.join)(home, ".verity"), SEEN_FILE, `${(/* @__PURE__ */ new Date()).toISOString()}
42880
43039
  `);
42881
43040
  }
42882
43041
  function repoLabel() {
@@ -42886,12 +43045,12 @@ function repoLabel() {
42886
43045
  if (parsed) return terminalText(`${parsed.owner}/${parsed.repo}`, 120);
42887
43046
  } catch {
42888
43047
  }
42889
- return terminalText((0, import_node_path61.basename)(repoRoot()), 120);
43048
+ return terminalText((0, import_node_path62.basename)(repoRoot()), 120);
42890
43049
  }
42891
43050
 
42892
43051
  // src/lib/prereqs.ts
42893
43052
  var import_node_child_process19 = require("node:child_process");
42894
- var import_node_fs74 = require("node:fs");
43053
+ var import_node_fs75 = require("node:fs");
42895
43054
  var MIN_NODE_MAJOR = 20;
42896
43055
  function which(bin) {
42897
43056
  return whichSync(bin, { real: false });
@@ -42959,7 +43118,7 @@ function checkAnalysisCli(opts = {}) {
42959
43118
  }
42960
43119
  function sameFile(a, b) {
42961
43120
  try {
42962
- return (0, import_node_fs74.realpathSync)(a) === (0, import_node_fs74.realpathSync)(b);
43121
+ return (0, import_node_fs75.realpathSync)(a) === (0, import_node_fs75.realpathSync)(b);
42963
43122
  } catch {
42964
43123
  return false;
42965
43124
  }
@@ -43019,12 +43178,12 @@ async function checkPrereqs(opts = {}) {
43019
43178
  }
43020
43179
 
43021
43180
  // src/lib/telemetry-local.ts
43022
- var import_node_path63 = require("node:path");
43181
+ var import_node_path64 = require("node:path");
43023
43182
 
43024
43183
  // src/lib/telemetry-settings.ts
43025
43184
  var import_promises14 = require("node:fs/promises");
43026
43185
  var import_node_os14 = require("node:os");
43027
- var import_node_path62 = require("node:path");
43186
+ var import_node_path63 = require("node:path");
43028
43187
  var SETTINGS_LOCAL_FILE2 = ".claude/settings.local.json";
43029
43188
  var OTEL_HEADERS_HELPER_CMD = "verity telemetry headers";
43030
43189
  var LEGACY_HEADER_KEY = "OTEL_EXPORTER_OTLP_HEADERS";
@@ -43035,10 +43194,10 @@ var OTLP_ENDPOINT_KEYS = [
43035
43194
  "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"
43036
43195
  ];
43037
43196
  function claudeConfigDir2() {
43038
- return process.env.CLAUDE_CONFIG_DIR || (0, import_node_path62.join)((0, import_node_os14.homedir)(), ".claude");
43197
+ return process.env.CLAUDE_CONFIG_DIR || (0, import_node_path63.join)((0, import_node_os14.homedir)(), ".claude");
43039
43198
  }
43040
43199
  function userSettingsPath() {
43041
- return (0, import_node_path62.join)(claudeConfigDir2(), "settings.json");
43200
+ return (0, import_node_path63.join)(claudeConfigDir2(), "settings.json");
43042
43201
  }
43043
43202
  function deriveOtlpEndpoint(serviceUrl) {
43044
43203
  return serviceUrl.replace(/\/+$/, "").replace(/\/v1$/, "") + "/v1/otlp";
@@ -43159,7 +43318,7 @@ async function healLocalTelemetry(root = repoRoot()) {
43159
43318
  if (settings.env && Object.keys(env).length === 0) delete settings.env;
43160
43319
  if (plan.helper) delete settings.otelHeadersHelper;
43161
43320
  const next = nextLocalBytes(local.raw, settings);
43162
- if (next !== null && !replaceInRoot((0, import_node_path63.join)(root, ".claude"), "settings.local.json", next)) {
43321
+ if (next !== null && !replaceInRoot((0, import_node_path64.join)(root, ".claude"), "settings.local.json", next)) {
43163
43322
  return { removed: [] };
43164
43323
  }
43165
43324
  return { removed: [...plan.envKeys, ...plan.helper ? ["otelHeadersHelper"] : []] };
@@ -43167,8 +43326,8 @@ async function healLocalTelemetry(root = repoRoot()) {
43167
43326
 
43168
43327
  // src/lib/telemetry-gate.ts
43169
43328
  var import_node_child_process20 = require("node:child_process");
43170
- var import_node_fs75 = require("node:fs");
43171
- var import_node_path64 = require("node:path");
43329
+ var import_node_fs76 = require("node:fs");
43330
+ var import_node_path65 = require("node:path");
43172
43331
  var PROJECT_MARKERS = ["setup.json", "config.json"];
43173
43332
  function writtenOnThisMachine(root, rel) {
43174
43333
  const r = (0, import_node_child_process20.spawnSync)("git", hardenedGitArgv(["ls-files", "--error-unmatch", "--", rel]), {
@@ -43185,10 +43344,10 @@ function writtenOnThisMachine(root, rel) {
43185
43344
  function isTelemetryProject() {
43186
43345
  for (const root of [repoRoot(), mainWorktreeRoot()]) {
43187
43346
  if (!root) continue;
43188
- const dir = (0, import_node_path64.join)(root, VERITY_DIR);
43347
+ const dir = (0, import_node_path65.join)(root, VERITY_DIR);
43189
43348
  if (isMachineStore(dir)) continue;
43190
43349
  for (const marker of PROJECT_MARKERS) {
43191
- if ((0, import_node_fs75.existsSync)((0, import_node_path64.join)(dir, marker)) && writtenOnThisMachine(root, `${VERITY_DIR}/${marker}`)) return true;
43350
+ if ((0, import_node_fs76.existsSync)((0, import_node_path65.join)(dir, marker)) && writtenOnThisMachine(root, `${VERITY_DIR}/${marker}`)) return true;
43192
43351
  }
43193
43352
  }
43194
43353
  return false;
@@ -43453,7 +43612,7 @@ function signInDetail(outcome) {
43453
43612
  }
43454
43613
  function formalDefault(previous, opts = {}) {
43455
43614
  const cfg = readProjectConfig();
43456
- if (previous?.init?.completed_at || opts.setUpBefore || cfg.formal !== void 0 || cfg.formal_refused) return false;
43615
+ if (previous?.init?.completed_at || opts.setUpBefore || cfg.formal !== void 0 || cfg.formal_refused || cfg.formal_off_refused) return false;
43457
43616
  writeProjectConfig({ formal: "push" });
43458
43617
  return true;
43459
43618
  }
@@ -43464,9 +43623,13 @@ function sayFormalOn(ui) {
43464
43623
  }
43465
43624
  function backgroundStep(ui, opts) {
43466
43625
  const { rail } = ui;
43467
- const formal = readProjectConfig().formal;
43468
- const said = opts.formalNew === true && formal === "push";
43469
- if (said) sayFormalOn(ui);
43626
+ const setting = formalSetting(readProjectConfig());
43627
+ const formal = setting.state;
43628
+ const said = formal === "push" && (opts.formalNew === true || setting.source === "default" && formalDefaultNoticeDue());
43629
+ if (said) {
43630
+ sayFormalOn(ui);
43631
+ recordFormalDefaultNotice();
43632
+ }
43470
43633
  const lean = shouldStartBackgroundInstall({ formal });
43471
43634
  const leanStarted = lean.start && startBackgroundInstall({ cli: opts.cli });
43472
43635
  const trivy = startTrivyPrewarm();
@@ -43597,7 +43760,9 @@ async function scaffoldStep(ui, given = {}) {
43597
43760
  rail.line(`Could not update CLAUDE.md: ${terminalText(err2.message, 300)}`, "warn");
43598
43761
  }
43599
43762
  const cfg = readProjectConfig();
43600
- if (cfg.formal_refused) rail.line(`Formal verification: off \u2014 ${formalRefusalMessage(cfg.formal_refused)}`, "warn");
43763
+ if (cfg.formal_off_refused && formalSetting(cfg).state === "push") {
43764
+ rail.line(`Formal verification: on \u2014 ${formalOffRefusalMessage(cfg.formal_off_refused)}`, "warn");
43765
+ }
43601
43766
  rail.settle();
43602
43767
  }
43603
43768
  async function askUntrackState(ui, tracked) {
@@ -43635,9 +43800,9 @@ function retireCodacyConfig(ui) {
43635
43800
  }
43636
43801
 
43637
43802
  // src/commands/init/wiring.ts
43638
- var import_node_fs76 = require("node:fs");
43803
+ var import_node_fs77 = require("node:fs");
43639
43804
  var import_promises16 = require("node:fs/promises");
43640
- var import_node_path65 = require("node:path");
43805
+ var import_node_path66 = require("node:path");
43641
43806
  var DEFAULT_MOMENTS = ["stop", "pre-commit", "pre-push"];
43642
43807
  async function momentsFromInstalledHooks() {
43643
43808
  const status = await checkAllVerityHooks();
@@ -43710,12 +43875,12 @@ var SKILLS = [
43710
43875
  ];
43711
43876
  function resolveDataDir2() {
43712
43877
  const candidates2 = [
43713
- (0, import_node_path65.join)(__dirname, "..", "data"),
43714
- (0, import_node_path65.join)(__dirname, "..", "..", "data"),
43715
- (0, import_node_path65.join)(process.cwd(), "cli", "data")
43878
+ (0, import_node_path66.join)(__dirname, "..", "data"),
43879
+ (0, import_node_path66.join)(__dirname, "..", "..", "data"),
43880
+ (0, import_node_path66.join)(process.cwd(), "cli", "data")
43716
43881
  ];
43717
43882
  for (const candidate of candidates2) {
43718
- if ((0, import_node_fs76.existsSync)((0, import_node_path65.join)(candidate, "skills"))) return candidate;
43883
+ if ((0, import_node_fs77.existsSync)((0, import_node_path66.join)(candidate, "skills"))) return candidate;
43719
43884
  }
43720
43885
  throw new Error("Could not find Verity skill data. Reinstall: npm install -g @codacy/verity-cli");
43721
43886
  }
@@ -43723,9 +43888,9 @@ async function skillIsCurrent(src, dest) {
43723
43888
  const list2 = (dir) => {
43724
43889
  const out2 = [];
43725
43890
  const walk2 = (d, prefix) => {
43726
- for (const e of (0, import_node_fs76.readdirSync)(d, { withFileTypes: true })) {
43891
+ for (const e of (0, import_node_fs77.readdirSync)(d, { withFileTypes: true })) {
43727
43892
  const rel = prefix ? `${prefix}/${e.name}` : e.name;
43728
- if (e.isDirectory()) walk2((0, import_node_path65.join)(d, e.name), rel);
43893
+ if (e.isDirectory()) walk2((0, import_node_path66.join)(d, e.name), rel);
43729
43894
  else if (e.isFile()) out2.push(rel);
43730
43895
  }
43731
43896
  };
@@ -43736,7 +43901,7 @@ async function skillIsCurrent(src, dest) {
43736
43901
  const shipped = list2(src);
43737
43902
  if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
43738
43903
  for (const rel of shipped) {
43739
- if (await (0, import_promises16.readFile)((0, import_node_path65.join)(src, rel), "utf-8") !== await (0, import_promises16.readFile)((0, import_node_path65.join)(dest, rel), "utf-8")) return false;
43904
+ if (await (0, import_promises16.readFile)((0, import_node_path66.join)(src, rel), "utf-8") !== await (0, import_promises16.readFile)((0, import_node_path66.join)(dest, rel), "utf-8")) return false;
43740
43905
  }
43741
43906
  return true;
43742
43907
  } catch {
@@ -43744,16 +43909,16 @@ async function skillIsCurrent(src, dest) {
43744
43909
  }
43745
43910
  }
43746
43911
  async function installSkills(force) {
43747
- const source2 = (0, import_node_path65.join)(resolveDataDir2(), "skills");
43912
+ const source2 = (0, import_node_path66.join)(resolveDataDir2(), "skills");
43748
43913
  const missing = [];
43749
43914
  for (const skill of SKILLS) {
43750
- const src = (0, import_node_path65.join)(source2, skill);
43751
- const dest = (0, import_node_path65.join)(".claude/skills", skill);
43752
- if (!(0, import_node_fs76.existsSync)(src)) {
43915
+ const src = (0, import_node_path66.join)(source2, skill);
43916
+ const dest = (0, import_node_path66.join)(".claude/skills", skill);
43917
+ if (!(0, import_node_fs77.existsSync)(src)) {
43753
43918
  missing.push(skill);
43754
43919
  continue;
43755
43920
  }
43756
- if ((0, import_node_fs76.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) continue;
43921
+ if ((0, import_node_fs77.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) continue;
43757
43922
  await (0, import_promises16.mkdir)(dest, { recursive: true });
43758
43923
  await (0, import_promises16.cp)(src, dest, { recursive: true, force: true });
43759
43924
  }
@@ -43793,8 +43958,8 @@ async function hooksStep(ui, ctx) {
43793
43958
  }
43794
43959
 
43795
43960
  // src/commands/init/standard.ts
43796
- var import_node_fs77 = require("node:fs");
43797
- var import_node_path66 = require("node:path");
43961
+ var import_node_fs78 = require("node:fs");
43962
+ var import_node_path67 = require("node:path");
43798
43963
  var import_yaml10 = __toESM2(require_dist());
43799
43964
 
43800
43965
  // src/lib/catalogue-client.ts
@@ -43985,9 +44150,9 @@ function localStandard() {
43985
44150
  function removeLocalStandard() {
43986
44151
  const path = projectPath(STANDARD_FILE);
43987
44152
  try {
43988
- const folder = (0, import_node_fs77.lstatSync)((0, import_node_path66.dirname)(path));
44153
+ const folder = (0, import_node_fs78.lstatSync)((0, import_node_path67.dirname)(path));
43989
44154
  if (!folder.isDirectory() || folder.isSymbolicLink()) return;
43990
- if ((0, import_node_fs77.lstatSync)(path).isFile()) (0, import_node_fs77.unlinkSync)(path);
44155
+ if ((0, import_node_fs78.lstatSync)(path).isFile()) (0, import_node_fs78.unlinkSync)(path);
43991
44156
  } catch {
43992
44157
  }
43993
44158
  }
@@ -44001,7 +44166,7 @@ function setLocalStandardAside(now = /* @__PURE__ */ new Date(), remove = remove
44001
44166
  return { ok: false, message: `Could not keep a copy of ${STANDARD_FILE} (${terminalText(err2 instanceof Error ? err2.message : String(err2), 200)}), so it was not set aside.` };
44002
44167
  }
44003
44168
  remove();
44004
- if ((0, import_node_fs77.existsSync)(projectPath(STANDARD_FILE))) return { ok: false, message: `Could not remove ${STANDARD_FILE} after copying it to ${path}.` };
44169
+ if ((0, import_node_fs78.existsSync)(projectPath(STANDARD_FILE))) return { ok: false, message: `Could not remove ${STANDARD_FILE} after copying it to ${path}.` };
44005
44170
  return { ok: true, path };
44006
44171
  }
44007
44172
  async function standardStep(ui, ctx) {
@@ -44063,7 +44228,7 @@ async function standardStep(ui, ctx) {
44063
44228
  rail.line(team2.status === "none" ? `There is no Standard on the service either, so reviews have no rules. Fix ${STANDARD_FILE}, or delete it, then run verity init again.` : team2.status === "unavailable" ? `The Verity service did not answer (${terminalText(team2.reason, 200)}), so no Standard is confirmed. Fix ${STANDARD_FILE}, then run verity init again.` : team2.status === "denied" && refusalOutcome(team2.code) === "denied" ? `Verity has no access to this repository (${terminalText(team2.reason, 200)}). Fix ${STANDARD_FILE}, give the Verity GitHub App access, then run verity login and verity init.` : team2.status === "denied" ? `The Verity service did not accept your sign-in (${terminalText(team2.reason, 200)}). Fix ${STANDARD_FILE}, then run verity login and verity init.` : `No Standard on the service was looked up. Fix ${STANDARD_FILE}, or sign in, then run verity init again.`);
44064
44229
  return end({ source: "none", version: null, profile: notAsked });
44065
44230
  };
44066
- if (ctx.standard === "new" && (0, import_node_fs77.lstatSync)(projectPath(STANDARD_FILE), { throwIfNoEntry: false })) {
44231
+ if (ctx.standard === "new" && (0, import_node_fs78.lstatSync)(projectPath(STANDARD_FILE), { throwIfNoEntry: false })) {
44067
44232
  const aside = setLocalStandardAside();
44068
44233
  if (!aside.ok) {
44069
44234
  rail.warn("Could not set your Standard aside for a new one");
@@ -44140,7 +44305,7 @@ async function standardStep(ui, ctx) {
44140
44305
  await keptHints();
44141
44306
  return end({ source: "kept", version, profile: notAsked });
44142
44307
  };
44143
- if ((0, import_node_fs77.existsSync)(projectPath(STANDARD_FILE))) {
44308
+ if ((0, import_node_fs78.existsSync)(projectPath(STANDARD_FILE))) {
44144
44309
  const local = localStandard();
44145
44310
  if (!local.ok) return unusableHere(local.problem);
44146
44311
  return keptHere(local.content);
@@ -44266,8 +44431,8 @@ function sayChanged(ui, before) {
44266
44431
  }
44267
44432
 
44268
44433
  // src/commands/migrate.ts
44269
- var import_node_fs78 = require("node:fs");
44270
- var import_node_path67 = require("node:path");
44434
+ var import_node_fs79 = require("node:fs");
44435
+ var import_node_path68 = require("node:path");
44271
44436
  var import_node_child_process22 = require("node:child_process");
44272
44437
  var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
44273
44438
  function defaultNpmRemover(pkg) {
@@ -44331,12 +44496,12 @@ async function runMigration(opts = {}) {
44331
44496
  return { actions, migrated: actions.length > 0 };
44332
44497
  }
44333
44498
  function migrateProjectDir(root, actions) {
44334
- const gateDir = (0, import_node_path67.join)(root, ".gate");
44335
- const verityDir = (0, import_node_path67.join)(root, ".verity");
44336
- if ((0, import_node_fs78.existsSync)(gateDir) && !(0, import_node_fs78.existsSync)(verityDir)) {
44499
+ const gateDir = (0, import_node_path68.join)(root, ".gate");
44500
+ const verityDir = (0, import_node_path68.join)(root, ".verity");
44501
+ if ((0, import_node_fs79.existsSync)(gateDir) && !(0, import_node_fs79.existsSync)(verityDir)) {
44337
44502
  return migrateProjectDirRename(root, gateDir, verityDir, actions);
44338
44503
  }
44339
- if ((0, import_node_fs78.existsSync)(gateDir) && (0, import_node_fs78.existsSync)(verityDir)) {
44504
+ if ((0, import_node_fs79.existsSync)(gateDir) && (0, import_node_fs79.existsSync)(verityDir)) {
44340
44505
  return migrateProjectDirCarry(gateDir, verityDir, actions);
44341
44506
  }
44342
44507
  return false;
@@ -44357,13 +44522,13 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
44357
44522
  }
44358
44523
  }
44359
44524
  if (moved) {
44360
- if ((0, import_node_fs78.existsSync)(gateDir)) {
44525
+ if ((0, import_node_fs79.existsSync)(gateDir)) {
44361
44526
  const carried = carryLegacyContents(gateDir, verityDir);
44362
44527
  if (carried > 0) {
44363
44528
  actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
44364
44529
  }
44365
44530
  try {
44366
- (0, import_node_fs78.rmSync)(gateDir, { recursive: true, force: true });
44531
+ (0, import_node_fs79.rmSync)(gateDir, { recursive: true, force: true });
44367
44532
  } catch {
44368
44533
  }
44369
44534
  }
@@ -44379,18 +44544,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
44379
44544
  actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
44380
44545
  }
44381
44546
  try {
44382
- (0, import_node_fs78.rmSync)(gateDir, { recursive: true, force: true });
44547
+ (0, import_node_fs79.rmSync)(gateDir, { recursive: true, force: true });
44383
44548
  } catch {
44384
44549
  }
44385
44550
  return carried > 0;
44386
44551
  }
44387
44552
  function migrateGlobalCredentials(home, actions) {
44388
44553
  if (!home) return;
44389
- const gateCreds = (0, import_node_path67.join)(home, ".gate", "credentials");
44390
- const verityCreds = (0, import_node_path67.join)(home, ".verity", "credentials");
44391
- if (!(0, import_node_fs78.existsSync)(gateCreds)) return;
44392
- if (!(0, import_node_fs78.existsSync)(verityCreds)) {
44393
- (0, import_node_fs78.mkdirSync)((0, import_node_path67.join)(home, ".verity"), { recursive: true });
44554
+ const gateCreds = (0, import_node_path68.join)(home, ".gate", "credentials");
44555
+ const verityCreds = (0, import_node_path68.join)(home, ".verity", "credentials");
44556
+ if (!(0, import_node_fs79.existsSync)(gateCreds)) return;
44557
+ if (!(0, import_node_fs79.existsSync)(verityCreds)) {
44558
+ (0, import_node_fs79.mkdirSync)((0, import_node_path68.join)(home, ".verity"), { recursive: true });
44394
44559
  moveFile(gateCreds, verityCreds);
44395
44560
  actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
44396
44561
  return;
@@ -44412,8 +44577,8 @@ async function migrateLegacyHooks(root, actions) {
44412
44577
  }
44413
44578
  }
44414
44579
  async function migrateClaudeMd(root, actions) {
44415
- const claudeMd = (0, import_node_path67.join)(root, "CLAUDE.md");
44416
- const hadLegacyBlock = (0, import_node_fs78.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
44580
+ const claudeMd = (0, import_node_path68.join)(root, "CLAUDE.md");
44581
+ const hadLegacyBlock = (0, import_node_fs79.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
44417
44582
  if (!hadLegacyBlock) return;
44418
44583
  try {
44419
44584
  await ensureClaudeMdPointer(root);
@@ -44423,9 +44588,9 @@ async function migrateClaudeMd(root, actions) {
44423
44588
  }
44424
44589
  }
44425
44590
  function migrateStandardFile(root, actions) {
44426
- const gateMd = (0, import_node_path67.join)(root, "GATE.md");
44427
- const verityMd = (0, import_node_path67.join)(root, "VERITY.md");
44428
- if (!(0, import_node_fs78.existsSync)(gateMd) || (0, import_node_fs78.existsSync)(verityMd)) return;
44591
+ const gateMd = (0, import_node_path68.join)(root, "GATE.md");
44592
+ const verityMd = (0, import_node_path68.join)(root, "VERITY.md");
44593
+ if (!(0, import_node_fs79.existsSync)(gateMd) || (0, import_node_fs79.existsSync)(verityMd)) return;
44429
44594
  let moved = false;
44430
44595
  if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
44431
44596
  try {
@@ -44437,7 +44602,7 @@ function migrateStandardFile(root, actions) {
44437
44602
  if (!moved) moveFile(gateMd, verityMd);
44438
44603
  const content = readFileSyncSafe(verityMd);
44439
44604
  const refreshed = content.split("GATE.md").join("VERITY.md");
44440
- if (refreshed !== content) (0, import_node_fs78.writeFileSync)(verityMd, refreshed);
44605
+ if (refreshed !== content) (0, import_node_fs79.writeFileSync)(verityMd, refreshed);
44441
44606
  actions.push("Renamed GATE.md \u2192 VERITY.md");
44442
44607
  }
44443
44608
  async function migrateLocalTelemetry(root, actions) {
@@ -44481,14 +44646,14 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
44481
44646
  }
44482
44647
  if (toAppend.length > 0) {
44483
44648
  const sep7 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
44484
- (0, import_node_fs78.writeFileSync)(verityCreds, verityContent + sep7 + toAppend.join("\n") + "\n");
44649
+ (0, import_node_fs79.writeFileSync)(verityCreds, verityContent + sep7 + toAppend.join("\n") + "\n");
44485
44650
  }
44486
- (0, import_node_fs78.rmSync)(gateCreds, { force: true });
44651
+ (0, import_node_fs79.rmSync)(gateCreds, { force: true });
44487
44652
  return toAppend.length;
44488
44653
  }
44489
44654
  function readFileSyncSafe(path) {
44490
44655
  try {
44491
- return (0, import_node_fs78.readFileSync)(path, "utf-8");
44656
+ return (0, import_node_fs79.readFileSync)(path, "utf-8");
44492
44657
  } catch {
44493
44658
  return "";
44494
44659
  }
@@ -44503,20 +44668,20 @@ function hasStagedChanges(root) {
44503
44668
  }
44504
44669
  function moveDir(from, to) {
44505
44670
  try {
44506
- (0, import_node_fs78.renameSync)(from, to);
44671
+ (0, import_node_fs79.renameSync)(from, to);
44507
44672
  } catch (err2) {
44508
44673
  if (err2.code !== "EXDEV") throw err2;
44509
- (0, import_node_fs78.cpSync)(from, to, { recursive: true });
44510
- (0, import_node_fs78.rmSync)(from, { recursive: true, force: true });
44674
+ (0, import_node_fs79.cpSync)(from, to, { recursive: true });
44675
+ (0, import_node_fs79.rmSync)(from, { recursive: true, force: true });
44511
44676
  }
44512
44677
  }
44513
44678
  function moveFile(from, to) {
44514
44679
  try {
44515
- (0, import_node_fs78.renameSync)(from, to);
44680
+ (0, import_node_fs79.renameSync)(from, to);
44516
44681
  } catch (err2) {
44517
44682
  if (err2.code !== "EXDEV") throw err2;
44518
- (0, import_node_fs78.cpSync)(from, to);
44519
- (0, import_node_fs78.rmSync)(from, { force: true });
44683
+ (0, import_node_fs79.cpSync)(from, to);
44684
+ (0, import_node_fs79.rmSync)(from, { force: true });
44520
44685
  }
44521
44686
  }
44522
44687
  function carryLegacyContents(gateDir, verityDir) {
@@ -44525,12 +44690,12 @@ function carryLegacyContents(gateDir, verityDir) {
44525
44690
  const walk2 = (relDir) => {
44526
44691
  let entries;
44527
44692
  try {
44528
- entries = (0, import_node_fs78.readdirSync)((0, import_node_path67.join)(gateDir, relDir), { withFileTypes: true });
44693
+ entries = (0, import_node_fs79.readdirSync)((0, import_node_path68.join)(gateDir, relDir), { withFileTypes: true });
44529
44694
  } catch {
44530
44695
  return;
44531
44696
  }
44532
44697
  for (const entry of entries) {
44533
- const rel = relDir ? (0, import_node_path67.join)(relDir, entry.name) : entry.name;
44698
+ const rel = relDir ? (0, import_node_path68.join)(relDir, entry.name) : entry.name;
44534
44699
  if (entry.isSymbolicLink()) continue;
44535
44700
  if (entry.isDirectory()) {
44536
44701
  walk2(rel);
@@ -44540,7 +44705,7 @@ function carryLegacyContents(gateDir, verityDir) {
44540
44705
  const opened = openRegularInRoot(gateDir, rel);
44541
44706
  if (!opened.ok) continue;
44542
44707
  try {
44543
- (0, import_node_fs78.writeFileSync)((0, import_node_path67.join)(verityDir, rel), readOpened(opened.fd, opened.size), { flag: "wx", mode: 384 });
44708
+ (0, import_node_fs79.writeFileSync)((0, import_node_path68.join)(verityDir, rel), readOpened(opened.fd, opened.size), { flag: "wx", mode: 384 });
44544
44709
  copied++;
44545
44710
  } catch {
44546
44711
  }
@@ -44550,19 +44715,19 @@ function carryLegacyContents(gateDir, verityDir) {
44550
44715
  return copied;
44551
44716
  }
44552
44717
  function hasLegacyStandard(root = repoRoot()) {
44553
- if (!isRealDir((0, import_node_path67.join)(root, ".gate"))) return false;
44718
+ if (!isRealDir((0, import_node_path68.join)(root, ".gate"))) return false;
44554
44719
  try {
44555
- if (!(0, import_node_fs78.lstatSync)((0, import_node_path67.join)(root, ".gate", "standard.yaml")).isFile()) return false;
44720
+ if (!(0, import_node_fs79.lstatSync)((0, import_node_path68.join)(root, ".gate", "standard.yaml")).isFile()) return false;
44556
44721
  } catch {
44557
44722
  return false;
44558
44723
  }
44559
- const verityDir = (0, import_node_path67.join)(root, ".verity");
44724
+ const verityDir = (0, import_node_path68.join)(root, ".verity");
44560
44725
  if (pathEntryExists(verityDir) && !isRealDir(verityDir)) return false;
44561
- return !pathEntryExists((0, import_node_path67.join)(verityDir, "standard.yaml"));
44726
+ return !pathEntryExists((0, import_node_path68.join)(verityDir, "standard.yaml"));
44562
44727
  }
44563
44728
  function pathEntryExists(path) {
44564
44729
  try {
44565
- (0, import_node_fs78.lstatSync)(path);
44730
+ (0, import_node_fs79.lstatSync)(path);
44566
44731
  return true;
44567
44732
  } catch {
44568
44733
  return false;
@@ -44570,7 +44735,7 @@ function pathEntryExists(path) {
44570
44735
  }
44571
44736
  function isRealDir(path) {
44572
44737
  try {
44573
- const st = (0, import_node_fs78.lstatSync)(path);
44738
+ const st = (0, import_node_fs79.lstatSync)(path);
44574
44739
  return st.isDirectory() && !st.isSymbolicLink();
44575
44740
  } catch {
44576
44741
  return false;
@@ -44579,9 +44744,9 @@ function isRealDir(path) {
44579
44744
  function ensureRealDirs(root, relDir) {
44580
44745
  let current = root;
44581
44746
  for (const segment of relDir.split(/[\\/]/).filter(Boolean)) {
44582
- current = (0, import_node_path67.join)(current, segment);
44747
+ current = (0, import_node_path68.join)(current, segment);
44583
44748
  try {
44584
- (0, import_node_fs78.mkdirSync)(current);
44749
+ (0, import_node_fs79.mkdirSync)(current);
44585
44750
  } catch (e) {
44586
44751
  if (e.code !== "EEXIST") return false;
44587
44752
  }
@@ -44590,23 +44755,23 @@ function ensureRealDirs(root, relDir) {
44590
44755
  return true;
44591
44756
  }
44592
44757
  async function needsMigration(root = repoRoot()) {
44593
- const gateDir = (0, import_node_path67.join)(root, ".gate");
44594
- const verityDir = (0, import_node_path67.join)(root, ".verity");
44595
- if ((0, import_node_fs78.existsSync)(gateDir) && !(0, import_node_fs78.existsSync)(verityDir)) return true;
44596
- if ((0, import_node_fs78.existsSync)(gateDir) && (0, import_node_fs78.existsSync)(verityDir)) {
44597
- if ((0, import_node_fs78.existsSync)((0, import_node_path67.join)(gateDir, "credentials")) && !(0, import_node_fs78.existsSync)((0, import_node_path67.join)(verityDir, "credentials"))) {
44758
+ const gateDir = (0, import_node_path68.join)(root, ".gate");
44759
+ const verityDir = (0, import_node_path68.join)(root, ".verity");
44760
+ if ((0, import_node_fs79.existsSync)(gateDir) && !(0, import_node_fs79.existsSync)(verityDir)) return true;
44761
+ if ((0, import_node_fs79.existsSync)(gateDir) && (0, import_node_fs79.existsSync)(verityDir)) {
44762
+ if ((0, import_node_fs79.existsSync)((0, import_node_path68.join)(gateDir, "credentials")) && !(0, import_node_fs79.existsSync)((0, import_node_path68.join)(verityDir, "credentials"))) {
44598
44763
  return true;
44599
44764
  }
44600
- if ((0, import_node_fs78.existsSync)((0, import_node_path67.join)(gateDir, "memory")) && !(0, import_node_fs78.existsSync)((0, import_node_path67.join)(verityDir, "memory"))) {
44765
+ if ((0, import_node_fs79.existsSync)((0, import_node_path68.join)(gateDir, "memory")) && !(0, import_node_fs79.existsSync)((0, import_node_path68.join)(verityDir, "memory"))) {
44601
44766
  return true;
44602
44767
  }
44603
44768
  if (hasLegacyStandard(root)) return true;
44604
44769
  }
44605
- const claudeMd = (0, import_node_path67.join)(root, "CLAUDE.md");
44606
- if ((0, import_node_fs78.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
44770
+ const claudeMd = (0, import_node_path68.join)(root, "CLAUDE.md");
44771
+ if ((0, import_node_fs79.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
44607
44772
  return true;
44608
44773
  }
44609
- if ((0, import_node_fs78.existsSync)((0, import_node_path67.join)(root, "GATE.md")) && !(0, import_node_fs78.existsSync)((0, import_node_path67.join)(root, "VERITY.md"))) {
44774
+ if ((0, import_node_fs79.existsSync)((0, import_node_path68.join)(root, "GATE.md")) && !(0, import_node_fs79.existsSync)((0, import_node_path68.join)(root, "VERITY.md"))) {
44610
44775
  return true;
44611
44776
  }
44612
44777
  if (await hasLegacyHooksAt(root)) return true;
@@ -44846,7 +45011,7 @@ async function recordAnswers(ui, momentIds, telemetry, completed) {
44846
45011
  moments: momentIds,
44847
45012
  ...telemetry ? { telemetry } : {},
44848
45013
  // A failed run also clears an earlier stamp: "done" describes this checkout now.
44849
- init: completed ? { completed_at: (/* @__PURE__ */ new Date()).toISOString(), cli_version: true ? "0.35.4" : "dev" } : void 0
45014
+ init: completed ? { completed_at: (/* @__PURE__ */ new Date()).toISOString(), cli_version: true ? "0.35.5" : "dev" } : void 0
44850
45015
  });
44851
45016
  } catch (err2) {
44852
45017
  ui.rail.line(`Could not record the setup answers: ${terminalText(err2.message, 200)}`, "warn");
@@ -44899,7 +45064,7 @@ async function runInit(program2, opts) {
44899
45064
  const defaultsOnly = (opts.yes ?? false) || !interactive();
44900
45065
  const { givenMoments, givenTelemetry, profileAnswer, standardAnswer } = parseInitFlags(opts);
44901
45066
  const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
44902
- if (!projectMarkers.some((m) => (0, import_node_fs79.existsSync)(m))) {
45067
+ if (!projectMarkers.some((m) => (0, import_node_fs80.existsSync)(m))) {
44903
45068
  printError('No project detected in the current directory. Run "verity init" from your project root.');
44904
45069
  process.exit(1);
44905
45070
  }
@@ -44927,10 +45092,10 @@ async function runInit(program2, opts) {
44927
45092
  trace.mark("prerequisites", "ok");
44928
45093
  await scaffoldStep(ui, { untrackMemory: opts.untrackMemory === true, untrackStandard: opts.untrackStandard === true, untrackState: opts.untrackState === true });
44929
45094
  trace.mark("scaffold", "ok");
44930
- await (0, import_promises17.mkdir)((0, import_node_path68.join)((0, import_node_os15.homedir)(), ".verity"), { recursive: true });
45095
+ await (0, import_promises17.mkdir)((0, import_node_path69.join)((0, import_node_os15.homedir)(), ".verity"), { recursive: true });
44931
45096
  await repoStep(ui, detectProject());
44932
45097
  const previous = await readSetupState();
44933
- const setUpBefore = (0, import_node_fs79.existsSync)(projectPath(STANDARD_FILE));
45098
+ const setUpBefore = (0, import_node_fs80.existsSync)(projectPath(STANDARD_FILE));
44934
45099
  const answers = await askSetupQuestions(defaultsOnly, previous, { moments: givenMoments, telemetry: givenTelemetry });
44935
45100
  trace.mark("questions", "ok", givenMoments || givenTelemetry !== void 0 || profileAnswer || standardAnswer ? "asked" : "defaults");
44936
45101
  const plan = planMoments(answers.moments, { given: givenMoments !== void 0, defaultsOnly });
@@ -44980,7 +45145,7 @@ function registerInitCommand(program2) {
44980
45145
  }
44981
45146
 
44982
45147
  // src/commands/doctor.ts
44983
- var import_node_fs80 = require("node:fs");
45148
+ var import_node_fs81 = require("node:fs");
44984
45149
  var LEGACY_STANDARD_FILE = ".gate/standard.yaml";
44985
45150
  async function buildReport() {
44986
45151
  const prereqs = await checkPrereqs({ install: false });
@@ -44990,11 +45155,11 @@ async function buildReport() {
44990
45155
  const provenance = cliProvenance();
44991
45156
  const telemetry = await checkTelemetry();
44992
45157
  const artifacts = {
44993
- standard: (0, import_node_fs80.existsSync)(projectPath(STANDARD_FILE)),
45158
+ standard: (0, import_node_fs81.existsSync)(projectPath(STANDARD_FILE)),
44994
45159
  // The migration's own answer, not a bare existsSync: /verity:init skips a
44995
45160
  // question on this, so it must be true only when init will carry the file.
44996
45161
  legacyStandard: hasLegacyStandard(repoRoot()),
44997
- verityMd: (0, import_node_fs80.existsSync)(projectPath(VERITY_MD_FILE))
45162
+ verityMd: (0, import_node_fs81.existsSync)(projectPath(VERITY_MD_FILE))
44998
45163
  };
44999
45164
  const next = [];
45000
45165
  for (const c of prereqs.checks) {
@@ -45134,11 +45299,14 @@ function registerDoctorCommand(program2) {
45134
45299
  printInfo(` Git-moment gate: ${report.hooks.guardOn.length ? report.hooks.guardOn.join(", ") : "off"}`);
45135
45300
  {
45136
45301
  const cfg = readProjectConfig();
45137
- const formal = cfg.formal === "push";
45302
+ const setting = formalSetting(cfg);
45303
+ const formal = setting.state === "push";
45138
45304
  const tc = formal ? findToolchain() : null;
45139
45305
  const lean = tc ? "\u2713" : installProgressLine() ?? "MISSING \u2014 verity lean install";
45140
- printInfo(` Formal verification (push): ${formal ? `on, Lean ${lean} (ranking, model writing and replay run on the Verity service with your login)` : "off"}`);
45141
- if (cfg.formal_refused) printWarn(` ${formalRefusalMessage(cfg.formal_refused)}`);
45306
+ const how = setting.source === "default" ? " by default" : setting.source === "env" ? " (VERITY_GIT_MOMENT_FORMAL)" : "";
45307
+ printInfo(` Formal verification (push): ${formal ? `on${how}, Lean ${lean} (ranking, model writing and replay run on the Verity service with your login)` : `off${how}`}`);
45308
+ if (cfg.formal_off_refused && formal) printWarn(` ${formalOffRefusalMessage(cfg.formal_off_refused)}`);
45309
+ if (cfg.formal_off_unverified && !formal && setting.source === "config") printWarn(` ${formalOffUnverifiedNote()}`);
45142
45310
  }
45143
45311
  printInfo(` Infra (intent/baseline/compact/session-end): ${[report.hooks.intent, report.hooks.baseline, report.hooks.compact, report.hooks.sessionEnd].filter(Boolean).length}/4`);
45144
45312
  printInfo(
@@ -45164,8 +45332,8 @@ function registerDoctorCommand(program2) {
45164
45332
  }
45165
45333
 
45166
45334
  // src/commands/uninstall.ts
45167
- var import_node_fs81 = require("node:fs");
45168
- var import_node_path69 = require("node:path");
45335
+ var import_node_fs82 = require("node:fs");
45336
+ var import_node_path70 = require("node:path");
45169
45337
  function registerUninstallCommand(program2) {
45170
45338
  program2.command("uninstall").description("Remove Verity from this project (skills, hooks, .verity/, VERITY.md)").option("--dry-run", "Show what would be removed without doing it").option("--purge-global", "Also remove ~/.verity/ (deletes saved tokens \u2014 reconnect requires re-registration)").option("--keep-verity-md", "Keep the project root VERITY.md file").action(async (opts) => {
45171
45339
  const dryRun = opts.dryRun ?? false;
@@ -45174,11 +45342,11 @@ function registerUninstallCommand(program2) {
45174
45342
  const actions = [];
45175
45343
  const skillsRoot = projectPath(".claude/skills");
45176
45344
  for (const name2 of PROJECT_SKILL_NAMES) {
45177
- const dir = (0, import_node_path69.join)(skillsRoot, name2);
45178
- if ((0, import_node_fs81.existsSync)(dir)) {
45345
+ const dir = (0, import_node_path70.join)(skillsRoot, name2);
45346
+ if ((0, import_node_fs82.existsSync)(dir)) {
45179
45347
  actions.push({
45180
45348
  label: `Remove .claude/skills/${name2}/`,
45181
- apply: () => (0, import_node_fs81.rmSync)(dir, { recursive: true, force: true })
45349
+ apply: () => (0, import_node_fs82.rmSync)(dir, { recursive: true, force: true })
45182
45350
  });
45183
45351
  }
45184
45352
  }
@@ -45192,24 +45360,24 @@ function registerUninstallCommand(program2) {
45192
45360
  });
45193
45361
  }
45194
45362
  const verityDir = projectPath(VERITY_DIR);
45195
- if ((0, import_node_fs81.existsSync)(verityDir)) {
45363
+ if ((0, import_node_fs82.existsSync)(verityDir)) {
45196
45364
  actions.push({
45197
45365
  label: `Remove ${VERITY_DIR}/`,
45198
- apply: () => (0, import_node_fs81.rmSync)(verityDir, { recursive: true, force: true })
45366
+ apply: () => (0, import_node_fs82.rmSync)(verityDir, { recursive: true, force: true })
45199
45367
  });
45200
45368
  }
45201
45369
  if (!keepVerityMd) {
45202
45370
  const verityMd = projectPath(VERITY_MD_FILE);
45203
- if ((0, import_node_fs81.existsSync)(verityMd)) {
45371
+ if ((0, import_node_fs82.existsSync)(verityMd)) {
45204
45372
  actions.push({
45205
45373
  label: `Remove ${VERITY_MD_FILE}`,
45206
- apply: () => (0, import_node_fs81.rmSync)(verityMd, { force: true })
45374
+ apply: () => (0, import_node_fs82.rmSync)(verityMd, { force: true })
45207
45375
  });
45208
45376
  }
45209
45377
  }
45210
45378
  const cleanupEmptyDir = (path) => {
45211
- if ((0, import_node_fs81.existsSync)(path) && (0, import_node_fs81.statSync)(path).isDirectory() && (0, import_node_fs81.readdirSync)(path).length === 0) {
45212
- (0, import_node_fs81.rmdirSync)(path);
45379
+ if ((0, import_node_fs82.existsSync)(path) && (0, import_node_fs82.statSync)(path).isDirectory() && (0, import_node_fs82.readdirSync)(path).length === 0) {
45380
+ (0, import_node_fs82.rmdirSync)(path);
45213
45381
  }
45214
45382
  };
45215
45383
  actions.push({
@@ -45220,11 +45388,11 @@ function registerUninstallCommand(program2) {
45220
45388
  }
45221
45389
  });
45222
45390
  const home = process.env.HOME ?? "";
45223
- const globalVerityDir = (0, import_node_path69.join)(home, ".verity");
45224
- if (purgeGlobal && (0, import_node_fs81.existsSync)(globalVerityDir)) {
45391
+ const globalVerityDir = (0, import_node_path70.join)(home, ".verity");
45392
+ if (purgeGlobal && (0, import_node_fs82.existsSync)(globalVerityDir)) {
45225
45393
  actions.push({
45226
45394
  label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
45227
- apply: () => (0, import_node_fs81.rmSync)(globalVerityDir, { recursive: true, force: true })
45395
+ apply: () => (0, import_node_fs82.rmSync)(globalVerityDir, { recursive: true, force: true })
45228
45396
  });
45229
45397
  }
45230
45398
  if (actions.length === 0) {
@@ -45443,8 +45611,8 @@ function registerTaskCommands(program2) {
45443
45611
  }
45444
45612
 
45445
45613
  // src/commands/reset.ts
45446
- var import_node_fs82 = require("node:fs");
45447
- var import_node_path70 = require("node:path");
45614
+ var import_node_fs83 = require("node:fs");
45615
+ var import_node_path71 = require("node:path");
45448
45616
  function registerResetCommand(program2) {
45449
45617
  program2.command("reset").description("Close the current task and clear transient state").option("--keep-task", "Only purge caches; leave the current task open").option("--all", "Also purge diagnostic logs (.verity/.logs/)").action(async (opts) => {
45450
45618
  const globals = program2.opts();
@@ -45484,18 +45652,18 @@ function registerResetCommand(program2) {
45484
45652
  } catch {
45485
45653
  }
45486
45654
  }
45487
- const purged = purgeVerityDir((0, import_node_path70.basename)(CACHE_DIR), (name2) => name2.startsWith("pending-"));
45655
+ const purged = purgeVerityDir((0, import_node_path71.basename)(CACHE_DIR), (name2) => name2.startsWith("pending-"));
45488
45656
  if (purged === null) printError(`Did not purge ${CACHE_DIR}: it is not a directory inside ${VERITY_DIR}.`);
45489
45657
  const stateDir2 = projectPath(VERITY_DIR);
45490
45658
  const filesToClear = [
45491
- (0, import_node_path70.basename)(INTENT_FILE),
45492
- (0, import_node_path70.basename)(HASH_FILE),
45493
- (0, import_node_path70.basename)(BASELINE_SHA_FILE),
45659
+ (0, import_node_path71.basename)(INTENT_FILE),
45660
+ (0, import_node_path71.basename)(HASH_FILE),
45661
+ (0, import_node_path71.basename)(BASELINE_SHA_FILE),
45494
45662
  ".iteration-count",
45495
45663
  ".last-analysis"
45496
45664
  ];
45497
45665
  for (const name2 of filesToClear) {
45498
- if (lstatOrNull((0, import_node_path70.join)(stateDir2, name2)) && !replaceInRoot(stateDir2, name2, "")) {
45666
+ if (lstatOrNull((0, import_node_path71.join)(stateDir2, name2)) && !replaceInRoot(stateDir2, name2, "")) {
45499
45667
  printError(`Did not clear ${VERITY_DIR}/${name2}: it is not a regular file inside ${VERITY_DIR}.`);
45500
45668
  }
45501
45669
  }
@@ -45510,29 +45678,29 @@ function registerResetCommand(program2) {
45510
45678
  }
45511
45679
  function lstatOrNull(path) {
45512
45680
  try {
45513
- return (0, import_node_fs82.lstatSync)(path);
45681
+ return (0, import_node_fs83.lstatSync)(path);
45514
45682
  } catch {
45515
45683
  return null;
45516
45684
  }
45517
45685
  }
45518
45686
  function purgeVerityDir(child, select) {
45519
45687
  const verityDir = projectPath(VERITY_DIR);
45520
- const dir = (0, import_node_path70.join)(verityDir, child);
45688
+ const dir = (0, import_node_path71.join)(verityDir, child);
45521
45689
  const parent = lstatOrNull(verityDir);
45522
45690
  const st = lstatOrNull(dir);
45523
45691
  if (!st) return 0;
45524
45692
  if (!parent || parent.isSymbolicLink() || !parent.isDirectory()) return null;
45525
45693
  if (st.isSymbolicLink() || !st.isDirectory()) return null;
45526
45694
  try {
45527
- if ((0, import_node_fs82.realpathSync)(dir) !== (0, import_node_path70.join)((0, import_node_fs82.realpathSync)(verityDir), child)) return null;
45695
+ if ((0, import_node_fs83.realpathSync)(dir) !== (0, import_node_path71.join)((0, import_node_fs83.realpathSync)(verityDir), child)) return null;
45528
45696
  } catch {
45529
45697
  return null;
45530
45698
  }
45531
45699
  let removed = 0;
45532
- for (const entry of (0, import_node_fs82.readdirSync)(dir, { withFileTypes: true })) {
45700
+ for (const entry of (0, import_node_fs83.readdirSync)(dir, { withFileTypes: true })) {
45533
45701
  if (entry.isDirectory() || !select(entry.name)) continue;
45534
45702
  try {
45535
- (0, import_node_fs82.unlinkSync)((0, import_node_path70.join)(dir, entry.name));
45703
+ (0, import_node_fs83.unlinkSync)((0, import_node_path71.join)(dir, entry.name));
45536
45704
  removed++;
45537
45705
  } catch {
45538
45706
  }
@@ -45541,7 +45709,7 @@ function purgeVerityDir(child, select) {
45541
45709
  }
45542
45710
 
45543
45711
  // src/commands/reflect.ts
45544
- var import_node_fs83 = require("node:fs");
45712
+ var import_node_fs84 = require("node:fs");
45545
45713
 
45546
45714
  // src/lib/reflection-globs.ts
45547
45715
  var MAX_GLOBS = 6;
@@ -45579,7 +45747,7 @@ async function writeNodeToDisk(args2) {
45579
45747
  { treePaths: listTrackedFiles(), recordBaseline: false }
45580
45748
  );
45581
45749
  if (written === 0) return false;
45582
- return (0, import_node_fs83.existsSync)(projectPath(`${VERITY_DIR}/memory/${args2.filePath}`));
45750
+ return (0, import_node_fs84.existsSync)(projectPath(`${VERITY_DIR}/memory/${args2.filePath}`));
45583
45751
  } catch {
45584
45752
  return false;
45585
45753
  }
@@ -46016,7 +46184,7 @@ function registerRunCommand(program2) {
46016
46184
  }
46017
46185
 
46018
46186
  // src/commands/telemetry.ts
46019
- var import_node_fs84 = require("node:fs");
46187
+ var import_node_fs85 = require("node:fs");
46020
46188
  var SCOPE = "every Claude Code session on this machine";
46021
46189
  function declineHeaders(why) {
46022
46190
  process.stderr.write(`Verity telemetry is off here: ${why} Nothing is exported from this session.
@@ -46024,7 +46192,7 @@ function declineHeaders(why) {
46024
46192
  process.exitCode = 1;
46025
46193
  }
46026
46194
  async function recordTelemetryChoice(choice) {
46027
- if (!(0, import_node_fs84.existsSync)(projectPath(SETUP_STATE_FILE))) return;
46195
+ if (!(0, import_node_fs85.existsSync)(projectPath(SETUP_STATE_FILE))) return;
46028
46196
  try {
46029
46197
  if ((await readSetupState())?.telemetry === choice) return;
46030
46198
  await writeSetupState({ telemetry: choice });
@@ -46132,12 +46300,12 @@ function registerTelemetryCommands(program2) {
46132
46300
  }
46133
46301
 
46134
46302
  // src/commands/prove.ts
46135
- var import_node_fs86 = require("node:fs");
46136
- var import_node_path72 = require("node:path");
46303
+ var import_node_fs87 = require("node:fs");
46304
+ var import_node_path73 = require("node:path");
46137
46305
 
46138
46306
  // src/lib/prove/on-demand-run.ts
46139
- var import_node_fs85 = require("node:fs");
46140
- var import_node_path71 = require("node:path");
46307
+ var import_node_fs86 = require("node:fs");
46308
+ var import_node_path72 = require("node:path");
46141
46309
  var ON_DEMAND_RUN = `${PROOFS_DIR}/.results/.formal-run.json`;
46142
46310
  var ON_DEMAND_RUN_REUSE_MS = 18 * 6e4;
46143
46311
  function isLocalState2(root) {
@@ -46159,7 +46327,7 @@ function forgetOnDemandRun(root) {
46159
46327
  setFormalRun(null);
46160
46328
  if (!isLocalState2(root)) return;
46161
46329
  try {
46162
- (0, import_node_fs85.unlinkSync)((0, import_node_path71.join)(root, ON_DEMAND_RUN));
46330
+ (0, import_node_fs86.unlinkSync)((0, import_node_path72.join)(root, ON_DEMAND_RUN));
46163
46331
  } catch {
46164
46332
  }
46165
46333
  }
@@ -46336,7 +46504,7 @@ function registerProveCommand(program2) {
46336
46504
  process.exit(2);
46337
46505
  }
46338
46506
  const limit = Math.max(1, Math.min(50, Number(opts.limit) || 10));
46339
- let signals = collectRiskSignals(root, { since: opts.since, limit, paths: paths.map((p) => (0, import_node_path72.relative)(root, (0, import_node_path72.resolve)(p)) || ".") });
46507
+ let signals = collectRiskSignals(root, { since: opts.since, limit, paths: paths.map((p) => (0, import_node_path73.relative)(root, (0, import_node_path73.resolve)(p)) || ".") });
46340
46508
  if (opts.hint && paths.length === 0) {
46341
46509
  const hit = hintMatches(root, opts.hint);
46342
46510
  if (hit.files.length > 0) {
@@ -46390,7 +46558,7 @@ function registerProveCommand(program2) {
46390
46558
  });
46391
46559
  prove.command("check [model]").description("Elaborate a model (or every model) with the local Lean toolchain and report each property").option("--timeout <ms>", "Per-model timeout in ms", "120000").option("--json", "Machine-readable output").action((model, opts) => {
46392
46560
  const root = repoRoot();
46393
- if (!(0, import_node_fs86.existsSync)((0, import_node_path72.join)(root, PROOFS_DIR, "lakefile.toml"))) {
46561
+ if (!(0, import_node_fs87.existsSync)((0, import_node_path73.join)(root, PROOFS_DIR, "lakefile.toml"))) {
46394
46562
  printError(`No ${PROOFS_DIR}/ project here. Run \`verity prove init\` first.`);
46395
46563
  process.exit(2);
46396
46564
  }
@@ -46414,7 +46582,7 @@ ${build.stderr.split("\n").filter((l) => !l.startsWith("trace:")).slice(0, 20).j
46414
46582
  const reports = [];
46415
46583
  for (const f of files) {
46416
46584
  const report = checkModel(tc, root, f, { timeoutMs: Math.max(1e3, Number(opts.timeout) || 12e4) });
46417
- report.file = (0, import_node_path72.relative)(root, f);
46585
+ report.file = (0, import_node_path73.relative)(root, f);
46418
46586
  reports.push(report);
46419
46587
  try {
46420
46588
  writeResult(root, report);
@@ -46452,7 +46620,7 @@ ${build.stderr.split("\n").filter((l) => !l.startsWith("trace:")).slice(0, 20).j
46452
46620
  printError("Not logged in \u2014 replays run on the Verity service. Run `verity login` first.");
46453
46621
  process.exit(2);
46454
46622
  }
46455
- if (!(0, import_node_fs86.existsSync)((0, import_node_path72.join)(root, PROOFS_DIR, "lakefile.toml"))) {
46623
+ if (!(0, import_node_fs87.existsSync)((0, import_node_path73.join)(root, PROOFS_DIR, "lakefile.toml"))) {
46456
46624
  printError(`No ${PROOFS_DIR}/ project here. Run \`verity prove init\` first.`);
46457
46625
  process.exit(2);
46458
46626
  }
@@ -46491,7 +46659,7 @@ ${report.error ?? ""}`);
46491
46659
  process.exit(2);
46492
46660
  }
46493
46661
  }
46494
- const modelSource = readRegularFileInRoot(root, (0, import_node_path72.relative)(root, file), 512 * 1024);
46662
+ const modelSource = readRegularFileInRoot(root, (0, import_node_path73.relative)(root, file), 512 * 1024);
46495
46663
  if (!opts.json) printInfo(`replaying ${targets.length} counterexample(s) of ${model} in network-less containers (${Math.min(targets.length, REPLAY_CONCURRENCY)} at a time)\u2026`);
46496
46664
  const outcomes = await mapPool(targets, REPLAY_CONCURRENCY, async (p) => {
46497
46665
  const brief = buildReplayBrief(root, report, p, modelSource.ok ? modelSource.content : "");
@@ -46512,7 +46680,7 @@ ${report.error ?? ""}`);
46512
46680
  });
46513
46681
  prove.command("auto [files...]").description("The formal phase the pre-push guard runs: select one risky symbol among changed files, generate a model, check it, replay counterexamples (default files: the commits ahead of upstream)").option("--deadline <ms>", "Budget for the whole phase", "170000").option("--json", "Machine-readable output").action(async (paths, opts) => {
46514
46682
  const root = repoRoot();
46515
- let files = paths.map((p) => (0, import_node_path72.relative)(root, (0, import_node_path72.resolve)(p)));
46683
+ let files = paths.map((p) => (0, import_node_path73.relative)(root, (0, import_node_path73.resolve)(p)));
46516
46684
  if (files.length === 0) {
46517
46685
  const ahead = runGitSync(root, ["diff", "--name-only", "@{upstream}...HEAD"]);
46518
46686
  const fallback = ahead.ok ? ahead : runGitSync(root, ["diff", "--name-only", "HEAD~1..HEAD"]);
@@ -46586,7 +46754,7 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
46586
46754
  let revise;
46587
46755
  if (opts.revise) {
46588
46756
  const existing = resolveModelFile(root, opts.revise);
46589
- const src = existing ? readRegularFileInRoot(root, (0, import_node_path72.relative)(root, existing), 64 * 1024) : null;
46757
+ const src = existing ? readRegularFileInRoot(root, (0, import_node_path73.relative)(root, existing), 64 * 1024) : null;
46590
46758
  if (!src || !src.ok || !opts.note) {
46591
46759
  printError("--revise needs an existing model under Models/ and --note - with what the replay showed on stdin");
46592
46760
  process.exit(2);
@@ -46635,8 +46803,8 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
46635
46803
  });
46636
46804
  prove.command("waive <file>").description("Dismiss the remembered formal finding(s) on a file for its current bytes \u2014 the accepted-risk path for a formal block").requiredOption("--reason <text>", "The human disposition this records (reviewer finding, ADR, \u2026)").action((file, opts) => {
46637
46805
  const root = repoRoot();
46638
- const rel0 = (0, import_node_path72.relative)(root, (0, import_node_path72.isAbsolute)(file) ? file : (0, import_node_path72.join)(root, file)).replace(/\\/g, "/");
46639
- const rel = rel0.startsWith("..") || (0, import_node_path72.isAbsolute)(rel0) ? null : rel0;
46806
+ const rel0 = (0, import_node_path73.relative)(root, (0, import_node_path73.isAbsolute)(file) ? file : (0, import_node_path73.join)(root, file)).replace(/\\/g, "/");
46807
+ const rel = rel0.startsWith("..") || (0, import_node_path73.isAbsolute)(rel0) ? null : rel0;
46640
46808
  if (!rel) {
46641
46809
  printError(`${file} is not inside this repository`);
46642
46810
  process.exit(2);
@@ -46652,8 +46820,8 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
46652
46820
  });
46653
46821
  prove.command("hash <file>").description("Print the sha256 of a file, for a model header (Verity.model \u2026 sha256). Path is REPO-relative, as in the header").action((file) => {
46654
46822
  const root = repoRoot();
46655
- const rel = (0, import_node_path72.relative)(root, (0, import_node_path72.isAbsolute)(file) ? file : (0, import_node_path72.join)(root, file));
46656
- const digest = rel.startsWith("..") || (0, import_node_path72.isAbsolute)(rel) ? null : sha256InRoot(root, rel);
46823
+ const rel = (0, import_node_path73.relative)(root, (0, import_node_path73.isAbsolute)(file) ? file : (0, import_node_path73.join)(root, file));
46824
+ const digest = rel.startsWith("..") || (0, import_node_path73.isAbsolute)(rel) ? null : sha256InRoot(root, rel);
46657
46825
  if (!digest) {
46658
46826
  printError(`Cannot hash ${file}: it must be a regular file inside this repository (not a symlink)`);
46659
46827
  process.exit(2);
@@ -46687,10 +46855,10 @@ function refreshScaffold(root) {
46687
46855
  }
46688
46856
 
46689
46857
  // src/commands/lean.ts
46690
- var import_node_fs87 = require("node:fs");
46858
+ var import_node_fs88 = require("node:fs");
46691
46859
  var import_node_child_process24 = require("node:child_process");
46692
46860
  var import_node_os16 = require("node:os");
46693
- var import_node_path73 = require("node:path");
46861
+ var import_node_path74 = require("node:path");
46694
46862
  function registerLeanCommand(program2) {
46695
46863
  const lean = program2.command("lean").description("The Lean 4 toolchain formal verification needs (managed download, pinned by this CLI)");
46696
46864
  lean.command("status").option("--json", "Machine-readable output").description("Which toolchain would run, and whether it matches the pinned version").action((opts) => {
@@ -46709,7 +46877,7 @@ function registerLeanCommand(program2) {
46709
46877
  const bg = readInstallState();
46710
46878
  const background = bg ? { ...bg, running: bg.state === "running" && installRunning() } : null;
46711
46879
  if (opts.json) {
46712
- printJson({ pinned: LEAN_TOOLCHAIN, found: tc?.lake ?? null, version, matches_pin: matches, managed_dir: managed, managed_installed: (0, import_node_fs87.existsSync)((0, import_node_path73.join)(managed, "bin")), asset: leanAssetName(), background });
46880
+ printJson({ pinned: LEAN_TOOLCHAIN, found: tc?.lake ?? null, version, matches_pin: matches, managed_dir: managed, managed_installed: (0, import_node_fs88.existsSync)((0, import_node_path74.join)(managed, "bin")), asset: leanAssetName(), background });
46713
46881
  return;
46714
46882
  }
46715
46883
  printInfo(`pinned: ${LEAN_TOOLCHAIN}`);
@@ -46730,7 +46898,7 @@ function registerLeanCommand(program2) {
46730
46898
  process.exit(2);
46731
46899
  }
46732
46900
  const dir = pinnedVersionDir();
46733
- if ((0, import_node_fs87.existsSync)((0, import_node_path73.join)(dir, "bin", "lake")) && !opts.force) {
46901
+ if ((0, import_node_fs88.existsSync)((0, import_node_path74.join)(dir, "bin", "lake")) && !opts.force) {
46734
46902
  printInfo(`already installed at ${dir}`);
46735
46903
  return;
46736
46904
  }
@@ -46766,20 +46934,20 @@ function registerLeanCommand(program2) {
46766
46934
  });
46767
46935
  lean.command("remove").description("Delete the Verity-managed toolchain for the pinned version").action(() => {
46768
46936
  const dir = pinnedVersionDir();
46769
- if (!(0, import_node_fs87.existsSync)(dir)) {
46937
+ if (!(0, import_node_fs88.existsSync)(dir)) {
46770
46938
  printInfo("nothing to remove");
46771
46939
  return;
46772
46940
  }
46773
- (0, import_node_fs87.rmSync)(dir, { recursive: true, force: true });
46941
+ (0, import_node_fs88.rmSync)(dir, { recursive: true, force: true });
46774
46942
  printInfo(`removed ${dir}`);
46775
46943
  });
46776
46944
  }
46777
46945
 
46778
46946
  // src/cli.ts
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) => {
46947
+ program.name("verity").description("CLI for Verity quality gate service").version("0.35.5").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr").hook("preAction", async (_thisCommand, actionCommand) => {
46780
46948
  const isTelemetryHelper = actionCommand.name() === "headers" && actionCommand.parent?.name() === "telemetry";
46781
46949
  if (!isTelemetryHelper) {
46782
- installStderrLog(actionCommand.name(), process.argv.slice(2), "0.35.4");
46950
+ installStderrLog(actionCommand.name(), process.argv.slice(2), "0.35.5");
46783
46951
  }
46784
46952
  setUserNamedServiceUrl(program.opts().serviceUrl);
46785
46953
  try {