@codacy/verity-cli 0.31.1-experimental.80cf3ac → 0.31.1-experimental.be74f71

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
@@ -10519,13 +10519,20 @@ var ADVISORY_EPISODE_FILE = `${VERITY_DIR}/.advisory-episode`;
10519
10519
  var IGNORE_DECLARATION_FILE = `${VERITY_DIR}/.ignore-declaration`;
10520
10520
 
10521
10521
  // src/lib/output.ts
10522
- var RED = "\x1B[0;31m";
10523
- var YELLOW = "\x1B[1;33m";
10524
- var GREEN = "\x1B[0;32m";
10525
- var CYAN = "\x1B[0;36m";
10526
- var BOLD = "\x1B[1m";
10527
- var DIM = "\x1B[2m";
10528
- var NC = "\x1B[0m";
10522
+ function colorEnabled() {
10523
+ if (process.env.FORCE_COLOR) return true;
10524
+ if (process.env.NO_COLOR !== void 0) return false;
10525
+ if (process.env.TERM === "dumb") return false;
10526
+ return !!process.stderr.isTTY;
10527
+ }
10528
+ var COLOR = colorEnabled();
10529
+ var RED = COLOR ? "\x1B[0;31m" : "";
10530
+ var YELLOW = COLOR ? "\x1B[1;33m" : "";
10531
+ var GREEN = COLOR ? "\x1B[0;32m" : "";
10532
+ var CYAN = COLOR ? "\x1B[0;36m" : "";
10533
+ var BOLD = COLOR ? "\x1B[1m" : "";
10534
+ var DIM = COLOR ? "\x1B[2m" : "";
10535
+ var NC = COLOR ? "\x1B[0m" : "";
10529
10536
  function printJson(data) {
10530
10537
  process.stdout.write(JSON.stringify(data, null, 2) + "\n");
10531
10538
  }
@@ -11252,7 +11259,7 @@ async function resolveServiceUrlDetailed(flagUrl, opts = {}) {
11252
11259
  }
11253
11260
  return {
11254
11261
  ok: false,
11255
- error: 'No Verity service URL found. Run "verity login" to get started, or /verity-setup to configure this project.'
11262
+ error: 'No Verity service URL found. Run "verity login" to get started, or "verity init" to set up this project.'
11256
11263
  };
11257
11264
  }
11258
11265
  async function resolveServiceUrlForAuth(flagUrl) {
@@ -11299,7 +11306,7 @@ async function resolveToken(flagToken) {
11299
11306
  }
11300
11307
  return {
11301
11308
  ok: false,
11302
- error: 'No Verity token found. Run "verity login" to sign in, or /verity-setup to set up this project.'
11309
+ error: 'No Verity token found. Run "verity login" to sign in, or "verity init" to set up this project.'
11303
11310
  };
11304
11311
  }
