@codacy/verity-cli 0.23.3 → 0.24.0-experimental.6a390ac

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
@@ -10379,6 +10379,7 @@ var MAX_PLAN_FILES = 3;
10379
10379
  var MAX_PLAN_FILE_BYTES = 10240;
10380
10380
  var MAX_INTENT_CHARS = 2e3;
10381
10381
  var SNAPSHOT_DIR = `${VERITY_DIR}/.snapshot`;
10382
+ var BASELINE_DIR = `${VERITY_DIR}/.baseline`;
10382
10383
  var CONVERSATION_BUFFER_FILE = `${VERITY_DIR}/.conversation-buffer`;
10383
10384
  var CONVERSATION_MAX_ENTRIES = 10;
10384
10385
  var CONVERSATION_WINDOW_MINUTES = 15;
@@ -10473,7 +10474,8 @@ var SECURITY_PATTERNS = [
10473
10474
  /Cargo\.lock$/,
10474
10475
  /Dockerfile/
10475
10476
  ];
10476
- var DEFAULT_SERVICE_URL = "https://ofcamwrjwrkazqvdchko.supabase.co/functions/v1";
10477
+ var PROD_SERVICE_URL = "https://ofcamwrjwrkazqvdchko.supabase.co/functions/v1";
10478
+ var DEFAULT_SERVICE_URL = "https://yykkfdexzljmmkklpgyz.supabase.co/functions/v1".length > 0 ? "https://yykkfdexzljmmkklpgyz.supabase.co/functions/v1" : PROD_SERVICE_URL;
10477
10479
 
10478
10480
  // src/lib/auth.ts
10479
10481
  async function resolveToken(flagToken) {
@@ -10848,6 +10850,10 @@ var VERITY_INTENT_HOOK = {
10848
10850
  type: "command",
10849
10851
  command: "verity intent capture"
10850
10852
  };
10853
+ var VERITY_BASELINE_HOOK = {
10854
+ type: "command",
10855
+ command: "verity baseline capture"
10856
+ };
10851
10857
  var GUARD_TIMEOUT = 300;
10852
10858
  function buildGuardHook(on) {
10853
10859
  return {
@@ -10860,9 +10866,13 @@ function buildGuardHook(on) {
10860
10866
  var VERITY_STOP_RE = /(?:^|[\/\s"'])verity\s+analyze\b/;
10861
10867
  var VERITY_INTENT_RE = /(?:^|[\/\s"'])verity\s+intent\s+capture\b/;
10862
10868
  var VERITY_GUARD_RE = /(?:^|[\/\s"'])verity\s+guard\b/;
10869
+ var VERITY_BASELINE_RE = /(?:^|[\/\s"'])verity\s+baseline\s+capture\b/;
10863
10870
  function isVerityGuardHook(entry) {
10864
10871
  return VERITY_GUARD_RE.test(entry.command ?? "");
10865
10872
  }
10873
+ function isVerityBaselineHook(entry) {
10874
+ return VERITY_BASELINE_RE.test(entry.command ?? "");
10875
+ }
10866
10876
  var LEGACY_STOP_RE = /(?:^|[\/\s"'])gate\s+analyze\b/;
10867
10877
  var LEGACY_INTENT_RE = /(?:^|[\/\s"'])gate\s+intent\s+capture\b/;
10868
10878
  function isVerityStopHook(entry) {
@@ -10874,7 +10884,7 @@ function isVerityIntentHook(entry) {
10874
10884
  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");
10875
10885
  }
10876
10886
  function isVerityHook(entry) {
10877
- return isVerityStopHook(entry) || isVerityIntentHook(entry) || isVerityGuardHook(entry);
10887
+ return isVerityStopHook(entry) || isVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry);
10878
10888
  }
10879
10889
  function isCurrentVerityStopHook(entry) {
10880
10890
  const c = entry.command ?? "";
@@ -10885,7 +10895,7 @@ function isCurrentVerityIntentHook(entry) {
10885
10895
  return VERITY_INTENT_RE.test(c) || c.includes(".verity/hooks/capture-intent.sh");
10886
10896
  }
10887
10897
  function isCurrentVerityHook(entry) {
10888
- return isCurrentVerityStopHook(entry) || isCurrentVerityIntentHook(entry) || isVerityGuardHook(entry);
10898
+ return isCurrentVerityStopHook(entry) || isCurrentVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry);
10889
10899
  }
10890
10900
  function settingsHasLegacyHook(settings) {
10891
10901
  for (const groups of Object.values(settings.hooks ?? {})) {
@@ -10927,16 +10937,18 @@ async function readAllSettings() {
10927
10937
  async function checkAllVerityHooks() {
10928
10938
  let stop = false;
10929
10939
  let intent = false;
10940
+ let baseline = false;
10930
10941
  let guard = false;
10931
10942
  let guardOn = [];
10932
10943
  for (const settings of await readAllSettings()) {
10933
10944
  const r = checkVerityHooks(settings);
10934
10945
  stop = stop || r.stop;
10935
10946
  intent = intent || r.intent;
10947
+ baseline = baseline || r.baseline;
10936
10948
  guard = guard || r.guard;
10937
10949
  if (r.guardOn.length > guardOn.length) guardOn = r.guardOn;
10938
10950
  }
10939
- return { stop, intent, guard, guardOn };
10951
+ return { stop, intent, baseline, guard, guardOn };
10940
10952
  }
10941
10953
  async function checkExternalVerityHooks() {
10942
10954
  let stop = false;
@@ -10959,12 +10971,14 @@ async function checkExternalVerityHooks() {
10959
10971
  async function checkAllVerityHooksDetailed() {
10960
10972
  let stop = false;
10961
10973
  let intent = false;
10974
+ let baseline = false;
10962
10975
  let hasCurrent = false;
10963
10976
  let hasLegacy = false;
10964
10977
  for (const settings of await readAllSettings()) {
10965
10978
  const r = checkVerityHooks(settings);
10966
10979
  stop = stop || r.stop;
10967
10980
  intent = intent || r.intent;
10981
+ baseline = baseline || r.baseline;
10968
10982
  for (const groups of Object.values(settings.hooks ?? {})) {
10969
10983
  for (const g of groups ?? []) {
10970
10984
  for (const h of g.hooks ?? []) {
@@ -10974,7 +10988,7 @@ async function checkAllVerityHooksDetailed() {
10974
10988
  }
10975
10989
  }
10976
10990
  }
10977
- return { stop, intent, current: hasCurrent, legacyOnly: hasLegacy && !hasCurrent };
10991
+ return { stop, intent, baseline, current: hasCurrent, legacyOnly: hasLegacy && !hasCurrent };
10978
10992
  }
10979
10993
  async function writeSettings(settings) {
10980
10994
  await (0, import_promises4.mkdir)((0, import_node_path3.dirname)(CLAUDE_SETTINGS_FILE), { recursive: true });
@@ -11017,6 +11031,10 @@ function checkVerityHooks(settings) {
11017
11031
  const hasIntent = intentGroups.some(
11018
11032
  (g) => g.hooks?.some((h) => isCurrentVerityIntentHook(h))
11019
11033
  );
11034
+ const sessionStartGroups = hooks["SessionStart"] ?? [];
11035
+ const hasBaseline = sessionStartGroups.some(
11036
+ (g) => g.hooks?.some((h) => isVerityBaselineHook(h))
11037
+ );
11020
11038
  let guard = false;
11021
11039
  let guardOn = [];
11022
11040
  for (const g of hooks["PreToolUse"] ?? []) {
@@ -11029,16 +11047,17 @@ function checkVerityHooks(settings) {
11029
11047
  }
11030
11048
  }
11031
11049
  }
11032
- return { stop: hasStop, intent: hasIntent, guard, guardOn };
11050
+ return { stop: hasStop, intent: hasIntent, baseline: hasBaseline, guard, guardOn };
11033
11051
  }
11034
- function installVerityHooks(settings, force, externalPresent = { stop: false, intent: false }) {
11052
+ function installVerityHooks(settings, force, externalPresent = { stop: false, intent: false, baseline: false }) {
11035
11053
  const local = checkVerityHooks(settings);
11036
11054
  const existing = {
11037
11055
  stop: local.stop || externalPresent.stop,
11038
- intent: local.intent || externalPresent.intent
11056
+ intent: local.intent || externalPresent.intent,
11057
+ baseline: local.baseline || (externalPresent.baseline ?? false)
11039
11058
  };
11040
11059
  const hasLocalLegacy = settingsHasLegacyHook(settings);
11041
- if (existing.stop && existing.intent && !force && !hasLocalLegacy) {
11060
+ if (existing.stop && existing.intent && existing.baseline && !force && !hasLocalLegacy) {
11042
11061
  return { ok: false, error: "Verity hooks already installed. Use --force to overwrite." };
11043
11062
  }
11044
11063
  const newSettings = { ...settings };
@@ -11046,7 +11065,7 @@ function installVerityHooks(settings, force, externalPresent = { stop: false, in
11046
11065
  newSettings.hooks = {};
11047
11066
  }
11048
11067
  const shouldStrip = force ? isVerityHook : isLegacyHook;
11049
- for (const key of ["Stop", "UserPromptSubmit"]) {
11068
+ for (const key of ["Stop", "UserPromptSubmit", "SessionStart"]) {
11050
11069
  const groups = newSettings.hooks[key];
11051
11070
  if (groups) {
11052
11071
  newSettings.hooks[key] = groups.map((g) => ({
@@ -11073,6 +11092,15 @@ function installVerityHooks(settings, force, externalPresent = { stop: false, in
11073
11092
  if (!newSettings.hooks["UserPromptSubmit"]) newSettings.hooks["UserPromptSubmit"] = [];
11074
11093
  newSettings.hooks["UserPromptSubmit"].push({ hooks: [VERITY_INTENT_HOOK] });
11075
11094
  }
11095
+ if (!existing.baseline) {
11096
+ if (!newSettings.hooks["SessionStart"]) {
11097
+ newSettings.hooks["SessionStart"] = [];
11098
+ }
11099
+ newSettings.hooks["SessionStart"].push({ hooks: [VERITY_BASELINE_HOOK] });
11100
+ } else if (force && local.baseline) {
11101
+ if (!newSettings.hooks["SessionStart"]) newSettings.hooks["SessionStart"] = [];
11102
+ newSettings.hooks["SessionStart"].push({ hooks: [VERITY_BASELINE_HOOK] });
11103
+ }
11076
11104
  return { ok: true, data: newSettings };
11077
11105
  }
11078
11106
  function removeVerityHooks(settings) {
@@ -11106,6 +11134,7 @@ function reconcileMomentHooks(settings, moments, externalPresent = {
11106
11134
  (s.hooks[event] ??= []).push(group);
11107
11135
  };
11108
11136
  if (!externalPresent.intent) push("UserPromptSubmit", { hooks: [VERITY_INTENT_HOOK] });
11137
+ push("SessionStart", { hooks: [VERITY_BASELINE_HOOK] });
11109
11138
  if (moments.includes("stop") && !externalPresent.stop) {
11110
11139
  push("Stop", { hooks: [VERITY_STOP_HOOK] });
11111
11140
  }
@@ -11154,7 +11183,7 @@ function registerHooksCommands(program2) {
11154
11183
  return;
11155
11184
  }
11156
11185
  const detail = await checkAllVerityHooksDetailed();
11157
- const present = { stop: detail.stop, intent: detail.intent };
11186
+ const present = { stop: detail.stop, intent: detail.intent, baseline: detail.baseline };
11158
11187
  if (detail.legacyOnly) {
11159
11188
  printInfo("Found a legacy GATE.md hook \u2014 upgrading it to Verity...");
11160
11189
  const settings2 = removeVerityHooks(await readSettings());
@@ -11167,11 +11196,12 @@ function registerHooksCommands(program2) {
11167
11196
  printInfo("Verity hooks installed in .claude/settings.json (legacy hook removed)");
11168
11197
  printInfo(" Stop hook: verity analyze");
11169
11198
  printInfo(" UserPromptSubmit hook: verity intent capture");
11199
+ printInfo(" SessionStart hook: verity baseline capture");
11170
11200
  return;
11171
11201
  }
11172
11202
  const settings = await readSettings();
11173
11203
  const hasLocalLegacy = settingsHasLegacyHook(settings);
11174
- if (!force && present.stop && present.intent && !hasLocalLegacy) {
11204
+ if (!force && present.stop && present.intent && present.baseline && !hasLocalLegacy) {
11175
11205
  printInfo("Verity hooks already installed (found in .claude/settings.json, settings.local.json, or your global settings).");
11176
11206
  printInfo("Use --force to rewrite the project settings.json copy.");
11177
11207
  return;
@@ -11185,11 +11215,13 @@ function registerHooksCommands(program2) {
11185
11215
  printInfo("Verity hooks installed in .claude/settings.json");
11186
11216
  printInfo(" Stop hook: verity analyze");
11187
11217
  printInfo(" UserPromptSubmit hook: verity intent capture");
11218
+ printInfo(" SessionStart hook: verity baseline capture");
11188
11219
  });
11189
11220
  hooks.command("check").description("Check if Verity hooks are installed").action(async () => {
11190
11221
  const status = await checkAllVerityHooks();
11191
11222
  printInfo(`Stop hook (verity analyze): ${status.stop ? "installed" : "not installed"}`);
11192
11223
  printInfo(`Intent hook (verity intent capture): ${status.intent ? "installed" : "not installed"}`);
11224
+ printInfo(`Baseline hook (verity baseline capture): ${status.baseline ? "installed" : "not installed"}`);
11193
11225
  const gates = status.guard ? status.guardOn.join(", ") : "none";
11194
11226
  printInfo(`Git-moment gate (verity guard): ${status.guard ? `installed [${gates}]` : "not installed"}`);
11195
11227
  if (!status.stop && !status.guard) {
@@ -11242,15 +11274,28 @@ async function appendToConversationBuffer(prompt, sessionId) {
11242
11274
  } catch {
11243
11275
  }
11244
11276
  }
11245
- async function readAndClearConversationBuffer() {
11277
+ async function readAndClearConversationBuffer(currentSessionId) {
11246
11278
  try {
11247
11279
  if ((0, import_node_fs2.existsSync)(CONVERSATION_BUFFER_FILE)) {
11248
11280
  const entries = await readBufferEntries();
11249
- await (0, import_promises5.unlink)(CONVERSATION_BUFFER_FILE).catch(() => {
11250
- });
11251
- if (entries.length > 0) {
11281
+ let mine = entries;
11282
+ let others = [];
11283
+ if (currentSessionId) {
11284
+ mine = entries.filter((e) => e.session_id === currentSessionId || !e.session_id);
11285
+ others = entries.filter((e) => e.session_id && e.session_id !== currentSessionId);
11286
+ }
11287
+ if (others.length > 0) {
11288
+ const remaining = others.map((e) => JSON.stringify(e)).join("\n") + "\n";
11289
+ const tmpFile = `${CONVERSATION_BUFFER_FILE}.tmp`;
11290
+ await (0, import_promises5.writeFile)(tmpFile, remaining);
11291
+ await (0, import_promises5.rename)(tmpFile, CONVERSATION_BUFFER_FILE);
11292
+ } else {
11293
+ await (0, import_promises5.unlink)(CONVERSATION_BUFFER_FILE).catch(() => {
11294
+ });
11295
+ }
11296
+ if (mine.length > 0) {
11252
11297
  return {
11253
- prompts: entries,
11298
+ prompts: mine,
11254
11299
  recent_commits: getRecentCommitMessages()
11255
11300
  };
11256
11301
  }
@@ -12718,8 +12763,8 @@ async function sendGeneralFeedback(message, opts, globals) {
12718
12763
  }
12719
12764
 
12720
12765
  // src/commands/analyze.ts
12721
- var import_node_fs18 = require("node:fs");
12722
- var import_node_path13 = require("node:path");
12766
+ var import_node_fs19 = require("node:fs");
12767
+ var import_node_path14 = require("node:path");
12723
12768
 
12724
12769
  // src/lib/git.ts
12725
12770
  var import_node_child_process5 = require("node:child_process");
@@ -12811,6 +12856,26 @@ function getChangedFiles() {
12811
12856
  function getStagedFiles() {
12812
12857
  return splitLines(execGit("git diff --cached --name-only")).filter((f) => !f.startsWith(".verity/") && !f.startsWith(".verity\\"));
12813
12858
  }
12859
+ function getDirtyFiles() {
12860
+ const set = /* @__PURE__ */ new Set();
12861
+ for (const f of splitLines(execGit("git diff --name-only HEAD"))) set.add(f);
12862
+ for (const f of splitLines(execGit("git diff --name-only --cached"))) set.add(f);
12863
+ for (const f of splitLines(execGit("git ls-files --others --exclude-standard"))) set.add(f);
12864
+ return Array.from(set).filter((f) => !f.startsWith(".verity/") && !f.startsWith(".verity\\"));
12865
+ }
12866
+ function showContentAtRef(ref, repoRelPath) {
12867
+ if (!ref || ref === "no-git") return null;
12868
+ const normalizedPath = repoRelPath.replace(/\\/g, "/");
12869
+ try {
12870
+ return (0, import_node_child_process5.execFileSync)("git", ["show", `${ref}:${normalizedPath}`], {
12871
+ encoding: "utf-8",
12872
+ maxBuffer: 64 * 1024 * 1024,
12873
+ stdio: ["pipe", "pipe", "pipe"]
12874
+ });
12875
+ } catch {
12876
+ return null;
12877
+ }
12878
+ }
12814
12879
  function getPushRangeFiles() {
12815
12880
  const diff = (range) => splitLines(execGit(`git diff --name-only ${range}`)).filter((f) => !f.startsWith(".verity/") && !f.startsWith(".verity\\"));
12816
12881
  const resolvers = [
@@ -13463,15 +13528,207 @@ function cleanStaleSnapshots(dir, keepSet) {
13463
13528
  }
13464
13529
  }
13465
13530
 
13466
- // src/lib/offline.ts
13531
+ // src/lib/baseline.ts
13467
13532
  var import_node_fs13 = require("node:fs");
13533
+ var import_node_path11 = require("node:path");
13468
13534
  var import_node_crypto4 = require("node:crypto");
13535
+ var BASELINE_VERSION = 1;
13536
+ var BASELINE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
13537
+ var MIRROR_MAX_BYTES = 2 * 1024 * 1024;
13538
+ var DEFAULT_SESSION_KEY = "_default";
13539
+ function sessionKey(sessionId) {
13540
+ if (!sessionId) return DEFAULT_SESSION_KEY;
13541
+ return (0, import_node_crypto4.createHash)("sha256").update(sessionId).digest("hex").slice(0, 16);
13542
+ }
13543
+ function sessionDir(key) {
13544
+ return (0, import_node_path11.join)(projectPath(BASELINE_DIR), key);
13545
+ }
13546
+ function manifestPath(dir) {
13547
+ return (0, import_node_path11.join)(dir, "manifest.json");
13548
+ }
13549
+ function mirrorPath(dir, repoRelPath) {
13550
+ return (0, import_node_path11.join)(dir, "files", repoRelPath);
13551
+ }
13552
+ function captureBaseline(opts = {}) {
13553
+ const key = sessionKey(opts.sessionId);
13554
+ const dir = sessionDir(key);
13555
+ const existing = readManifest(dir);
13556
+ const freshStart = opts.source === "startup" || opts.source === "clear";
13557
+ if (existing && !freshStart) {
13558
+ return { baseline: existing, created: false };
13559
+ }
13560
+ const head_sha = getCurrentCommit();
13561
+ const dirty = getDirtyFiles();
13562
+ try {
13563
+ (0, import_node_fs13.rmSync)(dir, { recursive: true, force: true });
13564
+ } catch {
13565
+ }
13566
+ const filesDir = (0, import_node_path11.join)(dir, "files");
13567
+ const mirrored = [];
13568
+ try {
13569
+ (0, import_node_fs13.mkdirSync)(filesDir, { recursive: true });
13570
+ for (const p of dirty) {
13571
+ if (p.includes("..")) continue;
13572
+ const content = safeReadForMirror(projectPath(p));
13573
+ if (content === null) continue;
13574
+ const dest = mirrorPath(dir, p);
13575
+ try {
13576
+ (0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(dest), { recursive: true });
13577
+ (0, import_node_fs13.writeFileSync)(dest, content);
13578
+ mirrored.push(p);
13579
+ } catch {
13580
+ }
13581
+ }
13582
+ } catch {
13583
+ }
13584
+ const baseline = {
13585
+ session_id: opts.sessionId ?? "",
13586
+ head_sha,
13587
+ captured_at: Date.now(),
13588
+ dirty_paths: mirrored,
13589
+ version: BASELINE_VERSION
13590
+ };
13591
+ try {
13592
+ (0, import_node_fs13.mkdirSync)(dir, { recursive: true });
13593
+ (0, import_node_fs13.writeFileSync)(manifestPath(dir), JSON.stringify(baseline));
13594
+ } catch {
13595
+ }
13596
+ pruneOldBaselines();
13597
+ return { baseline, created: true };
13598
+ }
13599
+ function readBaseline(sessionId) {
13600
+ return readManifest(sessionDir(sessionKey(sessionId)));
13601
+ }
13602
+ function readManifest(dir) {
13603
+ const mp = manifestPath(dir);
13604
+ if (!(0, import_node_fs13.existsSync)(mp)) return null;
13605
+ try {
13606
+ const parsed = JSON.parse((0, import_node_fs13.readFileSync)(mp, "utf-8"));
13607
+ if (typeof parsed.head_sha !== "string" || typeof parsed.captured_at !== "number" || !Array.isArray(parsed.dirty_paths) || parsed.version !== BASELINE_VERSION) {
13608
+ return null;
13609
+ }
13610
+ return {
13611
+ session_id: typeof parsed.session_id === "string" ? parsed.session_id : "",
13612
+ head_sha: parsed.head_sha,
13613
+ captured_at: parsed.captured_at,
13614
+ dirty_paths: parsed.dirty_paths.filter((p) => typeof p === "string"),
13615
+ version: parsed.version
13616
+ };
13617
+ } catch {
13618
+ return null;
13619
+ }
13620
+ }
13621
+ var preImageCache = /* @__PURE__ */ new WeakMap();
13622
+ function preImage(repoRelPath, baseline) {
13623
+ let perBaseline = preImageCache.get(baseline);
13624
+ if (!perBaseline) {
13625
+ perBaseline = /* @__PURE__ */ new Map();
13626
+ preImageCache.set(baseline, perBaseline);
13627
+ }
13628
+ const cached = perBaseline.get(repoRelPath);
13629
+ if (cached) return cached;
13630
+ const resolved = resolvePreImage(repoRelPath, baseline);
13631
+ perBaseline.set(repoRelPath, resolved);
13632
+ return resolved;
13633
+ }
13634
+ function resolvePreImage(repoRelPath, baseline) {
13635
+ if (baseline.dirty_paths.includes(repoRelPath)) {
13636
+ const mp = mirrorPath(sessionDir(sessionKey(baseline.session_id)), repoRelPath);
13637
+ if ((0, import_node_fs13.existsSync)(mp)) {
13638
+ try {
13639
+ return { content: (0, import_node_fs13.readFileSync)(mp, "utf-8"), existed: true };
13640
+ } catch {
13641
+ }
13642
+ }
13643
+ }
13644
+ const atHead = showContentAtRef(baseline.head_sha, repoRelPath);
13645
+ if (atHead !== null) return { content: atHead, existed: true };
13646
+ return { content: "", existed: false };
13647
+ }
13648
+ function generateBaselineDiffs(files, baseline) {
13649
+ if (!baseline) return { diffs: [], has_baseline: false };
13650
+ const diffs = [];
13651
+ for (const file of files) {
13652
+ const language = file.language ?? detectLanguage(file.path);
13653
+ const pre = preImage(file.path, baseline);
13654
+ if (pre.existed) {
13655
+ if (pre.content === file.content) continue;
13656
+ const diff = computeDiff(pre.content, file.content, file.path);
13657
+ if (diff) diffs.push({ path: file.path, language, diff, status: "modified" });
13658
+ } else {
13659
+ const addedLines = file.content.split("\n").map((l) => `+${l}`).join("\n");
13660
+ diffs.push({
13661
+ path: file.path,
13662
+ language,
13663
+ diff: `--- /dev/null
13664
+ +++ b/${file.path}
13665
+ @@ -0,0 +1,${file.content.split("\n").length} @@
13666
+ ${addedLines}`,
13667
+ status: "added"
13668
+ });
13669
+ }
13670
+ }
13671
+ return { diffs, has_baseline: true };
13672
+ }
13673
+ function changedSinceBaseline(repoRelPath, baseline) {
13674
+ const pre = preImage(repoRelPath, baseline);
13675
+ let current;
13676
+ try {
13677
+ current = (0, import_node_fs13.readFileSync)(projectPath(repoRelPath), "utf-8");
13678
+ } catch {
13679
+ return pre.existed;
13680
+ }
13681
+ if (!pre.existed) return true;
13682
+ return current !== pre.content;
13683
+ }
13684
+ function safeReadForMirror(absPath) {
13685
+ try {
13686
+ if ((0, import_node_fs13.statSync)(absPath).size > MIRROR_MAX_BYTES) return null;
13687
+ const buf = (0, import_node_fs13.readFileSync)(absPath);
13688
+ if (buf.includes(0)) return null;
13689
+ return buf.toString("utf-8");
13690
+ } catch {
13691
+ return null;
13692
+ }
13693
+ }
13694
+ function pruneOldBaselines() {
13695
+ const root = projectPath(BASELINE_DIR);
13696
+ let entries;
13697
+ try {
13698
+ entries = (0, import_node_fs13.readdirSync)(root);
13699
+ } catch {
13700
+ return;
13701
+ }
13702
+ const now = Date.now();
13703
+ for (const name of entries) {
13704
+ const dir = (0, import_node_path11.join)(root, name);
13705
+ const manifest = readManifest(dir);
13706
+ if (!manifest) {
13707
+ try {
13708
+ if (now - (0, import_node_fs13.statSync)(dir).mtimeMs > BASELINE_TTL_MS) {
13709
+ (0, import_node_fs13.rmSync)(dir, { recursive: true, force: true });
13710
+ }
13711
+ } catch {
13712
+ }
13713
+ continue;
13714
+ }
13715
+ if (now - manifest.captured_at <= BASELINE_TTL_MS) continue;
13716
+ try {
13717
+ (0, import_node_fs13.rmSync)(dir, { recursive: true, force: true });
13718
+ } catch {
13719
+ }
13720
+ }
13721
+ }
13722
+
13723
+ // src/lib/offline.ts
13724
+ var import_node_fs14 = require("node:fs");
13725
+ var import_node_crypto5 = require("node:crypto");
13469
13726
  function cacheRequest(body) {
13470
13727
  try {
13471
- (0, import_node_fs13.mkdirSync)(CACHE_DIR, { recursive: true });
13472
- const suffix = (0, import_node_crypto4.randomBytes)(4).toString("hex");
13728
+ (0, import_node_fs14.mkdirSync)(CACHE_DIR, { recursive: true });
13729
+ const suffix = (0, import_node_crypto5.randomBytes)(4).toString("hex");
13473
13730
  const filename = `pending-${Math.floor(Date.now() / 1e3)}-${suffix}.json`;
13474
- (0, import_node_fs13.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(body));
13731
+ (0, import_node_fs14.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(body));
13475
13732
  } catch {
13476
13733
  }
13477
13734
  }
@@ -13485,7 +13742,7 @@ function buildOfflineFallback(reason, staticResults) {
13485
13742
  }
13486
13743
 
13487
13744
  // src/lib/context-files.ts
13488
- var import_node_fs14 = require("node:fs");
13745
+ var import_node_fs15 = require("node:fs");
13489
13746
  var MAX_CONTEXT_FILES = 10;
13490
13747
  var MAX_CONTEXT_FILE_BYTES = 10240;
13491
13748
  var MAX_CONTEXT_TOTAL_BYTES = 51200;
@@ -13497,7 +13754,7 @@ function gatherContextFiles(contextPaths, deltaFiles) {
13497
13754
  if (result.length >= MAX_CONTEXT_FILES) break;
13498
13755
  if (deltaPaths.has(filePath)) continue;
13499
13756
  try {
13500
- const content = (0, import_node_fs14.readFileSync)(filePath, "utf8");
13757
+ const content = (0, import_node_fs15.readFileSync)(filePath, "utf8");
13501
13758
  const bytes = Buffer.byteLength(content);
13502
13759
  if (bytes > MAX_CONTEXT_FILE_BYTES) {
13503
13760
  logEvent("context_file_skipped", { path: filePath, reason: "too_large", bytes });
@@ -13542,20 +13799,20 @@ function gatherContextFiles(contextPaths, deltaFiles) {
13542
13799
  }
13543
13800
 
13544
13801
  // src/lib/cache-cleanup.ts
13545
- var import_node_fs15 = require("node:fs");
13546
- var import_node_path11 = require("node:path");
13802
+ var import_node_fs16 = require("node:fs");
13803
+ var import_node_path12 = require("node:path");
13547
13804
  var CACHE_TTL_DAYS = 7;
13548
13805
  function pruneStaleCache() {
13549
13806
  try {
13550
13807
  const dir = projectPath(CACHE_DIR);
13551
13808
  const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
13552
- for (const entry of (0, import_node_fs15.readdirSync)(dir)) {
13809
+ for (const entry of (0, import_node_fs16.readdirSync)(dir)) {
13553
13810
  if (!entry.startsWith("pending-")) continue;
13554
- const path = (0, import_node_path11.join)(dir, entry);
13811
+ const path = (0, import_node_path12.join)(dir, entry);
13555
13812
  try {
13556
- const stat3 = (0, import_node_fs15.statSync)(path);
13813
+ const stat3 = (0, import_node_fs16.statSync)(path);
13557
13814
  if (stat3.mtimeMs < cutoff) {
13558
- (0, import_node_fs15.unlinkSync)(path);
13815
+ (0, import_node_fs16.unlinkSync)(path);
13559
13816
  logEvent("cache_entry_pruned", {
13560
13817
  path: entry,
13561
13818
  age_days: Math.round((Date.now() - stat3.mtimeMs) / 864e5)
@@ -13627,10 +13884,11 @@ function reconcileAnalysisMode(predictedMode, signals) {
13627
13884
  signals.noFilesChanged,
13628
13885
  signals.assistantResponse,
13629
13886
  signals.conversationPrompts,
13630
- signals.actionSummary
13887
+ signals.actionSummary,
13888
+ signals.sessionAuthoredCode
13631
13889
  );
13632
13890
  }
13633
- const agentAuthoredCode = !!(signals.actionSummary && (signals.actionSummary.files_edited.length > 0 || signals.actionSummary.files_created.length > 0));
13891
+ const agentAuthoredCode = !!(signals.actionSummary && (signals.actionSummary.files_edited.length > 0 || signals.actionSummary.files_created.length > 0)) || !!signals.sessionAuthoredCode;
13634
13892
  const agentInvestigated = didAgentInvestigate(signals.actionSummary);
13635
13893
  switch (predictedMode) {
13636
13894
  case "skip":
@@ -13655,8 +13913,8 @@ function didAgentInvestigate(summary) {
13655
13913
  function isValidMode(mode) {
13656
13914
  return mode === "standard" || mode === "plan" || mode === "debug" || mode === "skip";
13657
13915
  }
13658
- function detectAnalysisMode(noFilesChanged, assistantResponse, conversationPrompts, actionSummary) {
13659
- const agentAuthoredCode = !!(actionSummary && (actionSummary.files_edited.length > 0 || actionSummary.files_created.length > 0));
13916
+ function detectAnalysisMode(noFilesChanged, assistantResponse, conversationPrompts, actionSummary, sessionAuthoredCode) {
13917
+ const agentAuthoredCode = !!(actionSummary && (actionSummary.files_edited.length > 0 || actionSummary.files_created.length > 0)) || !!sessionAuthoredCode;
13660
13918
  if (conversationPrompts.length > 0 && conversationPrompts.every(isGitOnlyPrompt)) {
13661
13919
  if (!agentAuthoredCode) return "skip";
13662
13920
  }
@@ -13710,7 +13968,12 @@ function isReflectionQuestion(response) {
13710
13968
  /reflection\s+for\s+future\s+agents/i,
13711
13969
  /what(?:'s|\s+is)\s+one\s+thing\s+you\s+learned/i,
13712
13970
  /say\s+['"]?skip['"]?\s+to\s+skip/i,
13713
- /quick\s+reflection\s+question/i
13971
+ /quick\s+reflection\s+question/i,
13972
+ // Post-flip (VRT-21): the agent drafts the reflection itself and, when
13973
+ // interactive, asks the user to confirm/correct before recording. That
13974
+ // turn authors no code either, so it's still a reflection turn.
13975
+ /reflection\s+draft/i,
13976
+ /confirm,?\s+correct,?\s+or\s+add/i
13714
13977
  ];
13715
13978
  return markers.some((m) => m.test(response));
13716
13979
  }
@@ -13731,7 +13994,7 @@ function isMetaTaskLabel(label2) {
13731
13994
  }
13732
13995
 
13733
13996
  // src/lib/transcript.ts
13734
- var import_node_fs16 = require("node:fs");
13997
+ var import_node_fs17 = require("node:fs");
13735
13998
  var MAX_READ_BYTES = 256 * 1024;
13736
13999
  var SMALL_FILE_BYTES = 64 * 1024;
13737
14000
  var MAX_FILES_LIST = 20;
@@ -13753,14 +14016,14 @@ async function extractActionSummary(transcriptPath) {
13753
14016
  function readTurnLines(transcriptPath) {
13754
14017
  let size;
13755
14018
  try {
13756
- size = (0, import_node_fs16.statSync)(transcriptPath).size;
14019
+ size = (0, import_node_fs17.statSync)(transcriptPath).size;
13757
14020
  } catch {
13758
14021
  return null;
13759
14022
  }
13760
14023
  if (size === 0) return null;
13761
14024
  let raw;
13762
14025
  if (size <= SMALL_FILE_BYTES) {
13763
- raw = (0, import_node_fs16.readFileSync)(transcriptPath, "utf-8");
14026
+ raw = (0, import_node_fs17.readFileSync)(transcriptPath, "utf-8");
13764
14027
  } else {
13765
14028
  const buf = Buffer.alloc(Math.min(MAX_READ_BYTES, size));
13766
14029
  const fd = require("node:fs").openSync(transcriptPath, "r");
@@ -13848,6 +14111,12 @@ function buildSummary(lines) {
13848
14111
  case "Edit":
13849
14112
  addPath(filesEdited, input.file_path);
13850
14113
  break;
14114
+ case "MultiEdit":
14115
+ addPath(filesEdited, input.file_path);
14116
+ break;
14117
+ case "NotebookEdit":
14118
+ addPath(filesEdited, input.notebook_path ?? input.file_path);
14119
+ break;
13851
14120
  case "Write":
13852
14121
  addPath(filesCreated, input.file_path);
13853
14122
  addPath(filesEdited, input.file_path);
@@ -13931,8 +14200,8 @@ function capArray(set, max) {
13931
14200
 
13932
14201
  // src/lib/seed-runner.ts
13933
14202
  var import_promises11 = require("node:fs/promises");
13934
- var import_node_fs17 = require("node:fs");
13935
- var import_node_path12 = require("node:path");
14203
+ var import_node_fs18 = require("node:fs");
14204
+ var import_node_path13 = require("node:path");
13936
14205
  var import_yaml2 = __toESM(require_dist());
13937
14206
 
13938
14207
  // src/lib/seed.ts
@@ -14171,7 +14440,7 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
14171
14440
  return fm;
14172
14441
  }
14173
14442
  async function runSeed(opts) {
14174
- if (!(0, import_node_fs17.existsSync)(STANDARD_FILE)) {
14443
+ if (!(0, import_node_fs18.existsSync)(STANDARD_FILE)) {
14175
14444
  return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
14176
14445
  }
14177
14446
  let standardDoc;
@@ -14183,7 +14452,7 @@ async function runSeed(opts) {
14183
14452
  }
14184
14453
  const knowledgeSpec = standardDoc.knowledge_spec ?? {};
14185
14454
  let readmeContent;
14186
- if ((0, import_node_fs17.existsSync)("README.md")) {
14455
+ if ((0, import_node_fs18.existsSync)("README.md")) {
14187
14456
  try {
14188
14457
  readmeContent = await (0, import_promises11.readFile)("README.md", "utf-8");
14189
14458
  } catch {
@@ -14191,7 +14460,7 @@ async function runSeed(opts) {
14191
14460
  }
14192
14461
  let claudeMdContent;
14193
14462
  for (const p of ["CLAUDE.md", ".claude/CLAUDE.md"]) {
14194
- if ((0, import_node_fs17.existsSync)(p)) {
14463
+ if ((0, import_node_fs18.existsSync)(p)) {
14195
14464
  try {
14196
14465
  claudeMdContent = await (0, import_promises11.readFile)(p, "utf-8");
14197
14466
  break;
@@ -14214,8 +14483,8 @@ async function runSeed(opts) {
14214
14483
  if (candidates.length === 0) {
14215
14484
  return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
14216
14485
  }
14217
- const overviewPath = (0, import_node_path12.join)(MEMORY_DIR, "domain", "project-overview.md");
14218
- if ((0, import_node_fs17.existsSync)(overviewPath) && !opts.force) {
14486
+ const overviewPath = (0, import_node_path13.join)(MEMORY_DIR, "domain", "project-overview.md");
14487
+ if ((0, import_node_fs18.existsSync)(overviewPath) && !opts.force) {
14219
14488
  return { created: 0, failed: 0, skipped: "already_seeded", candidates };
14220
14489
  }
14221
14490
  if (opts.dryRun) {
@@ -14250,9 +14519,9 @@ async function runSeed(opts) {
14250
14519
  }
14251
14520
  const nodeId = res.data.node_id;
14252
14521
  const filePathRel = res.data.file_path;
14253
- const targetPath = (0, import_node_path12.join)(MEMORY_DIR, filePathRel);
14522
+ const targetPath = (0, import_node_path13.join)(MEMORY_DIR, filePathRel);
14254
14523
  try {
14255
- await (0, import_promises11.mkdir)((0, import_node_path12.dirname)(targetPath), { recursive: true });
14524
+ await (0, import_promises11.mkdir)((0, import_node_path13.dirname)(targetPath), { recursive: true });
14256
14525
  await (0, import_promises11.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
14257
14526
  created++;
14258
14527
  opts.onCreated?.(nodeId, filePathRel, c);
@@ -14322,6 +14591,15 @@ async function runAnalyze(opts, globals) {
14322
14591
  }
14323
14592
  const { assistantMessage: assistantResponse, stopReason, transcriptPath, sessionId } = await readStopHookStdin();
14324
14593
  const actionSummary = transcriptPath ? await extractActionSummary(transcriptPath) : null;
14594
+ const baselineSessionId = sessionId || process.env.CLAUDE_SESSION_ID || void 0;
14595
+ const baseline = readBaseline(baselineSessionId);
14596
+ if (baseline) {
14597
+ logEvent("baseline_loaded", {
14598
+ head: baseline.head_sha.slice(0, 12),
14599
+ dirty_count: baseline.dirty_paths.length,
14600
+ age_ms: Date.now() - baseline.captured_at
14601
+ });
14602
+ }
14325
14603
  const { files: allChanged, hasRecentCommitFiles } = getChangedFiles();
14326
14604
  const analyzable = filterAnalyzable(allChanged);
14327
14605
  const reviewable = filterReviewable(allChanged);
@@ -14331,7 +14609,7 @@ async function runAnalyze(opts, globals) {
14331
14609
  passAndExit("No analyzable files changed");
14332
14610
  }
14333
14611
  const allForReview = Array.from(/* @__PURE__ */ new Set([...analyzable, ...reviewable]));
14334
- const conversation = await readAndClearConversationBuffer();
14612
+ const conversation = await readAndClearConversationBuffer(sessionId ?? void 0);
14335
14613
  const specs = discoverSpecs();
14336
14614
  const plans = discoverPlans();
14337
14615
  const latestPrompt = conversation?.prompts?.[conversation.prompts.length - 1]?.prompt ?? "";
@@ -14381,13 +14659,14 @@ async function runAnalyze(opts, globals) {
14381
14659
  }
14382
14660
  const conversationPrompts = (conversation?.prompts ?? []).map((p) => p.prompt);
14383
14661
  let analysisMode;
14662
+ const sessionAuthoredCode = !!baseline && allForReview.some((f) => changedSinceBaseline(f, baseline));
14384
14663
  const modeOverride = opts.mode;
14385
14664
  if (modeOverride && ["standard", "plan", "debug", "skip"].includes(modeOverride)) {
14386
14665
  analysisMode = modeOverride;
14387
14666
  } else {
14388
14667
  analysisMode = reconcileAnalysisMode(
14389
14668
  predictedMode,
14390
- { noFilesChanged, assistantResponse, actionSummary, conversationPrompts }
14669
+ { noFilesChanged, assistantResponse, actionSummary, conversationPrompts, sessionAuthoredCode }
14391
14670
  );
14392
14671
  }
14393
14672
  if (analysisMode === "skip") {
@@ -14445,10 +14724,16 @@ async function runAnalyze(opts, globals) {
14445
14724
  const baseForReview = agentNarrowed.length > 0 ? agentNarrowed : allForReview;
14446
14725
  const recentForReview = narrowToRecent(baseForReview);
14447
14726
  if (!opts.skipStatic && isCodacyAvailable()) {
14448
- const allScannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles]));
14449
- staticResults = runCodacyAnalysis(allScannable);
14727
+ let allScannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles]));
14728
+ if (baseline) {
14729
+ allScannable = allScannable.filter((f) => changedSinceBaseline(f, baseline));
14730
+ }
14731
+ if (allScannable.length > 0) {
14732
+ staticResults = runCodacyAnalysis(allScannable);
14733
+ }
14450
14734
  }
14451
- codeDelta = collectCodeDelta(recentForReview, {
14735
+ const deltaSet = baseline ? recentForReview.filter((f) => changedSinceBaseline(f, baseline)) : recentForReview;
14736
+ codeDelta = collectCodeDelta(deltaSet, {
14452
14737
  maxFiles: parseInt(opts.maxFiles, 10),
14453
14738
  maxFileBytes: parseInt(opts.maxFileSize, 10),
14454
14739
  maxTotalBytes: parseInt(opts.maxTotalSize, 10)
@@ -14463,7 +14748,12 @@ async function runAnalyze(opts, globals) {
14463
14748
  }
14464
14749
  }
14465
14750
  if (analysisMode !== "plan") {
14466
- snapshotResult = generateSnapshotDiffs(codeDelta.files);
14751
+ if (baseline) {
14752
+ const baselineDiffs = generateBaselineDiffs(codeDelta.files, baseline);
14753
+ snapshotResult = { has_snapshots: baselineDiffs.diffs.length > 0, diffs: baselineDiffs.diffs };
14754
+ } else {
14755
+ snapshotResult = generateSnapshotDiffs(codeDelta.files);
14756
+ }
14467
14757
  currentCommit = getCurrentCommit();
14468
14758
  const maxIterations = parseInt(opts.maxIterations, 10);
14469
14759
  const iterResult = checkMaxIterations(currentCommit, maxIterations, contentHash ?? void 0);
@@ -14495,9 +14785,9 @@ async function runAnalyze(opts, globals) {
14495
14785
  let autoSeedNotice = null;
14496
14786
  try {
14497
14787
  await ensureMemoryDir();
14498
- const seedMarker = (0, import_node_path13.join)(VERITY_DIR, ".seeded");
14499
- const hasStandard = (0, import_node_fs18.existsSync)(STANDARD_FILE);
14500
- const alreadyTried = (0, import_node_fs18.existsSync)(seedMarker);
14788
+ const seedMarker = (0, import_node_path14.join)(VERITY_DIR, ".seeded");
14789
+ const hasStandard = (0, import_node_fs19.existsSync)(STANDARD_FILE);
14790
+ const alreadyTried = (0, import_node_fs19.existsSync)(seedMarker);
14501
14791
  if (hasStandard && !alreadyTried) {
14502
14792
  const preManifest = await buildManifest();
14503
14793
  if (preManifest.nodes.length === 0) {
@@ -14510,7 +14800,7 @@ async function runAnalyze(opts, globals) {
14510
14800
  dryRun: false
14511
14801
  });
14512
14802
  if (seedResult.created > 0) {
14513
- (0, import_node_fs18.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
14803
+ (0, import_node_fs19.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
14514
14804
  `);
14515
14805
  autoSeedNotice = `Seeded ${seedResult.created} knowledge node(s) from your existing Standard (one-time).`;
14516
14806
  logEvent("auto_seed_ran", {
@@ -14518,7 +14808,7 @@ async function runAnalyze(opts, globals) {
14518
14808
  failed: seedResult.failed
14519
14809
  });
14520
14810
  } else if (seedResult.skipped === "already_seeded") {
14521
- (0, import_node_fs18.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
14811
+ (0, import_node_fs19.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
14522
14812
  `);
14523
14813
  } else {
14524
14814
  logEvent("auto_seed_noop", {
@@ -14836,8 +15126,54 @@ async function runAnalyze(opts, globals) {
14836
15126
  }
14837
15127
  }
14838
15128
 
15129
+ // src/commands/baseline.ts
15130
+ var import_node_fs20 = require("node:fs");
15131
+ function registerBaselineCommands(program2) {
15132
+ const baseline = program2.command("baseline").description("Manage the task-start working-tree baseline");
15133
+ baseline.command("capture").description("Snapshot the working tree at task start (used by SessionStart hook)").option("--session-id <id>", "Session id (overrides any value from stdin)").option("--source <source>", "Lifecycle hint: startup|resume|clear|compact").action(async (opts) => {
15134
+ try {
15135
+ try {
15136
+ process.chdir(repoRoot());
15137
+ } catch {
15138
+ }
15139
+ if (!(0, import_node_fs20.existsSync)(VERITY_DIR)) {
15140
+ process.exit(0);
15141
+ }
15142
+ let sessionId = opts.sessionId;
15143
+ let source = opts.source;
15144
+ if (!process.stdin.isTTY) {
15145
+ const input = (await readStdin()).trim();
15146
+ if (input) {
15147
+ try {
15148
+ const event = JSON.parse(input);
15149
+ sessionId = sessionId ?? event.session_id;
15150
+ source = source ?? event.source;
15151
+ } catch {
15152
+ }
15153
+ }
15154
+ }
15155
+ const result = captureBaseline({ sessionId, source });
15156
+ logEvent("baseline_capture", {
15157
+ created: result.created,
15158
+ source: source ?? null,
15159
+ dirty_count: result.baseline.dirty_paths.length,
15160
+ head: result.baseline.head_sha.slice(0, 12)
15161
+ });
15162
+ } catch {
15163
+ }
15164
+ process.exit(0);
15165
+ });
15166
+ }
15167
+ async function readStdin() {
15168
+ const chunks = [];
15169
+ for await (const chunk of process.stdin) {
15170
+ chunks.push(chunk);
15171
+ }
15172
+ return Buffer.concat(chunks).toString("utf-8");
15173
+ }
15174
+
14839
15175
  // src/commands/review.ts
14840
- var import_node_fs19 = require("node:fs");
15176
+ var import_node_fs21 = require("node:fs");
14841
15177
  function registerReviewCommand(program2) {
14842
15178
  program2.command("review").description("Run on-demand Verity analysis (advisory, never blocks)").requiredOption("--files <paths>", "Comma-separated file list").option("--changed <paths>", "Subset of --files that were modified").option("--intent <text>", "User intent description (max 2000 chars)").option("--specs <paths>", "Comma-separated spec file paths").option("--json", "Output raw JSON response").action(async (opts) => {
14843
15179
  const globals = program2.opts();
@@ -14856,7 +15192,7 @@ async function runReview(opts, globals) {
14856
15192
  const securityFiles = filterSecurity(allFiles);
14857
15193
  let staticResults;
14858
15194
  if (isCodacyAvailable()) {
14859
- const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs19.existsSync)(f) || resolveFile(f) !== null);
15195
+ const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs21.existsSync)(f) || resolveFile(f) !== null);
14860
15196
  staticResults = runCodacyAnalysis(scannable);
14861
15197
  } else {
14862
15198
  staticResults = {
@@ -14881,10 +15217,10 @@ async function runReview(opts, globals) {
14881
15217
  const specPaths = opts.specs.split(",").map((f) => f.trim()).filter(Boolean);
14882
15218
  specs = [];
14883
15219
  for (const p of specPaths) {
14884
- if (!(0, import_node_fs19.existsSync)(p)) continue;
15220
+ if (!(0, import_node_fs21.existsSync)(p)) continue;
14885
15221
  try {
14886
- const { readFileSync: readFileSync11 } = await import("node:fs");
14887
- const content = readFileSync11(p, "utf-8");
15222
+ const { readFileSync: readFileSync12 } = await import("node:fs");
15223
+ const content = readFileSync12(p, "utf-8");
14888
15224
  specs.push({ path: p, content: content.slice(0, 10240) });
14889
15225
  } catch {
14890
15226
  }
@@ -14941,10 +15277,10 @@ async function runReview(opts, globals) {
14941
15277
  }
14942
15278
 
14943
15279
  // src/commands/guard.ts
14944
- var import_node_fs20 = require("node:fs");
14945
- var import_node_path14 = require("node:path");
15280
+ var import_node_fs22 = require("node:fs");
15281
+ var import_node_path15 = require("node:path");
14946
15282
  var GUARD_BLOCK_CAP = 2;
14947
- var GUARD_ITER_FILE = (0, import_node_path14.join)(VERITY_DIR, ".guard-iteration");
15283
+ var GUARD_ITER_FILE = (0, import_node_path15.join)(VERITY_DIR, ".guard-iteration");
14948
15284
  function readPreToolUseStdin() {
14949
15285
  const empty = { command: "", cwd: null, sessionId: null };
14950
15286
  return new Promise((resolve) => {
@@ -15008,7 +15344,7 @@ function classifyCommand(command, on) {
15008
15344
  }
15009
15345
  function readIterMap() {
15010
15346
  try {
15011
- const raw = JSON.parse((0, import_node_fs20.readFileSync)(GUARD_ITER_FILE, "utf-8"));
15347
+ const raw = JSON.parse((0, import_node_fs22.readFileSync)(GUARD_ITER_FILE, "utf-8"));
15012
15348
  if (raw && typeof raw === "object") {
15013
15349
  if (typeof raw.moment === "string" && typeof raw.count === "number") {
15014
15350
  return { [raw.moment]: raw.count };
@@ -15028,10 +15364,10 @@ function readIter(moment) {
15028
15364
  }
15029
15365
  function writeIter(moment, count) {
15030
15366
  try {
15031
- (0, import_node_fs20.mkdirSync)(VERITY_DIR, { recursive: true });
15367
+ (0, import_node_fs22.mkdirSync)(VERITY_DIR, { recursive: true });
15032
15368
  const map = readIterMap();
15033
15369
  map[moment] = count;
15034
- (0, import_node_fs20.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
15370
+ (0, import_node_fs22.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
15035
15371
  } catch {
15036
15372
  }
15037
15373
  }
@@ -15041,10 +15377,10 @@ function resetIter(moment) {
15041
15377
  if (!(moment in map)) return;
15042
15378
  delete map[moment];
15043
15379
  if (Object.keys(map).length === 0) {
15044
- if ((0, import_node_fs20.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs20.unlinkSync)(GUARD_ITER_FILE);
15380
+ if ((0, import_node_fs22.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs22.unlinkSync)(GUARD_ITER_FILE);
15045
15381
  } else {
15046
- (0, import_node_fs20.mkdirSync)(VERITY_DIR, { recursive: true });
15047
- (0, import_node_fs20.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
15382
+ (0, import_node_fs22.mkdirSync)(VERITY_DIR, { recursive: true });
15383
+ (0, import_node_fs22.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
15048
15384
  }
15049
15385
  } catch {
15050
15386
  }
@@ -15108,7 +15444,7 @@ function buildGuardRequest(moment, files, iter, sessionId, command) {
15108
15444
  const securityFiles = filterSecurity(files);
15109
15445
  let staticResults;
15110
15446
  if (isCodacyAvailable()) {
15111
- const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs20.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
15447
+ const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs22.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
15112
15448
  staticResults = runCodacyAnalysis(scannable);
15113
15449
  } else {
15114
15450
  staticResults = { tool: "@codacy/analysis-cli", findings: [], summary: { total_findings: 0, by_severity: {}, tools_run: [] } };
@@ -15153,7 +15489,7 @@ function emitAllowNotice(userMsg, agentMsg) {
15153
15489
  async function runGuard(opts, globals) {
15154
15490
  const on = opts.on.split(",").map((s) => s.trim()).filter((s) => s === "commit" || s === "push");
15155
15491
  const { command, cwd, sessionId } = await readPreToolUseStdin();
15156
- if (cwd && (0, import_node_fs20.existsSync)(cwd)) {
15492
+ if (cwd && (0, import_node_fs22.existsSync)(cwd)) {
15157
15493
  try {
15158
15494
  process.chdir(cwd);
15159
15495
  } catch {
@@ -15258,14 +15594,14 @@ function writeBlockMessage(moment, response) {
15258
15594
  }
15259
15595
 
15260
15596
  // src/commands/init.ts
15261
- var import_node_fs22 = require("node:fs");
15597
+ var import_node_fs24 = require("node:fs");
15262
15598
  var import_promises12 = require("node:fs/promises");
15263
- var import_node_path16 = require("node:path");
15599
+ var import_node_path17 = require("node:path");
15264
15600
  var import_node_child_process9 = require("node:child_process");
15265
15601
 
15266
15602
  // src/commands/migrate.ts
15267
- var import_node_fs21 = require("node:fs");
15268
- var import_node_path15 = require("node:path");
15603
+ var import_node_fs23 = require("node:fs");
15604
+ var import_node_path16 = require("node:path");
15269
15605
  var import_node_child_process8 = require("node:child_process");
15270
15606
  var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
15271
15607
  function defaultNpmRemover(pkg) {
@@ -15301,12 +15637,12 @@ async function runMigration(opts = {}) {
15301
15637
  return { actions, migrated: actions.length > 0 };
15302
15638
  }
15303
15639
  function migrateProjectDir(root, actions) {
15304
- const gateDir = (0, import_node_path15.join)(root, ".gate");
15305
- const verityDir = (0, import_node_path15.join)(root, ".verity");
15306
- if ((0, import_node_fs21.existsSync)(gateDir) && !(0, import_node_fs21.existsSync)(verityDir)) {
15640
+ const gateDir = (0, import_node_path16.join)(root, ".gate");
15641
+ const verityDir = (0, import_node_path16.join)(root, ".verity");
15642
+ if ((0, import_node_fs23.existsSync)(gateDir) && !(0, import_node_fs23.existsSync)(verityDir)) {
15307
15643
  return migrateProjectDirRename(root, gateDir, verityDir, actions);
15308
15644
  }
15309
- if ((0, import_node_fs21.existsSync)(gateDir) && (0, import_node_fs21.existsSync)(verityDir)) {
15645
+ if ((0, import_node_fs23.existsSync)(gateDir) && (0, import_node_fs23.existsSync)(verityDir)) {
15310
15646
  return migrateProjectDirCarry(gateDir, verityDir, actions);
15311
15647
  }
15312
15648
  return false;
@@ -15327,13 +15663,13 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
15327
15663
  }
15328
15664
  }
15329
15665
  if (moved) {
15330
- if ((0, import_node_fs21.existsSync)(gateDir)) {
15666
+ if ((0, import_node_fs23.existsSync)(gateDir)) {
15331
15667
  const carried = carryLegacyContents(gateDir, verityDir);
15332
15668
  if (carried > 0) {
15333
15669
  actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
15334
15670
  }
15335
15671
  try {
15336
- (0, import_node_fs21.rmSync)(gateDir, { recursive: true, force: true });
15672
+ (0, import_node_fs23.rmSync)(gateDir, { recursive: true, force: true });
15337
15673
  } catch {
15338
15674
  }
15339
15675
  }
@@ -15349,18 +15685,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
15349
15685
  actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
15350
15686
  }
15351
15687
  try {
15352
- (0, import_node_fs21.rmSync)(gateDir, { recursive: true, force: true });
15688
+ (0, import_node_fs23.rmSync)(gateDir, { recursive: true, force: true });
15353
15689
  } catch {
15354
15690
  }
15355
15691
  return carried > 0;
15356
15692
  }
15357
15693
  function migrateGlobalCredentials(home, actions) {
15358
15694
  if (!home) return;
15359
- const gateCreds = (0, import_node_path15.join)(home, ".gate", "credentials");
15360
- const verityCreds = (0, import_node_path15.join)(home, ".verity", "credentials");
15361
- if (!(0, import_node_fs21.existsSync)(gateCreds)) return;
15362
- if (!(0, import_node_fs21.existsSync)(verityCreds)) {
15363
- (0, import_node_fs21.mkdirSync)((0, import_node_path15.join)(home, ".verity"), { recursive: true });
15695
+ const gateCreds = (0, import_node_path16.join)(home, ".gate", "credentials");
15696
+ const verityCreds = (0, import_node_path16.join)(home, ".verity", "credentials");
15697
+ if (!(0, import_node_fs23.existsSync)(gateCreds)) return;
15698
+ if (!(0, import_node_fs23.existsSync)(verityCreds)) {
15699
+ (0, import_node_fs23.mkdirSync)((0, import_node_path16.join)(home, ".verity"), { recursive: true });
15364
15700
  moveFile(gateCreds, verityCreds);
15365
15701
  actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
15366
15702
  return;
@@ -15382,8 +15718,8 @@ async function migrateLegacyHooks(root, actions) {
15382
15718
  }
15383
15719
  }
15384
15720
  async function migrateClaudeMd(root, actions) {
15385
- const claudeMd = (0, import_node_path15.join)(root, "CLAUDE.md");
15386
- const hadLegacyBlock = (0, import_node_fs21.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
15721
+ const claudeMd = (0, import_node_path16.join)(root, "CLAUDE.md");
15722
+ const hadLegacyBlock = (0, import_node_fs23.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
15387
15723
  if (!hadLegacyBlock) return;
15388
15724
  try {
15389
15725
  await ensureClaudeMdPointer(root);
@@ -15393,9 +15729,9 @@ async function migrateClaudeMd(root, actions) {
15393
15729
  }
15394
15730
  }
15395
15731
  function migrateStandardFile(root, actions) {
15396
- const gateMd = (0, import_node_path15.join)(root, "GATE.md");
15397
- const verityMd = (0, import_node_path15.join)(root, "VERITY.md");
15398
- if (!(0, import_node_fs21.existsSync)(gateMd) || (0, import_node_fs21.existsSync)(verityMd)) return;
15732
+ const gateMd = (0, import_node_path16.join)(root, "GATE.md");
15733
+ const verityMd = (0, import_node_path16.join)(root, "VERITY.md");
15734
+ if (!(0, import_node_fs23.existsSync)(gateMd) || (0, import_node_fs23.existsSync)(verityMd)) return;
15399
15735
  let moved = false;
15400
15736
  if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
15401
15737
  try {
@@ -15407,7 +15743,7 @@ function migrateStandardFile(root, actions) {
15407
15743
  if (!moved) moveFile(gateMd, verityMd);
15408
15744
  const content = readFileSyncSafe(verityMd);
15409
15745
  const refreshed = content.split("GATE.md").join("VERITY.md");
15410
- if (refreshed !== content) (0, import_node_fs21.writeFileSync)(verityMd, refreshed);
15746
+ if (refreshed !== content) (0, import_node_fs23.writeFileSync)(verityMd, refreshed);
15411
15747
  actions.push("Renamed GATE.md \u2192 VERITY.md");
15412
15748
  }
15413
15749
  function removeLegacyPackage(movedProjectDir, npmRemover, actions) {
@@ -15441,14 +15777,14 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
15441
15777
  }
15442
15778
  if (toAppend.length > 0) {
15443
15779
  const sep = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
15444
- (0, import_node_fs21.writeFileSync)(verityCreds, verityContent + sep + toAppend.join("\n") + "\n");
15780
+ (0, import_node_fs23.writeFileSync)(verityCreds, verityContent + sep + toAppend.join("\n") + "\n");
15445
15781
  }
15446
- (0, import_node_fs21.rmSync)(gateCreds, { force: true });
15782
+ (0, import_node_fs23.rmSync)(gateCreds, { force: true });
15447
15783
  return toAppend.length;
15448
15784
  }
15449
15785
  function readFileSyncSafe(path) {
15450
15786
  try {
15451
- return (0, import_node_fs21.readFileSync)(path, "utf-8");
15787
+ return (0, import_node_fs23.readFileSync)(path, "utf-8");
15452
15788
  } catch {
15453
15789
  return "";
15454
15790
  }
@@ -15463,35 +15799,35 @@ function hasStagedChanges(root) {
15463
15799
  }
15464
15800
  function moveDir(from, to) {
15465
15801
  try {
15466
- (0, import_node_fs21.renameSync)(from, to);
15802
+ (0, import_node_fs23.renameSync)(from, to);
15467
15803
  } catch (err) {
15468
15804
  if (err.code !== "EXDEV") throw err;
15469
- (0, import_node_fs21.cpSync)(from, to, { recursive: true });
15470
- (0, import_node_fs21.rmSync)(from, { recursive: true, force: true });
15805
+ (0, import_node_fs23.cpSync)(from, to, { recursive: true });
15806
+ (0, import_node_fs23.rmSync)(from, { recursive: true, force: true });
15471
15807
  }
15472
15808
  }
15473
15809
  function moveFile(from, to) {
15474
15810
  try {
15475
- (0, import_node_fs21.renameSync)(from, to);
15811
+ (0, import_node_fs23.renameSync)(from, to);
15476
15812
  } catch (err) {
15477
15813
  if (err.code !== "EXDEV") throw err;
15478
- (0, import_node_fs21.cpSync)(from, to);
15479
- (0, import_node_fs21.rmSync)(from, { force: true });
15814
+ (0, import_node_fs23.cpSync)(from, to);
15815
+ (0, import_node_fs23.rmSync)(from, { force: true });
15480
15816
  }
15481
15817
  }
15482
15818
  function carryLegacyContents(gateDir, verityDir) {
15483
15819
  let copied = 0;
15484
15820
  const walk = (relDir) => {
15485
- const srcDir = (0, import_node_path15.join)(gateDir, relDir);
15486
- for (const entry of (0, import_node_fs21.readdirSync)(srcDir)) {
15487
- const rel = relDir ? (0, import_node_path15.join)(relDir, entry) : entry;
15488
- const src = (0, import_node_path15.join)(gateDir, rel);
15489
- const dest = (0, import_node_path15.join)(verityDir, rel);
15490
- if ((0, import_node_fs21.statSync)(src).isDirectory()) {
15821
+ const srcDir = (0, import_node_path16.join)(gateDir, relDir);
15822
+ for (const entry of (0, import_node_fs23.readdirSync)(srcDir)) {
15823
+ const rel = relDir ? (0, import_node_path16.join)(relDir, entry) : entry;
15824
+ const src = (0, import_node_path16.join)(gateDir, rel);
15825
+ const dest = (0, import_node_path16.join)(verityDir, rel);
15826
+ if ((0, import_node_fs23.statSync)(src).isDirectory()) {
15491
15827
  walk(rel);
15492
- } else if (!(0, import_node_fs21.existsSync)(dest)) {
15493
- (0, import_node_fs21.mkdirSync)((0, import_node_path15.dirname)(dest), { recursive: true });
15494
- (0, import_node_fs21.cpSync)(src, dest);
15828
+ } else if (!(0, import_node_fs23.existsSync)(dest)) {
15829
+ (0, import_node_fs23.mkdirSync)((0, import_node_path16.dirname)(dest), { recursive: true });
15830
+ (0, import_node_fs23.cpSync)(src, dest);
15495
15831
  copied++;
15496
15832
  }
15497
15833
  }
@@ -15500,22 +15836,22 @@ function carryLegacyContents(gateDir, verityDir) {
15500
15836
  return copied;
15501
15837
  }
15502
15838
  async function needsMigration(root = repoRoot()) {
15503
- const gateDir = (0, import_node_path15.join)(root, ".gate");
15504
- const verityDir = (0, import_node_path15.join)(root, ".verity");
15505
- if ((0, import_node_fs21.existsSync)(gateDir) && !(0, import_node_fs21.existsSync)(verityDir)) return true;
15506
- if ((0, import_node_fs21.existsSync)(gateDir) && (0, import_node_fs21.existsSync)(verityDir)) {
15507
- if ((0, import_node_fs21.existsSync)((0, import_node_path15.join)(gateDir, "credentials")) && !(0, import_node_fs21.existsSync)((0, import_node_path15.join)(verityDir, "credentials"))) {
15839
+ const gateDir = (0, import_node_path16.join)(root, ".gate");
15840
+ const verityDir = (0, import_node_path16.join)(root, ".verity");
15841
+ if ((0, import_node_fs23.existsSync)(gateDir) && !(0, import_node_fs23.existsSync)(verityDir)) return true;
15842
+ if ((0, import_node_fs23.existsSync)(gateDir) && (0, import_node_fs23.existsSync)(verityDir)) {
15843
+ if ((0, import_node_fs23.existsSync)((0, import_node_path16.join)(gateDir, "credentials")) && !(0, import_node_fs23.existsSync)((0, import_node_path16.join)(verityDir, "credentials"))) {
15508
15844
  return true;
15509
15845
  }
15510
- if ((0, import_node_fs21.existsSync)((0, import_node_path15.join)(gateDir, "memory")) && !(0, import_node_fs21.existsSync)((0, import_node_path15.join)(verityDir, "memory"))) {
15846
+ if ((0, import_node_fs23.existsSync)((0, import_node_path16.join)(gateDir, "memory")) && !(0, import_node_fs23.existsSync)((0, import_node_path16.join)(verityDir, "memory"))) {
15511
15847
  return true;
15512
15848
  }
15513
15849
  }
15514
- const claudeMd = (0, import_node_path15.join)(root, "CLAUDE.md");
15515
- if ((0, import_node_fs21.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
15850
+ const claudeMd = (0, import_node_path16.join)(root, "CLAUDE.md");
15851
+ if ((0, import_node_fs23.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
15516
15852
  return true;
15517
15853
  }
15518
- if ((0, import_node_fs21.existsSync)((0, import_node_path15.join)(root, "GATE.md")) && !(0, import_node_fs21.existsSync)((0, import_node_path15.join)(root, "VERITY.md"))) {
15854
+ if ((0, import_node_fs23.existsSync)((0, import_node_path16.join)(root, "GATE.md")) && !(0, import_node_fs23.existsSync)((0, import_node_path16.join)(root, "VERITY.md"))) {
15519
15855
  return true;
15520
15856
  }
15521
15857
  if (await hasLegacyHooksAt(root)) return true;
@@ -15543,15 +15879,15 @@ function registerMigrateCommand(program2) {
15543
15879
  // src/commands/init.ts
15544
15880
  function resolveDataDir() {
15545
15881
  const candidates = [
15546
- (0, import_node_path16.join)(__dirname, "..", "data"),
15882
+ (0, import_node_path17.join)(__dirname, "..", "data"),
15547
15883
  // installed: node_modules/@codacy/verity-cli/data
15548
- (0, import_node_path16.join)(__dirname, "..", "..", "data"),
15884
+ (0, import_node_path17.join)(__dirname, "..", "..", "data"),
15549
15885
  // edge case: nested resolution
15550
- (0, import_node_path16.join)(process.cwd(), "cli", "data")
15886
+ (0, import_node_path17.join)(process.cwd(), "cli", "data")
15551
15887
  // local dev: running from repo root
15552
15888
  ];
15553
15889
  for (const candidate of candidates) {
15554
- if ((0, import_node_fs22.existsSync)((0, import_node_path16.join)(candidate, "skills"))) {
15890
+ if ((0, import_node_fs24.existsSync)((0, import_node_path17.join)(candidate, "skills"))) {
15555
15891
  return candidate;
15556
15892
  }
15557
15893
  }
@@ -15567,7 +15903,7 @@ function registerInitCommand(program2) {
15567
15903
  program2.command("init").description("Initialize Verity in the current project").option("--force", "Overwrite existing skills and hooks").action(async (opts) => {
15568
15904
  const force = opts.force ?? false;
15569
15905
  const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
15570
- const isProject = projectMarkers.some((m) => (0, import_node_fs22.existsSync)(m));
15906
+ const isProject = projectMarkers.some((m) => (0, import_node_fs24.existsSync)(m));
15571
15907
  if (!isProject) {
15572
15908
  printError("No project detected in the current directory.");
15573
15909
  printInfo('Run "verity init" from your project root.');
@@ -15630,21 +15966,21 @@ function registerInitCommand(program2) {
15630
15966
  console.log("");
15631
15967
  printInfo("Installing skills...");
15632
15968
  const dataDir = resolveDataDir();
15633
- const skillsSource = (0, import_node_path16.join)(dataDir, "skills");
15969
+ const skillsSource = (0, import_node_path17.join)(dataDir, "skills");
15634
15970
  const skillsDest = ".claude/skills";
15635
15971
  const skills = ["verity-setup", "verity-analyze", "verity-status", "verity-feedback", "verity-learn", "verity-memory", "verity-insights", "verity-reflect"];
15636
15972
  let skillsInstalled = 0;
15637
15973
  for (const skill of skills) {
15638
- const src = (0, import_node_path16.join)(skillsSource, skill);
15639
- const dest = (0, import_node_path16.join)(skillsDest, skill);
15640
- if (!(0, import_node_fs22.existsSync)(src)) {
15974
+ const src = (0, import_node_path17.join)(skillsSource, skill);
15975
+ const dest = (0, import_node_path17.join)(skillsDest, skill);
15976
+ if (!(0, import_node_fs24.existsSync)(src)) {
15641
15977
  printWarn(` Skill data not found: ${skill}`);
15642
15978
  continue;
15643
15979
  }
15644
- if ((0, import_node_fs22.existsSync)(dest) && !force) {
15645
- const srcSkill = (0, import_node_path16.join)(src, "SKILL.md");
15646
- const destSkill = (0, import_node_path16.join)(dest, "SKILL.md");
15647
- if ((0, import_node_fs22.existsSync)(destSkill)) {
15980
+ if ((0, import_node_fs24.existsSync)(dest) && !force) {
15981
+ const srcSkill = (0, import_node_path17.join)(src, "SKILL.md");
15982
+ const destSkill = (0, import_node_path17.join)(dest, "SKILL.md");
15983
+ if ((0, import_node_fs24.existsSync)(destSkill)) {
15648
15984
  try {
15649
15985
  const srcContent = await (0, import_promises12.readFile)(srcSkill, "utf-8");
15650
15986
  const destContent = await (0, import_promises12.readFile)(destSkill, "utf-8");
@@ -15668,6 +16004,7 @@ function registerInitCommand(program2) {
15668
16004
  await writeSettings(hookResult.data);
15669
16005
  printInfo(" Stop hook: verity analyze \u2713");
15670
16006
  printInfo(" Intent hook: verity intent capture \u2713");
16007
+ printInfo(" Baseline hook: verity baseline capture \u2713");
15671
16008
  } else {
15672
16009
  printWarn(` ${hookResult.error}`);
15673
16010
  printInfo(' Run "verity hooks install --force" to overwrite.');
@@ -15680,7 +16017,7 @@ function registerInitCommand(program2) {
15680
16017
  } catch (err) {
15681
16018
  printWarn(` Could not update CLAUDE.md: ${err.message}`);
15682
16019
  }
15683
- const globalVerityDir = (0, import_node_path16.join)(process.env.HOME ?? "", ".verity");
16020
+ const globalVerityDir = (0, import_node_path17.join)(process.env.HOME ?? "", ".verity");
15684
16021
  await (0, import_promises12.mkdir)(globalVerityDir, { recursive: true });
15685
16022
  console.log("");
15686
16023
  printInfo("Verity initialized!");
@@ -15703,8 +16040,8 @@ function registerInitCommand(program2) {
15703
16040
  }
15704
16041
 
15705
16042
  // src/commands/uninstall.ts
15706
- var import_node_fs23 = require("node:fs");
15707
- var import_node_path17 = require("node:path");
16043
+ var import_node_fs25 = require("node:fs");
16044
+ var import_node_path18 = require("node:path");
15708
16045
  var SKILL_NAMES = [
15709
16046
  "verity-setup",
15710
16047
  "verity-analyze",
@@ -15723,11 +16060,11 @@ function registerUninstallCommand(program2) {
15723
16060
  const actions = [];
15724
16061
  const skillsRoot = projectPath(".claude/skills");
15725
16062
  for (const name of SKILL_NAMES) {
15726
- const dir = (0, import_node_path17.join)(skillsRoot, name);
15727
- if ((0, import_node_fs23.existsSync)(dir)) {
16063
+ const dir = (0, import_node_path18.join)(skillsRoot, name);
16064
+ if ((0, import_node_fs25.existsSync)(dir)) {
15728
16065
  actions.push({
15729
16066
  label: `Remove .claude/skills/${name}/`,
15730
- apply: () => (0, import_node_fs23.rmSync)(dir, { recursive: true, force: true })
16067
+ apply: () => (0, import_node_fs25.rmSync)(dir, { recursive: true, force: true })
15731
16068
  });
15732
16069
  }
15733
16070
  }
@@ -15741,24 +16078,24 @@ function registerUninstallCommand(program2) {
15741
16078
  });
15742
16079
  }
15743
16080
  const verityDir = projectPath(VERITY_DIR);
15744
- if ((0, import_node_fs23.existsSync)(verityDir)) {
16081
+ if ((0, import_node_fs25.existsSync)(verityDir)) {
15745
16082
  actions.push({
15746
16083
  label: `Remove ${VERITY_DIR}/`,
15747
- apply: () => (0, import_node_fs23.rmSync)(verityDir, { recursive: true, force: true })
16084
+ apply: () => (0, import_node_fs25.rmSync)(verityDir, { recursive: true, force: true })
15748
16085
  });
15749
16086
  }
15750
16087
  if (!keepVerityMd) {
15751
16088
  const verityMd = projectPath(VERITY_MD_FILE);
15752
- if ((0, import_node_fs23.existsSync)(verityMd)) {
16089
+ if ((0, import_node_fs25.existsSync)(verityMd)) {
15753
16090
  actions.push({
15754
16091
  label: `Remove ${VERITY_MD_FILE}`,
15755
- apply: () => (0, import_node_fs23.rmSync)(verityMd, { force: true })
16092
+ apply: () => (0, import_node_fs25.rmSync)(verityMd, { force: true })
15756
16093
  });
15757
16094
  }
15758
16095
  }
15759
16096
  const cleanupEmptyDir = (path) => {
15760
- if ((0, import_node_fs23.existsSync)(path) && (0, import_node_fs23.statSync)(path).isDirectory() && (0, import_node_fs23.readdirSync)(path).length === 0) {
15761
- (0, import_node_fs23.rmdirSync)(path);
16097
+ if ((0, import_node_fs25.existsSync)(path) && (0, import_node_fs25.statSync)(path).isDirectory() && (0, import_node_fs25.readdirSync)(path).length === 0) {
16098
+ (0, import_node_fs25.rmdirSync)(path);
15762
16099
  }
15763
16100
  };
15764
16101
  actions.push({
@@ -15769,11 +16106,11 @@ function registerUninstallCommand(program2) {
15769
16106
  }
15770
16107
  });
15771
16108
  const home = process.env.HOME ?? "";
15772
- const globalVerityDir = (0, import_node_path17.join)(home, ".verity");
15773
- if (purgeGlobal && (0, import_node_fs23.existsSync)(globalVerityDir)) {
16109
+ const globalVerityDir = (0, import_node_path18.join)(home, ".verity");
16110
+ if (purgeGlobal && (0, import_node_fs25.existsSync)(globalVerityDir)) {
15774
16111
  actions.push({
15775
16112
  label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
15776
- apply: () => (0, import_node_fs23.rmSync)(globalVerityDir, { recursive: true, force: true })
16113
+ apply: () => (0, import_node_fs25.rmSync)(globalVerityDir, { recursive: true, force: true })
15777
16114
  });
15778
16115
  }
15779
16116
  if (actions.length === 0) {
@@ -15967,8 +16304,8 @@ function registerTaskCommands(program2) {
15967
16304
  }
15968
16305
 
15969
16306
  // src/commands/reset.ts
15970
- var import_node_fs24 = require("node:fs");
15971
- var import_node_path18 = require("node:path");
16307
+ var import_node_fs26 = require("node:fs");
16308
+ var import_node_path19 = require("node:path");
15972
16309
  function registerResetCommand(program2) {
15973
16310
  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) => {
15974
16311
  const globals = program2.opts();
@@ -16005,11 +16342,11 @@ function registerResetCommand(program2) {
16005
16342
  }
16006
16343
  const cacheDir = projectPath(CACHE_DIR);
16007
16344
  let purged = 0;
16008
- if ((0, import_node_fs24.existsSync)(cacheDir)) {
16009
- for (const entry of (0, import_node_fs24.readdirSync)(cacheDir)) {
16345
+ if ((0, import_node_fs26.existsSync)(cacheDir)) {
16346
+ for (const entry of (0, import_node_fs26.readdirSync)(cacheDir)) {
16010
16347
  if (entry.startsWith("pending-")) {
16011
16348
  try {
16012
- (0, import_node_fs24.unlinkSync)((0, import_node_path18.join)(cacheDir, entry));
16349
+ (0, import_node_fs26.unlinkSync)((0, import_node_path19.join)(cacheDir, entry));
16013
16350
  purged++;
16014
16351
  } catch {
16015
16352
  }
@@ -16024,19 +16361,19 @@ function registerResetCommand(program2) {
16024
16361
  projectPath(`${VERITY_DIR}/.last-analysis`)
16025
16362
  ];
16026
16363
  for (const file of filesToClear) {
16027
- if ((0, import_node_fs24.existsSync)(file)) {
16364
+ if ((0, import_node_fs26.existsSync)(file)) {
16028
16365
  try {
16029
- (0, import_node_fs24.writeFileSync)(file, "");
16366
+ (0, import_node_fs26.writeFileSync)(file, "");
16030
16367
  } catch {
16031
16368
  }
16032
16369
  }
16033
16370
  }
16034
16371
  if (opts.all) {
16035
16372
  const logsDir = projectPath(`${VERITY_DIR}/.logs`);
16036
- if ((0, import_node_fs24.existsSync)(logsDir)) {
16037
- for (const entry of (0, import_node_fs24.readdirSync)(logsDir)) {
16373
+ if ((0, import_node_fs26.existsSync)(logsDir)) {
16374
+ for (const entry of (0, import_node_fs26.readdirSync)(logsDir)) {
16038
16375
  try {
16039
- (0, import_node_fs24.unlinkSync)((0, import_node_path18.join)(logsDir, entry));
16376
+ (0, import_node_fs26.unlinkSync)((0, import_node_path19.join)(logsDir, entry));
16040
16377
  } catch {
16041
16378
  }
16042
16379
  }
@@ -16047,10 +16384,29 @@ function registerResetCommand(program2) {
16047
16384
  });
16048
16385
  }
16049
16386
 
16387
+ // src/lib/run-mode.ts
16388
+ function parseAutonomousEnv(raw) {
16389
+ if (raw === void 0) return void 0;
16390
+ const v = raw.trim().toLowerCase();
16391
+ if (v === "") return void 0;
16392
+ if (v === "0" || v === "false" || v === "off" || v === "no") return false;
16393
+ return true;
16394
+ }
16395
+ function resolveRunMode(inputs = {}) {
16396
+ if (inputs.autonomousFlag === true) return "autonomous";
16397
+ if (inputs.autonomousFlag === false) return "interactive";
16398
+ const env = inputs.env ?? process.env;
16399
+ const envDecision = parseAutonomousEnv(env.VERITY_AUTONOMOUS);
16400
+ if (envDecision !== void 0) return envDecision ? "autonomous" : "interactive";
16401
+ const isTTY = inputs.isTTY ?? Boolean(process.stdin?.isTTY);
16402
+ return isTTY ? "interactive" : "autonomous";
16403
+ }
16404
+
16050
16405
  // src/commands/reflect.ts
16051
16406
  function registerReflectCommand(program2) {
16052
- program2.command("reflect").description("Capture learnings \u2014 auto-extract or submit a human reflection").option("--user-input <text>", "Your reflection (becomes a high-confidence knowledge node)").option("--kind <kind>", "Node kind (decision, gotcha, pattern, security, quality, intent, domain, integration)", "gotcha").option("--task-id <id>", "Task to reflect on (defaults to current task)").action(async (opts) => {
16407
+ program2.command("reflect").description("Capture learnings \u2014 auto-extract or submit a human reflection").option("--user-input <text>", "The reflection to record (the agent-drafted or user-confirmed text)").option("--kind <kind>", "Node kind (decision, gotcha, pattern, security, quality, intent, domain, integration)", "gotcha").option("--task-id <id>", "Task to reflect on (defaults to current task)").option("--autonomous", "Record the drafted reflection without a confirm step (auto-detected from TTY / VERITY_AUTONOMOUS when omitted)").action(async (opts) => {
16053
16408
  const globals = program2.opts();
16409
+ const mode = resolveRunMode({ autonomousFlag: opts.autonomous });
16054
16410
  await ensureMemoryDir();
16055
16411
  const tokenResult = await resolveToken(globals.token);
16056
16412
  if (!tokenResult.ok) {
@@ -16141,7 +16497,9 @@ function registerReflectCommand(program2) {
16141
16497
  const nodeId = result.data.node_id;
16142
16498
  const filePath = result.data.file_path;
16143
16499
  printInfo(`Queued: ${nodeId} (will sync to .verity/memory/${filePath} on next analysis).`);
16144
- printInfo("Your reflection is now part of the project knowledge base (confidence: 100%).");
16500
+ printInfo(
16501
+ mode === "autonomous" ? "Recorded autonomously (no confirm step) into the project knowledge base." : "Recorded your confirmed reflection into the project knowledge base."
16502
+ );
16145
16503
  if (taskResolution === "none") {
16146
16504
  printInfo("(No task context \u2014 reflection lives at the project level.)");
16147
16505
  }
@@ -16274,7 +16632,7 @@ function registerRunCommand(program2) {
16274
16632
 
16275
16633
  // src/lib/telemetry.ts
16276
16634
  var import_promises13 = require("node:fs/promises");
16277
- var import_node_path19 = require("node:path");
16635
+ var import_node_path20 = require("node:path");
16278
16636
  var SETTINGS_LOCAL_FILE2 = ".claude/settings.local.json";
16279
16637
  var GITIGNORE_FILE = ".gitignore";
16280
16638
  var GITIGNORE_ENTRY = ".claude/settings.local.json";
@@ -16312,7 +16670,7 @@ async function readSettingsLocal() {
16312
16670
  }
16313
16671
  async function writeSettingsLocal(settings) {
16314
16672
  const file = projectPath(SETTINGS_LOCAL_FILE2);
16315
- await (0, import_promises13.mkdir)((0, import_node_path19.dirname)(file), { recursive: true });
16673
+ await (0, import_promises13.mkdir)((0, import_node_path20.dirname)(file), { recursive: true });
16316
16674
  await (0, import_promises13.writeFile)(file, JSON.stringify(settings, null, 2) + "\n");
16317
16675
  }
16318
16676
  async function ensureGitignore() {
@@ -16408,7 +16766,7 @@ function registerTelemetryCommands(program2) {
16408
16766
  }
16409
16767
 
16410
16768
  // src/cli.ts
16411
- program.name("verity").description("CLI for Verity quality gate service").version("0.23.3").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr");
16769
+ program.name("verity").description("CLI for Verity quality gate service").version("0.24.0-experimental.6a390ac").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr");
16412
16770
  registerAuthCommands(program);
16413
16771
  registerHooksCommands(program);
16414
16772
  registerIntentCommands(program);
@@ -16417,6 +16775,7 @@ registerConfigCommands(program);
16417
16775
  registerStatusCommand(program);
16418
16776
  registerFeedbackCommand(program);
16419
16777
  registerAnalyzeCommand(program);
16778
+ registerBaselineCommands(program);
16420
16779
  registerReviewCommand(program);
16421
16780
  registerGuardCommand(program);
16422
16781
  registerInitCommand(program);