11305
11312
  async function whoami(token, serviceUrl, verbose) {
@@ -11393,6 +11400,91 @@ async function maybeHealServiceUrl(resolution, verbose) {
11393
11400
  var readline = __toESM(require("node:readline/promises"));
11394
11401
  var import_node_os = require("node:os");
11395
11402
 
11403
+ // src/lib/spinner.ts
11404
+ var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
11405
+ var FRAME_MS = 80;
11406
+ var DIM2 = "\x1B[2m";
11407
+ var GREEN2 = "\x1B[0;32m";
11408
+ var YELLOW2 = "\x1B[1;33m";
11409
+ var RESET = "\x1B[0m";
11410
+ function secondsSince(start) {
11411
+ return `${Math.round((Date.now() - start) / 1e3)}s`;
11412
+ }
11413
+ function startSpinner(label2, opts = {}) {
11414
+ const stream = process.stderr;
11415
+ const color = colorEnabled();
11416
+ const animate = opts.animate ?? !!stream.isTTY;
11417
+ const showElapsed = opts.elapsed ?? true;
11418
+ const start = Date.now();
11419
+ let current = label2;
11420
+ let frame = 0;
11421
+ let timer = null;
11422
+ let done = false;
11423
+ const fit = (label3, clock, columns) => {
11424
+ const budget = columns - 5;
11425
+ if (budget <= 0) return { label: "", clock: "" };
11426
+ if (label3.length + clock.length <= budget) return { label: label3, clock };
11427
+ if (clock.length >= budget) return { label: "", clock: clock.slice(0, budget) };
11428
+ const room = budget - clock.length;
11429
+ return { label: room <= 1 ? label3.slice(0, room) : `${label3.slice(0, room - 1)}\u2026`, clock };
11430
+ };
11431
+ const paint = () => {
11432
+ const glyph = FRAMES[frame++ % FRAMES.length];
11433
+ const columns = stream.columns ?? 80;
11434
+ const { label: label3, clock } = fit(current, showElapsed ? ` ${secondsSince(start)}` : "", columns);
11435
+ const line = color ? ` ${GREEN2}${glyph}${RESET} ${label3}${DIM2}${clock}${RESET}` : ` ${glyph} ${label3}${clock}`;
11436
+ stream.write(`\r\x1B[2K${line}`);
11437
+ };
11438
+ const clearLine = () => {
11439
+ if (animate) stream.write("\r\x1B[2K");
11440
+ };
11441
+ if (animate) {
11442
+ paint();
11443
+ timer = setInterval(paint, FRAME_MS);
11444
+ timer.unref?.();
11445
+ } else {
11446
+ stream.write(` ${current}\u2026
11447
+ `);
11448
+ }
11449
+ const finish = (render2) => {
11450
+ if (done) return;
11451
+ done = true;
11452
+ if (timer) clearInterval(timer);
11453
+ clearLine();
11454
+ render2();
11455
+ };
11456
+ return {
11457
+ update(next) {
11458
+ current = next;
11459
+ if (animate) paint();
11460
+ else stream.write(` ${next}\u2026
11461
+ `);
11462
+ },
11463
+ succeed(message) {
11464
+ finish(() => {
11465
+ const text = message ?? current;
11466
+ const clock = showElapsed ? ` (${secondsSince(start)})` : "";
11467
+ stream.write(
11468
+ color ? ` ${GREEN2}\u2713${RESET} ${text}${DIM2}${clock}${RESET}
11469
+ ` : ` \u2713 ${text}${clock}
11470
+ `
11471
+ );
11472
+ });
11473
+ },
11474
+ warn(message) {
11475
+ finish(() => {
11476
+ stream.write(color ? ` ${YELLOW2}\u26A0${RESET} ${message}
11477
+ ` : ` \u26A0 ${message}
11478
+ `);
11479
+ });
11480
+ },
11481
+ stop() {
11482
+ finish(() => {
11483
+ });
11484
+ }
11485
+ };
11486
+ }
11487
+
11396
11488
  // src/lib/provider-auth.ts
11397
11489
  var sleep = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
11398
11490
  var form = (fields) => new URLSearchParams(fields).toString();
@@ -11459,42 +11551,49 @@ async function githubDeviceFlow() {
11459
11551
  printInfo("");
11460
11552
  printInfo(`To authorize Verity, open: ${dc.verification_uri}`);
11461
11553
  printInfo(`And enter the code: ${dc.user_code}`);
11462
- printInfo("Waiting for authorization\u2026");
11554
+ const spinner = startSpinner(`Waiting for you to approve in the browser \xB7 code ${dc.user_code}`);
11463
11555
  const deadline = Date.now() + (dc.expires_in || 900) * 1e3;
11464
11556
  let interval = dc.interval || 5;
11465
- while (Date.now() < deadline) {
11466
- await sleep(interval * 1e3);
11467
- let data;
11468
- try {
11469
- const res = await fetch(GITHUB_ACCESS_TOKEN_URL, {
11470
- method: "POST",
11471
- headers: { Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded" },
11472
- body: form({
11473
- client_id: GITHUB_CLIENT_ID,
11474
- device_code: dc.device_code,
11475
- grant_type: "urn:ietf:params:oauth:grant-type:device_code"
11476
- })
11477
- });
11478
- data = await res.json().catch(() => ({}));
11479
- } catch {
11480
- continue;
11481
- }
11482
- if (data.access_token) return { ok: true, data: data.access_token };
11483
- switch (data.error) {
11484
- case "authorization_pending":
11485
- break;
11486
- case "slow_down":
11487
- interval += 5;
11488
- break;
11489
- case "access_denied":
11490
- return { ok: false, error: "Authorization was denied on GitHub." };
11491
- case "expired_token":
11492
- return { ok: false, error: "The authorization code expired. Re-run register." };
11493
- default:
11494
- if (data.error) return { ok: false, error: `GitHub auth error: ${data.error}` };
11557
+ try {
11558
+ while (Date.now() < deadline) {
11559
+ await sleep(interval * 1e3);
11560
+ let data;
11561
+ try {
11562
+ const res = await fetch(GITHUB_ACCESS_TOKEN_URL, {
11563
+ method: "POST",
11564
+ headers: { Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded" },
11565
+ body: form({
11566
+ client_id: GITHUB_CLIENT_ID,
11567
+ device_code: dc.device_code,
11568
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code"
11569
+ })
11570
+ });
11571
+ data = await res.json().catch(() => ({}));
11572
+ } catch {
11573
+ continue;
11574
+ }
11575
+ if (data.access_token) {
11576
+ spinner.succeed("Authorized on GitHub");
11577
+ return { ok: true, data: data.access_token };
11578
+ }
11579
+ switch (data.error) {
11580
+ case "authorization_pending":
11581
+ break;
11582
+ case "slow_down":
11583
+ interval += 5;
11584
+ break;
11585
+ case "access_denied":
11586
+ return { ok: false, error: "Authorization was denied on GitHub." };
11587
+ case "expired_token":
11588
+ return { ok: false, error: "The authorization code expired. Re-run register." };
11589
+ default:
11590
+ if (data.error) return { ok: false, error: `GitHub auth error: ${data.error}` };
11591
+ }
11495
11592
  }
11593
+ return { ok: false, error: "Timed out waiting for GitHub authorization." };
11594
+ } finally {
11595
+ spinner.stop();
11496
11596
  }
11497
- return { ok: false, error: "Timed out waiting for GitHub authorization." };
11498
11597
  }
11499
11598
 
11500
11599
  // src/lib/register.ts
@@ -12263,12 +12362,20 @@ var VERITY_STOP_RE = /(?:^|[\/\s"'])verity\s+analyze\b/;
12263
12362
  var VERITY_INTENT_RE = /(?:^|[\/\s"'])verity\s+intent\s+capture\b/;
12264
12363
  var VERITY_GUARD_RE = /(?:^|[\/\s"'])verity\s+guard\b/;
12265
12364
  var VERITY_BASELINE_RE = /(?:^|[\/\s"'])verity\s+baseline\s+capture\b/;
12365
+ var VERITY_COMPACT_RE = /(?:^|[\/\s"'])verity\s+compact\b/;
12366
+ var VERITY_SESSION_END_RE = /(?:^|[\/\s"'])verity\s+session\s+end\b/;
12266
12367
  function isVerityGuardHook(entry) {
12267
12368
  return VERITY_GUARD_RE.test(entry.command ?? "");
12268
12369
  }
12269
12370
  function isVerityBaselineHook(entry) {
12270
12371
  return VERITY_BASELINE_RE.test(entry.command ?? "");
12271
12372
  }
12373
+ function isVerityCompactHook(entry) {
12374
+ return VERITY_COMPACT_RE.test(entry.command ?? "");
12375
+ }
12376
+ function isVeritySessionEndHook(entry) {
12377
+ return VERITY_SESSION_END_RE.test(entry.command ?? "");
12378
+ }
12272
12379
  var LEGACY_STOP_RE = /(?:^|[\/\s"'])gate\s+analyze\b/;
12273
12380
  var LEGACY_INTENT_RE = /(?:^|[\/\s"'])gate\s+intent\s+capture\b/;
12274
12381
  function isVerityStopHook(entry) {
@@ -12280,7 +12387,7 @@ function isVerityIntentHook(entry) {
12280
12387
  return VERITY_INTENT_RE.test(c) || LEGACY_INTENT_RE.test(c) || c.includes(".verity/hooks/capture-intent.sh") || c.includes(".gate/hooks/capture-intent.sh");
12281
12388
  }
12282
12389
  function isVerityHook(entry) {
12283
- return isVerityStopHook(entry) || isVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry);
12390
+ return isVerityStopHook(entry) || isVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry) || isVerityCompactHook(entry) || isVeritySessionEndHook(entry);
12284
12391
  }
12285
12392
  function isCurrentVerityStopHook(entry) {
12286
12393
  const c = entry.command ?? "";
@@ -12291,7 +12398,7 @@ function isCurrentVerityIntentHook(entry) {
12291
12398
  return VERITY_INTENT_RE.test(c) || c.includes(".verity/hooks/capture-intent.sh");
12292
12399
  }
12293
12400
  function isCurrentVerityHook(entry) {
12294
- return isCurrentVerityStopHook(entry) || isCurrentVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry);
12401
+ return isCurrentVerityStopHook(entry) || isCurrentVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry) || isVerityCompactHook(entry) || isVeritySessionEndHook(entry);
12295
12402
  }
12296
12403
  function settingsHasLegacyHook(settings) {
12297
12404
  for (const groups of Object.values(settings.hooks ?? {})) {
@@ -12353,6 +12460,8 @@ async function checkAllVerityHooks() {
12353
12460
  async function checkExternalVerityHooks() {
12354
12461
  let stop = false;
12355
12462
  let intent = false;
12463
+ let compact = false;
12464
+ let sessionEnd = false;
12356
12465
  let guardOn = [];
12357
12466
  for (const f of [SETTINGS_LOCAL_FILE, globalSettingsFile()]) {
12358
12467
  let settings;
@@ -12364,9 +12473,11 @@ async function checkExternalVerityHooks() {
12364
12473
  const r = checkVerityHooks(settings);
12365
12474
  stop = stop || r.stop;
12366
12475
  intent = intent || r.intent;
12476
+ compact = compact || r.compact;
12477
+ sessionEnd = sessionEnd || r.sessionEnd;
12367
12478
  if (r.guardOn.length > guardOn.length) guardOn = r.guardOn;
12368
12479
  }
12369
- return { stop, intent, guardOn };
12480
+ return { stop, intent, compact, sessionEnd, guardOn };
12370
12481
  }
12371
12482
  async function checkAllVerityHooksDetailed() {
12372
12483
  let stop = false;
@@ -12446,11 +12557,11 @@ function checkVerityHooks(settings) {
12446
12557
  }
12447
12558
  const compactGroups = hooks["PostCompact"] ?? [];
12448
12559
  const hasCompact = compactGroups.some(
12449
- (g) => g.hooks?.some((h) => h.command?.trim() === "verity compact")
12560
+ (g) => g.hooks?.some((h) => isVerityCompactHook(h))
12450
12561
  );
12451
12562
  const endGroups = hooks["SessionEnd"] ?? [];
12452
12563
  const hasSessionEnd = endGroups.some(
12453
- (g) => g.hooks?.some((h) => h.command?.trim() === "verity session end")
12564
+ (g) => g.hooks?.some((h) => isVeritySessionEndHook(h))
12454
12565
  );
12455
12566
  return {
12456
12567
  stop: hasStop,
@@ -12564,6 +12675,8 @@ function reconcileMomentHooks(settings, moments, externalPresent = {
12564
12675
  };
12565
12676
  if (!externalPresent.intent) push("UserPromptSubmit", { hooks: [VERITY_INTENT_HOOK] });
12566
12677
  push("SessionStart", { hooks: [VERITY_BASELINE_HOOK] });
12678
+ if (!externalPresent.compact) push("PostCompact", { hooks: [VERITY_COMPACT_HOOK] });
12679
+ if (!externalPresent.sessionEnd) push("SessionEnd", { hooks: [VERITY_SESSION_END_HOOK] });
12567
12680
  if (moments.includes("stop") && !externalPresent.stop) {
12568
12681
  push("Stop", { hooks: [VERITY_STOP_HOOK] });
12569
12682
  }
@@ -13540,6 +13653,74 @@ var LEGACY_MD_END = "<!-- gate-memory:end -->";
13540
13653
  var LEGACY_PRESERVE_START = "<!-- gate-memory:preserve -->";
13541
13654
  var LEGACY_PRESERVE_END = "<!-- /gate-memory:preserve -->";
13542
13655
  var CLAUDE_MD_PROSE = [
13656
+ "## Project Memory",
13657
+ "",
13658
+ "This project has a knowledge graph maintained at `.verity/memory/`. Before starting",
13659
+ "non-trivial work, scan `.verity/memory/index.md` for decisions, gotchas, and patterns",
13660
+ "that may apply to the change you are about to make. Open specific node files via",
13661
+ "the Read tool when the title or scope suggests relevance.",
13662
+ "",
13663
+ "The graph is auto-maintained by Verity. Files at `.verity/memory/_archive/` are",
13664
+ "superseded \u2014 ignore them unless investigating history.",
13665
+ "",
13666
+ "## Quality gate: accepted risks",
13667
+ "",
13668
+ "When the Verity pre-commit/pre-push gate FAILs, fix the findings \u2014 that is the",
13669
+ 'default. Use `verity waive <pattern-id> --file <path> --reason "\u2026"` ONLY to relay',
13670
+ "a risk a human has explicitly accepted: a named code-review finding, an ADR, or",
13671
+ "the user saying so in this conversation. The --reason must cite that source.",
13672
+ "",
13673
+ "Never waive on your own judgment, to get past a block, or pre-emptively. A waive",
13674
+ "binds to the file's current bytes and voids automatically when the file changes,",
13675
+ "and every waive is recorded in the run ledger. For a pattern-level false positive",
13676
+ "use `verity feedback finding <run-id> <pattern-id> false_positive` instead.",
13677
+ "",
13678
+ "## Post-task reflection",
13679
+ "",
13680
+ `When a task is complete (you've created a PR, the user says "done" or "ship it",`,
13681
+ "or the work is clearly finished), **draft the reflection yourself first** \u2014 1\u20133",
13682
+ "concrete things worth remembering (a decision, a gotcha, or a pattern), each",
13683
+ "cited with the files / PR / commands / error-signatures it came from. Skip",
13684
+ "entirely if nothing non-obvious happened.",
13685
+ "",
13686
+ "Then, depending on how the session is running:",
13687
+ "",
13688
+ "- **Interactive** (a person is at the keyboard): show your draft and ask one",
13689
+ ` question before recording \u2014 "Here's my reflection draft for the project`,
13690
+ " memory: <draft>. Anything to confirm, correct, or add before I record it?",
13691
+ ` (Say 'skip' to drop it.)" Record the final text (with their corrections) via`,
13692
+ ' `verity reflect --user-input "<final reflection>" --kind <kind>`. If they say',
13693
+ ' "skip", do not record.',
13694
+ "- **Autonomous** (headless / CI / cron, or `VERITY_AUTONOMOUS=1`): record your",
13695
+ ' draft directly, never blocking \u2014 `verity reflect --user-input "<your draft>"',
13696
+ " --kind <kind> --autonomous`.",
13697
+ "",
13698
+ "> Durable, hand-curated guidance goes in the preserve region below (it survives",
13699
+ "> regeneration) or anywhere OUTSIDE these markers. Everything else between the",
13700
+ "> markers is tool-owned and overwritten on each run.",
13701
+ "",
13702
+ "## Housekeeping Turns",
13703
+ "",
13704
+ "When a turn will be pure housekeeping \u2014 pulling, installing dependencies,",
13705
+ "rebasing, a formatting sweep you are not authoring \u2014 declare it BEFORE doing it:",
13706
+ "",
13707
+ "```bash",
13708
+ 'verity ignore --turn --agent --reason "pulling latest before starting"',
13709
+ "```",
13710
+ "",
13711
+ "This skips the review for that turn, which saves the turn Verity would",
13712
+ "otherwise spend saying it had nothing to say. Use `--for 30m` instead of",
13713
+ "`--turn` when a single piece of housekeeping spans several turns.",
13714
+ "",
13715
+ "**It is a claim about the turn, not a way to silence review.** The declaration",
13716
+ "is checked against what the turn actually did: if anything is authored \u2014 by you,",
13717
+ "by a subagent, or by a shell command that can write files \u2014 it voids, the review",
13718
+ "runs anyway, and the broken declaration is reported. So declare housekeeping you",
13719
+ "are about to do, never work you have already done, and never as a way to get past",
13720
+ "a finding. Declarations are budgeted per session and every one is recorded with",
13721
+ "its reason."
13722
+ ].join("\n");
13723
+ var CLAUDE_MD_PROSE_PRE_REFLECT = [
13543
13724
  "## Project Memory",
13544
13725
  "",
13545
13726
  "This project has a knowledge graph maintained at `.verity/memory/`. Before starting",
@@ -13750,6 +13931,7 @@ function stripKnownProse(interior) {
13750
13931
  const trimmed = interior.replace(/^\n+/, "");
13751
13932
  for (const prose of [
13752
13933
  CLAUDE_MD_PROSE,
13934
+ CLAUDE_MD_PROSE_PRE_REFLECT,
13753
13935
  CLAUDE_MD_PROSE_PRE_WAIVE,
13754
13936
  CLAUDE_MD_PROSE_PRE_IGNORE,
13755
13937
  CLAUDE_MD_PROSE_LEGACY
@@ -15795,33 +15977,6 @@ ${addedLines}`,
15795
15977
  }
15796
15978
  return { diffs, has_snapshots: true };
15797
15979
  }
15798
- function ensureSnapshotGitignored() {
15799
- let content = "";
15800
- try {
15801
- content = (0, import_node_fs16.readFileSync)(".gitignore", "utf-8");
15802
- } catch {
15803
- }
15804
- let ignored = null;
15805
- try {
15806
- (0, import_node_child_process6.execSync)("git check-ignore -q -- .verity/.snapshot/__probe__", { stdio: "pipe" });
15807
- ignored = true;
15808
- } catch (err) {
15809
- ignored = err.status === 1 ? false : null;
15810
- }
15811
- if (ignored === true) return "covered";
15812
- if (ignored === null) {
15813
- const lines = content.split("\n").map((l) => l.trim());
15814
- const covering = [".verity/.snapshot/", ".verity/.snapshot", ".verity/", ".verity", ".verity/*"];
15815
- if (lines.some((l) => covering.includes(l))) return "covered";
15816
- }
15817
- try {
15818
- const block = "# Verity \u2014 snapshots of analyzed files (machine state, never commit)\n.verity/.snapshot/\n";
15819
- (0, import_node_fs16.writeFileSync)(".gitignore", content ? content + (content.endsWith("\n") ? "" : "\n") + "\n" + block : block);
15820
- return "added";
15821
- } catch {
15822
- return "failed";
15823
- }
15824
- }
15825
15980
  function saveSnapshots(files) {
15826
15981
  const snapshotPaths = /* @__PURE__ */ new Set();
15827
15982
  for (const file of files) {
@@ -16743,19 +16898,19 @@ function loc(f) {
16743
16898
  if (!f.file) return "";
16744
16899
  return f.line != null ? `${f.file}:${f.line}` : f.file;
16745
16900
  }
16746
- function formatRunDetail(run) {
16901
+ function formatRunDetail(run2) {
16747
16902
  const lines = [];
16748
- const q = run.assessment?.quality_score;
16749
- const s = run.assessment?.security_score;
16903
+ const q = run2.assessment?.quality_score;
16904
+ const s = run2.assessment?.security_score;
16750
16905
  const qStr = q != null ? `${q}` : "-";
16751
16906
  const sStr = s != null ? `${s}` : "-";
16752
- lines.push(`${run.run_id} ${run.gate_decision} Q ${qStr}/10 S ${sStr}/10`);
16907
+ lines.push(`${run2.run_id} ${run2.gate_decision} Q ${qStr}/10 S ${sStr}/10`);
16753
16908
  const meta = [];
16754
- if (run.trigger) meta.push(`trigger: ${run.trigger}`);
16755
- if (run.standard_version != null) meta.push(`standard v${run.standard_version}`);
16756
- if (run.created_at) meta.push(run.created_at.slice(0, 19).replace("T", " "));
16909
+ if (run2.trigger) meta.push(`trigger: ${run2.trigger}`);
16910
+ if (run2.standard_version != null) meta.push(`standard v${run2.standard_version}`);
16911
+ if (run2.created_at) meta.push(run2.created_at.slice(0, 19).replace("T", " "));
16757
16912
  if (meta.length > 0) lines.push(meta.join(" \xB7 "));
16758
- const findings = run.findings ?? [];
16913
+ const findings = run2.findings ?? [];
16759
16914
  if (findings.length === 0) {
16760
16915
  lines.push("");
16761
16916
  lines.push("No findings \u2014 clean.");
@@ -16772,7 +16927,7 @@ function formatRunDetail(run) {
16772
16927
  if (f.scope === "pre-existing") lines.push(" (pre-existing)");
16773
16928
  }
16774
16929
  }
16775
- const pending = run.pending_items ?? [];
16930
+ const pending = run2.pending_items ?? [];
16776
16931
  if (pending.length > 0) {
16777
16932
  lines.push("");
16778
16933
  lines.push(`PENDING (${pending.length})`);
@@ -16780,9 +16935,9 @@ function formatRunDetail(run) {
16780
16935
  lines.push(` [${(p.priority ?? "").toUpperCase()}] ${p.description}`);
16781
16936
  }
16782
16937
  }
16783
- if (run.assessment?.narrative) {
16938
+ if (run2.assessment?.narrative) {
16784
16939
  lines.push("");
16785
- lines.push(run.assessment.narrative);
16940
+ lines.push(run2.assessment.narrative);
16786
16941
  }
16787
16942
  return lines;
16788
16943
  }
@@ -17154,7 +17309,7 @@ function registerStatusCommand(program2) {
17154
17309
  return;
17155
17310
  }
17156
17311
  if (mem?.configured === false) {
17157
- printInfo("Verity is not configured for this project. Run /verity-setup.");
17312
+ printInfo('Verity is not configured for this project. Run "verity init".');
17158
17313
  return;
17159
17314
  }
17160
17315
  printInfo("=== Verity Status ===");
@@ -17186,7 +17341,7 @@ function registerStatusCommand(program2) {
17186
17341
  if (hookStatus.stop) moments.push("stop");
17187
17342
  if (hookStatus.guardOn.includes("commit")) moments.push("pre-commit");
17188
17343
  if (hookStatus.guardOn.includes("push")) moments.push("pre-push/PR");
17189
- printInfo(`Moments: ${moments.length > 0 ? moments.join(", ") : "none (run /verity-setup)"}`);
17344
+ printInfo(`Moments: ${moments.length > 0 ? moments.join(", ") : 'none (run "verity init")'}`);
17190
17345
  if (!mem) return;
17191
17346
  if (mem.recent_runs) {
17192
17347
  const r = mem.recent_runs;
@@ -17272,12 +17427,12 @@ function registerStatusCommand(program2) {
17272
17427
  printInfo("");
17273
17428
  printInfo("--- Recent Runs ---");
17274
17429
  printInfo(`${"Run ID".padEnd(32)} ${"Decision".padEnd(10)}${"Q".padEnd(4)}${"S".padEnd(4)}${"Findings".padEnd(32)}Date`);
17275
- for (const run of runsResult.data.runs) {
17276
- const q = run.quality_score != null ? `${run.quality_score}` : "-";
17277
- const s = run.security_score != null ? `${run.security_score}` : "-";
17278
- const findings = formatFindingsSummary(run.findings_count);
17279
- const date = run.created_at.slice(0, 19).replace("T", " ");
17280
- printInfo(`${run.run_id.padEnd(32)} ${run.gate_decision.padEnd(10)}${q.padEnd(4)}${s.padEnd(4)}${findings.padEnd(32)}${date}`);
17430
+ for (const run2 of runsResult.data.runs) {
17431
+ const q = run2.quality_score != null ? `${run2.quality_score}` : "-";
17432
+ const s = run2.security_score != null ? `${run2.security_score}` : "-";
17433
+ const findings = formatFindingsSummary(run2.findings_count);
17434
+ const date = run2.created_at.slice(0, 19).replace("T", " ");
17435
+ printInfo(`${run2.run_id.padEnd(32)} ${run2.gate_decision.padEnd(10)}${q.padEnd(4)}${s.padEnd(4)}${findings.padEnd(32)}${date}`);
17281
17436
  }
17282
17437
  }
17283
17438
  }
@@ -17513,35 +17668,35 @@ function row(label2, value) {
17513
17668
  return ` \u25B8 ${label2.padEnd(10)} ${value}
17514
17669
  `;
17515
17670
  }
17516
- function formatRunEvidence(run, startedAt) {
17671
+ function formatRunEvidence(run2, startedAt) {
17517
17672
  const ms = Date.now() - startedAt;
17518
- const sent = run.codeDelta.files.filter((f) => f.role !== "context").map((f) => f.path);
17519
- const context = run.codeDelta.files.filter((f) => f.role === "context").map((f) => f.path);
17673
+ const sent = run2.codeDelta.files.filter((f) => f.role !== "context").map((f) => f.path);
17674
+ const context = run2.codeDelta.files.filter((f) => f.role === "context").map((f) => f.path);
17520
17675
  let out = ` \u2500\u2500 what verity saw \u2500\u2500
17521
17676
  `;
17522
- out += row("turn", `${run.turnId || "(unminted)"}${run.sessionId ? ` \xB7 session ${run.sessionId}` : ""}`);
17523
- out += row("reached", `${run.phaseReached || "(none)"}${run.skipReason ? ` \xB7 SKIPPED: ${run.skipReason}` : ""} \xB7 ${ms}ms`);
17524
- if (run.treeFrame) {
17525
- const f = run.treeFrame;
17677
+ out += row("turn", `${run2.turnId || "(unminted)"}${run2.sessionId ? ` \xB7 session ${run2.sessionId}` : ""}`);
17678
+ out += row("reached", `${run2.phaseReached || "(none)"}${run2.skipReason ? ` \xB7 SKIPPED: ${run2.skipReason}` : ""} \xB7 ${ms}ms`);
17679
+ if (run2.treeFrame) {
17680
+ const f = run2.treeFrame;
17526
17681
  out += row("tree", f.worktreeRoot ? `${f.worktreeRoot}${f.isLinkedWorktree ? " \xB7 linked worktree" : ""}${f.branch ? ` \xB7 branch ${f.branch}` : " \xB7 detached"}` : `(unresolved: ${f.refusal ?? "unknown"})`);
17527
17682
  }
17528
- out += row("changed", `${run.changedUniverse.length} from git \xB7 analyzable ${run.analyzable.length} \xB7 reviewable ${run.reviewable.length} \xB7 security ${run.securityFiles.length} \xB7 forReview ${run.allForReview.length}`);
17529
- const done = (phase) => run.phasesCompleted.includes(phase);
17683
+ out += row("changed", `${run2.changedUniverse.length} from git \xB7 analyzable ${run2.analyzable.length} \xB7 reviewable ${run2.reviewable.length} \xB7 security ${run2.securityFiles.length} \xB7 forReview ${run2.allForReview.length}`);
17684
+ const done = (phase) => run2.phasesCompleted.includes(phase);
17530
17685
  const ifDone = (phase, value) => done(phase) ? value : "?";
17531
- const md = run.modeDecision;
17686
+ const md = run2.modeDecision;
17532
17687
  if (md) {
17533
17688
  const how = md.forced ? "forced by --mode" : `predicted=${md.predicted ?? "none"} \u2192 ${md.resolved}`;
17534
17689
  out += row("mode", `${md.resolved} \xB7 ${how}` + (md.flip ? ` (flipped to plan: no delta at ${md.flip})` : "") + ` \xB7 authored=${md.authored ? "yes" : "no"} \xB7 investigated=${md.investigated ? "yes" : "no"}`);
17535
17690
  } else {
17536
- out += row("mode", `? (this run stopped in ${run.phaseReached || "no phase"}, before the mode was decided)`);
17691
+ out += row("mode", `? (this run stopped in ${run2.phaseReached || "no phase"}, before the mode was decided)`);
17537
17692
  }
17538
- out += row("signals", `baseline=${ifDone("bootstrap", run.baseline ? "yes" : "no")} \xB7 authored=${ifDone("intentInputs", run.turnAuthoredCode ? "yes" : "no")} \xB7 observable=${ifDone("intentInputs", run.authorshipIsObservable ? "yes" : "no")}` + (run.actionSummary?.transcript_windowed ? ` \xB7 window=${run.actionSummary.transcript_windowed}` : ""));
17693
+ out += row("signals", `baseline=${ifDone("bootstrap", run2.baseline ? "yes" : "no")} \xB7 authored=${ifDone("intentInputs", run2.turnAuthoredCode ? "yes" : "no")} \xB7 observable=${ifDone("intentInputs", run2.authorshipIsObservable ? "yes" : "no")}` + (run2.actionSummary?.transcript_windowed ? ` \xB7 window=${run2.actionSummary.transcript_windowed}` : ""));
17539
17694
  if (!done("intentInputs")) {
17540
- out += row("", `(\`?\` = the phase that determines it did not complete \u2014 this run stopped in ${run.phaseReached})`);
17695
+ out += row("", `(\`?\` = the phase that determines it did not complete \u2014 this run stopped in ${run2.phaseReached})`);
17541
17696
  }
17542
17697
  out += row("sent", `${sent.length} \xB7 ${list(sent)}`);
17543
17698
  if (context.length > 0) out += row("context", `${context.length} \xB7 ${list(context)}`);
17544
- const withheld = run.reviewCoverage.notReviewed;
17699
+ const withheld = run2.reviewCoverage.notReviewed;
17545
17700
  if (withheld.length > 0) {
17546
17701
  const byReason = /* @__PURE__ */ new Map();
17547
17702
  for (const w of withheld) {
@@ -17554,18 +17709,18 @@ function formatRunEvidence(run, startedAt) {
17554
17709
  first = false;
17555
17710
  }
17556
17711
  } else {
17557
- const sentSet = new Set(run.codeDelta.files.map((f) => f.path));
17558
- const notSent = run.changedUniverse.filter((p) => !sentSet.has(p));
17712
+ const sentSet = new Set(run2.codeDelta.files.map((f) => f.path));
17713
+ const notSent = run2.changedUniverse.filter((p) => !sentSet.has(p));
17559
17714
  if (notSent.length > 0) {
17560
17715
  out += row("not sent", `${list(notSent)}`);
17561
- out += row("", `(stage unknown \u2014 the coverage ledger is built in phase 13, and this run reached ${run.phaseReached || "no phase"})`);
17562
- } else if (run.changedUniverse.length > 0) {
17716
+ out += row("", `(stage unknown \u2014 the coverage ledger is built in phase 13, and this run reached ${run2.phaseReached || "no phase"})`);
17717
+ } else if (run2.changedUniverse.length > 0) {
17563
17718
  out += row("withheld", "(nothing \u2014 every changed file was reviewed)");
17564
17719
  }
17565
17720
  }
17566
- const cov = run.foldResult?.coverage;
17721
+ const cov = run2.foldResult?.coverage;
17567
17722
  if (cov) {
17568
- const delegated = run.foldResult.authored.filter((a) => a.owner === "subagent").length;
17723
+ const delegated = run2.foldResult.authored.filter((a) => a.owner === "subagent").length;
17569
17724
  if (cov.dispatched > 0 || cov.subagentFiles > 0 || cov.subagentSkipped > 0) {
17570
17725
  out += row("delegated", `${cov.dispatched} dispatched \xB7 ${cov.subagentFiles} agent log(s) read \xB7 ${delegated} path(s) attributed to subagents`);
17571
17726
  }
@@ -17579,43 +17734,43 @@ function formatRunEvidence(run, startedAt) {
17579
17734
  out += row("", `${cov.outsideRepo} authored path(s) refused as outside the repo`);
17580
17735
  }
17581
17736
  }
17582
- if (run.foldResult?.tools?.length) {
17583
- const shown = run.foldResult.tools.slice(0, 6).map((t) => {
17737
+ if (run2.foldResult?.tools?.length) {
17738
+ const shown = run2.foldResult.tools.slice(0, 6).map((t) => {
17584
17739
  const outcome = t.failed > 0 ? `${t.failed} failed` : t.last_status === 0 ? "ok" : "?";
17585
17740
  const where = t.targets.length > 0 ? ` \u2192 ${t.targets.slice(0, 2).join(", ")}` : "";
17586
17741
  return `${t.runs}\xD7 ${t.name} (${outcome})${where}`;
17587
17742
  });
17588
- const more = run.foldResult.tools.length > 6 ? ` \u2026 +${run.foldResult.tools.length - 6} more` : "";
17743
+ const more = run2.foldResult.tools.length > 6 ? ` \u2026 +${run2.foldResult.tools.length - 6} more` : "";
17589
17744
  out += row("tools", shown.join(" \xB7 ") + more);
17590
- if (run.foldResult.coverage.toolNamesDropped > 0) {
17591
- out += row("", `\u26A0 ${run.foldResult.coverage.toolNamesDropped} tool name(s) refused by the cap`);
17745
+ if (run2.foldResult.coverage.toolNamesDropped > 0) {
17746
+ out += row("", `\u26A0 ${run2.foldResult.coverage.toolNamesDropped} tool name(s) refused by the cap`);
17592
17747
  }
17593
17748
  }
17594
- if (run.foldResult?.tasks?.length) {
17595
- const t = run.foldResult.tasks;
17749
+ if (run2.foldResult?.tasks?.length) {
17750
+ const t = run2.foldResult.tasks;
17596
17751
  const done2 = t.filter((x) => x.status === "completed").length;
17597
17752
  out += row("tasks", `${t.length} \xB7 ${done2} completed \xB7 ` + list(t.slice(0, 4).map((x) => `#${x.id} ${x.name} [${x.status}]`), 4));
17598
17753
  }
17599
- if (run.specs?.length) {
17600
- const readThisSession = new Set(run.actionSummary?.files_read ?? []);
17601
- const labelled = run.specs.map(
17754
+ if (run2.specs?.length) {
17755
+ const readThisSession = new Set(run2.actionSummary?.files_read ?? []);
17756
+ const labelled = run2.specs.map(
17602
17757
  (s) => `${s.path}${readThisSession.has(s.path) ? " (read)" : " (positional)"}`
17603
17758
  );
17604
- out += row("specs", `${run.specs.length} \xB7 ${list(labelled, 5)}`);
17759
+ out += row("specs", `${run2.specs.length} \xB7 ${list(labelled, 5)}`);
17605
17760
  }
17606
- if (run.staticResults.findings.length > 0) {
17607
- out += row("static", `${run.staticResults.findings.length} finding(s) from ${run.staticResults.summary.tools_run.join(", ") || "no tools"}`);
17761
+ if (run2.staticResults.findings.length > 0) {
17762
+ out += row("static", `${run2.staticResults.findings.length} finding(s) from ${run2.staticResults.summary.tools_run.join(", ") || "no tools"}`);
17608
17763
  }
17609
- if (run.decision && run.decision !== "(unrecognised)") {
17610
- out += row("verdict", run.decision + (run.silenced ? ` \xB7 agent channel silenced (${run.silenced})` : ""));
17764
+ if (run2.decision && run2.decision !== "(unrecognised)") {
17765
+ out += row("verdict", run2.decision + (run2.silenced ? ` \xB7 agent channel silenced (${run2.silenced})` : ""));
17611
17766
  }
17612
17767
  return out;
17613
17768
  }
17614
- function installRunEvidence(run) {
17769
+ function installRunEvidence(run2) {
17615
17770
  const startedAt = Date.now();
17616
17771
  process.on("exit", () => {
17617
17772
  try {
17618
- logToFileOnly(formatRunEvidence(run, startedAt));
17773
+ logToFileOnly(formatRunEvidence(run2, startedAt));
17619
17774
  } catch {
17620
17775
  }
17621
17776
  });
@@ -18266,13 +18421,13 @@ async function readStopHookStdin() {
18266
18421
  return empty;
18267
18422
  }
18268
18423
  }
18269
- async function bootstrap(run) {
18270
- const { opts, globals } = run;
18424
+ async function bootstrap(run2) {
18425
+ const { opts, globals } = run2;
18271
18426
  try {
18272
18427
  process.chdir(repoRoot());
18273
18428
  } catch {
18274
18429
  }
18275
- run.treeFrame = resolveFrame({ command: "", on: [], hookCwd: null }).frame;
18430
+ run2.treeFrame = resolveFrame({ command: "", on: [], hookCwd: null }).frame;
18276
18431
  const turnId = `t-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
18277
18432
  let reachability = resolveReachability({
18278
18433
  autonomousFlag: process.env.VERITY_AUTONOMOUS === "1" || opts.mode === "autonomous",
@@ -18286,7 +18441,7 @@ async function bootstrap(run) {
18286
18441
  const rawSessionId = sessionId || process.env.CLAUDE_SESSION_ID || void 0;
18287
18442
  const baselineSessionId = sessionScopeKey(scopeToken, rawSessionId);
18288
18443
  if (tokenResult.ok) {
18289
- run.beacon = {
18444
+ run2.beacon = {
18290
18445
  resolveServiceUrl: async () => {
18291
18446
  const u = await resolveServiceUrl(globals.serviceUrl);
18292
18447
  return u.ok ? u.data : null;
@@ -18306,7 +18461,7 @@ async function bootstrap(run) {
18306
18461
  age_ms: Date.now() - baseline.captured_at
18307
18462
  });
18308
18463
  }
18309
- Object.assign(run, { actionSummary, assistantResponse, baseline, baselineSessionId, reachability, sessionId, stopReason, tokenResult, transcriptPath, turnId });
18464
+ Object.assign(run2, { actionSummary, assistantResponse, baseline, baselineSessionId, reachability, sessionId, stopReason, tokenResult, transcriptPath, turnId });
18310
18465
  }
18311
18466
 
18312
18467
  // src/lib/self-scope.ts
@@ -18459,7 +18614,7 @@ function channelSilence(input) {
18459
18614
  // src/lib/cli-version.ts
18460
18615
  function cliVersion() {
18461
18616
  try {
18462
- return true ? "0.31.1-experimental.80cf3ac" : "dev";
18617
+ return true ? "0.31.1-experimental.be74f71" : "dev";
18463
18618
  } catch {
18464
18619
  return "dev";
18465
18620
  }
@@ -18565,12 +18720,12 @@ function runCodacyAnalysis(files) {
18565
18720
  spawnError: proc.error?.message
18566
18721
  });
18567
18722
  }
18568
- function interpretAnalyzerRun(run) {
18569
- const output = run.stdout ?? "";
18723
+ function interpretAnalyzerRun(run2) {
18724
+ const output = run2.stdout ?? "";
18570
18725
  if (!output.trim()) {
18571
18726
  return withFailure(
18572
- run.spawnError ? "spawn_failed" : "no_output",
18573
- run.spawnError ?? run.stderr ?? `exit ${run.status}`
18727
+ run2.spawnError ? "spawn_failed" : "no_output",
18728
+ run2.spawnError ?? run2.stderr ?? `exit ${run2.status}`
18574
18729
  );
18575
18730
  }
18576
18731
  let parsed;
@@ -18737,9 +18892,9 @@ function localOnlyAndExit(staticResults) {
18737
18892
  });
18738
18893
  process.exit(0);
18739
18894
  }
18740
- async function passAndExit(run, reason, skip, kindOverride) {
18741
- run.skipReason = skip;
18742
- const sent = await sendSkipBeacon(run.beacon, skip);
18895
+ async function passAndExit(run2, reason, skip, kindOverride) {
18896
+ run2.skipReason = skip;
18897
+ const sent = await sendSkipBeacon(run2.beacon, skip);
18743
18898
  logEvent("skip", { reason: skip, beacon: sent });
18744
18899
  const POLICY_SKIPS = /* @__PURE__ */ new Set([
18745
18900
  "no-analyzable-files",
@@ -18754,7 +18909,7 @@ async function passAndExit(run, reason, skip, kindOverride) {
18754
18909
  "no-delta-since-last-review"
18755
18910
  ]);
18756
18911
  const skipKind = kindOverride ?? (POLICY_SKIPS.has(skip) ? "policy" : "capacity");
18757
- const changed = run.changedUniverse;
18912
+ const changed = run2.changedUniverse;
18758
18913
  const { coverage, unaccounted } = reconcileCoverage(changed, {
18759
18914
  reviewed: [],
18760
18915
  notReviewed: changed.map((path) => ({ path, reason: skip, stage: "pre-flight", kind: skipKind }))
@@ -18782,10 +18937,10 @@ async function passAndExit(run, reason, skip, kindOverride) {
18782
18937
  }
18783
18938
 
18784
18939
  // src/commands/analyze/phases/02-scope.ts
18785
- async function scope(run) {
18786
- const { assistantResponse } = run;
18940
+ async function scope(run2) {
18941
+ const { assistantResponse } = run2;
18787
18942
  const { files: allChanged, hasRecentCommitFiles } = getChangedFiles();
18788
- run.changedUniverse = allChanged;
18943
+ run2.changedUniverse = allChanged;
18789
18944
  const { kept: external } = partitionVerityOwned(allChanged);
18790
18945
  const verityIgnore = loadVerityIgnore();
18791
18946
  const ignored = partitionIgnored(external, verityIgnore);
@@ -18810,10 +18965,10 @@ async function scope(run) {
18810
18965
  const securityFiles = filterSecurity(inScope);
18811
18966
  const noFilesChanged = analyzable.length === 0 && reviewable.length === 0 && securityFiles.length === 0;
18812
18967
  if (noFilesChanged && !assistantResponse) {
18813
- await passAndExit(run, "No analyzable files changed", "no-analyzable-files");
18968
+ await passAndExit(run2, "No analyzable files changed", "no-analyzable-files");
18814
18969
  }
18815
18970
  const allForReview = Array.from(/* @__PURE__ */ new Set([...analyzable, ...reviewable]));
18816
- Object.assign(run, { allChanged, allForReview, analyzable, hasRecentCommitFiles, noFilesChanged, reviewable, securityFiles, verityIgnored: ignored });
18971
+ Object.assign(run2, { allChanged, allForReview, analyzable, hasRecentCommitFiles, noFilesChanged, reviewable, securityFiles, verityIgnored: ignored });
18817
18972
  }
18818
18973
 
18819
18974
  // src/lib/specs.ts
@@ -18959,8 +19114,8 @@ function discoverGuardDocs(rangeFiles2) {
18959
19114
  }
18960
19115
 
18961
19116
  // src/commands/analyze/phases/03-intent-inputs.ts
18962
- async function intentInputs(run) {
18963
- const { actionSummary, allForReview, assistantResponse, baseline, baselineSessionId } = run;
19117
+ async function intentInputs(run2) {
19118
+ const { actionSummary, allForReview, assistantResponse, baseline, baselineSessionId } = run2;
18964
19119
  if (isCommandOnlyTurn({
18965
19120
  userCommands: actionSummary?.user_commands,
18966
19121
  userCommandsTruncated: actionSummary?.user_commands_truncated,
@@ -18968,11 +19123,11 @@ async function intentInputs(run) {
18968
19123
  agentToolCalls: actionSummary?.total_tool_calls ?? 0,
18969
19124
  authorshipIsObservable: !!actionSummary && actionSummary.transcript_windowed !== "orphaned"
18970
19125
  })) {
18971
- await passAndExit(run, "User command only \u2014 skipping analysis", "command-only-turn");
19126
+ await passAndExit(run2, "User command only \u2014 skipping analysis", "command-only-turn");
18972
19127
  }
18973
19128
  {
18974
19129
  const ignoreKeys = ignoreStateKeys(
18975
- run.tokenResult.ok ? run.tokenResult.data.token : void 0,
19130
+ run2.tokenResult.ok ? run2.tokenResult.data.token : void 0,
18976
19131
  null
18977
19132
  );
18978
19133
  const found = resolveIgnoreState([baselineSessionId, ...ignoreKeys]);
@@ -18996,7 +19151,7 @@ async function intentInputs(run) {
18996
19151
  if (declaration.scope === "turn" && found) clearActiveDeclaration(found.key);
18997
19152
  logEvent("ignore_honoured", { scope: declaration.scope, origin: declaration.origin });
18998
19153
  await passAndExit(
18999
- run,
19154
+ run2,
19000
19155
  `skipping this turn \u2014 declared housekeeping ("${declaration.reason}")`,
19001
19156
  "declared-ignore"
19002
19157
  );
@@ -19010,7 +19165,7 @@ async function intentInputs(run) {
19010
19165
  const notice = `Verity: the ignore declared for this window ("${declaration.reason}") was voided \u2014 ${outcome.why}. Reviewing normally.`;
19011
19166
  process.stderr.write(`${notice}
19012
19167
  `);
19013
- run.voidedIgnoreNotice = notice;
19168
+ run2.voidedIgnoreNotice = notice;
19014
19169
  }
19015
19170
  }
19016
19171
  }
@@ -19032,32 +19187,32 @@ async function intentInputs(run) {
19032
19187
  const adopted = absorbIntoBaseline(setupAuthored, baselineSessionId);
19033
19188
  logEvent("baseline_absorbed", { skip: "verity-command", offered: setupAuthored.length, adopted });
19034
19189
  }
19035
- await passAndExit(run, "Verity command \u2014 skipping analysis", "verity-command");
19190
+ await passAndExit(run2, "Verity command \u2014 skipping analysis", "verity-command");
19036
19191
  }
19037
19192
  if (shouldSkipForBareAck({ prompt: latestPrompt, turnAuthoredCode, canSeeTurnAuthorship })) {
19038
- await passAndExit(run, "Bare acknowledgment \u2014 skipping analysis", "bare-acknowledgment");
19193
+ await passAndExit(run2, "Bare acknowledgment \u2014 skipping analysis", "bare-acknowledgment");
19039
19194
  }
19040
19195
  if (isReflectionQuestion(assistantResponse) && !turnAuthoredCode && canSeeTurnAuthorship) {
19041
- await passAndExit(run, "Reflection-prompt turn \u2014 skipping analysis", "reflection-prompt");
19196
+ await passAndExit(run2, "Reflection-prompt turn \u2014 skipping analysis", "reflection-prompt");
19042
19197
  }
19043
- Object.assign(run, { authorshipIsObservable, conversation, earlyFold, plans, specs, turnAuthoredCode });
19198
+ Object.assign(run2, { authorshipIsObservable, conversation, earlyFold, plans, specs, turnAuthoredCode });
19044
19199
  }
19045
19200
 
19046
19201
  // src/commands/analyze/phases/04-connect.ts
19047
- async function connect(run) {
19048
- const { opts, globals } = run;
19049
- const { analyzable, baseline, securityFiles, tokenResult } = run;
19202
+ async function connect(run2) {
19203
+ const { opts, globals } = run2;
19204
+ const { analyzable, baseline, securityFiles, tokenResult } = run2;
19050
19205
  const urlResult = await resolveServiceUrl(globals.serviceUrl);
19051
19206
  if (!tokenResult.ok || !urlResult.ok) {
19052
19207
  localOnlyAndExit(runLocalStatic(analyzable, securityFiles, baseline, !!opts.skipStatic));
19053
19208
  }
19054
- Object.assign(run, { urlResult, serviceUrl: urlResult.data, token: tokenResult.data.token });
19209
+ Object.assign(run2, { urlResult, serviceUrl: urlResult.data, token: tokenResult.data.token });
19055
19210
  }
19056
19211
 
19057
19212
  // src/commands/analyze/phases/05-mode.ts
19058
- async function mode(run) {
19059
- const { opts, globals } = run;
19060
- const { actionSummary, allForReview, assistantResponse, baseline, conversation, memory, noFilesChanged, serviceUrl, sessionId, token, turnAuthoredCode } = run;
19213
+ async function mode(run2) {
19214
+ const { opts, globals } = run2;
19215
+ const { actionSummary, allForReview, assistantResponse, baseline, conversation, memory, noFilesChanged, serviceUrl, sessionId, token, turnAuthoredCode } = run2;
19061
19216
  const sessionIdForMemory = sessionId || process.env.CLAUDE_SESSION_ID || "";
19062
19217
  let contextFilePaths = [];
19063
19218
  let predictedMode;
@@ -19098,7 +19253,7 @@ async function mode(run) {
19098
19253
  );
19099
19254
  }
19100
19255
  const investigated = didAgentInvestigate(actionSummary);
19101
- run.modeDecision = {
19256
+ run2.modeDecision = {
19102
19257
  predicted: predictedMode ?? null,
19103
19258
  resolved: analysisMode,
19104
19259
  authored: turnAuthoredCode,
@@ -19118,13 +19273,13 @@ async function mode(run) {
19118
19273
  });
19119
19274
  if (analysisMode === "skip") {
19120
19275
  await passAndExit(
19121
- run,
19276
+ run2,
19122
19277
  "Skip mode \u2014 no code work to analyze",
19123
19278
  "skip-mode",
19124
19279
  turnAuthoredCode ? "capacity" : void 0
19125
19280
  );
19126
19281
  }
19127
- Object.assign(run, { analysisMode, contextFilePaths, sessionAuthoredCode, sessionIdForMemory });
19282
+ Object.assign(run2, { analysisMode, contextFilePaths, sessionAuthoredCode, sessionIdForMemory });
19128
19283
  }
19129
19284
 
19130
19285
  // src/lib/fold.ts
@@ -19584,12 +19739,12 @@ function checkConservation(changedFiles, result, repoRoot2) {
19584
19739
  }
19585
19740
 
19586
19741
  // src/commands/analyze/phases/06-evidence.ts
19587
- async function evidence(run) {
19588
- const { opts } = run;
19589
- const { actionSummary, allForReview, analyzable, assistantResponse, authorshipIsObservable, baseline, baselineSessionId, hasRecentCommitFiles, reviewable, securityFiles, sessionAuthoredCode, transcriptPath, turnAuthoredCode } = run;
19590
- let { analysisMode, earlyFold } = run;
19742
+ async function evidence(run2) {
19743
+ const { opts } = run2;
19744
+ const { actionSummary, allForReview, analyzable, assistantResponse, authorshipIsObservable, baseline, baselineSessionId, hasRecentCommitFiles, reviewable, securityFiles, sessionAuthoredCode, transcriptPath, turnAuthoredCode } = run2;
19745
+ let { analysisMode, earlyFold } = run2;
19591
19746
  const recordFlip = (stage) => {
19592
- if (run.modeDecision) run.modeDecision = { ...run.modeDecision, resolved: "plan", flip: stage };
19747
+ if (run2.modeDecision) run2.modeDecision = { ...run2.modeDecision, resolved: "plan", flip: stage };
19593
19748
  logEvent("mode_flipped", { stage, to: "plan" });
19594
19749
  };
19595
19750
  const planWorthy = !!assistantResponse && !turnAuthoredCode;
@@ -19616,7 +19771,7 @@ async function evidence(run) {
19616
19771
  analysisMode = "plan";
19617
19772
  recordFlip("debounce");
19618
19773
  } else {
19619
- await passAndExit(run, debounceSkip, "debounce");
19774
+ await passAndExit(run2, debounceSkip, "debounce");
19620
19775
  }
19621
19776
  }
19622
19777
  if (analysisMode !== "plan") {
@@ -19627,7 +19782,7 @@ async function evidence(run) {
19627
19782
  analysisMode = "plan";
19628
19783
  recordFlip("mtime");
19629
19784
  } else {
19630
- await passAndExit(run, mtimeSkip, "no-delta-since-last-review");
19785
+ await passAndExit(run2, mtimeSkip, "no-delta-since-last-review");
19631
19786
  }
19632
19787
  }
19633
19788
  }
@@ -19640,7 +19795,7 @@ async function evidence(run) {
19640
19795
  analysisMode = "plan";
19641
19796
  recordFlip("content-hash");
19642
19797
  } else {
19643
- await passAndExit(run, hashResult.skip, "no-delta-since-last-review");
19798
+ await passAndExit(run2, hashResult.skip, "no-delta-since-last-review");
19644
19799
  }
19645
19800
  }
19646
19801
  contentHash = hashResult.hash;
@@ -19648,7 +19803,7 @@ async function evidence(run) {
19648
19803
  const scoped = scopeToAuthored(allForReview, actionSummary);
19649
19804
  const canTrustNoneAuthored = scoped.signal === "none-authored" && authorshipIsObservable;
19650
19805
  if (canTrustNoneAuthored && !hasNonEditAuthorship(actionSummary, sessionAuthoredCode)) {
19651
- await passAndExit(run, "No agent-authored code this turn \u2014 working-tree changes were not authored by this session", "zero-increment");
19806
+ await passAndExit(run2, "No agent-authored code this turn \u2014 working-tree changes were not authored by this session", "zero-increment");
19652
19807
  }
19653
19808
  if (scoped.signal === "none-authored" && !authorshipIsObservable) {
19654
19809
  logEvent("none_authored_unverifiable", {
@@ -19705,7 +19860,7 @@ async function evidence(run) {
19705
19860
  recordFlip("empty-after-scoping");
19706
19861
  } else {
19707
19862
  await passAndExit(
19708
- run,
19863
+ run2,
19709
19864
  "No files within size limits to analyze",
19710
19865
  "size-limit",
19711
19866
  codeDelta.excluded.length > 0 ? "capacity" : "policy"
@@ -19730,7 +19885,7 @@ async function evidence(run) {
19730
19885
  currentCommit = getCurrentCommit();
19731
19886
  iteration = readIteration(currentCommit);
19732
19887
  }
19733
- Object.assign(run, { analysisMode, codeDelta, contentHash, currentCommit, earlyFold, iteration, snapshotResult, staticResults });
19888
+ Object.assign(run2, { analysisMode, codeDelta, contentHash, currentCommit, earlyFold, iteration, snapshotResult, staticResults });
19734
19889
  }
19735
19890
 
19736
19891
  // src/lib/cache-cleanup.ts
@@ -19827,8 +19982,8 @@ function gatherContextFiles(contextPaths, deltaFiles) {
19827
19982
  }
19828
19983
 
19829
19984
  // src/commands/analyze/phases/07-context-files.ts
19830
- async function contextFiles(run) {
19831
- const { codeDelta, contextFilePaths } = run;
19985
+ async function contextFiles(run2) {
19986
+ const { codeDelta, contextFilePaths } = run2;
19832
19987
  const { kept: externalContext } = partitionVerityOwned(contextFilePaths ?? []);
19833
19988
  const contextFiles2 = gatherContextFiles(externalContext, codeDelta.files);
19834
19989
  for (const f of codeDelta.files) {
@@ -20185,9 +20340,9 @@ async function runSeed(opts) {
20185
20340
  // src/commands/analyze/phases/08-memory-manifest.ts
20186
20341
  var import_node_fs32 = require("node:fs");
20187
20342
  var import_node_path24 = require("node:path");
20188
- async function memoryManifest(run) {
20189
- const { globals } = run;
20190
- const { serviceUrl, token } = run;
20343
+ async function memoryManifest(run2) {
20344
+ const { globals } = run2;
20345
+ const { serviceUrl, token } = run2;
20191
20346
  let memoryManifest2;
20192
20347
  let deletedNodePaths = [];
20193
20348
  let editedUploads = [];
@@ -20239,12 +20394,12 @@ async function memoryManifest(run) {
20239
20394
  editedUploads = await computeEditedNodeUploads();
20240
20395
  } catch {
20241
20396
  }
20242
- Object.assign(run, { autoSeedNotice, deletedNodePaths, editedUploads, memoryManifest: memoryManifest2 });
20397
+ Object.assign(run2, { autoSeedNotice, deletedNodePaths, editedUploads, memoryManifest: memoryManifest2 });
20243
20398
  }
20244
20399
 
20245
20400
  // src/commands/analyze/phases/09-fold-transcript.ts
20246
- async function foldTranscript(run) {
20247
- const { allForReview, earlyFold, transcriptPath } = run;
20401
+ async function foldTranscript(run2) {
20402
+ const { allForReview, earlyFold, transcriptPath } = run2;
20248
20403
  let foldResult = null;
20249
20404
  let foldConservation = null;
20250
20405
  if (transcriptPath) {
@@ -20261,7 +20416,7 @@ async function foldTranscript(run) {
20261
20416
  foldResult = null;
20262
20417
  }
20263
20418
  }
20264
- Object.assign(run, { foldConservation, foldResult });
20419
+ Object.assign(run2, { foldConservation, foldResult });
20265
20420
  }
20266
20421
 
20267
20422
  // src/lib/increment.ts
@@ -20313,10 +20468,10 @@ function computeIncrement(reviewedPaths, hashOf, priorAuthored) {
20313
20468
 
20314
20469
  // src/commands/analyze/phases/10-working-memory.ts
20315
20470
  var import_node_path25 = require("node:path");
20316
- async function workingMemory(run) {
20317
- const { opts } = run;
20318
- const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run;
20319
- let { reachability } = run;
20471
+ async function workingMemory(run2) {
20472
+ const { opts } = run2;
20473
+ const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run2;
20474
+ let { reachability } = run2;
20320
20475
  const memorySession = sessionDossier(token, sessionId ?? process.env.CLAUDE_SESSION_ID ?? null);
20321
20476
  let memory = null;
20322
20477
  let incrementReport = null;
@@ -20402,7 +20557,7 @@ async function workingMemory(run) {
20402
20557
  hasUserPrompt: (conversation?.prompts?.length ?? 0) > 0,
20403
20558
  isTTY: process.stdout.isTTY === true
20404
20559
  });
20405
- Object.assign(run, { incrementReport, memory, memorySession, reachability });
20560
+ Object.assign(run2, { incrementReport, memory, memorySession, reachability });
20406
20561
  }
20407
20562
 
20408
20563
  // src/lib/note-budget.ts
@@ -20521,8 +20676,8 @@ function resolveTaskContext(opts) {
20521
20676
  // src/commands/analyze/phases/11-build-request.ts
20522
20677
  var MAX_ASSISTANT_RESPONSE_CHARS_PLAN = 32768;
20523
20678
  var MAX_ASSISTANT_RESPONSE_CHARS_DEFAULT = 8e3;
20524
- async function buildRequest(run) {
20525
- const { actionSummary, allChanged, allForReview, analysisMode, analyzable, assistantResponse, codeDelta, conversation, deletedNodePaths, editedUploads, foldConservation, foldResult, incrementReport, iteration, memory, memoryManifest: memoryManifest2, memorySession, plans, reachability, reviewable, securityFiles, sessionId, snapshotResult, specs, staticResults, stopReason, turnId } = run;
20679
+ async function buildRequest(run2) {
20680
+ const { actionSummary, allChanged, allForReview, analysisMode, analyzable, assistantResponse, codeDelta, conversation, deletedNodePaths, editedUploads, foldConservation, foldResult, incrementReport, iteration, memory, memoryManifest: memoryManifest2, memorySession, plans, reachability, reviewable, securityFiles, sessionId, snapshotResult, specs, staticResults, stopReason, turnId } = run2;
20526
20681
  const excludedByReason = {};
20527
20682
  for (const e of codeDelta.excluded ?? []) {
20528
20683
  excludedByReason[e.reason] = (excludedByReason[e.reason] ?? 0) + 1;
@@ -20552,15 +20707,15 @@ async function buildRequest(run) {
20552
20707
  // the state, so the number is one turn lagged by construction. The
20553
20708
  // degenerate win for the budget is a dead channel that looks like clean
20554
20709
  // code; this is what makes "did delivery rate collapse" a query.
20555
- advisory_delivered_prior: readAdvisoryEpisode(run.baselineSessionId)?.delivered ?? 0,
20710
+ advisory_delivered_prior: readAdvisoryEpisode(run2.baselineSessionId)?.delivered ?? 0,
20556
20711
  // `.verityignore` — see CoverageTelemetry.verityignore for why the SHARE is
20557
20712
  // the number that matters and why no paths travel with it.
20558
20713
  verityignore: {
20559
- rules: run.verityIgnored.rules,
20560
- excluded: run.verityIgnored.ignored.length,
20561
- share: ignoreShare(run.verityIgnored.kept.length, run.verityIgnored.ignored.length),
20562
- security_excluded: run.verityIgnored.securityExcluded.length,
20563
- suspended: run.verityIgnored.suspended
20714
+ rules: run2.verityIgnored.rules,
20715
+ excluded: run2.verityIgnored.ignored.length,
20716
+ share: ignoreShare(run2.verityIgnored.kept.length, run2.verityIgnored.ignored.length),
20717
+ security_excluded: run2.verityIgnored.securityExcluded.length,
20718
+ suspended: run2.verityIgnored.suspended
20564
20719
  }
20565
20720
  };
20566
20721
  const requestBody = {
@@ -20755,7 +20910,7 @@ async function buildRequest(run) {
20755
20910
  }
20756
20911
  requestBody.intent_context = intentContext;
20757
20912
  }
20758
- Object.assign(run, { requestBody });
20913
+ Object.assign(run2, { requestBody });
20759
20914
  }
20760
20915
 
20761
20916
  // src/lib/offline.ts
@@ -20816,9 +20971,9 @@ function shouldWarmRetryAnalyze(result) {
20816
20971
  }
20817
20972
 
20818
20973
  // src/commands/analyze/phases/12-transmit.ts
20819
- async function transmit(run) {
20820
- const { globals } = run;
20821
- const { codeDelta, requestBody, serviceUrl, staticResults, token } = run;
20974
+ async function transmit(run2) {
20975
+ const { globals } = run2;
20976
+ const { codeDelta, requestBody, serviceUrl, staticResults, token } = run2;
20822
20977
  const ANALYZE_TIMEOUT_MS = 1e5;
20823
20978
  let result = await analyzeRequest({
20824
20979
  serviceUrl,
@@ -20881,14 +21036,14 @@ async function transmit(run) {
20881
21036
  }
20882
21037
  const response = result.data;
20883
21038
  const decision = response.gate_decision ?? "(unrecognised)";
20884
- Object.assign(run, { decision, response });
21039
+ Object.assign(run2, { decision, response });
20885
21040
  }
20886
21041
 
20887
21042
  // src/commands/analyze/phases/13-reconcile.ts
20888
21043
  var import_node_fs35 = require("node:fs");
20889
21044
  var import_node_path26 = require("node:path");
20890
- async function reconcile(run) {
20891
- const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run;
21045
+ async function reconcile(run2) {
21046
+ const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run2;
20892
21047
  const sentPaths = codeDelta.files.map((f) => f.path);
20893
21048
  if (memorySession) {
20894
21049
  try {
@@ -20989,7 +21144,7 @@ async function reconcile(run) {
20989
21144
  // below is the signal that replaces the noise.
20990
21145
  //
20991
21146
  // Taken from the run, not recomputed — see context.ts `verityIgnored`.
20992
- ...run.verityIgnored.ignored.map((path) => ({
21147
+ ...run2.verityIgnored.ignored.map((path) => ({
20993
21148
  path,
20994
21149
  reason: "verityignore",
20995
21150
  stage: "verityignore",
@@ -21109,11 +21264,11 @@ async function reconcile(run) {
21109
21264
  `
21110
21265
  );
21111
21266
  }
21112
- Object.assign(run, { intentRepeatCount, openElsewhere, priorPendingFingerprints, reviewCoverage, sentPaths, silenced, watermarkHash, watermarkIsPartial });
21267
+ Object.assign(run2, { intentRepeatCount, openElsewhere, priorPendingFingerprints, reviewCoverage, sentPaths, silenced, watermarkHash, watermarkIsPartial });
21113
21268
  }
21114
21269
 
21115
21270
  // src/lib/emit.ts
21116
- var YELLOW2 = "\x1B[33m";
21271
+ var YELLOW3 = "\x1B[33m";
21117
21272
  var NC2 = "\x1B[0m";
21118
21273
  function emitVerdict(input) {
21119
21274
  const exit = input.exit ?? ((code) => process.exit(code));
@@ -21124,7 +21279,7 @@ function emitVerdict(input) {
21124
21279
  const note = [describeCoverage(coverage), describeOpenElsewhere(openElsewhere)].filter(Boolean).join("\n\n") || null;
21125
21280
  if (unaccounted.length > 0) {
21126
21281
  process.stderr.write(
21127
- `${YELLOW2}Verity: ${unaccounted.length} changed file(s) could not be attributed to any review stage \u2014 counted as unreviewed.${NC2}
21282
+ `${YELLOW3}Verity: ${unaccounted.length} changed file(s) could not be attributed to any review stage \u2014 counted as unreviewed.${NC2}
21128
21283
  `
21129
21284
  );
21130
21285
  }
@@ -21136,7 +21291,7 @@ ${input.agentContext}
21136
21291
  `);
21137
21292
  }
21138
21293
  if (note && !input.silenced) process.stderr.write(`
21139
- ${YELLOW2}${note}${NC2}
21294
+ ${YELLOW3}${note}${NC2}
21140
21295
  `);
21141
21296
  return exit(2);
21142
21297
  }
@@ -21222,10 +21377,10 @@ function screenRemediation(fix, findingFile) {
21222
21377
  function agentContextFor(response, intentRepeat = 0, priorPendingFingerprints = []) {
21223
21378
  return buildAgentContext(channelInputFrom(response, intentRepeat, priorPendingFingerprints));
21224
21379
  }
21225
- async function render(run) {
21226
- const { opts, globals } = run;
21227
- const { actionSummary, assistantResponse, autoSeedNotice, voidedIgnoreNotice, baselineSessionId, codeDelta, contentHash, conversation, currentCommit, decision, intentRepeatCount, memory, openElsewhere, priorPendingFingerprints, response, reviewCoverage, serviceUrl, sessionIdForMemory, silenced, token, watermarkHash, watermarkIsPartial } = run;
21228
- let { iteration } = run;
21380
+ async function render(run2) {
21381
+ const { opts, globals } = run2;
21382
+ const { actionSummary, assistantResponse, autoSeedNotice, voidedIgnoreNotice, baselineSessionId, codeDelta, contentHash, conversation, currentCommit, decision, intentRepeatCount, memory, openElsewhere, priorPendingFingerprints, response, reviewCoverage, serviceUrl, sessionIdForMemory, silenced, token, watermarkHash, watermarkIsPartial } = run2;
21383
+ let { iteration } = run2;
21229
21384
  const metadata = response.metadata ?? {};
21230
21385
  const intentAmbiguity = metadata.intent_ambiguity;
21231
21386
  if (intentAmbiguity != null && intentAmbiguity > 5) {
@@ -21332,7 +21487,7 @@ async function render(run) {
21332
21487
  const blocks = prior.blocks + 1;
21333
21488
  const decisionNow = mayBlock({
21334
21489
  reviewedFileCount: codeDelta.files.length,
21335
- staticFindingCount: run.staticResults?.findings?.length ?? 0,
21490
+ staticFindingCount: run2.staticResults?.findings?.length ?? 0,
21336
21491
  cycleCutFired: silenced !== null,
21337
21492
  attempts,
21338
21493
  blocks,
@@ -21363,7 +21518,7 @@ async function render(run) {
21363
21518
  });
21364
21519
  emitVerdict({
21365
21520
  proposed: "WARN",
21366
- changed: run.changedUniverse,
21521
+ changed: run2.changedUniverse,
21367
21522
  coverage: reviewCoverage,
21368
21523
  userSummary: lines.length > 0 ? `${summary}
21369
21524
  ${lines.join("\n")}` : summary,
@@ -21455,7 +21610,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
21455
21610
  `);
21456
21611
  emitVerdict({
21457
21612
  proposed: "FAIL",
21458
- changed: run.changedUniverse,
21613
+ changed: run2.changedUniverse,
21459
21614
  coverage: reviewCoverage,
21460
21615
  userSummary: "",
21461
21616
  // Subject to the SAME cycle cut as PASS/WARN. Suppressing here is safe:
@@ -21480,7 +21635,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
21480
21635
  userSummary += loginNudge + grantNudge;
21481
21636
  emitVerdict({
21482
21637
  proposed: "PASS",
21483
- changed: run.changedUniverse,
21638
+ changed: run2.changedUniverse,
21484
21639
  coverage: reviewCoverage,
21485
21640
  userSummary,
21486
21641
  agentContext: silenced ? null : agentContextFor(response, intentRepeatCount, priorPendingFingerprints),
@@ -21502,7 +21657,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
21502
21657
  userSummary += loginNudge + grantNudge;
21503
21658
  emitVerdict({
21504
21659
  proposed: "WARN",
21505
- changed: run.changedUniverse,
21660
+ changed: run2.changedUniverse,
21506
21661
  coverage: reviewCoverage,
21507
21662
  userSummary,
21508
21663
  agentContext: silenced ? null : agentContextFor(response, intentRepeatCount, priorPendingFingerprints),
@@ -21527,7 +21682,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
21527
21682
  process.exit(0);
21528
21683
  }
21529
21684
  }
21530
- Object.assign(run, { iteration });
21685
+ Object.assign(run2, { iteration });
21531
21686
  }
21532
21687
 
21533
21688
  // src/commands/analyze/index.ts
@@ -21577,18 +21732,18 @@ function registerAnalyzeCommand(program2) {
21577
21732
  }
21578
21733
  var tracing = () => process.env.VERITY_TRACE_PHASES === "1";
21579
21734
  async function runAnalyze(opts, globals) {
21580
- const run = createRun(opts, globals);
21581
- installRunEvidence(run);
21735
+ const run2 = createRun(opts, globals);
21736
+ installRunEvidence(run2);
21582
21737
  for (const [name, phase] of PIPELINE) {
21583
- run.phaseReached = name;
21738
+ run2.phaseReached = name;
21584
21739
  if (!tracing()) {
21585
- await phase(run);
21586
- run.phasesCompleted.push(name);
21740
+ await phase(run2);
21741
+ run2.phasesCompleted.push(name);
21587
21742
  continue;
21588
21743
  }
21589
21744
  const started = Date.now();
21590
- await phase(run);
21591
- run.phasesCompleted.push(name);
21745
+ await phase(run2);
21746
+ run2.phasesCompleted.push(name);
21592
21747
  process.stderr.write(`verity\xB7phase ${name} ${Date.now() - started}ms
21593
21748
  `);
21594
21749
  }
@@ -21691,8 +21846,8 @@ async function runReview(opts, globals) {
21691
21846
  for (const p of specPaths) {
21692
21847
  if (!(0, import_node_fs37.existsSync)(p)) continue;
21693
21848
  try {
21694
- const { readFileSync: readFileSync24 } = await import("node:fs");
21695
- const content = readFileSync24(p, "utf-8");
21849
+ const { readFileSync: readFileSync25 } = await import("node:fs");
21850
+ const content = readFileSync25(p, "utf-8");
21696
21851
  specs.push({ path: p, content: content.slice(0, 10240) });
21697
21852
  } catch {
21698
21853
  }
@@ -22281,22 +22436,297 @@ function registerWaiveCommand(program2) {
22281
22436
  }
22282
22437
 
22283
22438
  // src/commands/init.ts
22284
- var import_node_fs41 = require("node:fs");
22285
- var import_promises13 = require("node:fs/promises");
22439
+ var import_node_fs44 = require("node:fs");
22440
+ var import_promises14 = require("node:fs/promises");
22286
22441
  var import_node_path29 = require("node:path");
22287
- var import_node_child_process11 = require("node:child_process");
22288
- var readline2 = __toESM(require("node:readline/promises"));
22442
+ var import_node_child_process13 = require("node:child_process");
22289
22443
 
22290
- // src/commands/migrate.ts
22291
- var import_node_fs40 = require("node:fs");
22292
- var import_node_path28 = require("node:path");
22444
+ // src/lib/banner.ts
22445
+ var WORDMARK = [
22446
+ "\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557",
22447
+ "\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D",
22448
+ "\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2554\u255D ",
22449
+ "\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2554\u255D ",
22450
+ " \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 ",
22451
+ " \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D "
22452
+ ];
22453
+ var WORDMARK_NARROW = [
22454
+ "\u2588 \u2588 \u2588\u2580\u2580\u2580\u2580 \u2588\u2580\u2580\u2580\u2584 \u2580\u2580\u2588\u2580\u2580 \u2580\u2580\u2588\u2580\u2580 \u2588 \u2588",
22455
+ "\u2588 \u2588 \u2588\u2580\u2580\u2580 \u2588\u2584\u2584\u2584\u2580 \u2588 \u2588 \u2580\u2584\u2580 ",
22456
+ " \u2580\u2584\u2580 \u2588\u2584\u2584\u2584\u2584 \u2588 \u2580\u2584 \u2584\u2584\u2588\u2584\u2584 \u2588 \u2588 "
22457
+ ];
22458
+ var TAGLINE = "reviews every turn, remembers every lesson";
22459
+ var WORDMARK_COLOR = ["\x1B[0;32m"];
22460
+ var DIM3 = "\x1B[2m";
22461
+ var RESET2 = "\x1B[0m";
22462
+ var INDENT = " ";
22463
+ function artWidth(art) {
22464
+ return Math.max(...art.map((r) => r.length)) + INDENT.length;
22465
+ }
22466
+ function canRenderArt() {
22467
+ return !!process.stderr.isTTY;
22468
+ }
22469
+ function printBanner(opts) {
22470
+ if (!opts.interactive) return;
22471
+ const columns = opts.columns ?? process.stderr.columns ?? 80;
22472
+ const color = colorEnabled();
22473
+ const version = `v${cliVersion()}`;
22474
+ const art = [WORDMARK, WORDMARK_NARROW].find((a) => artWidth(a) <= columns) ?? null;
22475
+ const dim = (text) => color ? `${DIM3}${text}${RESET2}` : text;
22476
+ process.stderr.write("\n");
22477
+ if (!art) {
22478
+ const candidates = [`Verity ${version}`, "Verity"];
22479
+ const text = candidates.find((c) => c.length + INDENT.length <= columns);
22480
+ if (text) process.stderr.write(`${INDENT}${dim(text)}
22481
+ `);
22482
+ process.stderr.write("\n");
22483
+ return;
22484
+ }
22485
+ art.forEach((row2, i) => {
22486
+ const tint = color && WORDMARK_COLOR.length > 0 ? WORDMARK_COLOR[Math.min(i, WORDMARK_COLOR.length - 1)] : "";
22487
+ const reset = color && tint ? RESET2 : "";
22488
+ process.stderr.write(`${INDENT}${tint}${row2}${reset}
22489
+ `);
22490
+ });
22491
+ if (TAGLINE.length + INDENT.length <= columns) {
22492
+ process.stderr.write(`${INDENT}${dim(TAGLINE)}
22493
+ `);
22494
+ }
22495
+ if (version.length + INDENT.length <= columns) {
22496
+ process.stderr.write(`${INDENT}${dim(version)}
22497
+ `);
22498
+ }
22499
+ process.stderr.write("\n");
22500
+ }
22501
+ function printPhase(n, of, title, subtitle) {
22502
+ const color = colorEnabled();
22503
+ const columns = process.stderr.columns ?? 72;
22504
+ const width = Math.min(columns, 72);
22505
+ const label2 = `\u2500\u2500 Phase ${n} of ${of} \xB7 ${title} `;
22506
+ const rule = label2 + "\u2500".repeat(Math.max(0, width - label2.length - 2));
22507
+ process.stderr.write("\n");
22508
+ process.stderr.write(color ? ` ${DIM3}${rule}${RESET2}
22509
+ ` : ` ${rule}
22510
+ `);
22511
+ if (subtitle && subtitle.length + INDENT.length <= columns) {
22512
+ process.stderr.write(color ? ` ${DIM3}${subtitle}${RESET2}
22513
+ ` : ` ${subtitle}
22514
+ `);
22515
+ }
22516
+ process.stderr.write("\n");
22517
+ }
22518
+
22519
+ // src/commands/doctor.ts
22520
+ var import_node_fs42 = require("node:fs");
22521
+
22522
+ // src/lib/prereqs.ts
22293
22523
  var import_node_child_process10 = require("node:child_process");
22524
+ var MIN_NODE_MAJOR = 20;
22525
+ function which(bin) {
22526
+ try {
22527
+ const out = (0, import_node_child_process10.execSync)(`command -v ${bin}`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
22528
+ return out || null;
22529
+ } catch {
22530
+ return null;
22531
+ }
22532
+ }
22533
+ function checkNode() {
22534
+ const version = process.version;
22535
+ const major = Number.parseInt(version.slice(1), 10);
22536
+ const ok = Number.isFinite(major) && major >= MIN_NODE_MAJOR;
22537
+ return {
22538
+ id: "node",
22539
+ label: "Node.js",
22540
+ status: ok ? "ok" : "missing",
22541
+ detail: version,
22542
+ remedy: ok ? void 0 : `Node.js ${MIN_NODE_MAJOR}+ required \u2014 update from https://nodejs.org`,
22543
+ required: true
22544
+ };
22545
+ }
22546
+ function checkGit() {
22547
+ let detail = "";
22548
+ try {
22549
+ detail = (0, import_node_child_process10.execSync)("git --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
22550
+ } catch {
22551
+ return {
22552
+ id: "git",
22553
+ label: "git",
22554
+ status: "missing",
22555
+ detail: "not found",
22556
+ remedy: "Install git from https://git-scm.com",
22557
+ required: true
22558
+ };
22559
+ }
22560
+ return { id: "git", label: "git", status: "ok", detail, required: true };
22561
+ }
22562
+ function checkClaude() {
22563
+ const path = which("claude");
22564
+ return {
22565
+ id: "claude",
22566
+ label: "Claude Code",
22567
+ status: path ? "ok" : "warn",
22568
+ detail: path ?? "not found",
22569
+ remedy: path ? void 0 : "Hooks are wired but need Claude Code to fire \u2014 https://claude.com/claude-code",
22570
+ required: false
22571
+ };
22572
+ }
22573
+ function checkAnalysisCli() {
22574
+ const path = which("codacy-analysis");
22575
+ return {
22576
+ id: "analysis-cli",
22577
+ label: "@codacy/analysis-cli",
22578
+ status: path ? "ok" : "warn",
22579
+ detail: path ?? "not found",
22580
+ remedy: path ? void 0 : "npm install -g @codacy/analysis-cli (static findings are unavailable until then)",
22581
+ required: false
22582
+ };
22583
+ }
22584
+ var INSTALL_TIMEOUT_MS = 12e4;
22585
+ function run(command, args, opts = {}) {
22586
+ return new Promise((resolve4) => {
22587
+ const child = (0, import_node_child_process10.spawn)(command, args, {
22588
+ stdio: opts.inherit ? "inherit" : "pipe",
22589
+ timeout: INSTALL_TIMEOUT_MS
22590
+ });
22591
+ child.on("error", () => resolve4(false));
22592
+ child.on("close", (code) => resolve4(code === 0));
22593
+ });
22594
+ }
22595
+ async function installAnalysisCli() {
22596
+ const spinner = startSpinner("Installing @codacy/analysis-cli");
22597
+ const ok = await run("npm", ["install", "-g", "@codacy/analysis-cli"]);
22598
+ if (ok) {
22599
+ const check = checkAnalysisCli();
22600
+ if (check.status === "ok") {
22601
+ spinner.succeed("@codacy/analysis-cli installed");
22602
+ return { ...check, justInstalled: true };
22603
+ }
22604
+ spinner.warn("npm reported success but codacy-analysis is not on PATH");
22605
+ return check;
22606
+ }
22607
+ spinner.stop();
22608
+ {
22609
+ const failed = {
22610
+ id: "analysis-cli",
22611
+ label: "@codacy/analysis-cli",
22612
+ status: "warn",
22613
+ detail: "install failed",
22614
+ remedy: "Install manually: npm install -g @codacy/analysis-cli",
22615
+ required: false
22616
+ };
22617
+ if (!process.stdin.isTTY || !process.stdout.isTTY) return failed;
22618
+ process.stderr.write(" Retrying with sudo (you may be asked for your password)\u2026\n");
22619
+ const sudoOk = await run("sudo", ["npm", "install", "-g", "@codacy/analysis-cli"], { inherit: true });
22620
+ if (!sudoOk) return failed;
22621
+ const check = checkAnalysisCli();
22622
+ return check.status === "ok" ? { ...check, justInstalled: true } : check;
22623
+ }
22624
+ }
22625
+ async function checkPrereqs(opts = {}) {
22626
+ const checks = [checkNode(), checkGit(), checkClaude()];
22627
+ let analysis = checkAnalysisCli();
22628
+ if (analysis.status !== "ok" && opts.install) {
22629
+ analysis = await installAnalysisCli();
22630
+ }
22631
+ checks.push(analysis);
22632
+ return { checks, blocked: checks.some((c) => c.required && c.status !== "ok") };
22633
+ }
22294
22634
 
22295
22635
  // src/lib/telemetry.ts
22296
22636
  var import_promises12 = require("node:fs/promises");
22637
+
22638
+ // src/lib/gitignore.ts
22639
+ var import_node_child_process11 = require("node:child_process");
22640
+ var import_node_fs40 = require("node:fs");
22641
+ var VERITY_GITIGNORE_MARKER = "# Verity \u2014 machine-local state.";
22642
+ var SETTINGS_LOCAL_IGNORE_ENTRY = ".claude/settings.local.json";
22643
+ var VERITY_GITIGNORE_BLOCK = [
22644
+ "# Verity \u2014 machine-local state. Everything in .verity/ is ignored EXCEPT the",
22645
+ "# shared standard and the knowledge graph, which are meant to be committed.",
22646
+ ".verity/*",
22647
+ "!.verity/standard.yaml",
22648
+ "!.verity/memory/",
22649
+ ".verity/memory/log.md",
22650
+ SETTINGS_LOCAL_IGNORE_ENTRY,
22651
+ ""
22652
+ ].join("\n");
22653
+ var BREAKING_ENTRIES = /* @__PURE__ */ new Set([".verity/", ".verity"]);
22654
+ function isIgnored2(path) {
22655
+ try {
22656
+ (0, import_node_child_process11.execSync)(`git check-ignore -q -- "${path}"`, { stdio: "pipe" });
22657
+ return true;
22658
+ } catch (err) {
22659
+ return err.status === 1 ? false : null;
22660
+ }
22661
+ }
22662
+ function semanticsHold() {
22663
+ const snapshot = isIgnored2(".verity/.snapshot/__probe__");
22664
+ const standard = isIgnored2(".verity/standard.yaml");
22665
+ const node = isIgnored2(".verity/memory/domain/__probe__.md");
22666
+ const futureState = isIgnored2(".verity/.__probe-future-state__");
22667
+ if (snapshot === null || standard === null || node === null || futureState === null) return null;
22668
+ return snapshot === true && futureState === true && standard === false && node === false;
22669
+ }
22670
+ function ensureVerityGitignore() {
22671
+ let content = "";
22672
+ try {
22673
+ content = (0, import_node_fs40.readFileSync)(".gitignore", "utf-8");
22674
+ } catch {
22675
+ }
22676
+ const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
22677
+ const lines = content.split("\n");
22678
+ const breakingCount = lines.filter((l) => BREAKING_ENTRIES.has(l.trim())).length;
22679
+ const needsRepair = breakingCount > 0;
22680
+ const verified = (result) => semanticsHold() === false ? "conflict" : result;
22681
+ if (hasMarker && !needsRepair) return verified("covered");
22682
+ if (!hasMarker && !needsRepair) {
22683
+ if (semanticsHold() === true) return "covered";
22684
+ }
22685
+ try {
22686
+ let next = content;
22687
+ if (needsRepair) {
22688
+ next = lines.map((l) => BREAKING_ENTRIES.has(l.trim()) ? ".verity/*" : l).join("\n");
22689
+ }
22690
+ if (!hasMarker) {
22691
+ const sep2 = next === "" ? "" : next.endsWith("\n") ? "\n" : "\n\n";
22692
+ next = next + sep2 + VERITY_GITIGNORE_BLOCK;
22693
+ }
22694
+ (0, import_node_fs40.writeFileSync)(".gitignore", next);
22695
+ return verified(needsRepair ? "repaired" : "added");
22696
+ } catch {
22697
+ return "failed";
22698
+ }
22699
+ }
22700
+ function committedVerityState() {
22701
+ let out = "";
22702
+ try {
22703
+ out = (0, import_node_child_process11.execSync)("git ls-files -z -- .verity", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
22704
+ } catch {
22705
+ return [];
22706
+ }
22707
+ return out.split("\0").filter(Boolean).filter((p) => p !== ".verity/standard.yaml" && !(p.startsWith(".verity/memory/") && p !== ".verity/memory/log.md"));
22708
+ }
22709
+ function untrackVerityState() {
22710
+ const tracked = committedVerityState();
22711
+ if (tracked.length === 0) return "none";
22712
+ try {
22713
+ (0, import_node_child_process11.execSync)("git rm -r --cached --quiet -- .verity", { stdio: "pipe" });
22714
+ for (const keep of [".verity/standard.yaml", ".verity/memory"]) {
22715
+ try {
22716
+ (0, import_node_child_process11.execSync)(`git add -- "${keep}"`, { stdio: "pipe" });
22717
+ } catch {
22718
+ }
22719
+ }
22720
+ return "untracked";
22721
+ } catch {
22722
+ return "failed";
22723
+ }
22724
+ }
22725
+
22726
+ // src/lib/telemetry.ts
22297
22727
  var SETTINGS_LOCAL_FILE2 = ".claude/settings.local.json";
22298
22728
  var GITIGNORE_FILE = ".gitignore";
22299
- var GITIGNORE_ENTRY = ".claude/settings.local.json";
22729
+ var GITIGNORE_ENTRY = SETTINGS_LOCAL_IGNORE_ENTRY;
22300
22730
  var OTEL_HEADERS_HELPER_CMD = "verity telemetry headers";
22301
22731
  var LEGACY_TELEMETRY_ENV_KEYS = ["OTEL_EXPORTER_OTLP_HEADERS"];
22302
22732
  function deriveOtlpEndpoint(serviceUrl) {
@@ -22382,14 +22812,119 @@ async function uninstallTelemetry() {
22382
22812
  return { ok: true, data: { removed } };
22383
22813
  }
22384
22814
 
22815
+ // src/lib/setup-state.ts
22816
+ var import_promises13 = require("node:fs/promises");
22817
+ var import_node_fs41 = require("node:fs");
22818
+ var SETUP_STATE_FILE = `${VERITY_DIR}/setup.json`;
22819
+ async function readSetupState() {
22820
+ const path = projectPath(SETUP_STATE_FILE);
22821
+ if (!(0, import_node_fs41.existsSync)(path)) return null;
22822
+ try {
22823
+ const parsed = JSON.parse(await (0, import_promises13.readFile)(path, "utf-8"));
22824
+ return parsed && typeof parsed === "object" ? parsed : null;
22825
+ } catch {
22826
+ return null;
22827
+ }
22828
+ }
22829
+ async function writeSetupState(patch) {
22830
+ const current = await readSetupState() ?? { version: 1 };
22831
+ const next = { ...current, ...patch, version: 1 };
22832
+ await writeJsonFilePreservingStyle(projectPath(SETUP_STATE_FILE), next);
22833
+ return next;
22834
+ }
22835
+
22836
+ // src/commands/doctor.ts
22837
+ async function buildReport() {
22838
+ const prereqs = await checkPrereqs({ install: false });
22839
+ const state = await readSetupState();
22840
+ const hooks = await checkAllVerityHooks();
22841
+ const telemetry = await checkTelemetry();
22842
+ const artifacts = {
22843
+ standard: (0, import_node_fs42.existsSync)(projectPath(STANDARD_FILE)),
22844
+ analysisConfig: (0, import_node_fs42.existsSync)(projectPath(CODACY_CONFIG_FILE)),
22845
+ verityMd: (0, import_node_fs42.existsSync)(projectPath(VERITY_MD_FILE))
22846
+ };
22847
+ const next = [];
22848
+ for (const c of prereqs.checks) {
22849
+ if (c.status !== "ok" && c.remedy) next.push(c.remedy);
22850
+ }
22851
+ if (!state?.init) next.push('Run "verity init" \u2014 the deterministic setup phase has not completed here.');
22852
+ if (!artifacts.standard || !artifacts.analysisConfig || !artifacts.verityMd) {
22853
+ next.push("Run /verity-setup in Claude Code \u2014 the Standard, analysis config, and VERITY.md are synthesized there.");
22854
+ }
22855
+ const noAnalysisMoment = !hooks.stop && hooks.guardOn.length === 0;
22856
+ if (noAnalysisMoment) {
22857
+ next.push('No analysis moment is active \u2014 run "verity hooks install --moments stop" or re-run "verity init".');
22858
+ }
22859
+ if (state?.telemetry === "deferred") {
22860
+ next.push('Telemetry was requested but needs a token \u2014 run "verity login", then "verity telemetry install".');
22861
+ }
22862
+ return {
22863
+ prerequisites: prereqs.checks,
22864
+ blocked: prereqs.blocked,
22865
+ phases: {
22866
+ init: { done: !!state?.init, ...state?.init ?? {} },
22867
+ setup: { done: artifacts.standard && artifacts.analysisConfig && artifacts.verityMd }
22868
+ },
22869
+ answers: {
22870
+ intensity: state?.intensity ?? null,
22871
+ moments: state?.moments ?? null,
22872
+ telemetry: state?.telemetry ?? null
22873
+ },
22874
+ hooks: { ...hooks, noAnalysisMoment },
22875
+ telemetry: { enabled: telemetry.enabled, endpoint: telemetry.endpoint },
22876
+ artifacts,
22877
+ next
22878
+ };
22879
+ }
22880
+ function registerDoctorCommand(program2) {
22881
+ program2.command("doctor").description("Report prerequisites, setup phase, hooks, and what is still missing").option("--json", "Output the full report as JSON (what /verity-setup reads)").action(async (opts) => {
22882
+ const report = await buildReport();
22883
+ if (opts.json) {
22884
+ printJson(report);
22885
+ if (report.blocked) process.exit(1);
22886
+ return;
22887
+ }
22888
+ printInfo("Prerequisites:");
22889
+ for (const c of report.prerequisites) {
22890
+ if (c.status === "ok") printInfo(` ${c.label} ${c.detail} \u2713`);
22891
+ else printWarn(` ${c.label}: ${c.detail}${c.remedy ? ` \u2014 ${c.remedy}` : ""}`);
22892
+ }
22893
+ printInfo("Setup:");
22894
+ printInfo(` verity init: ${report.phases.init.done ? `done ${report.phases.init.completed_at ?? ""}`.trim() : "NOT run here"}`);
22895
+ printInfo(` /verity-setup: ${report.phases.setup.done ? "done" : "not completed"}`);
22896
+ printInfo(` intensity: ${report.answers.intensity ?? "\u2014"} moments: ${report.answers.moments?.join(", ") ?? "\u2014"}`);
22897
+ printInfo("Hooks:");
22898
+ printInfo(` Stop (verity analyze): ${report.hooks.stop ? "on" : "off"}`);
22899
+ printInfo(` Git-moment gate: ${report.hooks.guardOn.length ? report.hooks.guardOn.join(", ") : "off"}`);
22900
+ printInfo(` Infra (intent/baseline/compact/session-end): ${[report.hooks.intent, report.hooks.baseline, report.hooks.compact, report.hooks.sessionEnd].filter(Boolean).length}/4`);
22901
+ printInfo(`Telemetry: ${report.telemetry.enabled ? `enabled \u2192 ${report.telemetry.endpoint}` : "disabled"}`);
22902
+ printInfo("Artifacts:");
22903
+ printInfo(` .verity/standard.yaml: ${report.artifacts.standard ? "\u2713" : "missing"}`);
22904
+ printInfo(` .codacy/codacy.config.json: ${report.artifacts.analysisConfig ? "\u2713" : "missing"}`);
22905
+ printInfo(` VERITY.md: ${report.artifacts.verityMd ? "\u2713" : "missing"}`);
22906
+ if (report.next.length > 0) {
22907
+ console.log("");
22908
+ printWarn("Next:");
22909
+ for (const n of report.next) printWarn(` - ${n}`);
22910
+ } else {
22911
+ printInfo("Setup is complete.");
22912
+ }
22913
+ if (report.blocked) process.exit(1);
22914
+ });
22915
+ }
22916
+
22385
22917
  // src/commands/migrate.ts
22918
+ var import_node_fs43 = require("node:fs");
22919
+ var import_node_path28 = require("node:path");
22920
+ var import_node_child_process12 = require("node:child_process");
22386
22921
  var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
22387
22922
  function defaultNpmRemover(pkg) {
22388
- (0, import_node_child_process10.execSync)(`npm rm -g ${pkg}`, { stdio: "pipe", timeout: 12e4 });
22923
+ (0, import_node_child_process12.execSync)(`npm rm -g ${pkg}`, { stdio: "pipe", timeout: 12e4 });
22389
22924
  }
22390
22925
  function isGitTracked(cwd, relPath) {
22391
22926
  try {
22392
- (0, import_node_child_process10.execSync)(`git ls-files --error-unmatch ${relPath}`, { cwd, stdio: "pipe" });
22927
+ (0, import_node_child_process12.execSync)(`git ls-files --error-unmatch ${relPath}`, { cwd, stdio: "pipe" });
22393
22928
  return true;
22394
22929
  } catch {
22395
22930
  return false;
@@ -22397,7 +22932,7 @@ function isGitTracked(cwd, relPath) {
22397
22932
  }
22398
22933
  function isGitRepo(cwd) {
22399
22934
  try {
22400
- (0, import_node_child_process10.execSync)("git rev-parse --is-inside-work-tree", { cwd, stdio: "pipe" });
22935
+ (0, import_node_child_process12.execSync)("git rev-parse --is-inside-work-tree", { cwd, stdio: "pipe" });
22401
22936
  return true;
22402
22937
  } catch {
22403
22938
  return false;
@@ -22420,10 +22955,10 @@ async function runMigration(opts = {}) {
22420
22955
  function migrateProjectDir(root, actions) {
22421
22956
  const gateDir = (0, import_node_path28.join)(root, ".gate");
22422
22957
  const verityDir = (0, import_node_path28.join)(root, ".verity");
22423
- if ((0, import_node_fs40.existsSync)(gateDir) && !(0, import_node_fs40.existsSync)(verityDir)) {
22958
+ if ((0, import_node_fs43.existsSync)(gateDir) && !(0, import_node_fs43.existsSync)(verityDir)) {
22424
22959
  return migrateProjectDirRename(root, gateDir, verityDir, actions);
22425
22960
  }
22426
- if ((0, import_node_fs40.existsSync)(gateDir) && (0, import_node_fs40.existsSync)(verityDir)) {
22961
+ if ((0, import_node_fs43.existsSync)(gateDir) && (0, import_node_fs43.existsSync)(verityDir)) {
22427
22962
  return migrateProjectDirCarry(gateDir, verityDir, actions);
22428
22963
  }
22429
22964
  return false;
@@ -22437,20 +22972,20 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
22437
22972
  );
22438
22973
  }
22439
22974
  try {
22440
- (0, import_node_child_process10.execSync)("git mv .gate .verity", { cwd: root, stdio: "pipe" });
22975
+ (0, import_node_child_process12.execSync)("git mv .gate .verity", { cwd: root, stdio: "pipe" });
22441
22976
  actions.push("Moved .gate/ \u2192 .verity/ (git mv, staged)");
22442
22977
  moved = true;
22443
22978
  } catch {
22444
22979
  }
22445
22980
  }
22446
22981
  if (moved) {
22447
- if ((0, import_node_fs40.existsSync)(gateDir)) {
22982
+ if ((0, import_node_fs43.existsSync)(gateDir)) {
22448
22983
  const carried = carryLegacyContents(gateDir, verityDir);
22449
22984
  if (carried > 0) {
22450
22985
  actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
22451
22986
  }
22452
22987
  try {
22453
- (0, import_node_fs40.rmSync)(gateDir, { recursive: true, force: true });
22988
+ (0, import_node_fs43.rmSync)(gateDir, { recursive: true, force: true });
22454
22989
  } catch {
22455
22990
  }
22456
22991
  }
@@ -22466,7 +23001,7 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
22466
23001
  actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
22467
23002
  }
22468
23003
  try {
22469
- (0, import_node_fs40.rmSync)(gateDir, { recursive: true, force: true });
23004
+ (0, import_node_fs43.rmSync)(gateDir, { recursive: true, force: true });
22470
23005
  } catch {
22471
23006
  }
22472
23007
  return carried > 0;
@@ -22475,9 +23010,9 @@ function migrateGlobalCredentials(home, actions) {
22475
23010
  if (!home) return;
22476
23011
  const gateCreds = (0, import_node_path28.join)(home, ".gate", "credentials");
22477
23012
  const verityCreds = (0, import_node_path28.join)(home, ".verity", "credentials");
22478
- if (!(0, import_node_fs40.existsSync)(gateCreds)) return;
22479
- if (!(0, import_node_fs40.existsSync)(verityCreds)) {
22480
- (0, import_node_fs40.mkdirSync)((0, import_node_path28.join)(home, ".verity"), { recursive: true });
23013
+ if (!(0, import_node_fs43.existsSync)(gateCreds)) return;
23014
+ if (!(0, import_node_fs43.existsSync)(verityCreds)) {
23015
+ (0, import_node_fs43.mkdirSync)((0, import_node_path28.join)(home, ".verity"), { recursive: true });
22481
23016
  moveFile(gateCreds, verityCreds);
22482
23017
  actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
22483
23018
  return;
@@ -22500,7 +23035,7 @@ async function migrateLegacyHooks(root, actions) {
22500
23035
  }
22501
23036
  async function migrateClaudeMd(root, actions) {
22502
23037
  const claudeMd = (0, import_node_path28.join)(root, "CLAUDE.md");
22503
- const hadLegacyBlock = (0, import_node_fs40.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
23038
+ const hadLegacyBlock = (0, import_node_fs43.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
22504
23039
  if (!hadLegacyBlock) return;
22505
23040
  try {
22506
23041
  await ensureClaudeMdPointer(root);
@@ -22512,11 +23047,11 @@ async function migrateClaudeMd(root, actions) {
22512
23047
  function migrateStandardFile(root, actions) {
22513
23048
  const gateMd = (0, import_node_path28.join)(root, "GATE.md");
22514
23049
  const verityMd = (0, import_node_path28.join)(root, "VERITY.md");
22515
- if (!(0, import_node_fs40.existsSync)(gateMd) || (0, import_node_fs40.existsSync)(verityMd)) return;
23050
+ if (!(0, import_node_fs43.existsSync)(gateMd) || (0, import_node_fs43.existsSync)(verityMd)) return;
22516
23051
  let moved = false;
22517
23052
  if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
22518
23053
  try {
22519
- (0, import_node_child_process10.execSync)("git mv GATE.md VERITY.md", { cwd: root, stdio: "pipe" });
23054
+ (0, import_node_child_process12.execSync)("git mv GATE.md VERITY.md", { cwd: root, stdio: "pipe" });
22520
23055
  moved = true;
22521
23056
  } catch {
22522
23057
  }
@@ -22524,12 +23059,12 @@ function migrateStandardFile(root, actions) {
22524
23059
  if (!moved) moveFile(gateMd, verityMd);
22525
23060
  const content = readFileSyncSafe(verityMd);
22526
23061
  const refreshed = content.split("GATE.md").join("VERITY.md");
22527
- if (refreshed !== content) (0, import_node_fs40.writeFileSync)(verityMd, refreshed);
23062
+ if (refreshed !== content) (0, import_node_fs43.writeFileSync)(verityMd, refreshed);
22528
23063
  actions.push("Renamed GATE.md \u2192 VERITY.md");
22529
23064
  }
22530
23065
  async function migrateTelemetryHeaders(root, actions) {
22531
23066
  const file = (0, import_node_path28.join)(root, ".claude", "settings.local.json");
22532
- if (!(0, import_node_fs40.existsSync)(file)) return;
23067
+ if (!(0, import_node_fs43.existsSync)(file)) return;
22533
23068
  let settings;
22534
23069
  try {
22535
23070
  settings = JSON.parse(readFileSyncSafe(file) || "{}");
@@ -22577,21 +23112,21 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
22577
23112
  }
22578
23113
  if (toAppend.length > 0) {
22579
23114
  const sep2 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
22580
- (0, import_node_fs40.writeFileSync)(verityCreds, verityContent + sep2 + toAppend.join("\n") + "\n");
23115
+ (0, import_node_fs43.writeFileSync)(verityCreds, verityContent + sep2 + toAppend.join("\n") + "\n");
22581
23116
  }
22582
- (0, import_node_fs40.rmSync)(gateCreds, { force: true });
23117
+ (0, import_node_fs43.rmSync)(gateCreds, { force: true });
22583
23118
  return toAppend.length;
22584
23119
  }
22585
23120
  function readFileSyncSafe(path) {
22586
23121
  try {
22587
- return (0, import_node_fs40.readFileSync)(path, "utf-8");
23122
+ return (0, import_node_fs43.readFileSync)(path, "utf-8");
22588
23123
  } catch {
22589
23124
  return "";
22590
23125
  }
22591
23126
  }
22592
23127
  function hasStagedChanges(root) {
22593
23128
  try {
22594
- (0, import_node_child_process10.execSync)("git diff --cached --quiet", { cwd: root, stdio: "pipe" });
23129
+ (0, import_node_child_process12.execSync)("git diff --cached --quiet", { cwd: root, stdio: "pipe" });
22595
23130
  return false;
22596
23131
  } catch {
22597
23132
  return true;
@@ -22599,35 +23134,35 @@ function hasStagedChanges(root) {
22599
23134
  }
22600
23135
  function moveDir(from, to) {
22601
23136
  try {
22602
- (0, import_node_fs40.renameSync)(from, to);
23137
+ (0, import_node_fs43.renameSync)(from, to);
22603
23138
  } catch (err) {
22604
23139
  if (err.code !== "EXDEV") throw err;
22605
- (0, import_node_fs40.cpSync)(from, to, { recursive: true });
22606
- (0, import_node_fs40.rmSync)(from, { recursive: true, force: true });
23140
+ (0, import_node_fs43.cpSync)(from, to, { recursive: true });
23141
+ (0, import_node_fs43.rmSync)(from, { recursive: true, force: true });
22607
23142
  }
22608
23143
  }
22609
23144
  function moveFile(from, to) {
22610
23145
  try {
22611
- (0, import_node_fs40.renameSync)(from, to);
23146
+ (0, import_node_fs43.renameSync)(from, to);
22612
23147
  } catch (err) {
22613
23148
  if (err.code !== "EXDEV") throw err;
22614
- (0, import_node_fs40.cpSync)(from, to);
22615
- (0, import_node_fs40.rmSync)(from, { force: true });
23149
+ (0, import_node_fs43.cpSync)(from, to);
23150
+ (0, import_node_fs43.rmSync)(from, { force: true });
22616
23151
  }
22617
23152
  }
22618
23153
  function carryLegacyContents(gateDir, verityDir) {
22619
23154
  let copied = 0;
22620
23155
  const walk = (relDir) => {
22621
23156
  const srcDir = (0, import_node_path28.join)(gateDir, relDir);
22622
- for (const entry of (0, import_node_fs40.readdirSync)(srcDir)) {
23157
+ for (const entry of (0, import_node_fs43.readdirSync)(srcDir)) {
22623
23158
  const rel = relDir ? (0, import_node_path28.join)(relDir, entry) : entry;
22624
23159
  const src = (0, import_node_path28.join)(gateDir, rel);
22625
23160
  const dest = (0, import_node_path28.join)(verityDir, rel);
22626
- if ((0, import_node_fs40.statSync)(src).isDirectory()) {
23161
+ if ((0, import_node_fs43.statSync)(src).isDirectory()) {
22627
23162
  walk(rel);
22628
- } else if (!(0, import_node_fs40.existsSync)(dest)) {
22629
- (0, import_node_fs40.mkdirSync)((0, import_node_path28.dirname)(dest), { recursive: true });
22630
- (0, import_node_fs40.cpSync)(src, dest);
23163
+ } else if (!(0, import_node_fs43.existsSync)(dest)) {
23164
+ (0, import_node_fs43.mkdirSync)((0, import_node_path28.dirname)(dest), { recursive: true });
23165
+ (0, import_node_fs43.cpSync)(src, dest);
22631
23166
  copied++;
22632
23167
  }
22633
23168
  }
@@ -22638,20 +23173,20 @@ function carryLegacyContents(gateDir, verityDir) {
22638
23173
  async function needsMigration(root = repoRoot()) {
22639
23174
  const gateDir = (0, import_node_path28.join)(root, ".gate");
22640
23175
  const verityDir = (0, import_node_path28.join)(root, ".verity");
22641
- if ((0, import_node_fs40.existsSync)(gateDir) && !(0, import_node_fs40.existsSync)(verityDir)) return true;
22642
- if ((0, import_node_fs40.existsSync)(gateDir) && (0, import_node_fs40.existsSync)(verityDir)) {
22643
- if ((0, import_node_fs40.existsSync)((0, import_node_path28.join)(gateDir, "credentials")) && !(0, import_node_fs40.existsSync)((0, import_node_path28.join)(verityDir, "credentials"))) {
23176
+ if ((0, import_node_fs43.existsSync)(gateDir) && !(0, import_node_fs43.existsSync)(verityDir)) return true;
23177
+ if ((0, import_node_fs43.existsSync)(gateDir) && (0, import_node_fs43.existsSync)(verityDir)) {
23178
+ if ((0, import_node_fs43.existsSync)((0, import_node_path28.join)(gateDir, "credentials")) && !(0, import_node_fs43.existsSync)((0, import_node_path28.join)(verityDir, "credentials"))) {
22644
23179
  return true;
22645
23180
  }
22646
- if ((0, import_node_fs40.existsSync)((0, import_node_path28.join)(gateDir, "memory")) && !(0, import_node_fs40.existsSync)((0, import_node_path28.join)(verityDir, "memory"))) {
23181
+ if ((0, import_node_fs43.existsSync)((0, import_node_path28.join)(gateDir, "memory")) && !(0, import_node_fs43.existsSync)((0, import_node_path28.join)(verityDir, "memory"))) {
22647
23182
  return true;
22648
23183
  }
22649
23184
  }
22650
23185
  const claudeMd = (0, import_node_path28.join)(root, "CLAUDE.md");
22651
- if ((0, import_node_fs40.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
23186
+ if ((0, import_node_fs43.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
22652
23187
  return true;
22653
23188
  }
22654
- if ((0, import_node_fs40.existsSync)((0, import_node_path28.join)(root, "GATE.md")) && !(0, import_node_fs40.existsSync)((0, import_node_path28.join)(root, "VERITY.md"))) {
23189
+ if ((0, import_node_fs43.existsSync)((0, import_node_path28.join)(root, "GATE.md")) && !(0, import_node_fs43.existsSync)((0, import_node_path28.join)(root, "VERITY.md"))) {
22655
23190
  return true;
22656
23191
  }
22657
23192
  if (await hasLegacyHooksAt(root)) return true;
@@ -22676,17 +23211,96 @@ function registerMigrateCommand(program2) {
22676
23211
  });
22677
23212
  }
22678
23213
 
22679
- // src/commands/init.ts
22680
- async function promptYes(question) {
22681
- if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
22682
- const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
23214
+ // src/lib/prompt.ts
23215
+ var readline2 = __toESM(require("node:readline/promises"));
23216
+ function interactive() {
23217
+ return !!process.stdin.isTTY && !!process.stdout.isTTY;
23218
+ }
23219
+ async function askLine(question, io = {}) {
23220
+ const rl = readline2.createInterface({
23221
+ input: io.input ?? process.stdin,
23222
+ output: io.output ?? process.stdout
23223
+ });
22683
23224
  try {
22684
- const answer = (await rl.question(question)).trim().toLowerCase();
22685
- return answer === "" || answer === "y" || answer === "yes";
23225
+ return await new Promise((resolve4) => {
23226
+ rl.question(question).then((a) => resolve4(a.trim())).catch(() => resolve4(null));
23227
+ rl.once("close", () => setImmediate(() => resolve4(null)));
23228
+ });
22686
23229
  } finally {
22687
23230
  rl.close();
22688
23231
  }
22689
23232
  }
23233
+ var ask = (question) => askLine(question);
23234
+ function parseChoice(answer, choices, fallback) {
23235
+ const a = answer.trim().toLowerCase();
23236
+ if (a === "") return { id: fallback, recognized: true };
23237
+ const byNumber = Number.parseInt(a, 10);
23238
+ if (Number.isInteger(byNumber) && byNumber >= 1 && byNumber <= choices.length) {
23239
+ return { id: choices[byNumber - 1].id, recognized: true };
23240
+ }
23241
+ const byId = choices.find((c) => c.id.toLowerCase() === a || c.label.toLowerCase() === a);
23242
+ if (byId) return { id: byId.id, recognized: true };
23243
+ return { id: fallback, recognized: false };
23244
+ }
23245
+ function parseMultiSelect(answer, choices, fallback) {
23246
+ const a = answer.trim().toLowerCase();
23247
+ if (a === "") return { ids: [...fallback], recognized: true };
23248
+ const picked = /* @__PURE__ */ new Set();
23249
+ for (const part of a.split(",").map((s) => s.trim()).filter(Boolean)) {
23250
+ const n = Number.parseInt(part, 10);
23251
+ if (Number.isInteger(n) && n >= 1 && n <= choices.length) {
23252
+ picked.add(choices[n - 1].id);
23253
+ continue;
23254
+ }
23255
+ const byId = choices.find((c) => c.id.toLowerCase() === part || c.label.toLowerCase() === part);
23256
+ if (byId) picked.add(byId.id);
23257
+ }
23258
+ if (picked.size === 0) return { ids: [...fallback], recognized: false };
23259
+ return { ids: choices.filter((c) => picked.has(c.id)).map((c) => c.id), recognized: true };
23260
+ }
23261
+ async function promptYes(question, opts) {
23262
+ if (!interactive()) return opts.nonInteractive;
23263
+ const answer = await ask(question);
23264
+ if (answer === null) return opts.nonInteractive;
23265
+ const a = answer.toLowerCase();
23266
+ return a === "" || a === "y" || a === "yes";
23267
+ }
23268
+ function printOptions(question, choices) {
23269
+ console.log("");
23270
+ console.log(` ${question}`);
23271
+ choices.forEach((c, i) => {
23272
+ const tag = c.recommended ? " (recommended)" : "";
23273
+ console.log(` ${i + 1}. ${c.label}${tag}${c.hint ? ` \u2014 ${c.hint}` : ""}`);
23274
+ });
23275
+ }
23276
+ async function promptChoice(question, choices, fallback) {
23277
+ if (!interactive()) return fallback;
23278
+ printOptions(question, choices);
23279
+ const defaultIdx = choices.findIndex((c) => c.id === fallback);
23280
+ const answer = await ask(` Choose [${defaultIdx + 1}]: `);
23281
+ if (answer === null) {
23282
+ console.log(` (no answer \u2014 using ${fallback})`);
23283
+ return fallback;
23284
+ }
23285
+ const parsed = parseChoice(answer, choices, fallback);
23286
+ if (!parsed.recognized) console.log(` Unrecognized answer "${answer}" \u2014 using ${fallback}.`);
23287
+ return parsed.id;
23288
+ }
23289
+ async function promptMultiSelect(question, choices, fallback) {
23290
+ if (!interactive()) return [...fallback];
23291
+ printOptions(question, choices);
23292
+ const defaultLabel = choices.map((c, i) => fallback.includes(c.id) ? String(i + 1) : null).filter(Boolean).join(",");
23293
+ const answer = await ask(` Choose one or more, comma-separated [${defaultLabel}]: `);
23294
+ if (answer === null) {
23295
+ console.log(" (no answer \u2014 using the default)");
23296
+ return [...fallback];
23297
+ }
23298
+ const parsed = parseMultiSelect(answer, choices, fallback);
23299
+ if (!parsed.recognized) console.log(` Unrecognized answer "${answer}" \u2014 using the default.`);
23300
+ return parsed.ids;
23301
+ }
23302
+
23303
+ // src/commands/init.ts
22690
23304
  async function confirmExistingLogin(serviceUrl, remote, opts) {
22691
23305
  const existing = await resolveToken(opts.token);
22692
23306
  if (!existing.ok) return "drive-login";
@@ -22744,7 +23358,7 @@ async function runOptionalAuth(resolution, opts = {}) {
22744
23358
  }
22745
23359
  let remote = "";
22746
23360
  try {
22747
- remote = (0, import_node_child_process11.execSync)("git remote get-url origin", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
23361
+ remote = (0, import_node_child_process13.execSync)("git remote get-url origin", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
22748
23362
  } catch {
22749
23363
  }
22750
23364
  if (!healed) {
@@ -22755,7 +23369,7 @@ async function runOptionalAuth(resolution, opts = {}) {
22755
23369
  printInfo("Verity runs in local-only mode: the gate still runs and shows static findings, but nothing uploads.");
22756
23370
  printInfo(' Authenticate anytime: run "verity login" (one login covers every repo you can write to).');
22757
23371
  };
22758
- if (process.stdin.isTTY && process.stdout.isTTY) {
23372
+ if (interactive() && !opts.yes) {
22759
23373
  console.log("");
22760
23374
  console.log(" Signing in is optional. What it does:");
22761
23375
  console.log(" - Confirms which repositories you can write to. The GitHub token is");
@@ -22770,9 +23384,12 @@ async function runOptionalAuth(resolution, opts = {}) {
22770
23384
  console.log(" findings, but nothing is uploaded.");
22771
23385
  console.log("");
22772
23386
  }
22773
- const wantsAuth = await promptYes("Authenticate with GitHub now to upload results to Verity? [Y/skip] ");
23387
+ const wantsAuth = opts.yes ? false : await promptYes(
23388
+ "Authenticate with GitHub now to upload results to Verity? [Y/skip] ",
23389
+ { nonInteractive: false }
23390
+ );
22774
23391
  if (!wantsAuth) {
22775
- printInfo("Skipped authentication.");
23392
+ printInfo(opts.yes ? "Skipped authentication (unattended run)." : "Skipped authentication.");
22776
23393
  localOnlyNote();
22777
23394
  return;
22778
23395
  }
@@ -22795,7 +23412,7 @@ function resolveDataDir() {
22795
23412
  // local dev: running from repo root
22796
23413
  ];
22797
23414
  for (const candidate of candidates) {
22798
- if ((0, import_node_fs41.existsSync)((0, import_node_path29.join)(candidate, "skills"))) {
23415
+ if ((0, import_node_fs44.existsSync)((0, import_node_path29.join)(candidate, "skills"))) {
22799
23416
  return candidate;
22800
23417
  }
22801
23418
  }
@@ -22804,22 +23421,197 @@ function resolveDataDir() {
22804
23421
  );
22805
23422
  }
22806
23423
  async function copyDir(src, dest) {
22807
- await (0, import_promises13.mkdir)(dest, { recursive: true });
22808
- await (0, import_promises13.cp)(src, dest, { recursive: true, force: true });
23424
+ await (0, import_promises14.mkdir)(dest, { recursive: true });
23425
+ await (0, import_promises14.cp)(src, dest, { recursive: true, force: true });
23426
+ }
23427
+ async function skillIsCurrent(src, dest) {
23428
+ const list2 = (dir) => {
23429
+ const out = [];
23430
+ const walk = (d, prefix) => {
23431
+ for (const e of (0, import_node_fs44.readdirSync)(d, { withFileTypes: true })) {
23432
+ const rel = prefix ? `${prefix}/${e.name}` : e.name;
23433
+ if (e.isDirectory()) walk((0, import_node_path29.join)(d, e.name), rel);
23434
+ else if (e.isFile()) out.push(rel);
23435
+ }
23436
+ };
23437
+ walk(dir, "");
23438
+ return out.sort();
23439
+ };
23440
+ try {
23441
+ const shipped = list2(src);
23442
+ if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
23443
+ for (const rel of shipped) {
23444
+ const a = await (0, import_promises14.readFile)((0, import_node_path29.join)(src, rel), "utf-8");
23445
+ const b = await (0, import_promises14.readFile)((0, import_node_path29.join)(dest, rel), "utf-8");
23446
+ if (a !== b) return false;
23447
+ }
23448
+ return true;
23449
+ } catch {
23450
+ return false;
23451
+ }
23452
+ }
23453
+ var SKILLS = [
23454
+ "verity-setup",
23455
+ "verity-analyze",
23456
+ "verity-status",
23457
+ "verity-feedback",
23458
+ "verity-learn",
23459
+ "verity-memory",
23460
+ "verity-insights",
23461
+ "verity-reflect"
23462
+ ];
23463
+ var INTENSITY_CHOICES = [
23464
+ { id: "lightweight", label: "lightweight", hint: "critical security only, fastest (~3s)" },
23465
+ { id: "balanced", label: "balanced", hint: "security + quality (~8s)", recommended: true },
23466
+ { id: "thorough", label: "thorough", hint: "all tools, all rules (~15s)" }
23467
+ ];
23468
+ var MOMENT_CHOICES = [
23469
+ { id: "stop", label: "On stop", hint: "after every agent turn \u2014 fast feedback while you work", recommended: true },
23470
+ { id: "pre-commit", label: "Before commit", hint: "reviews the staged diff, blocks the commit on FAIL" },
23471
+ { id: "pre-push", label: "Before push / PR", hint: "reviews the to-be-pushed commits, blocks on FAIL" }
23472
+ ];
23473
+ var DEFAULT_MOMENTS = ["stop"];
23474
+ async function askSetupQuestions(defaultsOnly, previous) {
23475
+ const intensityDefault = previous?.intensity ?? "balanced";
23476
+ const momentsDefault = previous?.moments?.length ? previous.moments : DEFAULT_MOMENTS;
23477
+ if (defaultsOnly) {
23478
+ return { intensity: intensityDefault, moments: momentsDefault, telemetry: "not-asked" };
23479
+ }
23480
+ if (previous?.intensity || previous?.moments) {
23481
+ printInfo(`Current: ${intensityDefault} \xB7 ${momentsDefault.join(", ")} \u2014 press Enter to keep either.`);
23482
+ }
23483
+ const intensity = await promptChoice(
23484
+ "Analysis intensity \u2014 how deeply should Verity review?",
23485
+ INTENSITY_CHOICES,
23486
+ intensityDefault
23487
+ );
23488
+ const moments = await promptMultiSelect(
23489
+ "When should Verity review your code?",
23490
+ MOMENT_CHOICES,
23491
+ momentsDefault
23492
+ );
23493
+ const current = await checkTelemetry();
23494
+ if (current.enabled) {
23495
+ printInfo(`Cost & usage telemetry: already enabled \u2192 ${current.endpoint}`);
23496
+ printInfo(' (turn it off with "verity telemetry uninstall")');
23497
+ return { intensity, moments, telemetry: "already-on" };
23498
+ }
23499
+ console.log("");
23500
+ console.log(" Cost & usage telemetry (opt-in) \u2014 powers the /usage dashboard.");
23501
+ console.log(" Sends Claude Code's own OpenTelemetry metrics and traces only: model names,");
23502
+ console.log(" token counts, USD cost, agent types, session ids. NOT your prompts, code, or");
23503
+ console.log(" tool input/output. Without it, /usage stays empty.");
23504
+ const wants = await promptYes(" Enable cost & usage telemetry? [Y/n] ", { nonInteractive: false });
23505
+ return { intensity, moments, telemetry: wants ? "yes" : "no" };
23506
+ }
23507
+ function insideClaudeCode() {
23508
+ return !!process.env.CLAUDECODE || !!process.env.CLAUDE_SESSION_ID;
23509
+ }
23510
+ function resumeDeferredPending(previous) {
23511
+ return previous?.telemetry === "deferred";
23512
+ }
23513
+ var PHASE_TWO_ARTIFACTS = [
23514
+ {
23515
+ path: ".verity/standard.yaml",
23516
+ what: "the Standard, synthesized from your codebase",
23517
+ // The presence flag travels WITH the row. Read positionally from a parallel
23518
+ // array, a reorder of this list would silently move every ✓ onto the wrong
23519
+ // path — a report that is confidently wrong about what got created.
23520
+ present: (a) => a.standard
23521
+ },
23522
+ {
23523
+ path: ".codacy/codacy.config.json",
23524
+ what: "curated static-analysis patterns",
23525
+ present: (a) => a.analysisConfig
23526
+ },
23527
+ {
23528
+ path: "VERITY.md",
23529
+ what: "project quality overview",
23530
+ present: (a) => a.verityMd
23531
+ }
23532
+ ];
23533
+ async function reportPhaseTwo(startedAt) {
23534
+ const elapsed = Math.round((Date.now() - startedAt) / 1e3);
23535
+ let report = null;
23536
+ try {
23537
+ report = await buildReport();
23538
+ } catch {
23539
+ }
23540
+ console.log("");
23541
+ if (!report) {
23542
+ printWarn('Could not verify what the setup session produced \u2014 run "verity doctor".');
23543
+ return;
23544
+ }
23545
+ const { artifacts } = report;
23546
+ const complete = PHASE_TWO_ARTIFACTS.every((a) => a.present(artifacts));
23547
+ printInfo(complete ? `Setup complete (${elapsed}s).` : `Setup session ended after ${elapsed}s.`);
23548
+ for (const { path, what, present } of PHASE_TWO_ARTIFACTS) {
23549
+ const ok = present(artifacts);
23550
+ console.log(` ${ok ? "\u2713" : "\xB7"} ${path.padEnd(30)} ${ok ? what : `${what} \u2014 NOT created`}`);
23551
+ }
23552
+ if (!complete) {
23553
+ console.log("");
23554
+ printWarn('Setup did not finish. Re-run "/verity-setup" in Claude Code to complete it \u2014');
23555
+ printWarn(" nothing is lost; it picks up from what is already on disk.");
23556
+ }
23557
+ }
23558
+ async function handoffToSetup(enabled, claudeInstalled) {
23559
+ const instruct = (why) => {
23560
+ console.log("");
23561
+ printInfo("Still to do \u2014 this is what /verity-setup does (it needs a model):");
23562
+ for (const { path, what } of PHASE_TWO_ARTIFACTS) {
23563
+ console.log(` ${path.padEnd(30)} ${what}`);
23564
+ }
23565
+ console.log("");
23566
+ printInfo("Next step: run /verity-setup in Claude Code.");
23567
+ printInfo(` (${why})`);
23568
+ };
23569
+ if (!enabled) return instruct("--no-setup was passed");
23570
+ if (insideClaudeCode()) return instruct("you are already in a Claude Code session \u2014 invoke the skill there");
23571
+ if (!interactive()) return instruct("no interactive terminal here");
23572
+ if (!claudeInstalled) return instruct("Claude Code is not installed on this machine yet");
23573
+ printPhase(2, 2, "your Standard", "reading the codebase \xB7 synthesizing the Standard \xB7 curating patterns");
23574
+ console.log(" Claude Code takes over the screen from here. It will:");
23575
+ console.log(" \xB7 read your codebase \u2014 languages, frameworks, architecture");
23576
+ console.log(" \xB7 synthesize .verity/standard.yaml and show it to you");
23577
+ console.log(" \xB7 write the analysis config, then VERITY.md");
23578
+ console.log(" Usually a minute or two. Quit any time \u2014 re-running /verity-setup resumes.");
23579
+ console.log("");
23580
+ const startedAt = Date.now();
23581
+ const run2 = (0, import_node_child_process13.spawnSync)("claude", ["/verity-setup"], { stdio: "inherit" });
23582
+ if (run2.error) {
23583
+ printWarn(`Could not start Claude Code: ${run2.error.message}`);
23584
+ return instruct("start it yourself and run the skill there");
23585
+ }
23586
+ await reportPhaseTwo(startedAt);
22809
23587
  }
22810
23588
  function registerInitCommand(program2) {
22811
- program2.command("init").description("Initialize Verity in the current project").option("--force", "Overwrite existing skills and hooks").action(async (opts) => {
23589
+ program2.command("init").alias("setup").description("Set up Verity in the current project (asks the setup questions, then hands off to /verity-setup)").option("--force", "Reinstall the skills even when they are already up to date (hooks are always reconciled)").option("-y, --yes", "Take the recommended answer for every question (no prompts)").option("--no-setup", "Skip the /verity-setup handoff at the end").action(async (opts) => {
22812
23590
  const force = opts.force ?? false;
23591
+ const wantsHandoff = opts.setup !== false;
23592
+ const defaultsOnly = (opts.yes ?? false) || !interactive();
22813
23593
  const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
22814
- const isProject = projectMarkers.some((m) => (0, import_node_fs41.existsSync)(m));
23594
+ const isProject = projectMarkers.some((m) => (0, import_node_fs44.existsSync)(m));
22815
23595
  if (!isProject) {
22816
23596
  printError("No project detected in the current directory.");
22817
23597
  printInfo('Run "verity init" from your project root.');
22818
23598
  process.exit(1);
22819
23599
  }
22820
- console.log("");
22821
- printInfo("Initializing Verity in this project...");
22822
- console.log("");
23600
+ const showArt = canRenderArt() && !insideClaudeCode();
23601
+ printBanner({ interactive: showArt });
23602
+ if (!showArt) {
23603
+ console.log("");
23604
+ printInfo("Initializing Verity in this project...");
23605
+ console.log("");
23606
+ } else {
23607
+ printPhase(1, 2, "this machine", "prerequisites \xB7 skills \xB7 hooks \xB7 sign-in");
23608
+ }
23609
+ const TOTAL_STEPS = 8;
23610
+ let stepNo = 0;
23611
+ const step = (label2) => {
23612
+ stepNo++;
23613
+ printInfo(`${DIM}[${stepNo}/${TOTAL_STEPS}]${NC} ${label2}`);
23614
+ };
22823
23615
  if (await needsMigration()) {
22824
23616
  printInfo("Legacy GATE.md install detected \u2014 migrating to Verity...");
22825
23617
  try {
@@ -22830,143 +23622,171 @@ function registerInitCommand(program2) {
22830
23622
  }
22831
23623
  console.log("");
22832
23624
  }
22833
- printInfo("Checking prerequisites...");
22834
- const nodeVersion = process.version;
22835
- const nodeMajor = parseInt(nodeVersion.slice(1), 10);
22836
- if (nodeMajor < 20) {
22837
- printError(`Node.js 20+ required (found ${nodeVersion}). Update from https://nodejs.org`);
22838
- process.exit(1);
23625
+ step("Checking prerequisites");
23626
+ const prereqs = await checkPrereqs({ install: true });
23627
+ for (const c of prereqs.checks) {
23628
+ if (c.status === "ok") {
23629
+ if (c.justInstalled) continue;
23630
+ printInfo(` ${c.label} ${c.detail} \u2713`);
23631
+ } else {
23632
+ printWarn(` ${c.label}: ${c.detail}`);
23633
+ if (c.remedy) printWarn(` ${c.remedy}`);
23634
+ }
22839
23635
  }
22840
- printInfo(` Node.js ${nodeVersion} \u2713`);
22841
- try {
22842
- const gitVersion = (0, import_node_child_process11.execSync)("git --version", { encoding: "utf-8" }).trim();
22843
- printInfo(` ${gitVersion} \u2713`);
22844
- } catch {
22845
- printError("git is required but not installed. Install from https://git-scm.com");
23636
+ if (prereqs.blocked) {
23637
+ printError("A required prerequisite is missing \u2014 cannot continue.");
22846
23638
  process.exit(1);
22847
23639
  }
22848
- try {
22849
- (0, import_node_child_process11.execSync)("which claude", { encoding: "utf-8" });
22850
- printInfo(" Claude Code \u2713");
22851
- } catch {
22852
- printWarn(" Claude Code not found \u2014 hooks will be configured but need Claude Code to run.");
22853
- }
22854
- try {
22855
- (0, import_node_child_process11.execSync)("which codacy-analysis", { encoding: "utf-8", stdio: "pipe" });
22856
- printInfo(" @codacy/analysis-cli \u2713");
22857
- } catch {
22858
- printInfo(" Installing @codacy/analysis-cli...");
22859
- try {
22860
- (0, import_node_child_process11.execSync)("npm install -g @codacy/analysis-cli", { encoding: "utf-8", stdio: "pipe", timeout: 12e4 });
22861
- printInfo(" @codacy/analysis-cli installed \u2713");
22862
- } catch {
22863
- try {
22864
- printWarn(" Retrying with sudo...");
22865
- (0, import_node_child_process11.execSync)("sudo npm install -g @codacy/analysis-cli", { encoding: "utf-8", stdio: "inherit", timeout: 12e4 });
22866
- printInfo(" @codacy/analysis-cli installed \u2713");
22867
- } catch {
22868
- printWarn(" Could not install @codacy/analysis-cli automatically.");
22869
- printWarn(" Install manually: npm install -g @codacy/analysis-cli");
22870
- printWarn(" Static analysis will be unavailable until installed.");
22871
- }
22872
- }
22873
- }
23640
+ const claudeInstalled = prereqs.checks.some((c) => c.id === "claude" && c.status === "ok");
22874
23641
  console.log("");
22875
- printInfo("Installing skills...");
23642
+ step("Installing skills");
22876
23643
  const dataDir = resolveDataDir();
22877
23644
  const skillsSource = (0, import_node_path29.join)(dataDir, "skills");
22878
23645
  const skillsDest = ".claude/skills";
22879
- const skills = ["verity-setup", "verity-analyze", "verity-status", "verity-feedback", "verity-learn", "verity-memory", "verity-insights", "verity-reflect"];
22880
23646
  let skillsInstalled = 0;
22881
- for (const skill of skills) {
23647
+ for (const skill of SKILLS) {
22882
23648
  const src = (0, import_node_path29.join)(skillsSource, skill);
22883
23649
  const dest = (0, import_node_path29.join)(skillsDest, skill);
22884
- if (!(0, import_node_fs41.existsSync)(src)) {
23650
+ if (!(0, import_node_fs44.existsSync)(src)) {
22885
23651
  printWarn(` Skill data not found: ${skill}`);
22886
23652
  continue;
22887
23653
  }
22888
- if ((0, import_node_fs41.existsSync)(dest) && !force) {
22889
- const srcSkill = (0, import_node_path29.join)(src, "SKILL.md");
22890
- const destSkill = (0, import_node_path29.join)(dest, "SKILL.md");
22891
- if ((0, import_node_fs41.existsSync)(destSkill)) {
22892
- try {
22893
- const srcContent = await (0, import_promises13.readFile)(srcSkill, "utf-8");
22894
- const destContent = await (0, import_promises13.readFile)(destSkill, "utf-8");
22895
- if (srcContent === destContent) {
22896
- skillsInstalled++;
22897
- continue;
22898
- }
22899
- } catch {
22900
- }
22901
- }
23654
+ if ((0, import_node_fs44.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) {
23655
+ skillsInstalled++;
23656
+ continue;
22902
23657
  }
22903
23658
  await copyDir(src, dest);
22904
23659
  skillsInstalled++;
22905
23660
  }
22906
- printInfo(` ${skillsInstalled}/${skills.length} skills installed to .claude/skills/ \u2713`);
22907
- printInfo("Wiring Claude Code hooks...");
22908
- const present = await checkAllVerityHooks();
22909
- const settings = await readSettings();
22910
- const hookResult = installVerityHooks(settings, force, present);
22911
- if (hookResult.ok) {
22912
- await writeSettings(hookResult.data);
22913
- printInfo(" Stop hook: verity analyze \u2713");
22914
- printInfo(" Intent hook: verity intent capture \u2713");
22915
- printInfo(" Baseline hook: verity baseline capture \u2713");
22916
- } else {
22917
- printWarn(` ${hookResult.error}`);
22918
- printInfo(' Run "verity hooks install --force" to overwrite.');
23661
+ printInfo(` ${skillsInstalled}/${SKILLS.length} skills installed to .claude/skills/ \u2713`);
23662
+ step(defaultsOnly ? "Setup answers (defaults)" : "Your setup answers");
23663
+ const previous = await readSetupState();
23664
+ const answers = await askSetupQuestions(defaultsOnly, previous);
23665
+ const { intensity, moments } = answers;
23666
+ if (defaultsOnly) {
23667
+ printInfo(` intensity: ${intensity} \xB7 moments: ${moments.join(", ") || "none"} (no questions asked)`);
22919
23668
  }
22920
- await (0, import_promises13.mkdir)(VERITY_DIR, { recursive: true });
23669
+ step("Knowledge base, .gitignore and CLAUDE.md");
23670
+ await (0, import_promises14.mkdir)(VERITY_DIR, { recursive: true });
22921
23671
  await ensureMemoryDir();
22922
- const ignoreResult = ensureSnapshotGitignored();
23672
+ const ignoreResult = ensureVerityGitignore();
22923
23673
  if (ignoreResult === "failed") {
22924
- printWarn(" .gitignore: could not add .verity/.snapshot/ \u2014 add it manually (it holds copies of analyzed files)");
23674
+ printWarn(" .gitignore: could not write the Verity block \u2014 add it manually");
23675
+ printWarn(" (.verity/ holds copies of analyzed files, including any secret the gate flagged)");
23676
+ } else if (ignoreResult === "conflict") {
23677
+ printWarn(" .gitignore: the Verity block is in place but git still ignores .verity/standard.yaml");
23678
+ printWarn(" Something outside this file covers it \u2014 a global (~/.gitignore) or nested");
23679
+ printWarn(" .gitignore, or a pattern we do not recognise. Check: git check-ignore -v .verity/standard.yaml");
23680
+ printWarn(" Until it is fixed, the Standard and the knowledge graph cannot be committed.");
23681
+ } else if (ignoreResult === "repaired") {
23682
+ printInfo(" .gitignore: rewrote `.verity/` to `.verity/*` so the standard stays committable \u2713");
22925
23683
  } else {
22926
- printInfo(` .gitignore: .verity/.snapshot/ ${ignoreResult === "added" ? "added" : "already covered"} \u2713`);
23684
+ printInfo(` .gitignore: Verity block ${ignoreResult === "added" ? "added" : "already covered"} \u2713`);
23685
+ }
23686
+ const tracked = committedVerityState();
23687
+ if (tracked.length > 0) {
23688
+ printWarn(` ${tracked.length} Verity state file(s) are tracked in git (e.g. ${tracked[0]}).`);
23689
+ const untrack = defaultsOnly ? false : await promptYes(" Untrack them now (files stay on disk)? [Y/n] ", { nonInteractive: false });
23690
+ if (untrack) {
23691
+ const result = untrackVerityState();
23692
+ if (result === "untracked") printInfo(" Untracked (staged) \u2014 commit to finish \u2713");
23693
+ else if (result === "failed") printWarn(' Could not untrack \u2014 run "git rm -r --cached .verity" manually');
23694
+ } else {
23695
+ printWarn(" Left tracked. Fix with: git rm -r --cached .verity && git add .verity/standard.yaml .verity/memory");
23696
+ }
22927
23697
  }
22928
23698
  try {
22929
23699
  await ensureClaudeMdPointer();
22930
- printInfo(" CLAUDE.md memory pointer \u2713");
23700
+ printInfo(" CLAUDE.md instructions \u2713");
22931
23701
  } catch (err) {
22932
23702
  printWarn(` Could not update CLAUDE.md: ${err.message}`);
22933
23703
  }
22934
23704
  const globalVerityDir = (0, import_node_path29.join)(process.env.HOME ?? "", ".verity");
22935
- await (0, import_promises13.mkdir)(globalVerityDir, { recursive: true });
23705
+ await (0, import_promises14.mkdir)(globalVerityDir, { recursive: true });
23706
+ console.log("");
23707
+ step("Wiring Claude Code hooks");
23708
+ await applyMomentSelection(moments);
23709
+ const hookStatus = await checkAllVerityHooks();
23710
+ printInfo(` Stop (verity analyze): ${hookStatus.stop ? "on" : "off"}`);
23711
+ printInfo(` Pre-commit gate: ${hookStatus.guardOn.includes("commit") ? "on" : "off"}`);
23712
+ printInfo(` Pre-push/PR gate: ${hookStatus.guardOn.includes("push") ? "on" : "off"}`);
23713
+ printInfo(` Intent + baseline + compact + session-end: always on \u2713`);
23714
+ if (!hookStatus.stop && hookStatus.guardOn.length === 0) {
23715
+ printWarn(" No analysis moment is active \u2014 code changes will NOT be reviewed.");
23716
+ printWarn(" Enable one: verity hooks install --moments stop");
23717
+ }
22936
23718
  console.log("");
23719
+ step("Sign in to Verity (optional)");
22937
23720
  try {
22938
23721
  const globals = program2.opts();
22939
23722
  const resolution = await resolveServiceUrlForAuth(globals.serviceUrl);
22940
23723
  await runOptionalAuth(resolution, {
22941
23724
  token: globals.token,
22942
- verbose: globals.verbose
23725
+ verbose: globals.verbose,
23726
+ yes: defaultsOnly
22943
23727
  });
22944
23728
  } catch (err) {
22945
23729
  printWarn(`Authentication step skipped: ${err.message}`);
22946
23730
  }
23731
+ const resumeDeferred = answers.telemetry === "not-asked" && resumeDeferredPending(previous);
23732
+ const wantsTelemetry = answers.telemetry === "yes" || resumeDeferred;
23733
+ step("Cost & usage telemetry");
23734
+ if (answers.telemetry === "not-asked" && !resumeDeferredPending(previous)) {
23735
+ printInfo(' not asked (unattended run) \u2014 enable later with "verity telemetry install"');
23736
+ } else if (answers.telemetry === "no") {
23737
+ printInfo(' declined \u2014 enable later with "verity telemetry install"');
23738
+ }
23739
+ let telemetryChoice = answers.telemetry === "already-on" ? "enabled" : answers.telemetry === "no" ? "declined" : wantsTelemetry ? "deferred" : void 0;
23740
+ if (wantsTelemetry) {
23741
+ const globals = program2.opts();
23742
+ const token = await resolveToken(globals.token);
23743
+ const url = await resolveServiceUrl(globals.serviceUrl);
23744
+ if (token.ok && url.ok) {
23745
+ const installed2 = await installTelemetry(url.data);
23746
+ if (installed2.ok) {
23747
+ telemetryChoice = "enabled";
23748
+ printInfo(`Telemetry enabled \u2192 ${installed2.data.endpoint}`);
23749
+ printInfo(" takes effect on your NEXT Claude Code session; view cost & usage at /usage");
23750
+ } else {
23751
+ printWarn(`Could not enable telemetry: ${installed2.error}`);
23752
+ }
23753
+ } else {
23754
+ printWarn('Telemetry needs a Verity token \u2014 run "verity login", then "verity telemetry install".');
23755
+ }
23756
+ }
23757
+ step("Recording your answers");
23758
+ try {
23759
+ await writeSetupState({
23760
+ intensity,
23761
+ moments,
23762
+ ...telemetryChoice ? { telemetry: telemetryChoice } : {},
23763
+ init: {
23764
+ completed_at: (/* @__PURE__ */ new Date()).toISOString(),
23765
+ cli_version: true ? "0.31.1-experimental.be74f71" : "dev"
23766
+ }
23767
+ });
23768
+ } catch (err) {
23769
+ printWarn(`Could not record setup answers: ${err.message}`);
23770
+ }
22947
23771
  console.log("");
22948
- printInfo("Verity initialized!");
23772
+ printInfo("This machine is set up.");
22949
23773
  console.log("");
22950
- console.log(" Installed:");
22951
- console.log(" .claude/skills/verity-setup/ \u2014 project configuration");
22952
- console.log(" .claude/skills/verity-analyze/ \u2014 on-demand analysis");
22953
- console.log(" .claude/skills/verity-status/ \u2014 project health");
22954
- console.log(" .claude/skills/verity-feedback/ \u2014 finding feedback + suppressions");
22955
- console.log(" .claude/skills/verity-learn/ \u2014 view project knowledge");
22956
- console.log(" .claude/skills/verity-memory/ \u2014 browse knowledge graph");
22957
- console.log(" .claude/skills/verity-insights/ \u2014 quality metrics + evolution");
22958
- console.log(" .claude/skills/verity-reflect/ \u2014 capture learnings");
22959
- console.log(" .claude/settings.json \u2014 hooks (verity analyze + intent capture)");
22960
- console.log(" .verity/memory/ \u2014 knowledge base (8 domains, commit to git)");
23774
+ console.log(" .claude/skills/verity-*/ 8 skills (setup, analyze, status, feedback,");
23775
+ console.log(" learn, memory, insights, reflect)");
23776
+ console.log(" .claude/settings.json hooks, reconciled to your chosen moments");
23777
+ console.log(" .verity/memory/ knowledge base (commit to git)");
23778
+ console.log(" .verity/setup.json your answers, read by /verity-setup");
23779
+ console.log(" .gitignore Verity block (whitelist form)");
23780
+ console.log(" CLAUDE.md memory pointer, waive policy, reflection");
22961
23781
  console.log("");
22962
- console.log(" Next step: open this project in Claude Code and run /verity-setup");
22963
- console.log(' (Not authenticated? Verity runs in local-only mode until you run "verity login".)');
23782
+ console.log(` Intensity: ${intensity} Moments: ${moments.join(", ") || "none"}`);
23783
+ await handoffToSetup(wantsHandoff, claudeInstalled);
22964
23784
  console.log("");
22965
23785
  });
22966
23786
  }
22967
23787
 
22968
23788
  // src/commands/uninstall.ts
22969
- var import_node_fs42 = require("node:fs");
23789
+ var import_node_fs45 = require("node:fs");
22970
23790
  var import_node_path30 = require("node:path");
22971
23791
  var SKILL_NAMES = [
22972
23792
  "verity-setup",
@@ -22987,10 +23807,10 @@ function registerUninstallCommand(program2) {
22987
23807
  const skillsRoot = projectPath(".claude/skills");
22988
23808
  for (const name of SKILL_NAMES) {
22989
23809
  const dir = (0, import_node_path30.join)(skillsRoot, name);
22990
- if ((0, import_node_fs42.existsSync)(dir)) {
23810
+ if ((0, import_node_fs45.existsSync)(dir)) {
22991
23811
  actions.push({
22992
23812
  label: `Remove .claude/skills/${name}/`,
22993
- apply: () => (0, import_node_fs42.rmSync)(dir, { recursive: true, force: true })
23813
+ apply: () => (0, import_node_fs45.rmSync)(dir, { recursive: true, force: true })
22994
23814
  });
22995
23815
  }
22996
23816
  }
@@ -23004,24 +23824,24 @@ function registerUninstallCommand(program2) {
23004
23824
  });
23005
23825
  }
23006
23826
  const verityDir = projectPath(VERITY_DIR);
23007
- if ((0, import_node_fs42.existsSync)(verityDir)) {
23827
+ if ((0, import_node_fs45.existsSync)(verityDir)) {
23008
23828
  actions.push({
23009
23829
  label: `Remove ${VERITY_DIR}/`,
23010
- apply: () => (0, import_node_fs42.rmSync)(verityDir, { recursive: true, force: true })
23830
+ apply: () => (0, import_node_fs45.rmSync)(verityDir, { recursive: true, force: true })
23011
23831
  });
23012
23832
  }
23013
23833
  if (!keepVerityMd) {
23014
23834
  const verityMd = projectPath(VERITY_MD_FILE);
23015
- if ((0, import_node_fs42.existsSync)(verityMd)) {
23835
+ if ((0, import_node_fs45.existsSync)(verityMd)) {
23016
23836
  actions.push({
23017
23837
  label: `Remove ${VERITY_MD_FILE}`,
23018
- apply: () => (0, import_node_fs42.rmSync)(verityMd, { force: true })
23838
+ apply: () => (0, import_node_fs45.rmSync)(verityMd, { force: true })
23019
23839
  });
23020
23840
  }
23021
23841
  }
23022
23842
  const cleanupEmptyDir = (path) => {
23023
- if ((0, import_node_fs42.existsSync)(path) && (0, import_node_fs42.statSync)(path).isDirectory() && (0, import_node_fs42.readdirSync)(path).length === 0) {
23024
- (0, import_node_fs42.rmdirSync)(path);
23843
+ if ((0, import_node_fs45.existsSync)(path) && (0, import_node_fs45.statSync)(path).isDirectory() && (0, import_node_fs45.readdirSync)(path).length === 0) {
23844
+ (0, import_node_fs45.rmdirSync)(path);
23025
23845
  }
23026
23846
  };
23027
23847
  actions.push({
@@ -23033,10 +23853,10 @@ function registerUninstallCommand(program2) {
23033
23853
  });
23034
23854
  const home = process.env.HOME ?? "";
23035
23855
  const globalVerityDir = (0, import_node_path30.join)(home, ".verity");
23036
- if (purgeGlobal && (0, import_node_fs42.existsSync)(globalVerityDir)) {
23856
+ if (purgeGlobal && (0, import_node_fs45.existsSync)(globalVerityDir)) {
23037
23857
  actions.push({
23038
23858
  label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
23039
- apply: () => (0, import_node_fs42.rmSync)(globalVerityDir, { recursive: true, force: true })
23859
+ apply: () => (0, import_node_fs45.rmSync)(globalVerityDir, { recursive: true, force: true })
23040
23860
  });
23041
23861
  }
23042
23862
  if (actions.length === 0) {
@@ -23056,7 +23876,7 @@ function registerUninstallCommand(program2) {
23056
23876
  if (!purgeGlobal) {
23057
23877
  printInfo('Saved tokens at ~/.verity/credentials are preserved \u2014 re-run "verity init" to reconnect.');
23058
23878
  } else {
23059
- printWarn("Global credentials wiped \u2014 re-register with /verity-setup to reconnect.");
23879
+ printWarn('Global credentials wiped \u2014 run "verity login" (or "verity init") to reconnect.');
23060
23880
  }
23061
23881
  });
23062
23882
  }
@@ -23230,7 +24050,7 @@ function registerTaskCommands(program2) {
23230
24050
  }
23231
24051
 
23232
24052
  // src/commands/reset.ts
23233
- var import_node_fs43 = require("node:fs");
24053
+ var import_node_fs46 = require("node:fs");
23234
24054
  var import_node_path31 = require("node:path");
23235
24055
  function registerResetCommand(program2) {
23236
24056
  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) => {
@@ -23268,11 +24088,11 @@ function registerResetCommand(program2) {
23268
24088
  }
23269
24089
  const cacheDir = projectPath(CACHE_DIR);
23270
24090
  let purged = 0;
23271
- if ((0, import_node_fs43.existsSync)(cacheDir)) {
23272
- for (const entry of (0, import_node_fs43.readdirSync)(cacheDir)) {
24091
+ if ((0, import_node_fs46.existsSync)(cacheDir)) {
24092
+ for (const entry of (0, import_node_fs46.readdirSync)(cacheDir)) {
23273
24093
  if (entry.startsWith("pending-")) {
23274
24094
  try {
23275
- (0, import_node_fs43.unlinkSync)((0, import_node_path31.join)(cacheDir, entry));
24095
+ (0, import_node_fs46.unlinkSync)((0, import_node_path31.join)(cacheDir, entry));
23276
24096
  purged++;
23277
24097
  } catch {
23278
24098
  }
@@ -23287,19 +24107,19 @@ function registerResetCommand(program2) {
23287
24107
  projectPath(`${VERITY_DIR}/.last-analysis`)
23288
24108
  ];
23289
24109
  for (const file of filesToClear) {
23290
- if ((0, import_node_fs43.existsSync)(file)) {
24110
+ if ((0, import_node_fs46.existsSync)(file)) {
23291
24111
  try {
23292
- (0, import_node_fs43.writeFileSync)(file, "");
24112
+ (0, import_node_fs46.writeFileSync)(file, "");
23293
24113
  } catch {
23294
24114
  }
23295
24115
  }
23296
24116
  }
23297
24117
  if (opts.all) {
23298
24118
  const logsDir = projectPath(`${VERITY_DIR}/.logs`);
23299
- if ((0, import_node_fs43.existsSync)(logsDir)) {
23300
- for (const entry of (0, import_node_fs43.readdirSync)(logsDir)) {
24119
+ if ((0, import_node_fs46.existsSync)(logsDir)) {
24120
+ for (const entry of (0, import_node_fs46.readdirSync)(logsDir)) {
23301
24121
  try {
23302
- (0, import_node_fs43.unlinkSync)((0, import_node_path31.join)(logsDir, entry));
24122
+ (0, import_node_fs46.unlinkSync)((0, import_node_path31.join)(logsDir, entry));
23303
24123
  } catch {
23304
24124
  }
23305
24125
  }
@@ -23607,8 +24427,8 @@ function registerTelemetryCommands(program2) {
23607
24427
  }
23608
24428
 
23609
24429
  // src/cli.ts
23610
- program.name("verity").description("CLI for Verity quality gate service").version("0.31.1-experimental.80cf3ac").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) => {
23611
- installStderrLog(actionCommand.name(), process.argv.slice(2), "0.31.1-experimental.80cf3ac");
24430
+ program.name("verity").description("CLI for Verity quality gate service").version("0.31.1-experimental.be74f71").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) => {
24431
+ installStderrLog(actionCommand.name(), process.argv.slice(2), "0.31.1-experimental.be74f71");
23612
24432
  setUserNamedServiceUrl(program.opts().serviceUrl);
23613
24433
  try {
23614
24434
  await foldLegacyLocalCredential();
@@ -23634,6 +24454,7 @@ registerGuardCommand(program);
23634
24454
  registerIgnoreCommand(program);
23635
24455
  registerWaiveCommand(program);
23636
24456
  registerInitCommand(program);
24457
+ registerDoctorCommand(program);
23637
24458
  registerUninstallCommand(program);
23638
24459
  registerTaskCommands(program);
23639
24460
  registerResetCommand(program);