@codacy/verity-cli 0.33.0-experimental.d60f544 → 0.33.1-experimental.1378de3

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/bin/verity.js +1024 -695
  3. package/package.json +2 -2
package/bin/verity.js CHANGED
@@ -10413,6 +10413,7 @@ var MAX_ITERATIONS = 2;
10413
10413
  var MAX_SPEC_FILES = 6;
10414
10414
  var MAX_SPEC_FILE_BYTES = 512e3;
10415
10415
  var MAX_TOTAL_SPEC_BYTES = 512e3;
10416
+ var MAX_EXPLICIT_SPEC_FILE_BYTES = 10240;
10416
10417
  var MAX_PLAN_FILES = 3;
10417
10418
  var MAX_PLAN_FILE_BYTES = 512e3;
10418
10419
  var MAX_INTENT_CHARS = 2e3;
@@ -10969,8 +10970,8 @@ function filterReviewable(files) {
10969
10970
  const ext = (0, import_node_path3.extname)(f).slice(1);
10970
10971
  if (ANALYZABLE_EXTENSIONS.has(ext)) return false;
10971
10972
  if (REVIEWABLE_EXTENSIONS.has(ext)) return true;
10972
- const basename4 = f.split("/").pop() ?? "";
10973
- if (REVIEWABLE_FILENAMES.has(basename4)) return true;
10973
+ const basename5 = f.split("/").pop() ?? "";
10974
+ if (REVIEWABLE_FILENAMES.has(basename5)) return true;
10974
10975
  if (REVIEWABLE_PATH_PATTERNS.some((p) => p.test(f))) return true;
10975
10976
  return false;
10976
10977
  });
@@ -12800,12 +12801,50 @@ function resolveGuardMoments(explicit) {
12800
12801
  }
12801
12802
 
12802
12803
  // src/lib/plugin-ownership.ts
12803
- var import_node_fs6 = require("node:fs");
12804
- var import_node_os2 = require("node:os");
12804
+ var import_node_fs7 = require("node:fs");
12805
+
12806
+ // src/lib/which.ts
12807
+ var import_node_fs5 = require("node:fs");
12805
12808
  var import_node_path7 = require("node:path");
12809
+ function executableExtensions(platform, pathext) {
12810
+ if (platform !== "win32") return [""];
12811
+ const raw = (pathext ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean);
12812
+ const out = [];
12813
+ for (const ext of raw) {
12814
+ const lower = ext.toLowerCase();
12815
+ if (!out.includes(lower)) out.push(lower);
12816
+ if (!out.includes(ext)) out.push(ext);
12817
+ }
12818
+ return out;
12819
+ }
12820
+ function whichSync(bin, opts = {}) {
12821
+ const platform = opts.platform ?? process.platform;
12822
+ const rawPath = opts.path ?? process.env.PATH ?? "";
12823
+ if (!rawPath) return null;
12824
+ const exts = executableExtensions(platform, opts.pathext ?? process.env.PATHEXT);
12825
+ const real = opts.real ?? true;
12826
+ for (const dir of rawPath.split(import_node_path7.delimiter)) {
12827
+ if (!dir) continue;
12828
+ for (const ext of exts) {
12829
+ const candidate = (0, import_node_path7.join)(dir, bin + ext);
12830
+ try {
12831
+ if (!(0, import_node_fs5.statSync)(candidate).isFile()) continue;
12832
+ if (platform !== "win32") (0, import_node_fs5.accessSync)(candidate, import_node_fs5.constants.X_OK);
12833
+ return real ? (0, import_node_fs5.realpathSync)(candidate) : candidate;
12834
+ } catch {
12835
+ continue;
12836
+ }
12837
+ }
12838
+ }
12839
+ return null;
12840
+ }
12841
+
12842
+ // src/lib/plugin-ownership.ts
12843
+ var import_node_os2 = require("node:os");
12844
+ var import_node_path8 = require("node:path");
12806
12845
 
12807
12846
  // src/lib/stderr-log.ts
12808
- var import_node_fs5 = require("node:fs");
12847
+ var import_node_fs6 = require("node:fs");
12809
12848
  var TOKEN_RE2 = /verity_[0-9a-f]{16,}/g;
12810
12849
  var ANSI_RE = /\u001b\[[0-?]*[ -/]*[@-~]/g;
12811
12850
  function scrub(s) {
@@ -12818,9 +12857,9 @@ function append(text) {
12818
12857
  try {
12819
12858
  const dir = projectPath(DEBUG_LOG_DIR);
12820
12859
  const file = projectPath(STDERR_LOG_FILE);
12821
- (0, import_node_fs5.mkdirSync)(dir, { recursive: true });
12860
+ (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
12822
12861
  rotateIfNeeded(file);
12823
- (0, import_node_fs5.appendFileSync)(file, text);
12862
+ (0, import_node_fs6.appendFileSync)(file, text);
12824
12863
  } catch {
12825
12864
  }
12826
12865
  }
@@ -12868,14 +12907,15 @@ function markerPath() {
12868
12907
  }
12869
12908
  function readMarker() {
12870
12909
  try {
12871
- if (!(0, import_node_fs6.existsSync)(markerPath())) return null;
12872
- const raw = JSON.parse((0, import_node_fs6.readFileSync)(markerPath(), "utf-8"));
12910
+ if (!(0, import_node_fs7.existsSync)(markerPath())) return null;
12911
+ const raw = JSON.parse((0, import_node_fs7.readFileSync)(markerPath(), "utf-8"));
12873
12912
  const pluginRoot = typeof raw.plugin_root === "string" ? raw.plugin_root : "";
12874
12913
  if (!pluginRoot || CONTROL_CHARS.test(pluginRoot)) return null;
12914
+ const version = typeof raw.version === "string" && !CONTROL_CHARS.test(raw.version) ? raw.version : null;
12875
12915
  return {
12876
12916
  session_id: typeof raw.session_id === "string" ? raw.session_id : null,
12877
12917
  plugin_root: pluginRoot,
12878
- version: typeof raw.version === "string" ? raw.version : null,
12918
+ version,
12879
12919
  ts: typeof raw.ts === "number" ? raw.ts : 0
12880
12920
  };
12881
12921
  } catch {
@@ -12886,23 +12926,23 @@ function recordPluginOwnership(sessionId) {
12886
12926
  const pluginRoot = process.env.VERITY_PLUGIN_ROOT;
12887
12927
  if (!pluginRoot) return;
12888
12928
  try {
12889
- (0, import_node_fs6.mkdirSync)(projectPath(VERITY_DIR), { recursive: true });
12929
+ (0, import_node_fs7.mkdirSync)(projectPath(VERITY_DIR), { recursive: true });
12890
12930
  const marker = {
12891
12931
  session_id: sessionId,
12892
12932
  plugin_root: pluginRoot,
12893
12933
  version: process.env.VERITY_PLUGIN_VERSION || null,
12894
12934
  ts: Math.floor(Date.now() / 1e3)
12895
12935
  };
12896
- (0, import_node_fs6.writeFileSync)(markerPath(), JSON.stringify(marker));
12936
+ (0, import_node_fs7.writeFileSync)(markerPath(), JSON.stringify(marker));
12897
12937
  } catch {
12898
12938
  }
12899
12939
  }
12900
12940
  function claudeConfigDir() {
12901
- return process.env.CLAUDE_CONFIG_DIR || (0, import_node_path7.join)((0, import_node_os2.homedir)(), ".claude");
12941
+ return process.env.CLAUDE_CONFIG_DIR || (0, import_node_path8.join)((0, import_node_os2.homedir)(), ".claude");
12902
12942
  }
12903
12943
  function readJsonFile(path) {
12904
12944
  try {
12905
- const parsed = JSON.parse((0, import_node_fs6.readFileSync)(path, "utf-8"));
12945
+ const parsed = JSON.parse((0, import_node_fs7.readFileSync)(path, "utf-8"));
12906
12946
  return parsed && typeof parsed === "object" ? parsed : null;
12907
12947
  } catch {
12908
12948
  return null;
@@ -12910,9 +12950,9 @@ function readJsonFile(path) {
12910
12950
  }
12911
12951
  function enabledPluginSetting(key) {
12912
12952
  const files = [
12913
- projectPath((0, import_node_path7.join)(".claude", "settings.local.json")),
12914
- projectPath((0, import_node_path7.join)(".claude", "settings.json")),
12915
- (0, import_node_path7.join)(claudeConfigDir(), "settings.json")
12953
+ projectPath((0, import_node_path8.join)(".claude", "settings.local.json")),
12954
+ projectPath((0, import_node_path8.join)(".claude", "settings.json")),
12955
+ (0, import_node_path8.join)(claudeConfigDir(), "settings.json")
12916
12956
  ];
12917
12957
  for (const file of files) {
12918
12958
  const map = readJsonFile(file)?.enabledPlugins;
@@ -12924,27 +12964,16 @@ function enabledPluginSetting(key) {
12924
12964
  }
12925
12965
  function marketplaceLocations() {
12926
12966
  const out = /* @__PURE__ */ new Map();
12927
- const known = readJsonFile((0, import_node_path7.join)(claudeConfigDir(), "plugins", "known_marketplaces.json"));
12967
+ const known = readJsonFile((0, import_node_path8.join)(claudeConfigDir(), "plugins", "known_marketplaces.json"));
12928
12968
  if (!known) return out;
12929
12969
  for (const [name, entry] of Object.entries(known)) {
12930
12970
  const loc2 = entry?.installLocation;
12931
- if (typeof loc2 === "string" && loc2) out.set(name, (0, import_node_path7.resolve)(loc2));
12971
+ if (typeof loc2 === "string" && loc2) out.set(name, (0, import_node_path8.resolve)(loc2));
12932
12972
  }
12933
12973
  return out;
12934
12974
  }
12935
12975
  function verityPathEntry() {
12936
- const path = process.env.PATH;
12937
- if (!path) return null;
12938
- for (const dir of path.split(import_node_path7.delimiter)) {
12939
- if (!dir) continue;
12940
- const candidate = (0, import_node_path7.join)(dir, "verity");
12941
- try {
12942
- (0, import_node_fs6.accessSync)(candidate, import_node_fs6.constants.X_OK);
12943
- return candidate;
12944
- } catch {
12945
- }
12946
- }
12947
- return null;
12976
+ return whichSync("verity", { real: false });
12948
12977
  }
12949
12978
  function verityOnPath() {
12950
12979
  return verityPathEntry() !== null;
@@ -12953,27 +12982,13 @@ function globalVerityVersion() {
12953
12982
  const entry = verityPathEntry();
12954
12983
  if (!entry) return null;
12955
12984
  try {
12956
- const pkg = readJsonFile((0, import_node_path7.join)((0, import_node_path7.dirname)((0, import_node_fs6.realpathSync)(entry)), "..", "package.json"));
12985
+ const pkg = readJsonFile((0, import_node_path8.join)((0, import_node_path8.dirname)((0, import_node_fs7.realpathSync)(entry)), "..", "package.json"));
12957
12986
  if (pkg?.name !== "@codacy/verity-cli" || typeof pkg.version !== "string") return null;
12958
12987
  return pkg.version;
12959
12988
  } catch {
12960
12989
  return null;
12961
12990
  }
12962
12991
  }
12963
- function pluginCliInvocation() {
12964
- const root = process.env.VERITY_PLUGIN_ROOT;
12965
- if (!root) return null;
12966
- const onPath = globalVerityVersion();
12967
- if (onPath !== null && onPath === activePluginVersion()) return null;
12968
- return `node ${JSON.stringify((0, import_node_path7.join)(root, "scripts", "verity.mjs"))}`;
12969
- }
12970
- function cliVersionSkew() {
12971
- if (!process.env.VERITY_PLUGIN_ROOT) return null;
12972
- const onPath = globalVerityVersion();
12973
- const plugin = activePluginVersion();
12974
- if (!onPath || !plugin || onPath === plugin) return null;
12975
- return { global: onPath, plugin };
12976
- }
12977
12992
  function activePluginVersion() {
12978
12993
  const fromEnv = process.env.VERITY_PLUGIN_VERSION;
12979
12994
  if (fromEnv) return fromEnv;
@@ -12984,7 +12999,7 @@ var VERITY_MARKETPLACE_REPO = "codacy/verity";
12984
12999
  function marketplaceConflict() {
12985
13000
  const wanted = VERITY_MARKETPLACE;
12986
13001
  for (const file of ["settings.json", "settings.local.json"]) {
12987
- const path = (0, import_node_path7.join)(claudeConfigDir(), file);
13002
+ const path = (0, import_node_path8.join)(claudeConfigDir(), file);
12988
13003
  const declared = readJsonFile(path)?.extraKnownMarketplaces ?? null;
12989
13004
  const entry2 = declared && typeof declared === "object" ? declared[wanted] : void 0;
12990
13005
  if (entry2 && typeof entry2 === "object") {
@@ -12994,7 +13009,7 @@ function marketplaceConflict() {
12994
13009
  }
12995
13010
  }
12996
13011
  }
12997
- const known = readJsonFile((0, import_node_path7.join)(claudeConfigDir(), "plugins", "known_marketplaces.json"));
13012
+ const known = readJsonFile((0, import_node_path8.join)(claudeConfigDir(), "plugins", "known_marketplaces.json"));
12998
13013
  const entry = known?.[wanted];
12999
13014
  if (entry && typeof entry === "object" && !pointsAtVerity(entry.source)) {
13000
13015
  return { name: wanted, declaredAs: describeSource(entry.source) };
@@ -13015,7 +13030,7 @@ function describeSource(src) {
13015
13030
  return target ? `${kind} \u2192 ${target}` : kind;
13016
13031
  }
13017
13032
  function legacyMarketplaceInstall() {
13018
- const plugins = readJsonFile((0, import_node_path7.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
13033
+ const plugins = readJsonFile((0, import_node_path8.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
13019
13034
  if (!plugins || typeof plugins !== "object") return null;
13020
13035
  for (const key of Object.keys(plugins)) {
13021
13036
  const at = key.lastIndexOf("@");
@@ -13027,13 +13042,13 @@ function legacyMarketplaceInstall() {
13027
13042
  }
13028
13043
  function realpathOr(p) {
13029
13044
  try {
13030
- return import_node_fs6.realpathSync.native(p);
13045
+ return import_node_fs7.realpathSync.native(p);
13031
13046
  } catch {
13032
- return (0, import_node_path7.resolve)(p);
13047
+ return (0, import_node_path8.resolve)(p);
13033
13048
  }
13034
13049
  }
13035
13050
  function isWithin(want, dir) {
13036
- return want === dir || want.startsWith(dir + import_node_path7.sep);
13051
+ return want === dir || want.startsWith(dir + import_node_path8.sep);
13037
13052
  }
13038
13053
  function entryAppliesHere(entry, here) {
13039
13054
  const e = entry;
@@ -13043,9 +13058,9 @@ function entryAppliesHere(entry, here) {
13043
13058
  return forProject === here;
13044
13059
  }
13045
13060
  function registrySays(pluginRoot) {
13046
- const plugins = readJsonFile((0, import_node_path7.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
13061
+ const plugins = readJsonFile((0, import_node_path8.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
13047
13062
  if (!plugins || typeof plugins !== "object") return "unverified";
13048
- const want = (0, import_node_path7.resolve)(pluginRoot);
13063
+ const want = (0, import_node_path8.resolve)(pluginRoot);
13049
13064
  const here = realpathOr(repoRoot());
13050
13065
  const markets = marketplaceLocations();
13051
13066
  for (const [key, value] of Object.entries(plugins)) {
@@ -13054,15 +13069,15 @@ function registrySays(pluginRoot) {
13054
13069
  const applicable = (Array.isArray(value) ? value : []).filter((entry) => entryAppliesHere(entry, here));
13055
13070
  const claims = applicable.some((entry) => {
13056
13071
  const installPath = entry?.installPath;
13057
- return typeof installPath === "string" && (0, import_node_path7.resolve)(installPath) === want;
13072
+ return typeof installPath === "string" && (0, import_node_path8.resolve)(installPath) === want;
13058
13073
  }) || source !== void 0 && applicable.length > 0 && isWithin(want, source);
13059
13074
  if (claims) {
13060
13075
  if (enabledPluginSetting(key) === false) return "gone";
13061
- return (0, import_node_fs6.existsSync)(pluginRoot) ? "live" : "gone";
13076
+ return (0, import_node_fs7.existsSync)(pluginRoot) ? "live" : "gone";
13062
13077
  }
13063
13078
  }
13064
- const managed = (0, import_node_path7.resolve)((0, import_node_path7.join)(claudeConfigDir(), "plugins", "cache"));
13065
- return want === managed || want.startsWith(managed + import_node_path7.sep) ? "gone" : "unverified";
13079
+ const managed = (0, import_node_path8.resolve)((0, import_node_path8.join)(claudeConfigDir(), "plugins", "cache"));
13080
+ return want === managed || want.startsWith(managed + import_node_path8.sep) ? "gone" : "unverified";
13066
13081
  }
13067
13082
  var _live = /* @__PURE__ */ new Map();
13068
13083
  function pluginLiveness(pluginRoot) {
@@ -13076,7 +13091,7 @@ function clearStalePluginMarker() {
13076
13091
  const marker = readMarker();
13077
13092
  if (!marker || pluginLiveness(marker.plugin_root) !== "gone") return null;
13078
13093
  try {
13079
- (0, import_node_fs6.rmSync)(markerPath(), { force: true });
13094
+ (0, import_node_fs7.rmSync)(markerPath(), { force: true });
13080
13095
  } catch {
13081
13096
  return null;
13082
13097
  }
@@ -13104,7 +13119,7 @@ function pluginActiveHere() {
13104
13119
  return activePluginInstall() !== null;
13105
13120
  }
13106
13121
  function registeredVerityPlugin() {
13107
- const plugins = readJsonFile((0, import_node_path7.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
13122
+ const plugins = readJsonFile((0, import_node_path8.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
13108
13123
  if (!plugins || typeof plugins !== "object") return null;
13109
13124
  const here = realpathOr(repoRoot());
13110
13125
  for (const [key, value] of Object.entries(plugins)) {
@@ -13114,7 +13129,7 @@ function registeredVerityPlugin() {
13114
13129
  for (const entry of Array.isArray(value) ? value : []) {
13115
13130
  const e = entry;
13116
13131
  const installPath = typeof e.installPath === "string" ? e.installPath : "";
13117
- if (!installPath || !(0, import_node_fs6.existsSync)(installPath)) continue;
13132
+ if (!installPath || !(0, import_node_fs7.existsSync)(installPath)) continue;
13118
13133
  if (!entryAppliesHere(entry, here)) continue;
13119
13134
  return { pluginRoot: installPath, version: typeof e.version === "string" ? e.version : null };
13120
13135
  }
@@ -13165,6 +13180,150 @@ async function resolveHookWiring() {
13165
13180
  };
13166
13181
  }
13167
13182
 
13183
+ // src/lib/cli-provenance.ts
13184
+ var import_node_fs8 = require("node:fs");
13185
+ var import_node_os3 = require("node:os");
13186
+ var import_node_path9 = require("node:path");
13187
+ var CLI_PACKAGE = "@codacy/verity-cli";
13188
+ var CLI_ENTRY = (0, import_node_path9.join)("node_modules", CLI_PACKAGE, "bin", "verity.js");
13189
+ function readJson(path) {
13190
+ try {
13191
+ const parsed = JSON.parse((0, import_node_fs8.readFileSync)(path, "utf-8"));
13192
+ return parsed && typeof parsed === "object" ? parsed : null;
13193
+ } catch {
13194
+ return null;
13195
+ }
13196
+ }
13197
+ function versionUnder(base) {
13198
+ const entry = (0, import_node_path9.join)(base, CLI_ENTRY);
13199
+ if (!(0, import_node_fs8.existsSync)(entry)) return null;
13200
+ const pkg = readJson((0, import_node_path9.join)(base, "node_modules", CLI_PACKAGE, "package.json"));
13201
+ return typeof pkg?.version === "string" ? pkg.version : null;
13202
+ }
13203
+ function versionForEntry(entry) {
13204
+ try {
13205
+ const pkg = readJson((0, import_node_path9.join)((0, import_node_path9.dirname)((0, import_node_fs8.realpathSync)(entry)), "..", "package.json"));
13206
+ return typeof pkg?.version === "string" ? pkg.version : null;
13207
+ } catch {
13208
+ return null;
13209
+ }
13210
+ }
13211
+ function resolveHooksCli(pluginRoot) {
13212
+ const override = process.env.VERITY_CLI_PATH;
13213
+ if (override && (0, import_node_fs8.existsSync)(override)) {
13214
+ return { version: versionForEntry(override), rung: "override" };
13215
+ }
13216
+ const fromPlugin = versionUnder(pluginRoot);
13217
+ if (fromPlugin !== null) return { version: fromPlugin, rung: "plugin" };
13218
+ if ((0, import_node_fs8.existsSync)((0, import_node_path9.join)(pluginRoot, CLI_ENTRY))) return { version: null, rung: "plugin" };
13219
+ const dataDir = process.env.CLAUDE_PLUGIN_DATA || (0, import_node_path9.join)((0, import_node_os3.homedir)(), ".verity", "plugin-cli");
13220
+ const fromData = versionUnder(dataDir);
13221
+ if (fromData !== null) return { version: fromData, rung: "plugin-data" };
13222
+ if ((0, import_node_fs8.existsSync)((0, import_node_path9.join)(dataDir, CLI_ENTRY))) return { version: null, rung: "plugin-data" };
13223
+ const global = globalVerityVersion();
13224
+ if (global !== null) return { version: global, rung: "global" };
13225
+ return null;
13226
+ }
13227
+ function compareVersions(a, b) {
13228
+ const parse = (v) => {
13229
+ const [core, ...rest] = v.split("-");
13230
+ const parts = core.split(".");
13231
+ if (parts.length !== 3) return null;
13232
+ const nums = parts.map((p) => /^\d+$/.test(p) ? Number(p) : NaN);
13233
+ if (nums.some(Number.isNaN)) return null;
13234
+ return { nums, pre: rest.join("-") };
13235
+ };
13236
+ const x = parse(a);
13237
+ const y = parse(b);
13238
+ if (!x || !y) return null;
13239
+ for (let i = 0; i < 3; i++) {
13240
+ if (x.nums[i] !== y.nums[i]) return x.nums[i] < y.nums[i] ? -1 : 1;
13241
+ }
13242
+ if (x.pre === y.pre) return 0;
13243
+ if (!x.pre) return 1;
13244
+ if (!y.pre) return -1;
13245
+ return null;
13246
+ }
13247
+ var PLUGIN_UPDATE_REMEDY = "claude plugin update verity@verity, then /reload-plugins (or restart Claude Code)";
13248
+ function globalUpdateRemedy(version) {
13249
+ return `npm install -g ${CLI_PACKAGE}@${version}`;
13250
+ }
13251
+ function remedyFor(global, hooks) {
13252
+ const order = compareVersions(global, hooks);
13253
+ if (order === -1) return { behind: "global", remedy: globalUpdateRemedy(hooks) };
13254
+ if (order === 1) return { behind: "plugin", remedy: PLUGIN_UPDATE_REMEDY };
13255
+ return {
13256
+ behind: "unknown",
13257
+ remedy: `${globalUpdateRemedy(hooks)} \u2014 or, if the plugin is the older one, ${PLUGIN_UPDATE_REMEDY}`
13258
+ };
13259
+ }
13260
+ function cliProvenance() {
13261
+ const envRoot = process.env.VERITY_PLUGIN_ROOT;
13262
+ const install = envRoot ? { pluginRoot: envRoot, version: process.env.VERITY_PLUGIN_VERSION || activePluginInstall()?.version || null } : activePluginInstall();
13263
+ const global = globalVerityVersion();
13264
+ if (!install) return { plugin: null, hooksCli: null, global, skew: null };
13265
+ const hooksCli = resolveHooksCli(install.pluginRoot);
13266
+ return {
13267
+ plugin: { root: install.pluginRoot, version: install.version },
13268
+ hooksCli,
13269
+ global,
13270
+ skew: computeSkew(global, hooksCli)
13271
+ };
13272
+ }
13273
+ function computeSkew(global, hooksCli) {
13274
+ if (!global || !hooksCli?.version) return null;
13275
+ if (global === hooksCli.version) return null;
13276
+ return { global, hooks: hooksCli.version, ...remedyFor(global, hooksCli.version) };
13277
+ }
13278
+ function cliVersionSkew() {
13279
+ return cliProvenance().skew;
13280
+ }
13281
+ function versionReport(p = cliProvenance()) {
13282
+ if (!p.plugin) return null;
13283
+ return {
13284
+ plugin: p.plugin.version,
13285
+ hooksCli: p.hooksCli?.version ?? null,
13286
+ hooksCliRung: p.hooksCli?.rung ?? null,
13287
+ global: p.global,
13288
+ skew: p.skew
13289
+ };
13290
+ }
13291
+ function versionLines(v) {
13292
+ if (!v) return { info: [], warn: [] };
13293
+ const plugin = v.plugin ? `plugin ${v.plugin}` : "plugin (version unreadable)";
13294
+ const rung = v.hooksCliRung && v.hooksCliRung !== "plugin" ? ` via ${RUNG_LABELS[v.hooksCliRung]}` : "";
13295
+ const hooks = v.hooksCli ? `hooks run ${CLI_PACKAGE} ${v.hooksCli}${rung}` : "hooks run a CLI whose version could not be read";
13296
+ if (!v.skew) {
13297
+ const agrees = v.global && v.hooksCli && v.global === v.hooksCli ? " \xB7 `verity` on PATH matches \u2713" : "";
13298
+ return { info: [` Versions: ${plugin} \xB7 ${hooks}${agrees}`], warn: [] };
13299
+ }
13300
+ return {
13301
+ info: [` Versions: ${plugin} \xB7 ${hooks}`],
13302
+ warn: [
13303
+ ` \u26A0 \`verity\` on PATH is ${v.skew.global}, which is NOT the CLI the hooks run (${v.skew.hooks}).`,
13304
+ ` The gate and your terminal are different builds. Fix: ${v.skew.remedy}`
13305
+ ]
13306
+ };
13307
+ }
13308
+ var RUNG_LABELS = {
13309
+ override: "VERITY_CLI_PATH",
13310
+ plugin: "the plugin's node_modules",
13311
+ "plugin-data": "the plugin's data directory",
13312
+ global: "the global install on PATH"
13313
+ };
13314
+ function pluginCliInvocation() {
13315
+ const root = process.env.VERITY_PLUGIN_ROOT;
13316
+ if (!root) return null;
13317
+ const onPath = globalVerityVersion();
13318
+ if (onPath === null) return resolverCommand(root);
13319
+ const hooksCli = resolveHooksCli(root);
13320
+ if (hooksCli?.version && hooksCli.version === onPath) return null;
13321
+ return resolverCommand(root);
13322
+ }
13323
+ function resolverCommand(root) {
13324
+ return `node ${JSON.stringify((0, import_node_path9.join)(root, "scripts", "verity.mjs"))}`;
13325
+ }
13326
+
13168
13327
  // src/commands/hooks.ts
13169
13328
  var ALL_MOMENTS = ["stop", "pre-commit", "pre-push"];
13170
13329
  function parseMomentSelection(raw) {
@@ -13259,6 +13418,9 @@ function registerHooksCommands(program2) {
13259
13418
  const moments = status.guardOn;
13260
13419
  const inherited = wiring.gitMoments.source === "main-worktree" && wiring.gitMoments.path ? ` (inherited from the main worktree: ${wiring.gitMoments.path})` : "";
13261
13420
  printInfo("Wired by the Verity Claude Code plugin (not .claude/settings.json):");
13421
+ const versionOut = versionLines(versionReport());
13422
+ for (const line of versionOut.info) printInfo(line);
13423
+ for (const line of versionOut.warn) printWarn(line);
13262
13424
  printInfo(" Stop hook (verity analyze): installed");
13263
13425
  printInfo(" Intent hook (verity intent capture): installed");
13264
13426
  printInfo(" Baseline hook (verity baseline capture): installed");
@@ -13299,7 +13461,7 @@ var import_node_crypto8 = require("node:crypto");
13299
13461
 
13300
13462
  // src/lib/conversation-buffer.ts
13301
13463
  var import_promises5 = require("node:fs/promises");
13302
- var import_node_fs7 = require("node:fs");
13464
+ var import_node_fs9 = require("node:fs");
13303
13465
  var import_node_child_process5 = require("node:child_process");
13304
13466
  var import_node_crypto = require("node:crypto");
13305
13467
  function stripImageReferences(text) {
@@ -13335,7 +13497,7 @@ async function appendToConversationBuffer(prompt, sessionId) {
13335
13497
  }
13336
13498
  async function readAndClearConversationBuffer(currentSessionId) {
13337
13499
  try {
13338
- if ((0, import_node_fs7.existsSync)(CONVERSATION_BUFFER_FILE)) {
13500
+ if ((0, import_node_fs9.existsSync)(CONVERSATION_BUFFER_FILE)) {
13339
13501
  const entries = await readBufferEntries();
13340
13502
  let mine = entries;
13341
13503
  let others = [];
@@ -13359,7 +13521,7 @@ async function readAndClearConversationBuffer(currentSessionId) {
13359
13521
  };
13360
13522
  }
13361
13523
  }
13362
- if ((0, import_node_fs7.existsSync)(INTENT_FILE)) {
13524
+ if ((0, import_node_fs9.existsSync)(INTENT_FILE)) {
13363
13525
  try {
13364
13526
  const content = await (0, import_promises5.readFile)(INTENT_FILE, "utf-8");
13365
13527
  await (0, import_promises5.unlink)(INTENT_FILE).catch(() => {
@@ -13652,9 +13814,9 @@ function isCommandOnlyTurn(input) {
13652
13814
 
13653
13815
  // src/lib/context-identity.ts
13654
13816
  var import_node_crypto2 = require("node:crypto");
13655
- var import_node_fs8 = require("node:fs");
13656
- var import_node_os3 = require("node:os");
13657
- var import_node_path8 = require("node:path");
13817
+ var import_node_fs10 = require("node:fs");
13818
+ var import_node_os4 = require("node:os");
13819
+ var import_node_path10 = require("node:path");
13658
13820
  var SHARED_SENTINELS = /* @__PURE__ */ new Set([
13659
13821
  "",
13660
13822
  "-",
@@ -13692,7 +13854,7 @@ function contextIdentity(input) {
13692
13854
  if (rawTree && !isSharedSentinel(rawTree)) {
13693
13855
  let resolved = rawTree;
13694
13856
  try {
13695
- resolved = import_node_fs8.realpathSync.native(rawTree);
13857
+ resolved = import_node_fs10.realpathSync.native(rawTree);
13696
13858
  } catch {
13697
13859
  }
13698
13860
  treeKey = (0, import_node_crypto2.createHash)("sha256").update(resolved).digest("hex").slice(0, 12);
@@ -13708,13 +13870,13 @@ function contextIdentity(input) {
13708
13870
  }
13709
13871
  function verityHome() {
13710
13872
  const override = process.env.VERITY_HOME;
13711
- return override && override.trim() ? (0, import_node_path8.resolve)(override) : (0, import_node_path8.join)((0, import_node_os3.homedir)(), ".verity");
13873
+ return override && override.trim() ? (0, import_node_path10.resolve)(override) : (0, import_node_path10.join)((0, import_node_os4.homedir)(), ".verity");
13712
13874
  }
13713
13875
  function dossierDir(identity) {
13714
- return (0, import_node_path8.join)(verityHome(), "sessions", identity.userKey, identity.treeKey, identity.sessionKey);
13876
+ return (0, import_node_path10.join)(verityHome(), "sessions", identity.userKey, identity.treeKey, identity.sessionKey);
13715
13877
  }
13716
13878
  function treeDir(identity) {
13717
- return (0, import_node_path8.join)(verityHome(), "sessions", identity.userKey, identity.treeKey);
13879
+ return (0, import_node_path10.join)(verityHome(), "sessions", identity.userKey, identity.treeKey);
13718
13880
  }
13719
13881
  function scopeIdentity(token, sessionId) {
13720
13882
  const t = (token ?? "").trim();
@@ -13729,8 +13891,8 @@ function sessionScopeKey(token, sessionId) {
13729
13891
 
13730
13892
  // src/lib/task-context-buffer.ts
13731
13893
  var import_promises6 = require("node:fs/promises");
13732
- var import_node_fs9 = require("node:fs");
13733
- var import_node_path9 = require("node:path");
13894
+ var import_node_fs11 = require("node:fs");
13895
+ var import_node_path11 = require("node:path");
13734
13896
  var TASK_CONTEXT_DIR = `${VERITY_DIR}/.task-context`;
13735
13897
  var MAX_BUFFER_BYTES = 500 * 1024;
13736
13898
  var MAX_PROMPT_CHARS = 2e3;
@@ -13769,7 +13931,7 @@ async function appendResponseToTaskBuffer(taskId, assistantResponse, actionSumma
13769
13931
  }
13770
13932
  async function readTaskContextBuffer(taskId) {
13771
13933
  const filePath = bufferPath(taskId);
13772
- if (!(0, import_node_fs9.existsSync)(filePath)) return null;
13934
+ if (!(0, import_node_fs11.existsSync)(filePath)) return null;
13773
13935
  try {
13774
13936
  const content = await (0, import_promises6.readFile)(filePath, "utf-8");
13775
13937
  if (!content.trim()) return null;
@@ -13803,12 +13965,12 @@ async function readTaskContextBuffer(taskId) {
13803
13965
  }
13804
13966
  async function cleanupTaskContextBuffers() {
13805
13967
  try {
13806
- if (!(0, import_node_fs9.existsSync)(TASK_CONTEXT_DIR)) return;
13968
+ if (!(0, import_node_fs11.existsSync)(TASK_CONTEXT_DIR)) return;
13807
13969
  const files = await (0, import_promises6.readdir)(TASK_CONTEXT_DIR);
13808
13970
  const cutoffMs = Date.now() - RETENTION_DAYS * 24 * 60 * 60 * 1e3;
13809
13971
  for (const file of files) {
13810
13972
  if (!file.endsWith(".jsonl")) continue;
13811
- const filePath = (0, import_node_path9.join)(TASK_CONTEXT_DIR, file);
13973
+ const filePath = (0, import_node_path11.join)(TASK_CONTEXT_DIR, file);
13812
13974
  try {
13813
13975
  const stats = await (0, import_promises6.stat)(filePath);
13814
13976
  if (stats.mtimeMs < cutoffMs) {
@@ -13822,13 +13984,13 @@ async function cleanupTaskContextBuffers() {
13822
13984
  }
13823
13985
  function bufferPath(taskId) {
13824
13986
  const safe = taskId.replace(/[^a-zA-Z0-9_-]/g, "");
13825
- return (0, import_node_path9.join)(TASK_CONTEXT_DIR, `${safe}.jsonl`);
13987
+ return (0, import_node_path11.join)(TASK_CONTEXT_DIR, `${safe}.jsonl`);
13826
13988
  }
13827
13989
  async function appendEntry(taskId, entry) {
13828
13990
  try {
13829
13991
  await (0, import_promises6.mkdir)(TASK_CONTEXT_DIR, { recursive: true });
13830
13992
  const filePath = bufferPath(taskId);
13831
- if ((0, import_node_fs9.existsSync)(filePath)) {
13993
+ if ((0, import_node_fs11.existsSync)(filePath)) {
13832
13994
  const stats = await (0, import_promises6.stat)(filePath);
13833
13995
  if (stats.size >= MAX_BUFFER_BYTES) {
13834
13996
  const content = await (0, import_promises6.readFile)(filePath, "utf-8");
@@ -13839,7 +14001,7 @@ async function appendEntry(taskId, entry) {
13839
14001
  }
13840
14002
  }
13841
14003
  const line = JSON.stringify(entry) + "\n";
13842
- const existing = (0, import_node_fs9.existsSync)(filePath) ? await (0, import_promises6.readFile)(filePath, "utf-8") : "";
14004
+ const existing = (0, import_node_fs11.existsSync)(filePath) ? await (0, import_promises6.readFile)(filePath, "utf-8") : "";
13843
14005
  await (0, import_promises6.writeFile)(filePath, existing + line);
13844
14006
  } catch {
13845
14007
  }
@@ -13847,20 +14009,20 @@ async function appendEntry(taskId, entry) {
13847
14009
 
13848
14010
  // src/lib/memory-retrieval.ts
13849
14011
  var import_promises8 = require("node:fs/promises");
13850
- var import_node_fs11 = require("node:fs");
13851
- var import_node_path11 = require("node:path");
14012
+ var import_node_fs13 = require("node:fs");
14013
+ var import_node_path13 = require("node:path");
13852
14014
 
13853
14015
  // src/lib/org-mirror.ts
13854
- var import_node_fs10 = require("node:fs");
14016
+ var import_node_fs12 = require("node:fs");
13855
14017
  var import_promises7 = require("node:fs/promises");
13856
- var import_node_path10 = require("node:path");
14018
+ var import_node_path12 = require("node:path");
13857
14019
  var ORG_KINDS = ["decision", "security", "gotcha", "pattern", "domain", "integration"];
13858
14020
  var STATE_FILE = ".org-pull-state.json";
13859
14021
  var BODY_MAX = 8192;
13860
14022
  function orgMirrorDir(remote = requestRemote()) {
13861
14023
  const parsed = parseRemote(remote);
13862
14024
  if (!parsed) return null;
13863
- return (0, import_node_path10.join)(verityHome(), "orgs", parsed.host, parsed.owner.toLowerCase(), "memory");
14025
+ return (0, import_node_path12.join)(verityHome(), "orgs", parsed.host, parsed.owner.toLowerCase(), "memory");
13864
14026
  }
13865
14027
  function slugify(s) {
13866
14028
  return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
@@ -13926,7 +14088,7 @@ function parseOrgNode(content) {
13926
14088
  }
13927
14089
  async function readState(dir) {
13928
14090
  try {
13929
- const parsed = JSON.parse(await (0, import_promises7.readFile)((0, import_node_path10.join)(dir, STATE_FILE), "utf-8"));
14091
+ const parsed = JSON.parse(await (0, import_promises7.readFile)((0, import_node_path12.join)(dir, STATE_FILE), "utf-8"));
13930
14092
  return {
13931
14093
  version: typeof parsed?.version === "string" ? parsed.version : null,
13932
14094
  organization: parsed?.organization && typeof parsed.organization.id === "string" ? parsed.organization : null,
@@ -13938,7 +14100,7 @@ async function readState(dir) {
13938
14100
  }
13939
14101
  async function writeState(dir, state) {
13940
14102
  await (0, import_promises7.mkdir)(dir, { recursive: true });
13941
- await (0, import_promises7.writeFile)((0, import_node_path10.join)(dir, STATE_FILE), JSON.stringify({
14103
+ await (0, import_promises7.writeFile)((0, import_node_path12.join)(dir, STATE_FILE), JSON.stringify({
13942
14104
  ...state.version ? { version: state.version } : {},
13943
14105
  organization: state.organization,
13944
14106
  pulled_at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -14003,24 +14165,24 @@ async function pullOrgKnowledge(opts) {
14003
14165
  for (const n of nodes) {
14004
14166
  const rel = orgNodePath(n);
14005
14167
  if (written.has(rel)) continue;
14006
- await (0, import_promises7.mkdir)((0, import_node_path10.join)(dir, rel.split("/")[0]), { recursive: true });
14007
- await (0, import_promises7.writeFile)((0, import_node_path10.join)(dir, rel), renderOrgNode(n, org?.name ?? ""));
14168
+ await (0, import_promises7.mkdir)((0, import_node_path12.join)(dir, rel.split("/")[0]), { recursive: true });
14169
+ await (0, import_promises7.writeFile)((0, import_node_path12.join)(dir, rel), renderOrgNode(n, org?.name ?? ""));
14008
14170
  written.add(rel);
14009
14171
  }
14010
14172
  for (const rel of state.files) {
14011
- if (!written.has(rel)) await (0, import_promises7.rm)((0, import_node_path10.join)(dir, rel), { force: true });
14173
+ if (!written.has(rel)) await (0, import_promises7.rm)((0, import_node_path12.join)(dir, rel), { force: true });
14012
14174
  }
14013
- await (0, import_promises7.writeFile)((0, import_node_path10.join)(dir, "index.md"), renderIndex(org?.name ?? "no organization", nodes));
14175
+ await (0, import_promises7.writeFile)((0, import_node_path12.join)(dir, "index.md"), renderIndex(org?.name ?? "no organization", nodes));
14014
14176
  await writeState(dir, { version: org ? page.version : null, organization: org, files: [...written].sort() });
14015
14177
  return { ok: true, status: org ? "pulled" : "none", received: nodes.length, dir };
14016
14178
  }
14017
14179
  async function readOrgMirror(remote = requestRemote()) {
14018
14180
  const dir = orgMirrorDir(remote);
14019
- if (!dir || !(0, import_node_fs10.existsSync)(dir)) return [];
14181
+ if (!dir || !(0, import_node_fs12.existsSync)(dir)) return [];
14020
14182
  const out = [];
14021
14183
  for (const kind of ORG_KINDS) {
14022
- const kindDir = (0, import_node_path10.join)(dir, kind);
14023
- if (!(0, import_node_fs10.existsSync)(kindDir)) continue;
14184
+ const kindDir = (0, import_node_path12.join)(dir, kind);
14185
+ if (!(0, import_node_fs12.existsSync)(kindDir)) continue;
14024
14186
  let files;
14025
14187
  try {
14026
14188
  files = await (0, import_promises7.readdir)(kindDir);
@@ -14030,7 +14192,7 @@ async function readOrgMirror(remote = requestRemote()) {
14030
14192
  for (const file of files) {
14031
14193
  if (!file.endsWith(".md")) continue;
14032
14194
  try {
14033
- const node = parseOrgNode(await (0, import_promises7.readFile)((0, import_node_path10.join)(kindDir, file), "utf-8"));
14195
+ const node = parseOrgNode(await (0, import_promises7.readFile)((0, import_node_path12.join)(kindDir, file), "utf-8"));
14034
14196
  if (node) out.push(node);
14035
14197
  } catch {
14036
14198
  }
@@ -14153,19 +14315,19 @@ function parseFrontmatter(content) {
14153
14315
  return { fm, body: match[2].trim() };
14154
14316
  }
14155
14317
  async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = DEFAULT_BUDGET_TOKENS) {
14156
- const hasRepoGraph = (0, import_node_fs11.existsSync)(memoryDir());
14318
+ const hasRepoGraph = (0, import_node_fs13.existsSync)(memoryDir());
14157
14319
  const budget = Math.min(budgetTokens, MAX_BUDGET_TOKENS);
14158
14320
  const promptTokens = tokenize(promptText);
14159
14321
  const nodes = [];
14160
14322
  for (const domain of hasRepoGraph ? DOMAINS : []) {
14161
- const domainDir = (0, import_node_path11.join)(memoryDir(), domain);
14162
- if (!(0, import_node_fs11.existsSync)(domainDir)) continue;
14323
+ const domainDir = (0, import_node_path13.join)(memoryDir(), domain);
14324
+ if (!(0, import_node_fs13.existsSync)(domainDir)) continue;
14163
14325
  try {
14164
14326
  const files = await (0, import_promises8.readdir)(domainDir);
14165
14327
  for (const file of files) {
14166
14328
  if (!file.endsWith(".md")) continue;
14167
14329
  try {
14168
- const content = await (0, import_promises8.readFile)((0, import_node_path11.join)(domainDir, file), "utf-8");
14330
+ const content = await (0, import_promises8.readFile)((0, import_node_path13.join)(domainDir, file), "utf-8");
14169
14331
  const { fm, body } = parseFrontmatter(content);
14170
14332
  if (fm.status && fm.status !== "active") continue;
14171
14333
  nodes.push({
@@ -14232,13 +14394,13 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
14232
14394
 
14233
14395
  // src/lib/memory-sync.ts
14234
14396
  var import_promises9 = require("node:fs/promises");
14235
- var import_node_fs14 = require("node:fs");
14236
- var import_node_path13 = require("node:path");
14397
+ var import_node_fs16 = require("node:fs");
14398
+ var import_node_path15 = require("node:path");
14237
14399
  var import_node_crypto3 = require("node:crypto");
14238
14400
 
14239
14401
  // src/lib/gitignore.ts
14240
14402
  var import_node_child_process6 = require("node:child_process");
14241
- var import_node_fs12 = require("node:fs");
14403
+ var import_node_fs14 = require("node:fs");
14242
14404
  var VERITY_GITIGNORE_MARKER = "# Verity \u2014 machine-local state.";
14243
14405
  var SETTINGS_LOCAL_IGNORE_ENTRY = ".claude/settings.local.json";
14244
14406
  var VERITY_GITIGNORE_BLOCK = [
@@ -14322,7 +14484,7 @@ function fenceMemoryLines(lines) {
14322
14484
  function ensureVerityGitignore() {
14323
14485
  let content = "";
14324
14486
  try {
14325
- content = (0, import_node_fs12.readFileSync)(".gitignore", "utf-8");
14487
+ content = (0, import_node_fs14.readFileSync)(".gitignore", "utf-8");
14326
14488
  } catch {
14327
14489
  }
14328
14490
  const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
@@ -14349,7 +14511,7 @@ function ensureVerityGitignore() {
14349
14511
  const sep4 = text === "" ? "" : text.endsWith("\n") ? "\n" : "\n\n";
14350
14512
  text = text + sep4 + VERITY_GITIGNORE_BLOCK;
14351
14513
  }
14352
- if (text !== content) (0, import_node_fs12.writeFileSync)(".gitignore", text);
14514
+ if (text !== content) (0, import_node_fs14.writeFileSync)(".gitignore", text);
14353
14515
  return verified(
14354
14516
  memoryIsCommitted ? "memory-tracked" : hasSupersededMemory ? "memory-fenced" : needsRepair ? "repaired" : "added"
14355
14517
  );
@@ -14369,7 +14531,7 @@ function untrackMemory() {
14369
14531
  function writeFencedBlock() {
14370
14532
  let content = "";
14371
14533
  try {
14372
- content = (0, import_node_fs12.readFileSync)(".gitignore", "utf-8");
14534
+ content = (0, import_node_fs14.readFileSync)(".gitignore", "utf-8");
14373
14535
  } catch {
14374
14536
  }
14375
14537
  const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
@@ -14381,7 +14543,7 @@ function writeFencedBlock() {
14381
14543
  text = text + sep4 + VERITY_GITIGNORE_BLOCK;
14382
14544
  }
14383
14545
  try {
14384
- (0, import_node_fs12.writeFileSync)(".gitignore", text);
14546
+ (0, import_node_fs14.writeFileSync)(".gitignore", text);
14385
14547
  return true;
14386
14548
  } catch {
14387
14549
  return false;
@@ -14390,14 +14552,14 @@ function writeFencedBlock() {
14390
14552
  function fenceMemory() {
14391
14553
  let original = null;
14392
14554
  try {
14393
- original = (0, import_node_fs12.readFileSync)(".gitignore", "utf-8");
14555
+ original = (0, import_node_fs14.readFileSync)(".gitignore", "utf-8");
14394
14556
  } catch {
14395
14557
  original = null;
14396
14558
  }
14397
14559
  const restore = () => {
14398
14560
  try {
14399
- if (original === null) (0, import_node_fs12.rmSync)(".gitignore", { force: true });
14400
- else (0, import_node_fs12.writeFileSync)(".gitignore", original);
14561
+ if (original === null) (0, import_node_fs14.rmSync)(".gitignore", { force: true });
14562
+ else (0, import_node_fs14.writeFileSync)(".gitignore", original);
14401
14563
  } catch {
14402
14564
  }
14403
14565
  };
@@ -14415,7 +14577,7 @@ function fenceMemory() {
14415
14577
  }
14416
14578
  function memoryOptOut() {
14417
14579
  try {
14418
- return (0, import_node_fs12.readFileSync)(".gitignore", "utf-8").includes(MEMORY_OPT_OUT_MARKER);
14580
+ return (0, import_node_fs14.readFileSync)(".gitignore", "utf-8").includes(MEMORY_OPT_OUT_MARKER);
14419
14581
  } catch {
14420
14582
  return false;
14421
14583
  }
@@ -14423,13 +14585,13 @@ function memoryOptOut() {
14423
14585
  function keepMemoryTracked() {
14424
14586
  let content = "";
14425
14587
  try {
14426
- content = (0, import_node_fs12.readFileSync)(".gitignore", "utf-8");
14588
+ content = (0, import_node_fs14.readFileSync)(".gitignore", "utf-8");
14427
14589
  } catch {
14428
14590
  }
14429
14591
  if (content.includes(MEMORY_OPT_OUT_MARKER)) return "already";
14430
14592
  try {
14431
14593
  const sep4 = content === "" ? "" : content.endsWith("\n") ? "\n" : "\n\n";
14432
- (0, import_node_fs12.writeFileSync)(".gitignore", content + sep4 + MEMORY_OPT_OUT_STANZA);
14594
+ (0, import_node_fs14.writeFileSync)(".gitignore", content + sep4 + MEMORY_OPT_OUT_STANZA);
14433
14595
  } catch {
14434
14596
  return "failed";
14435
14597
  }
@@ -14464,26 +14626,26 @@ function untrackVerityState() {
14464
14626
  }
14465
14627
 
14466
14628
  // src/lib/safe-path.ts
14467
- var import_node_fs13 = require("node:fs");
14468
- var import_node_path12 = require("node:path");
14629
+ var import_node_fs15 = require("node:fs");
14630
+ var import_node_path14 = require("node:path");
14469
14631
  function resolveInside(baseDir, candidate) {
14470
14632
  if (typeof candidate !== "string" || candidate.length === 0) return null;
14471
- if ((0, import_node_path12.isAbsolute)(candidate)) return null;
14472
- const baseAbs = (0, import_node_path12.resolve)(baseDir);
14473
- const full = (0, import_node_path12.resolve)(baseAbs, candidate);
14474
- const baseSep = baseAbs.endsWith(import_node_path12.sep) ? baseAbs : baseAbs + import_node_path12.sep;
14633
+ if ((0, import_node_path14.isAbsolute)(candidate)) return null;
14634
+ const baseAbs = (0, import_node_path14.resolve)(baseDir);
14635
+ const full = (0, import_node_path14.resolve)(baseAbs, candidate);
14636
+ const baseSep = baseAbs.endsWith(import_node_path14.sep) ? baseAbs : baseAbs + import_node_path14.sep;
14475
14637
  if (full !== baseAbs && !full.startsWith(baseSep)) return null;
14476
14638
  try {
14477
- if ((0, import_node_fs13.existsSync)(baseAbs)) {
14478
- const realBase = (0, import_node_fs13.realpathSync)(baseAbs);
14479
- const realBaseSep = realBase.endsWith(import_node_path12.sep) ? realBase : realBase + import_node_path12.sep;
14639
+ if ((0, import_node_fs15.existsSync)(baseAbs)) {
14640
+ const realBase = (0, import_node_fs15.realpathSync)(baseAbs);
14641
+ const realBaseSep = realBase.endsWith(import_node_path14.sep) ? realBase : realBase + import_node_path14.sep;
14480
14642
  let probe = full;
14481
- while (!(0, import_node_fs13.existsSync)(probe)) {
14482
- const parent = (0, import_node_path12.dirname)(probe);
14643
+ while (!(0, import_node_fs15.existsSync)(probe)) {
14644
+ const parent = (0, import_node_path14.dirname)(probe);
14483
14645
  if (parent === probe) break;
14484
14646
  probe = parent;
14485
14647
  }
14486
- const realProbe = (0, import_node_fs13.realpathSync)(probe);
14648
+ const realProbe = (0, import_node_fs15.realpathSync)(probe);
14487
14649
  if (realProbe !== realBase && !realProbe.startsWith(realBaseSep)) return null;
14488
14650
  }
14489
14651
  } catch {
@@ -14491,6 +14653,42 @@ function resolveInside(baseDir, candidate) {
14491
14653
  }
14492
14654
  return full;
14493
14655
  }
14656
+ var O_NOFOLLOW = typeof import_node_fs15.constants.O_NOFOLLOW === "number" ? import_node_fs15.constants.O_NOFOLLOW : 0;
14657
+ function readFileInside(baseDir, candidate, maxBytes) {
14658
+ const full = resolveInside(baseDir, candidate);
14659
+ if (!full) return null;
14660
+ let realParent;
14661
+ let realBase;
14662
+ try {
14663
+ realParent = (0, import_node_fs15.realpathSync)((0, import_node_path14.dirname)(full));
14664
+ realBase = (0, import_node_fs15.realpathSync)((0, import_node_path14.resolve)(baseDir));
14665
+ } catch {
14666
+ return null;
14667
+ }
14668
+ const realBaseSep = realBase.endsWith(import_node_path14.sep) ? realBase : realBase + import_node_path14.sep;
14669
+ if (realParent !== realBase && !realParent.startsWith(realBaseSep)) return null;
14670
+ const target = (0, import_node_path14.join)(realParent, (0, import_node_path14.basename)(full));
14671
+ let fd = null;
14672
+ try {
14673
+ fd = (0, import_node_fs15.openSync)(target, import_node_fs15.constants.O_RDONLY | O_NOFOLLOW);
14674
+ const st = (0, import_node_fs15.fstatSync)(fd);
14675
+ if (!st.isFile()) return null;
14676
+ const cap = Math.min(maxBytes, st.size);
14677
+ if (cap <= 0) return "";
14678
+ const buf = Buffer.alloc(cap);
14679
+ const bytesRead = (0, import_node_fs15.readSync)(fd, buf, 0, cap, 0);
14680
+ return buf.subarray(0, bytesRead).toString("utf-8");
14681
+ } catch {
14682
+ return null;
14683
+ } finally {
14684
+ if (fd !== null) {
14685
+ try {
14686
+ (0, import_node_fs15.closeSync)(fd);
14687
+ } catch {
14688
+ }
14689
+ }
14690
+ }
14691
+ }
14494
14692
 
14495
14693
  // src/lib/glob-match.ts
14496
14694
  function globToRegex(glob) {
@@ -14568,32 +14766,32 @@ var syncStateFile = () => projectPath(`${VERITY_DIR}/.memory-sync-state.json`);
14568
14766
  async function ensureMemoryDir() {
14569
14767
  await (0, import_promises9.mkdir)(memoryDir2(), { recursive: true });
14570
14768
  for (const domain of DOMAINS2) {
14571
- await (0, import_promises9.mkdir)((0, import_node_path13.join)(memoryDir2(), domain), { recursive: true });
14769
+ await (0, import_promises9.mkdir)((0, import_node_path15.join)(memoryDir2(), domain), { recursive: true });
14572
14770
  }
14573
- if (!(0, import_node_fs14.existsSync)((0, import_node_path13.join)(memoryDir2(), "SCHEMA.md"))) {
14574
- await (0, import_promises9.writeFile)((0, import_node_path13.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
14771
+ if (!(0, import_node_fs16.existsSync)((0, import_node_path15.join)(memoryDir2(), "SCHEMA.md"))) {
14772
+ await (0, import_promises9.writeFile)((0, import_node_path15.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
14575
14773
  }
14576
- if (!(0, import_node_fs14.existsSync)((0, import_node_path13.join)(memoryDir2(), "index.md"))) {
14577
- await (0, import_promises9.writeFile)((0, import_node_path13.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
14774
+ if (!(0, import_node_fs16.existsSync)((0, import_node_path15.join)(memoryDir2(), "index.md"))) {
14775
+ await (0, import_promises9.writeFile)((0, import_node_path15.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
14578
14776
  }
14579
- if (!(0, import_node_fs14.existsSync)((0, import_node_path13.join)(memoryDir2(), "log.md"))) {
14580
- await (0, import_promises9.writeFile)((0, import_node_path13.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
14777
+ if (!(0, import_node_fs16.existsSync)((0, import_node_path15.join)(memoryDir2(), "log.md"))) {
14778
+ await (0, import_promises9.writeFile)((0, import_node_path15.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
14581
14779
  }
14582
14780
  }
14583
14781
  async function buildManifest() {
14584
- if (!(0, import_node_fs14.existsSync)(memoryDir2())) {
14782
+ if (!(0, import_node_fs16.existsSync)(memoryDir2())) {
14585
14783
  return { schema_version: 1, nodes: [], index_hash: null, log_length: 0 };
14586
14784
  }
14587
14785
  const nodes = [];
14588
14786
  for (const domain of DOMAINS2) {
14589
- const domainDir = (0, import_node_path13.join)(memoryDir2(), domain);
14590
- if (!(0, import_node_fs14.existsSync)(domainDir)) continue;
14787
+ const domainDir = (0, import_node_path15.join)(memoryDir2(), domain);
14788
+ if (!(0, import_node_fs16.existsSync)(domainDir)) continue;
14591
14789
  try {
14592
14790
  const files = await (0, import_promises9.readdir)(domainDir);
14593
14791
  for (const file of files) {
14594
14792
  if (!file.endsWith(".md")) continue;
14595
14793
  const filePath = `${domain}/${file}`;
14596
- const fullPath = (0, import_node_path13.join)(memoryDir2(), filePath);
14794
+ const fullPath = (0, import_node_path15.join)(memoryDir2(), filePath);
14597
14795
  try {
14598
14796
  const content = await (0, import_promises9.readFile)(fullPath, "utf-8");
14599
14797
  const hash = (0, import_node_crypto3.createHash)("sha256").update(content).digest("hex").slice(0, 16);
@@ -14606,13 +14804,13 @@ async function buildManifest() {
14606
14804
  }
14607
14805
  let indexHash = null;
14608
14806
  try {
14609
- const indexContent = await (0, import_promises9.readFile)((0, import_node_path13.join)(memoryDir2(), "index.md"), "utf-8");
14807
+ const indexContent = await (0, import_promises9.readFile)((0, import_node_path15.join)(memoryDir2(), "index.md"), "utf-8");
14610
14808
  indexHash = `sha256:${(0, import_node_crypto3.createHash)("sha256").update(indexContent).digest("hex").slice(0, 16)}`;
14611
14809
  } catch {
14612
14810
  }
14613
14811
  let logLength = 0;
14614
14812
  try {
14615
- const logContent = await (0, import_promises9.readFile)((0, import_node_path13.join)(memoryDir2(), "log.md"), "utf-8");
14813
+ const logContent = await (0, import_promises9.readFile)((0, import_node_path15.join)(memoryDir2(), "log.md"), "utf-8");
14616
14814
  logLength = logContent.split("\n").length;
14617
14815
  } catch {
14618
14816
  }
@@ -14623,15 +14821,15 @@ function hashContent(content) {
14623
14821
  }
14624
14822
  async function readOnDiskNodes() {
14625
14823
  const out = /* @__PURE__ */ new Map();
14626
- if (!(0, import_node_fs14.existsSync)(memoryDir2())) return out;
14824
+ if (!(0, import_node_fs16.existsSync)(memoryDir2())) return out;
14627
14825
  for (const domain of DOMAINS2) {
14628
- const domainDir = (0, import_node_path13.join)(memoryDir2(), domain);
14629
- if (!(0, import_node_fs14.existsSync)(domainDir)) continue;
14826
+ const domainDir = (0, import_node_path15.join)(memoryDir2(), domain);
14827
+ if (!(0, import_node_fs16.existsSync)(domainDir)) continue;
14630
14828
  try {
14631
14829
  for (const file of await (0, import_promises9.readdir)(domainDir)) {
14632
14830
  if (!file.endsWith(".md")) continue;
14633
14831
  try {
14634
- out.set(`${domain}/${file}`, hashContent(await (0, import_promises9.readFile)((0, import_node_path13.join)(domainDir, file), "utf-8")));
14832
+ out.set(`${domain}/${file}`, hashContent(await (0, import_promises9.readFile)((0, import_node_path15.join)(domainDir, file), "utf-8")));
14635
14833
  } catch {
14636
14834
  }
14637
14835
  }
@@ -14668,7 +14866,7 @@ async function recordSyncedNodePaths() {
14668
14866
  }
14669
14867
  }
14670
14868
  async function writeFileAtomic(path, content) {
14671
- await (0, import_promises9.mkdir)((0, import_node_path13.dirname)(path), { recursive: true });
14869
+ await (0, import_promises9.mkdir)((0, import_node_path15.dirname)(path), { recursive: true });
14672
14870
  const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
14673
14871
  await (0, import_promises9.writeFile)(tmp, content);
14674
14872
  await (0, import_promises9.rename)(tmp, path);
@@ -14682,8 +14880,8 @@ async function computeEditedNodeUploads() {
14682
14880
  const uploads = [];
14683
14881
  for (const [path, prevHash] of prev) {
14684
14882
  if (prevHash == null) continue;
14685
- const full = (0, import_node_path13.join)(memoryDir2(), path);
14686
- if (!(0, import_node_fs14.existsSync)(full)) continue;
14883
+ const full = (0, import_node_path15.join)(memoryDir2(), path);
14884
+ if (!(0, import_node_fs16.existsSync)(full)) continue;
14687
14885
  let content;
14688
14886
  try {
14689
14887
  content = await (0, import_promises9.readFile)(full, "utf-8");
@@ -14727,8 +14925,8 @@ async function applyMemoryWrites(writes, opts = {}) {
14727
14925
  const logLines = [`- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)} \u2014 Applied ${count} write(s) from server`];
14728
14926
  for (const n of notes) logLines.push(` - ${n}`);
14729
14927
  try {
14730
- const existing = (0, import_node_fs14.existsSync)((0, import_node_path13.join)(memoryDir2(), "log.md")) ? await (0, import_promises9.readFile)((0, import_node_path13.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
14731
- await (0, import_promises9.writeFile)((0, import_node_path13.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
14928
+ const existing = (0, import_node_fs16.existsSync)((0, import_node_path15.join)(memoryDir2(), "log.md")) ? await (0, import_promises9.readFile)((0, import_node_path15.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
14929
+ await (0, import_promises9.writeFile)((0, import_node_path15.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
14732
14930
  } catch {
14733
14931
  }
14734
14932
  if (opts.baseline === "written") await mergeSyncBaseline(synced);
@@ -14738,7 +14936,7 @@ async function applyMemoryWrites(writes, opts = {}) {
14738
14936
  async function mergeSyncBaseline(entries) {
14739
14937
  if (entries.size === 0) return;
14740
14938
  try {
14741
- if ((0, import_node_fs14.existsSync)(syncStateFile())) {
14939
+ if ((0, import_node_fs16.existsSync)(syncStateFile())) {
14742
14940
  try {
14743
14941
  JSON.parse(await (0, import_promises9.readFile)(syncStateFile(), "utf-8"));
14744
14942
  } catch {
@@ -14766,7 +14964,7 @@ async function applyOneWrite(write, treePaths, lastServed) {
14766
14964
  notes.push(`${write.path}: dropped unmatched file_globs [${grounded.dropped.join(", ")}]`);
14767
14965
  }
14768
14966
  }
14769
- if ((0, import_node_fs14.existsSync)(fullPath)) {
14967
+ if ((0, import_node_fs16.existsSync)(fullPath)) {
14770
14968
  let existing = "";
14771
14969
  try {
14772
14970
  existing = await (0, import_promises9.readFile)(fullPath, "utf-8");
@@ -14782,7 +14980,7 @@ async function applyOneWrite(write, treePaths, lastServed) {
14782
14980
  notes.push(`${write.path}: updated from server (untouched here since the server delivered it)`);
14783
14981
  }
14784
14982
  }
14785
- await (0, import_promises9.mkdir)((0, import_node_path13.dirname)(fullPath), { recursive: true });
14983
+ await (0, import_promises9.mkdir)((0, import_node_path15.dirname)(fullPath), { recursive: true });
14786
14984
  await (0, import_promises9.writeFile)(fullPath, content);
14787
14985
  return { written: true, syncedHash: hashContent(content), notes };
14788
14986
  }
@@ -14823,8 +15021,8 @@ async function regenerateIndex() {
14823
15021
  ];
14824
15022
  let totalNodes = 0;
14825
15023
  for (const domain of DOMAINS2.filter((d) => d !== "_archive")) {
14826
- const domainDir = (0, import_node_path13.join)(memoryDir2(), domain);
14827
- if (!(0, import_node_fs14.existsSync)(domainDir)) continue;
15024
+ const domainDir = (0, import_node_path15.join)(memoryDir2(), domain);
15025
+ if (!(0, import_node_fs16.existsSync)(domainDir)) continue;
14828
15026
  try {
14829
15027
  const files = await (0, import_promises9.readdir)(domainDir);
14830
15028
  const mdFiles = files.filter((f) => f.endsWith(".md"));
@@ -14834,7 +15032,7 @@ async function regenerateIndex() {
14834
15032
  for (const file of mdFiles.sort()) {
14835
15033
  const slug = file.replace(/\.md$/, "");
14836
15034
  try {
14837
- const content = await (0, import_promises9.readFile)((0, import_node_path13.join)(domainDir, file), "utf-8");
15035
+ const content = await (0, import_promises9.readFile)((0, import_node_path15.join)(domainDir, file), "utf-8");
14838
15036
  const title = pickFrontmatter(content, "title") ?? slug;
14839
15037
  const kind = pickFrontmatter(content, "kind") ?? "-";
14840
15038
  const confidence = pickFrontmatter(content, "confidence");
@@ -14858,7 +15056,7 @@ async function regenerateIndex() {
14858
15056
  lines.push("No nodes yet. Run an analysis to start building the knowledge graph.");
14859
15057
  }
14860
15058
  const next = lines.join("\n") + "\n";
14861
- const indexPath = (0, import_node_path13.join)(memoryDir2(), "index.md");
15059
+ const indexPath = (0, import_node_path15.join)(memoryDir2(), "index.md");
14862
15060
  let existing = null;
14863
15061
  try {
14864
15062
  existing = await (0, import_promises9.readFile)(indexPath, "utf-8");
@@ -15255,9 +15453,9 @@ function hasLegacyMemoryBlock(text) {
15255
15453
  return findMarker(text, LEGACY_MD_START) !== -1;
15256
15454
  }
15257
15455
  async function ensureClaudeMdPointer(cwd = repoRoot()) {
15258
- const claudeMdPath = (0, import_node_path13.join)(cwd, "CLAUDE.md");
15456
+ const claudeMdPath = (0, import_node_path15.join)(cwd, "CLAUDE.md");
15259
15457
  let existing = "";
15260
- if ((0, import_node_fs14.existsSync)(claudeMdPath)) {
15458
+ if ((0, import_node_fs16.existsSync)(claudeMdPath)) {
15261
15459
  existing = await (0, import_promises9.readFile)(claudeMdPath, "utf-8");
15262
15460
  }
15263
15461
  let startTag = CLAUDE_MD_START;
@@ -15398,9 +15596,9 @@ Body content (\u22648KB). Use [[node-id]] wikilinks for cross-references.
15398
15596
  `;
15399
15597
 
15400
15598
  // src/lib/dossier-session.ts
15401
- var import_node_fs19 = require("node:fs");
15599
+ var import_node_fs21 = require("node:fs");
15402
15600
  var import_node_crypto7 = require("node:crypto");
15403
- var import_node_path16 = require("node:path");
15601
+ var import_node_path18 = require("node:path");
15404
15602
 
15405
15603
  // src/lib/pending-repeat.ts
15406
15604
  var STOP = /* @__PURE__ */ new Set([
@@ -15505,8 +15703,8 @@ function statementAnchorKey(file, patternId) {
15505
15703
 
15506
15704
  // src/lib/dossier/log.ts
15507
15705
  var import_node_crypto4 = require("node:crypto");
15508
- var import_node_fs15 = require("node:fs");
15509
- var import_node_path14 = require("node:path");
15706
+ var import_node_fs17 = require("node:fs");
15707
+ var import_node_path16 = require("node:path");
15510
15708
  var CRC_TABLE = (() => {
15511
15709
  const t = new Int32Array(256);
15512
15710
  for (let i = 0; i < 256; i++) {
@@ -15525,13 +15723,13 @@ function crc32(s) {
15525
15723
  function openDossier(identity) {
15526
15724
  try {
15527
15725
  const dir = dossierDir(identity);
15528
- (0, import_node_fs15.mkdirSync)(dir, { recursive: true, mode: 448 });
15726
+ (0, import_node_fs17.mkdirSync)(dir, { recursive: true, mode: 448 });
15529
15727
  return {
15530
15728
  dir,
15531
15729
  identity,
15532
- eventsPath: (0, import_node_path14.join)(dir, "events.jsonl"),
15533
- foldPath: (0, import_node_path14.join)(dir, "fold.json"),
15534
- rotatedDir: (0, import_node_path14.join)(dir, "rotated")
15730
+ eventsPath: (0, import_node_path16.join)(dir, "events.jsonl"),
15731
+ foldPath: (0, import_node_path16.join)(dir, "fold.json"),
15732
+ rotatedDir: (0, import_node_path16.join)(dir, "rotated")
15535
15733
  };
15536
15734
  } catch {
15537
15735
  return null;
@@ -15593,7 +15791,7 @@ function appendEvent(d, ev) {
15593
15791
  at: ev.at ?? (/* @__PURE__ */ new Date()).toISOString(),
15594
15792
  ...ev
15595
15793
  });
15596
- (0, import_node_fs15.appendFileSync)(d.eventsPath, line, { mode: 384 });
15794
+ (0, import_node_fs17.appendFileSync)(d.eventsPath, line, { mode: 384 });
15597
15795
  return true;
15598
15796
  } catch {
15599
15797
  return false;
@@ -15601,14 +15799,14 @@ function appendEvent(d, ev) {
15601
15799
  }
15602
15800
  function rotateIfNeeded2(d) {
15603
15801
  try {
15604
- if (!(0, import_node_fs15.existsSync)(d.eventsPath)) return;
15605
- if ((0, import_node_fs15.statSync)(d.eventsPath).size < ROTATE_BYTES) return;
15606
- (0, import_node_fs15.mkdirSync)(d.rotatedDir, { recursive: true, mode: 448 });
15607
- (0, import_node_fs15.renameSync)(d.eventsPath, (0, import_node_path14.join)(d.rotatedDir, `events.${Date.now()}.jsonl`));
15608
- const kept = (0, import_node_fs15.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
15802
+ if (!(0, import_node_fs17.existsSync)(d.eventsPath)) return;
15803
+ if ((0, import_node_fs17.statSync)(d.eventsPath).size < ROTATE_BYTES) return;
15804
+ (0, import_node_fs17.mkdirSync)(d.rotatedDir, { recursive: true, mode: 448 });
15805
+ (0, import_node_fs17.renameSync)(d.eventsPath, (0, import_node_path16.join)(d.rotatedDir, `events.${Date.now()}.jsonl`));
15806
+ const kept = (0, import_node_fs17.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
15609
15807
  for (const stale of kept.slice(0, Math.max(0, kept.length - ROTATE_KEEP))) {
15610
15808
  try {
15611
- (0, import_node_fs15.renameSync)((0, import_node_path14.join)(d.rotatedDir, stale), (0, import_node_path14.join)(d.rotatedDir, `${stale}.pruned`));
15809
+ (0, import_node_fs17.renameSync)((0, import_node_path16.join)(d.rotatedDir, stale), (0, import_node_path16.join)(d.rotatedDir, `${stale}.pruned`));
15612
15810
  } catch {
15613
15811
  }
15614
15812
  }
@@ -15618,8 +15816,8 @@ function rotateIfNeeded2(d) {
15618
15816
 
15619
15817
  // src/lib/dossier/fold-dossier.ts
15620
15818
  var import_node_crypto5 = require("node:crypto");
15621
- var import_node_fs16 = require("node:fs");
15622
- var import_node_path15 = require("node:path");
15819
+ var import_node_fs18 = require("node:fs");
15820
+ var import_node_path17 = require("node:path");
15623
15821
  var EMPTY_CAPABILITIES = () => ({
15624
15822
  human_reachable: { value: "unknown", tier: "unknown" },
15625
15823
  authorship_observability: { value: "unknown", tier: "unknown" },
@@ -15670,12 +15868,12 @@ function foldDossier(d, opts = {}) {
15670
15868
  }
15671
15869
  };
15672
15870
  try {
15673
- if ((0, import_node_fs16.existsSync)(d.rotatedDir)) {
15674
- const files = (0, import_node_fs16.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
15871
+ if ((0, import_node_fs18.existsSync)(d.rotatedDir)) {
15872
+ const files = (0, import_node_fs18.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
15675
15873
  state.meta.rotations = files.length;
15676
15874
  for (const f of files) {
15677
15875
  try {
15678
- ingest((0, import_node_fs16.readFileSync)((0, import_node_path15.join)(d.rotatedDir, f), "utf8"));
15876
+ ingest((0, import_node_fs18.readFileSync)((0, import_node_path17.join)(d.rotatedDir, f), "utf8"));
15679
15877
  } catch {
15680
15878
  state.meta.dropped_lines++;
15681
15879
  }
@@ -15684,9 +15882,9 @@ function foldDossier(d, opts = {}) {
15684
15882
  } catch {
15685
15883
  }
15686
15884
  try {
15687
- if ((0, import_node_fs16.existsSync)(d.eventsPath)) {
15688
- state.meta.upto_offset = (0, import_node_fs16.statSync)(d.eventsPath).size;
15689
- ingest((0, import_node_fs16.readFileSync)(d.eventsPath, "utf8"));
15885
+ if ((0, import_node_fs18.existsSync)(d.eventsPath)) {
15886
+ state.meta.upto_offset = (0, import_node_fs18.statSync)(d.eventsPath).size;
15887
+ ingest((0, import_node_fs18.readFileSync)(d.eventsPath, "utf8"));
15690
15888
  }
15691
15889
  } catch {
15692
15890
  }
@@ -15957,7 +16155,7 @@ function applyBounds(state, input) {
15957
16155
  }
15958
16156
 
15959
16157
  // src/lib/dossier/cache.ts
15960
- var import_node_fs17 = require("node:fs");
16158
+ var import_node_fs19 = require("node:fs");
15961
16159
  function compactState(s) {
15962
16160
  const ms = (iso) => Date.parse(iso) || 0;
15963
16161
  return {
@@ -16086,20 +16284,20 @@ function encodeState(s) {
16086
16284
  function writeFoldCache(d, state) {
16087
16285
  try {
16088
16286
  const tmp = `${d.foldPath}.${process.pid}.tmp`;
16089
- (0, import_node_fs17.writeFileSync)(tmp, encodeState(state), { mode: 384 });
16090
- (0, import_node_fs17.renameSync)(tmp, d.foldPath);
16287
+ (0, import_node_fs19.writeFileSync)(tmp, encodeState(state), { mode: 384 });
16288
+ (0, import_node_fs19.renameSync)(tmp, d.foldPath);
16091
16289
  } catch {
16092
16290
  }
16093
16291
  }
16094
16292
  function readFoldCache(d) {
16095
16293
  try {
16096
- if (!(0, import_node_fs17.existsSync)(d.foldPath)) return null;
16097
- const raw = JSON.parse((0, import_node_fs17.readFileSync)(d.foldPath, "utf8"));
16294
+ if (!(0, import_node_fs19.existsSync)(d.foldPath)) return null;
16295
+ const raw = JSON.parse((0, import_node_fs19.readFileSync)(d.foldPath, "utf8"));
16098
16296
  if (raw?.v !== 1) return null;
16099
16297
  const cached2 = expandState(raw);
16100
16298
  if (!cached2?.meta) return null;
16101
- const size = (0, import_node_fs17.existsSync)(d.eventsPath) ? (0, import_node_fs17.statSync)(d.eventsPath).size : 0;
16102
- const rotations = (0, import_node_fs17.existsSync)(d.rotatedDir) ? (0, import_node_fs17.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).length : 0;
16299
+ const size = (0, import_node_fs19.existsSync)(d.eventsPath) ? (0, import_node_fs19.statSync)(d.eventsPath).size : 0;
16300
+ const rotations = (0, import_node_fs19.existsSync)(d.rotatedDir) ? (0, import_node_fs19.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).length : 0;
16103
16301
  if (cached2.meta.upto_offset !== size || cached2.meta.rotations !== rotations) return null;
16104
16302
  return cached2;
16105
16303
  } catch {
@@ -16150,13 +16348,13 @@ function assessContinuity(i) {
16150
16348
 
16151
16349
  // src/lib/dossier/reanchor.ts
16152
16350
  var import_node_crypto6 = require("node:crypto");
16153
- var import_node_fs18 = require("node:fs");
16351
+ var import_node_fs20 = require("node:fs");
16154
16352
  function lineSha(text) {
16155
16353
  return (0, import_node_crypto6.createHash)("sha256").update(text.trim()).digest("hex").slice(0, HASH_WIDTH);
16156
16354
  }
16157
16355
  function fileHash(path) {
16158
16356
  try {
16159
- return (0, import_node_crypto6.createHash)("sha256").update((0, import_node_fs18.readFileSync)(path)).digest("hex").slice(0, HASH_WIDTH);
16357
+ return (0, import_node_crypto6.createHash)("sha256").update((0, import_node_fs20.readFileSync)(path)).digest("hex").slice(0, HASH_WIDTH);
16160
16358
  } catch {
16161
16359
  return null;
16162
16360
  }
@@ -16528,20 +16726,20 @@ function foreignAuthoredPaths(identity, opts = {}) {
16528
16726
  let sessions = 0;
16529
16727
  try {
16530
16728
  const dir = treeDir(identity);
16531
- if (!(0, import_node_fs19.existsSync)(dir)) return { paths: [], sessions: 0 };
16532
- for (const entry of (0, import_node_fs19.readdirSync)(dir, { withFileTypes: true })) {
16729
+ if (!(0, import_node_fs21.existsSync)(dir)) return { paths: [], sessions: 0 };
16730
+ for (const entry of (0, import_node_fs21.readdirSync)(dir, { withFileTypes: true })) {
16533
16731
  if (!entry.isDirectory()) continue;
16534
16732
  if (entry.name === identity.sessionKey) continue;
16535
- const log = (0, import_node_path16.join)(dir, entry.name, "events.jsonl");
16733
+ const log = (0, import_node_path18.join)(dir, entry.name, "events.jsonl");
16536
16734
  try {
16537
- if (!(0, import_node_fs19.existsSync)(log)) continue;
16538
- if (now - (0, import_node_fs19.statSync)(log).mtimeMs > windowMs) continue;
16735
+ if (!(0, import_node_fs21.existsSync)(log)) continue;
16736
+ if (now - (0, import_node_fs21.statSync)(log).mtimeMs > windowMs) continue;
16539
16737
  const sib = {
16540
- dir: (0, import_node_path16.join)(dir, entry.name),
16738
+ dir: (0, import_node_path18.join)(dir, entry.name),
16541
16739
  identity,
16542
16740
  eventsPath: log,
16543
- foldPath: (0, import_node_path16.join)(dir, entry.name, "fold.json"),
16544
- rotatedDir: (0, import_node_path16.join)(dir, entry.name, "rotated")
16741
+ foldPath: (0, import_node_path18.join)(dir, entry.name, "fold.json"),
16742
+ rotatedDir: (0, import_node_path18.join)(dir, entry.name, "rotated")
16545
16743
  };
16546
16744
  const state = readFoldCache(sib) ?? foldDossier(sib);
16547
16745
  sessions++;
@@ -16569,25 +16767,25 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
16569
16767
  let removed = 0;
16570
16768
  try {
16571
16769
  const mine = dossierDir(identity);
16572
- const userDir = (0, import_node_path16.dirname)((0, import_node_path16.dirname)(mine));
16573
- if (!(0, import_node_fs19.existsSync)(userDir)) return 0;
16770
+ const userDir = (0, import_node_path18.dirname)((0, import_node_path18.dirname)(mine));
16771
+ if (!(0, import_node_fs21.existsSync)(userDir)) return 0;
16574
16772
  const cutoff = Date.now() - maxAgeMs;
16575
- for (const tree of (0, import_node_fs19.readdirSync)(userDir, { withFileTypes: true })) {
16773
+ for (const tree of (0, import_node_fs21.readdirSync)(userDir, { withFileTypes: true })) {
16576
16774
  if (!tree.isDirectory()) continue;
16577
- const treePath = (0, import_node_path16.join)(userDir, tree.name);
16775
+ const treePath = (0, import_node_path18.join)(userDir, tree.name);
16578
16776
  let live = 0;
16579
- for (const entry of (0, import_node_fs19.readdirSync)(treePath, { withFileTypes: true })) {
16777
+ for (const entry of (0, import_node_fs21.readdirSync)(treePath, { withFileTypes: true })) {
16580
16778
  if (!entry.isDirectory()) continue;
16581
- const dir = (0, import_node_path16.join)(treePath, entry.name);
16779
+ const dir = (0, import_node_path18.join)(treePath, entry.name);
16582
16780
  if (dir === mine) {
16583
16781
  live++;
16584
16782
  continue;
16585
16783
  }
16586
16784
  try {
16587
- const log = (0, import_node_path16.join)(dir, "events.jsonl");
16588
- const at = (0, import_node_fs19.existsSync)(log) ? (0, import_node_fs19.statSync)(log).mtimeMs : (0, import_node_fs19.statSync)(dir).mtimeMs;
16785
+ const log = (0, import_node_path18.join)(dir, "events.jsonl");
16786
+ const at = (0, import_node_fs21.existsSync)(log) ? (0, import_node_fs21.statSync)(log).mtimeMs : (0, import_node_fs21.statSync)(dir).mtimeMs;
16589
16787
  if (at < cutoff) {
16590
- (0, import_node_fs19.rmSync)(dir, { recursive: true, force: true });
16788
+ (0, import_node_fs21.rmSync)(dir, { recursive: true, force: true });
16591
16789
  removed++;
16592
16790
  } else {
16593
16791
  live++;
@@ -16597,7 +16795,7 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
16597
16795
  }
16598
16796
  if (live === 0) {
16599
16797
  try {
16600
- (0, import_node_fs19.rmSync)(treePath, { recursive: false, force: false });
16798
+ (0, import_node_fs21.rmSync)(treePath, { recursive: false, force: false });
16601
16799
  } catch {
16602
16800
  }
16603
16801
  }
@@ -16614,8 +16812,8 @@ function sessionDossier(token, sessionId) {
16614
16812
  }
16615
16813
  function hasActiveGoal(d) {
16616
16814
  try {
16617
- if (!(0, import_node_fs19.existsSync)(d.eventsPath)) return false;
16618
- return (0, import_node_fs19.readFileSync)(d.eventsPath, "utf8").includes('"k":"goal"');
16815
+ if (!(0, import_node_fs21.existsSync)(d.eventsPath)) return false;
16816
+ return (0, import_node_fs21.readFileSync)(d.eventsPath, "utf8").includes('"k":"goal"');
16619
16817
  } catch {
16620
16818
  return false;
16621
16819
  }
@@ -16639,7 +16837,7 @@ function recordTurn(d, t) {
16639
16837
  for (const a of t.authored) {
16640
16838
  const origin = a.owner === "subagent" ? "subagent" : "edit_tool";
16641
16839
  const prior = t.known?.authored?.get(a.p);
16642
- const hash = fileHash((0, import_node_path16.join)(root, a.p));
16840
+ const hash = fileHash((0, import_node_path18.join)(root, a.p));
16643
16841
  const hunks = Math.max(0, a.h - (prior?.hunks ?? 0));
16644
16842
  const adds = Math.max(0, a.a - (prior?.adds ?? 0));
16645
16843
  const dels = Math.max(0, a.d - (prior?.dels ?? 0));
@@ -16672,7 +16870,7 @@ function recordTurn(d, t) {
16672
16870
  }
16673
16871
  const seenDivergence = t.known?.divergence ?? /* @__PURE__ */ new Set();
16674
16872
  for (const u of t.unobserved) {
16675
- const hash = fileHash((0, import_node_path16.join)(root, u.p));
16873
+ const hash = fileHash((0, import_node_path18.join)(root, u.p));
16676
16874
  if (seenDivergence.has(divergenceKey(u.p, hash))) continue;
16677
16875
  appendEvent(d, { k: "divergence", kind: "external_mutation", path: u.p, hash });
16678
16876
  }
@@ -16707,8 +16905,8 @@ function recordVerdict(d, v) {
16707
16905
  if (!sent.has(f.file)) continue;
16708
16906
  if (!lines.has(f.file)) {
16709
16907
  try {
16710
- const abs = (0, import_node_path16.join)(root, f.file);
16711
- lines.set(f.file, (0, import_node_fs19.existsSync)(abs) ? (0, import_node_fs19.readFileSync)(abs, "utf8").split("\n") : null);
16908
+ const abs = (0, import_node_path18.join)(root, f.file);
16909
+ lines.set(f.file, (0, import_node_fs21.existsSync)(abs) ? (0, import_node_fs21.readFileSync)(abs, "utf8").split("\n") : null);
16712
16910
  } catch {
16713
16911
  lines.set(f.file, null);
16714
16912
  }
@@ -16808,8 +17006,8 @@ function recallMemory(d, identity, opts) {
16808
17006
  budgetBytes: opts.budgetBytes,
16809
17007
  readFileLines: (file) => {
16810
17008
  try {
16811
- const abs = (0, import_node_path16.join)(root, file);
16812
- return (0, import_node_fs19.existsSync)(abs) ? (0, import_node_fs19.readFileSync)(abs, "utf8").split("\n") : null;
17009
+ const abs = (0, import_node_path18.join)(root, file);
17010
+ return (0, import_node_fs21.existsSync)(abs) ? (0, import_node_fs21.readFileSync)(abs, "utf8").split("\n") : null;
16813
17011
  } catch {
16814
17012
  return null;
16815
17013
  }
@@ -16953,46 +17151,46 @@ async function fireClassify(prompt, sessionId, globals) {
16953
17151
  }
16954
17152
 
16955
17153
  // src/commands/lifecycle.ts
16956
- var import_node_fs23 = require("node:fs");
16957
- var import_node_path21 = require("node:path");
17154
+ var import_node_fs25 = require("node:fs");
17155
+ var import_node_path23 = require("node:path");
16958
17156
 
16959
17157
  // src/lib/baseline.ts
16960
- var import_node_fs22 = require("node:fs");
16961
- var import_node_path20 = require("node:path");
17158
+ var import_node_fs24 = require("node:fs");
17159
+ var import_node_path22 = require("node:path");
16962
17160
  var import_node_crypto9 = require("node:crypto");
16963
17161
 
16964
17162
  // src/lib/snapshot.ts
16965
- var import_node_fs21 = require("node:fs");
16966
- var import_node_path19 = require("node:path");
17163
+ var import_node_fs23 = require("node:fs");
17164
+ var import_node_path21 = require("node:path");
16967
17165
  var import_node_child_process7 = require("node:child_process");
16968
17166
 
16969
17167
  // src/lib/files.ts
16970
- var import_node_path18 = require("node:path");
17168
+ var import_node_path20 = require("node:path");
16971
17169
 
16972
17170
  // src/lib/safe-read.ts
16973
- var import_node_fs20 = require("node:fs");
16974
- var import_node_path17 = require("node:path");
16975
- var FLAGS = import_node_fs20.constants;
17171
+ var import_node_fs22 = require("node:fs");
17172
+ var import_node_path19 = require("node:path");
17173
+ var FLAGS = import_node_fs22.constants;
16976
17174
  var NOFOLLOW = FLAGS.O_NOFOLLOW;
16977
17175
  var NONBLOCK = FLAGS.O_NONBLOCK;
16978
17176
  function closeOpened(fd) {
16979
17177
  try {
16980
- (0, import_node_fs20.closeSync)(fd);
17178
+ (0, import_node_fs22.closeSync)(fd);
16981
17179
  } catch {
16982
17180
  }
16983
17181
  }
16984
17182
  function isInsideRoot(realRoot, realPath) {
16985
- return realPath === realRoot || realPath.startsWith(realRoot.endsWith(import_node_path17.sep) ? realRoot : realRoot + import_node_path17.sep);
17183
+ return realPath === realRoot || realPath.startsWith(realRoot.endsWith(import_node_path19.sep) ? realRoot : realRoot + import_node_path19.sep);
16986
17184
  }
16987
17185
  function sameOpenedFile(opened, current, nofollowAvailable) {
16988
17186
  if (!nofollowAvailable && (opened.ino === 0n || current.ino === 0n)) return false;
16989
17187
  return opened.ino === current.ino && opened.dev === current.dev;
16990
17188
  }
16991
17189
  function openRegularInRoot(root, path) {
16992
- const full = (0, import_node_path17.isAbsolute)(path) ? path : (0, import_node_path17.join)(root, path);
17190
+ const full = (0, import_node_path19.isAbsolute)(path) ? path : (0, import_node_path19.join)(root, path);
16993
17191
  let fd;
16994
17192
  try {
16995
- fd = (0, import_node_fs20.openSync)(full, import_node_fs20.constants.O_RDONLY | (NOFOLLOW ?? 0) | (NONBLOCK ?? 0));
17193
+ fd = (0, import_node_fs22.openSync)(full, import_node_fs22.constants.O_RDONLY | (NOFOLLOW ?? 0) | (NONBLOCK ?? 0));
16996
17194
  } catch (err) {
16997
17195
  const code = err.code;
16998
17196
  if (code === "ELOOP" || code === "EMLINK" || code === "EFTYPE") return { ok: false, reason: "symlink" };
@@ -17000,18 +17198,18 @@ function openRegularInRoot(root, path) {
17000
17198
  return { ok: false, reason: "unreadable" };
17001
17199
  }
17002
17200
  try {
17003
- const opened = (0, import_node_fs20.fstatSync)(fd, { bigint: true });
17201
+ const opened = (0, import_node_fs22.fstatSync)(fd, { bigint: true });
17004
17202
  if (!opened.isFile()) {
17005
17203
  closeOpened(fd);
17006
17204
  return { ok: false, reason: "not-regular" };
17007
17205
  }
17008
- const realRoot = import_node_fs20.realpathSync.native(root);
17009
- const realPath = import_node_fs20.realpathSync.native(full);
17206
+ const realRoot = import_node_fs22.realpathSync.native(root);
17207
+ const realPath = import_node_fs22.realpathSync.native(full);
17010
17208
  if (!isInsideRoot(realRoot, realPath)) {
17011
17209
  closeOpened(fd);
17012
17210
  return { ok: false, reason: "outside-root" };
17013
17211
  }
17014
- const current = (0, import_node_fs20.statSync)(realPath, { bigint: true });
17212
+ const current = (0, import_node_fs22.statSync)(realPath, { bigint: true });
17015
17213
  if (!sameOpenedFile(opened, current, NOFOLLOW !== void 0)) {
17016
17214
  closeOpened(fd);
17017
17215
  return { ok: false, reason: NOFOLLOW === void 0 ? "unreadable" : "outside-root" };
@@ -17033,7 +17231,7 @@ function readOpened(fd, size) {
17033
17231
  const buffer = Buffer.alloc(size);
17034
17232
  let offset = 0;
17035
17233
  while (offset < size) {
17036
- const n = (0, import_node_fs20.readSync)(fd, buffer, offset, size - offset, offset);
17234
+ const n = (0, import_node_fs22.readSync)(fd, buffer, offset, size - offset, offset);
17037
17235
  if (n === 0) break;
17038
17236
  offset += n;
17039
17237
  }
@@ -17127,7 +17325,7 @@ var LANG_MAP = {
17127
17325
  mk: "make"
17128
17326
  };
17129
17327
  function detectLanguage(filepath) {
17130
- const ext = (0, import_node_path18.extname)(filepath).slice(1);
17328
+ const ext = (0, import_node_path20.extname)(filepath).slice(1);
17131
17329
  return LANG_MAP[ext] ?? ext;
17132
17330
  }
17133
17331
  function sortByMtime(files) {
@@ -17218,16 +17416,16 @@ function collectCodeDelta(files, opts) {
17218
17416
 
17219
17417
  // src/lib/snapshot.ts
17220
17418
  function generateSnapshotDiffs(files) {
17221
- if (!(0, import_node_fs21.existsSync)(SNAPSHOT_DIR)) {
17419
+ if (!(0, import_node_fs23.existsSync)(SNAPSHOT_DIR)) {
17222
17420
  return { diffs: [], has_snapshots: false };
17223
17421
  }
17224
17422
  const diffs = [];
17225
17423
  for (const file of files) {
17226
17424
  if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
17227
- const snapshotPath = (0, import_node_path19.join)(SNAPSHOT_DIR, file.path);
17425
+ const snapshotPath = (0, import_node_path21.join)(SNAPSHOT_DIR, file.path);
17228
17426
  const language = file.language ?? detectLanguage(file.path);
17229
- if ((0, import_node_fs21.existsSync)(snapshotPath)) {
17230
- const oldContent = (0, import_node_fs21.readFileSync)(snapshotPath, "utf-8");
17427
+ if ((0, import_node_fs23.existsSync)(snapshotPath)) {
17428
+ const oldContent = (0, import_node_fs23.readFileSync)(snapshotPath, "utf-8");
17231
17429
  if (oldContent === file.content) continue;
17232
17430
  const diff = computeDiff(oldContent, file.content, file.path);
17233
17431
  if (diff) {
@@ -17252,20 +17450,20 @@ function saveSnapshots(files) {
17252
17450
  const snapshotPaths = /* @__PURE__ */ new Set();
17253
17451
  for (const file of files) {
17254
17452
  if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
17255
- const snapshotPath = (0, import_node_path19.join)(SNAPSHOT_DIR, file.path);
17453
+ const snapshotPath = (0, import_node_path21.join)(SNAPSHOT_DIR, file.path);
17256
17454
  snapshotPaths.add(snapshotPath);
17257
- (0, import_node_fs21.mkdirSync)((0, import_node_path19.dirname)(snapshotPath), { recursive: true });
17258
- (0, import_node_fs21.writeFileSync)(snapshotPath, file.content);
17455
+ (0, import_node_fs23.mkdirSync)((0, import_node_path21.dirname)(snapshotPath), { recursive: true });
17456
+ (0, import_node_fs23.writeFileSync)(snapshotPath, file.content);
17259
17457
  }
17260
17458
  cleanStaleSnapshots(SNAPSHOT_DIR, snapshotPaths);
17261
17459
  }
17262
17460
  function computeDiff(oldContent, newContent, filePath) {
17263
- const tmpOld = (0, import_node_path19.join)(SNAPSHOT_DIR, ".diff-old.tmp");
17264
- const tmpNew = (0, import_node_path19.join)(SNAPSHOT_DIR, ".diff-new.tmp");
17461
+ const tmpOld = (0, import_node_path21.join)(SNAPSHOT_DIR, ".diff-old.tmp");
17462
+ const tmpNew = (0, import_node_path21.join)(SNAPSHOT_DIR, ".diff-new.tmp");
17265
17463
  try {
17266
- (0, import_node_fs21.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
17267
- (0, import_node_fs21.writeFileSync)(tmpOld, oldContent);
17268
- (0, import_node_fs21.writeFileSync)(tmpNew, newContent);
17464
+ (0, import_node_fs23.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
17465
+ (0, import_node_fs23.writeFileSync)(tmpOld, oldContent);
17466
+ (0, import_node_fs23.writeFileSync)(tmpNew, newContent);
17269
17467
  const result = (0, import_node_child_process7.execSync)(
17270
17468
  `git diff --no-index --unified=10 -- "${tmpOld}" "${tmpNew}"`,
17271
17469
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
@@ -17279,32 +17477,32 @@ function computeDiff(oldContent, newContent, filePath) {
17279
17477
  return null;
17280
17478
  } finally {
17281
17479
  try {
17282
- (0, import_node_fs21.unlinkSync)(tmpOld);
17480
+ (0, import_node_fs23.unlinkSync)(tmpOld);
17283
17481
  } catch {
17284
17482
  }
17285
17483
  try {
17286
- (0, import_node_fs21.unlinkSync)(tmpNew);
17484
+ (0, import_node_fs23.unlinkSync)(tmpNew);
17287
17485
  } catch {
17288
17486
  }
17289
17487
  }
17290
17488
  }
17291
17489
  function cleanStaleSnapshots(dir, keepSet) {
17292
- if (!(0, import_node_fs21.existsSync)(dir)) return;
17490
+ if (!(0, import_node_fs23.existsSync)(dir)) return;
17293
17491
  try {
17294
- const entries = (0, import_node_fs21.readdirSync)(dir, { withFileTypes: true });
17492
+ const entries = (0, import_node_fs23.readdirSync)(dir, { withFileTypes: true });
17295
17493
  for (const entry of entries) {
17296
17494
  if (dir === SNAPSHOT_DIR && (entry.name === ".diff-old.tmp" || entry.name === ".diff-new.tmp")) continue;
17297
- const fullPath = (0, import_node_path19.join)(dir, entry.name);
17495
+ const fullPath = (0, import_node_path21.join)(dir, entry.name);
17298
17496
  if (entry.isDirectory()) {
17299
17497
  cleanStaleSnapshots(fullPath, keepSet);
17300
17498
  try {
17301
- const remaining = (0, import_node_fs21.readdirSync)(fullPath);
17302
- if (remaining.length === 0) (0, import_node_fs21.rmdirSync)(fullPath);
17499
+ const remaining = (0, import_node_fs23.readdirSync)(fullPath);
17500
+ if (remaining.length === 0) (0, import_node_fs23.rmdirSync)(fullPath);
17303
17501
  } catch {
17304
17502
  }
17305
17503
  } else if (!keepSet.has(fullPath)) {
17306
17504
  try {
17307
- (0, import_node_fs21.unlinkSync)(fullPath);
17505
+ (0, import_node_fs23.unlinkSync)(fullPath);
17308
17506
  } catch {
17309
17507
  }
17310
17508
  }
@@ -17323,20 +17521,20 @@ function sessionKey(sessionId) {
17323
17521
  return (0, import_node_crypto9.createHash)("sha256").update(sessionId).digest("hex").slice(0, 16);
17324
17522
  }
17325
17523
  function sessionDir(key) {
17326
- return (0, import_node_path20.join)(projectPath(BASELINE_DIR), key);
17524
+ return (0, import_node_path22.join)(projectPath(BASELINE_DIR), key);
17327
17525
  }
17328
17526
  function manifestPath(dir) {
17329
- return (0, import_node_path20.join)(dir, "manifest.json");
17527
+ return (0, import_node_path22.join)(dir, "manifest.json");
17330
17528
  }
17331
17529
  function mirrorPath(dir, repoRelPath) {
17332
- return (0, import_node_path20.join)(dir, "files", repoRelPath);
17530
+ return (0, import_node_path22.join)(dir, "files", repoRelPath);
17333
17531
  }
17334
17532
  var CARRY_FILE = `${BASELINE_DIR}/.carry`;
17335
17533
  var CARRY_WINDOW_MS = 12e4;
17336
17534
  function writeCarry(sessionId, headSha) {
17337
17535
  try {
17338
- (0, import_node_fs22.mkdirSync)(projectPath(BASELINE_DIR), { recursive: true });
17339
- (0, import_node_fs22.writeFileSync)(
17536
+ (0, import_node_fs24.mkdirSync)(projectPath(BASELINE_DIR), { recursive: true });
17537
+ (0, import_node_fs24.writeFileSync)(
17340
17538
  projectPath(CARRY_FILE),
17341
17539
  JSON.stringify({ from_key: sessionKey(sessionId), head_sha: headSha, ts: Date.now() })
17342
17540
  );
@@ -17346,10 +17544,10 @@ function writeCarry(sessionId, headSha) {
17346
17544
  function claimCarry(newKey) {
17347
17545
  const carryPath = projectPath(CARRY_FILE);
17348
17546
  try {
17349
- if (!(0, import_node_fs22.existsSync)(carryPath)) return null;
17350
- const carry = JSON.parse((0, import_node_fs22.readFileSync)(carryPath, "utf-8"));
17547
+ if (!(0, import_node_fs24.existsSync)(carryPath)) return null;
17548
+ const carry = JSON.parse((0, import_node_fs24.readFileSync)(carryPath, "utf-8"));
17351
17549
  try {
17352
- (0, import_node_fs22.rmSync)(carryPath, { force: true });
17550
+ (0, import_node_fs24.rmSync)(carryPath, { force: true });
17353
17551
  } catch {
17354
17552
  }
17355
17553
  if (!carry?.from_key || typeof carry.ts !== "number") return null;
@@ -17360,11 +17558,11 @@ function claimCarry(newKey) {
17360
17558
  if (!prior) return null;
17361
17559
  const toDir = sessionDir(newKey);
17362
17560
  try {
17363
- (0, import_node_fs22.rmSync)(toDir, { recursive: true, force: true });
17561
+ (0, import_node_fs24.rmSync)(toDir, { recursive: true, force: true });
17364
17562
  } catch {
17365
17563
  }
17366
- (0, import_node_fs22.renameSync)(fromDir, toDir);
17367
- (0, import_node_fs22.writeFileSync)(manifestPath(toDir), JSON.stringify({ ...prior, session_id: newKey }) + "\n");
17564
+ (0, import_node_fs24.renameSync)(fromDir, toDir);
17565
+ (0, import_node_fs24.writeFileSync)(manifestPath(toDir), JSON.stringify({ ...prior, session_id: newKey }) + "\n");
17368
17566
  return readManifest(toDir);
17369
17567
  } catch {
17370
17568
  return null;
@@ -17388,21 +17586,21 @@ function captureBaseline(opts = {}) {
17388
17586
  const head_sha = getCurrentCommit();
17389
17587
  const dirty = getDirtyFiles();
17390
17588
  try {
17391
- (0, import_node_fs22.rmSync)(dir, { recursive: true, force: true });
17589
+ (0, import_node_fs24.rmSync)(dir, { recursive: true, force: true });
17392
17590
  } catch {
17393
17591
  }
17394
- const filesDir = (0, import_node_path20.join)(dir, "files");
17592
+ const filesDir = (0, import_node_path22.join)(dir, "files");
17395
17593
  const mirrored = [];
17396
17594
  try {
17397
- (0, import_node_fs22.mkdirSync)(filesDir, { recursive: true });
17595
+ (0, import_node_fs24.mkdirSync)(filesDir, { recursive: true });
17398
17596
  for (const p of dirty) {
17399
17597
  if (p.includes("..")) continue;
17400
17598
  const content = safeReadForMirror(projectPath(p));
17401
17599
  if (content === null) continue;
17402
17600
  const dest = mirrorPath(dir, p);
17403
17601
  try {
17404
- (0, import_node_fs22.mkdirSync)((0, import_node_path20.dirname)(dest), { recursive: true });
17405
- (0, import_node_fs22.writeFileSync)(dest, content);
17602
+ (0, import_node_fs24.mkdirSync)((0, import_node_path22.dirname)(dest), { recursive: true });
17603
+ (0, import_node_fs24.writeFileSync)(dest, content);
17406
17604
  mirrored.push(p);
17407
17605
  } catch {
17408
17606
  }
@@ -17417,8 +17615,8 @@ function captureBaseline(opts = {}) {
17417
17615
  version: BASELINE_VERSION
17418
17616
  };
17419
17617
  try {
17420
- (0, import_node_fs22.mkdirSync)(dir, { recursive: true });
17421
- (0, import_node_fs22.writeFileSync)(manifestPath(dir), JSON.stringify(baseline));
17618
+ (0, import_node_fs24.mkdirSync)(dir, { recursive: true });
17619
+ (0, import_node_fs24.writeFileSync)(manifestPath(dir), JSON.stringify(baseline));
17422
17620
  } catch {
17423
17621
  }
17424
17622
  pruneOldBaselines();
@@ -17429,9 +17627,9 @@ function readBaseline(sessionId) {
17429
17627
  }
17430
17628
  function readManifest(dir) {
17431
17629
  const mp = manifestPath(dir);
17432
- if (!(0, import_node_fs22.existsSync)(mp)) return null;
17630
+ if (!(0, import_node_fs24.existsSync)(mp)) return null;
17433
17631
  try {
17434
- const parsed = JSON.parse((0, import_node_fs22.readFileSync)(mp, "utf-8"));
17632
+ const parsed = JSON.parse((0, import_node_fs24.readFileSync)(mp, "utf-8"));
17435
17633
  if (typeof parsed.head_sha !== "string" || typeof parsed.captured_at !== "number" || !Array.isArray(parsed.dirty_paths) || parsed.version !== BASELINE_VERSION) {
17436
17634
  return null;
17437
17635
  }
@@ -17462,9 +17660,9 @@ function preImage(repoRelPath, baseline) {
17462
17660
  function resolvePreImage(repoRelPath, baseline) {
17463
17661
  if (baseline.dirty_paths.includes(repoRelPath)) {
17464
17662
  const mp = mirrorPath(sessionDir(sessionKey(baseline.session_id)), repoRelPath);
17465
- if ((0, import_node_fs22.existsSync)(mp)) {
17663
+ if ((0, import_node_fs24.existsSync)(mp)) {
17466
17664
  try {
17467
- return { content: (0, import_node_fs22.readFileSync)(mp, "utf-8"), existed: true };
17665
+ return { content: (0, import_node_fs24.readFileSync)(mp, "utf-8"), existed: true };
17468
17666
  } catch {
17469
17667
  }
17470
17668
  }
@@ -17509,8 +17707,8 @@ function absorbIntoBaseline(paths, sessionId) {
17509
17707
  const content = safeReadForMirror(projectPath(p));
17510
17708
  if (content === null) continue;
17511
17709
  const dest = mirrorPath(dir, p);
17512
- (0, import_node_fs22.mkdirSync)((0, import_node_path20.dirname)(dest), { recursive: true });
17513
- (0, import_node_fs22.writeFileSync)(dest, content);
17710
+ (0, import_node_fs24.mkdirSync)((0, import_node_path22.dirname)(dest), { recursive: true });
17711
+ (0, import_node_fs24.writeFileSync)(dest, content);
17514
17712
  dirty.add(p);
17515
17713
  adopted++;
17516
17714
  } catch {
@@ -17519,7 +17717,7 @@ function absorbIntoBaseline(paths, sessionId) {
17519
17717
  if (adopted === 0) return 0;
17520
17718
  try {
17521
17719
  const updated = { ...baseline, dirty_paths: [...dirty] };
17522
- (0, import_node_fs22.writeFileSync)(manifestPath(dir), JSON.stringify(updated));
17720
+ (0, import_node_fs24.writeFileSync)(manifestPath(dir), JSON.stringify(updated));
17523
17721
  preImageCache.delete(baseline);
17524
17722
  } catch {
17525
17723
  return 0;
@@ -17530,7 +17728,7 @@ function changedSinceBaseline(repoRelPath, baseline) {
17530
17728
  const pre = preImage(repoRelPath, baseline);
17531
17729
  let current;
17532
17730
  try {
17533
- current = (0, import_node_fs22.readFileSync)(projectPath(repoRelPath), "utf-8");
17731
+ current = (0, import_node_fs24.readFileSync)(projectPath(repoRelPath), "utf-8");
17534
17732
  } catch {
17535
17733
  return pre.existed;
17536
17734
  }
@@ -17539,8 +17737,8 @@ function changedSinceBaseline(repoRelPath, baseline) {
17539
17737
  }
17540
17738
  function safeReadForMirror(absPath) {
17541
17739
  try {
17542
- if ((0, import_node_fs22.statSync)(absPath).size > MIRROR_MAX_BYTES) return null;
17543
- const buf = (0, import_node_fs22.readFileSync)(absPath);
17740
+ if ((0, import_node_fs24.statSync)(absPath).size > MIRROR_MAX_BYTES) return null;
17741
+ const buf = (0, import_node_fs24.readFileSync)(absPath);
17544
17742
  if (buf.includes(0)) return null;
17545
17743
  return buf.toString("utf-8");
17546
17744
  } catch {
@@ -17551,18 +17749,18 @@ function pruneOldBaselines() {
17551
17749
  const root = projectPath(BASELINE_DIR);
17552
17750
  let entries;
17553
17751
  try {
17554
- entries = (0, import_node_fs22.readdirSync)(root);
17752
+ entries = (0, import_node_fs24.readdirSync)(root);
17555
17753
  } catch {
17556
17754
  return;
17557
17755
  }
17558
17756
  const now = Date.now();
17559
17757
  for (const name of entries) {
17560
- const dir = (0, import_node_path20.join)(root, name);
17758
+ const dir = (0, import_node_path22.join)(root, name);
17561
17759
  const manifest = readManifest(dir);
17562
17760
  if (!manifest) {
17563
17761
  try {
17564
- if (now - (0, import_node_fs22.statSync)(dir).mtimeMs > BASELINE_TTL_MS) {
17565
- (0, import_node_fs22.rmSync)(dir, { recursive: true, force: true });
17762
+ if (now - (0, import_node_fs24.statSync)(dir).mtimeMs > BASELINE_TTL_MS) {
17763
+ (0, import_node_fs24.rmSync)(dir, { recursive: true, force: true });
17566
17764
  }
17567
17765
  } catch {
17568
17766
  }
@@ -17570,7 +17768,7 @@ function pruneOldBaselines() {
17570
17768
  }
17571
17769
  if (now - manifest.captured_at <= BASELINE_TTL_MS) continue;
17572
17770
  try {
17573
- (0, import_node_fs22.rmSync)(dir, { recursive: true, force: true });
17771
+ (0, import_node_fs24.rmSync)(dir, { recursive: true, force: true });
17574
17772
  } catch {
17575
17773
  }
17576
17774
  }
@@ -17745,8 +17943,8 @@ function buildCompactionContext(session) {
17745
17943
  commitsSince: commitsSincePaths(watermark, (state.authored ?? []).map((a) => a.path)),
17746
17944
  readFileLines: (file) => {
17747
17945
  try {
17748
- const abs = (0, import_node_path21.join)(root, file);
17749
- return (0, import_node_fs23.existsSync)(abs) ? (0, import_node_fs23.readFileSync)(abs, "utf8").split("\n") : null;
17946
+ const abs = (0, import_node_path23.join)(root, file);
17947
+ return (0, import_node_fs25.existsSync)(abs) ? (0, import_node_fs25.readFileSync)(abs, "utf8").split("\n") : null;
17750
17948
  } catch {
17751
17949
  return null;
17752
17950
  }
@@ -17803,24 +18001,24 @@ async function readHookStdin() {
17803
18001
 
17804
18002
  // src/commands/standard.ts
17805
18003
  var import_promises13 = require("node:fs/promises");
17806
- var import_node_fs30 = require("node:fs");
18004
+ var import_node_fs32 = require("node:fs");
17807
18005
  var import_yaml3 = __toESM(require_dist());
17808
18006
 
17809
18007
  // src/lib/synthesize.ts
17810
18008
  var import_node_child_process9 = require("node:child_process");
17811
- var import_node_fs26 = require("node:fs");
18009
+ var import_node_fs28 = require("node:fs");
17812
18010
  var import_promises10 = require("node:fs/promises");
17813
- var import_node_path24 = require("node:path");
18011
+ var import_node_path26 = require("node:path");
17814
18012
  var import_yaml = __toESM(require_dist());
17815
18013
 
17816
18014
  // src/lib/data-dir.ts
17817
- var import_node_fs24 = require("node:fs");
17818
- var import_node_path22 = require("node:path");
18015
+ var import_node_fs26 = require("node:fs");
18016
+ var import_node_path24 = require("node:path");
17819
18017
  function resolveDataDir() {
17820
18018
  const candidates2 = [
17821
- (0, import_node_path22.join)(__dirname, "..", "data"),
18019
+ (0, import_node_path24.join)(__dirname, "..", "data"),
17822
18020
  // installed: node_modules/@codacy/verity-cli/data
17823
- (0, import_node_path22.join)(__dirname, "..", "..", "data"),
18021
+ (0, import_node_path24.join)(__dirname, "..", "..", "data"),
17824
18022
  // edge case: nested resolution
17825
18023
  // THE COMMITTED SOURCE, for a source checkout that has not been built.
17826
18024
  // cli/data/skills/ is a BUILD ARTIFACT (scripts/build.js copies client/skills
@@ -17829,14 +18027,14 @@ function resolveDataDir() {
17829
18027
  // without this the synthesizer throws "Could not find Verity skill data"
17830
18028
  // for every test and every `verity` run from source. Resolved from this
17831
18029
  // module's own location, never the cwd: see the warning below.
17832
- (0, import_node_path22.join)(__dirname, "..", "..", "client"),
18030
+ (0, import_node_path24.join)(__dirname, "..", "..", "client"),
17833
18031
  // bundled: cli/bin/ → ../../client
17834
- (0, import_node_path22.join)(__dirname, "..", "..", "..", "client"),
18032
+ (0, import_node_path24.join)(__dirname, "..", "..", "..", "client"),
17835
18033
  // tsx: cli/src/lib/ → ../../../client
17836
18034
  ...process.env.VERITY_DEV_DATA_DIR ? [process.env.VERITY_DEV_DATA_DIR] : []
17837
18035
  ];
17838
18036
  for (const candidate of candidates2) {
17839
- if ((0, import_node_fs24.existsSync)((0, import_node_path22.join)(candidate, "skills"))) {
18037
+ if ((0, import_node_fs26.existsSync)((0, import_node_path24.join)(candidate, "skills"))) {
17840
18038
  return candidate;
17841
18039
  }
17842
18040
  }
@@ -17845,13 +18043,13 @@ function resolveDataDir() {
17845
18043
  );
17846
18044
  }
17847
18045
  function setupDataPath(file) {
17848
- return (0, import_node_path22.join)(resolveDataDir(), "skills", "verity-setup", file);
18046
+ return (0, import_node_path24.join)(resolveDataDir(), "skills", "verity-setup", file);
17849
18047
  }
17850
18048
 
17851
18049
  // src/lib/detect.ts
17852
18050
  var import_node_child_process8 = require("node:child_process");
17853
- var import_node_fs25 = require("node:fs");
17854
- var import_node_path23 = require("node:path");
18051
+ var import_node_fs27 = require("node:fs");
18052
+ var import_node_path25 = require("node:path");
17855
18053
  var TOOLED_LANGUAGES = /* @__PURE__ */ new Set([
17856
18054
  "typescript",
17857
18055
  "javascript",
@@ -17908,25 +18106,25 @@ function walk(root) {
17908
18106
  if (depth > WALK_MAX_DEPTH || found.length >= WALK_MAX_FILES) return;
17909
18107
  let entries;
17910
18108
  try {
17911
- entries = (0, import_node_fs25.readdirSync)(dir, { withFileTypes: true });
18109
+ entries = (0, import_node_fs27.readdirSync)(dir, { withFileTypes: true });
17912
18110
  } catch {
17913
18111
  return;
17914
18112
  }
17915
18113
  for (const entry of entries) {
17916
18114
  if (found.length >= WALK_MAX_FILES) return;
17917
18115
  if (IGNORED_SEGMENTS.includes(entry.name)) continue;
17918
- const full = (0, import_node_path23.join)(dir, entry.name);
18116
+ const full = (0, import_node_path25.join)(dir, entry.name);
17919
18117
  if (entry.isDirectory()) visit(full, depth + 1);
17920
- else if (entry.isFile()) found.push((0, import_node_path23.relative)(root, full));
18118
+ else if (entry.isFile()) found.push((0, import_node_path25.relative)(root, full));
17921
18119
  }
17922
18120
  };
17923
18121
  visit(root, 0);
17924
18122
  return found;
17925
18123
  }
17926
18124
  function languageOf(path) {
17927
- const name = (0, import_node_path23.basename)(path);
18125
+ const name = (0, import_node_path25.basename)(path);
17928
18126
  if (/^Dockerfile(\..+)?$/i.test(name)) return "dockerfile";
17929
- if (!(0, import_node_path23.extname)(name)) return null;
18127
+ if (!(0, import_node_path25.extname)(name)) return null;
17930
18128
  const lang = detectLanguage(path);
17931
18129
  return lang || null;
17932
18130
  }
@@ -17981,9 +18179,9 @@ var TOOL_CONFIG_MARKERS = [
17981
18179
  ["detekt", ["detekt.yml", "detekt.yaml"]],
17982
18180
  ["Hadolint", [".hadolint.yaml", ".hadolint.yml"]]
17983
18181
  ];
17984
- function readJson(path) {
18182
+ function readJson2(path) {
17985
18183
  try {
17986
- return JSON.parse((0, import_node_fs25.readFileSync)(path, "utf-8"));
18184
+ return JSON.parse((0, import_node_fs27.readFileSync)(path, "utf-8"));
17987
18185
  } catch {
17988
18186
  return null;
17989
18187
  }
@@ -18001,24 +18199,24 @@ var NESTED_MANIFEST_LIMIT = 25;
18001
18199
  function declaredDependencies(root, files) {
18002
18200
  const names2 = [];
18003
18201
  const readPackageJson = (path) => {
18004
- const pkg = readJson(path);
18202
+ const pkg = readJson2(path);
18005
18203
  if (!pkg) return;
18006
18204
  for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
18007
18205
  const deps = pkg[field];
18008
18206
  if (deps && typeof deps === "object") names2.push(...Object.keys(deps));
18009
18207
  }
18010
18208
  };
18011
- readPackageJson((0, import_node_path23.join)(root, "package.json"));
18012
- const nested = files.filter((f) => f.includes("/") && (0, import_node_path23.basename)(f) === "package.json").slice(0, NESTED_MANIFEST_LIMIT);
18013
- for (const rel of nested) readPackageJson((0, import_node_path23.join)(root, rel));
18209
+ readPackageJson((0, import_node_path25.join)(root, "package.json"));
18210
+ const nested = files.filter((f) => f.includes("/") && (0, import_node_path25.basename)(f) === "package.json").slice(0, NESTED_MANIFEST_LIMIT);
18211
+ for (const rel of nested) readPackageJson((0, import_node_path25.join)(root, rel));
18014
18212
  const pythonManifests = [
18015
- ...["pyproject.toml", "requirements.txt", "Pipfile", "setup.py"].map((f) => (0, import_node_path23.join)(root, f)),
18016
- ...files.filter((f) => f.includes("/") && /(^|\/)(pyproject\.toml|requirements\.txt)$/.test(f)).slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path23.join)(root, f))
18213
+ ...["pyproject.toml", "requirements.txt", "Pipfile", "setup.py"].map((f) => (0, import_node_path25.join)(root, f)),
18214
+ ...files.filter((f) => f.includes("/") && /(^|\/)(pyproject\.toml|requirements\.txt)$/.test(f)).slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path25.join)(root, f))
18017
18215
  ];
18018
18216
  for (const path of pythonManifests) {
18019
- if (!(0, import_node_fs25.existsSync)(path)) continue;
18217
+ if (!(0, import_node_fs27.existsSync)(path)) continue;
18020
18218
  try {
18021
- const text = (0, import_node_fs25.readFileSync)(path, "utf-8");
18219
+ const text = (0, import_node_fs27.readFileSync)(path, "utf-8");
18022
18220
  for (const m of text.matchAll(/^\s*["']?([A-Za-z][A-Za-z0-9._-]+)/gm)) names2.push(m[1]);
18023
18221
  for (const line of text.split("\n")) {
18024
18222
  if (!/dependencies\s*=/.test(line)) continue;
@@ -18028,13 +18226,13 @@ function declaredDependencies(root, files) {
18028
18226
  }
18029
18227
  }
18030
18228
  const goMods = [
18031
- (0, import_node_path23.join)(root, "go.mod"),
18032
- ...files.filter((f) => f.includes("/") && (0, import_node_path23.basename)(f) === "go.mod").slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path23.join)(root, f))
18229
+ (0, import_node_path25.join)(root, "go.mod"),
18230
+ ...files.filter((f) => f.includes("/") && (0, import_node_path25.basename)(f) === "go.mod").slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path25.join)(root, f))
18033
18231
  ];
18034
18232
  for (const path of goMods) {
18035
- if (!(0, import_node_fs25.existsSync)(path)) continue;
18233
+ if (!(0, import_node_fs27.existsSync)(path)) continue;
18036
18234
  try {
18037
- const text = (0, import_node_fs25.readFileSync)(path, "utf-8");
18235
+ const text = (0, import_node_fs27.readFileSync)(path, "utf-8");
18038
18236
  for (const m of text.matchAll(/^\s+([\w.-]+\/[\w./-]+)\s+v/gm)) {
18039
18237
  names2.push(m[1].replace(/^github\.com\//, ""));
18040
18238
  }
@@ -18042,10 +18240,10 @@ function declaredDependencies(root, files) {
18042
18240
  }
18043
18241
  }
18044
18242
  for (const file of ["pom.xml", "build.gradle", "build.gradle.kts", "Gemfile", "Cargo.toml"]) {
18045
- const path = (0, import_node_path23.join)(root, file);
18046
- if (!(0, import_node_fs25.existsSync)(path)) continue;
18243
+ const path = (0, import_node_path25.join)(root, file);
18244
+ if (!(0, import_node_fs27.existsSync)(path)) continue;
18047
18245
  try {
18048
- const text = (0, import_node_fs25.readFileSync)(path, "utf-8");
18246
+ const text = (0, import_node_fs27.readFileSync)(path, "utf-8");
18049
18247
  for (const m of text.matchAll(/["'<]([A-Za-z][A-Za-z0-9._-]{2,})["'>]/g)) names2.push(m[1]);
18050
18248
  } catch {
18051
18249
  }
@@ -18053,7 +18251,7 @@ function declaredDependencies(root, files) {
18053
18251
  return names2;
18054
18252
  }
18055
18253
  function detectBuildSystem(root, files) {
18056
- const has = (f) => (0, import_node_fs25.existsSync)((0, import_node_path23.join)(root, f)) || files.some((p) => (0, import_node_path23.basename)(p) === f);
18254
+ const has = (f) => (0, import_node_fs27.existsSync)((0, import_node_path25.join)(root, f)) || files.some((p) => (0, import_node_path25.basename)(p) === f);
18057
18255
  if (has("pnpm-lock.yaml")) return "pnpm";
18058
18256
  if (has("yarn.lock")) return "yarn";
18059
18257
  if (has("bun.lock") || has("bun.lockb")) return "bun";
@@ -18070,8 +18268,8 @@ function detectBuildSystem(root, files) {
18070
18268
  }
18071
18269
  function detectArchitecture(root, files) {
18072
18270
  const workspaceMarkers = ["lerna.json", "pnpm-workspace.yaml", "nx.json", "turbo.json", "rush.json"];
18073
- if (workspaceMarkers.some((m) => (0, import_node_fs25.existsSync)((0, import_node_path23.join)(root, m)))) return "monorepo";
18074
- const pkg = readJson((0, import_node_path23.join)(root, "package.json"));
18271
+ if (workspaceMarkers.some((m) => (0, import_node_fs27.existsSync)((0, import_node_path25.join)(root, m)))) return "monorepo";
18272
+ const pkg = readJson2((0, import_node_path25.join)(root, "package.json"));
18075
18273
  if (pkg && "workspaces" in pkg) return "monorepo";
18076
18274
  const manifests = files.filter((f) => /(^|\/)(package\.json|go\.mod|pyproject\.toml|Cargo\.toml|pom\.xml)$/.test(f));
18077
18275
  const nested = manifests.filter((f) => f.includes("/"));
@@ -18093,10 +18291,10 @@ function measureAvgFileLength(root, files, languages) {
18093
18291
  let total = 0;
18094
18292
  let counted = 0;
18095
18293
  for (let i = 0; i < candidates2.length; i += stride) {
18096
- const path = (0, import_node_path23.join)(root, candidates2[i]);
18294
+ const path = (0, import_node_path25.join)(root, candidates2[i]);
18097
18295
  try {
18098
- if ((0, import_node_fs25.statSync)(path).size > 2 * 1024 * 1024) continue;
18099
- total += (0, import_node_fs25.readFileSync)(path, "utf-8").split("\n").length;
18296
+ if ((0, import_node_fs27.statSync)(path).size > 2 * 1024 * 1024) continue;
18297
+ total += (0, import_node_fs27.readFileSync)(path, "utf-8").split("\n").length;
18100
18298
  counted++;
18101
18299
  } catch {
18102
18300
  }
@@ -18126,14 +18324,14 @@ function detectProject(root = repoRoot()) {
18126
18324
  const existingToolConfigs = [];
18127
18325
  for (const [tool, markers] of TOOL_CONFIG_MARKERS) {
18128
18326
  for (const marker of markers) {
18129
- if ((0, import_node_fs25.existsSync)((0, import_node_path23.join)(root, marker))) {
18327
+ if ((0, import_node_fs27.existsSync)((0, import_node_path25.join)(root, marker))) {
18130
18328
  existingToolConfigs.push({ tool, path: `./${marker}` });
18131
18329
  break;
18132
18330
  }
18133
18331
  }
18134
18332
  }
18135
18333
  return {
18136
- projectName: (0, import_node_path23.basename)(root),
18334
+ projectName: (0, import_node_path25.basename)(root),
18137
18335
  languages,
18138
18336
  languageCounts,
18139
18337
  frameworks: matchAll(dependencies, FRAMEWORK_BY_DEPENDENCY),
@@ -18231,8 +18429,8 @@ ${closingNote(input.origin)}
18231
18429
 
18232
18430
  // src/lib/synthesize.ts
18233
18431
  function loadCatalog() {
18234
- const catalog = (0, import_yaml.parse)((0, import_node_fs26.readFileSync)(setupDataPath("patterns-reference.yaml"), "utf-8"));
18235
- const template = (0, import_yaml.parse)((0, import_node_fs26.readFileSync)(setupDataPath("standard-template.yaml"), "utf-8"));
18432
+ const catalog = (0, import_yaml.parse)((0, import_node_fs28.readFileSync)(setupDataPath("patterns-reference.yaml"), "utf-8"));
18433
+ const template = (0, import_yaml.parse)((0, import_node_fs28.readFileSync)(setupDataPath("standard-template.yaml"), "utf-8"));
18236
18434
  return { catalog, template };
18237
18435
  }
18238
18436
  function selectTools(languages, intensity, catalog) {
@@ -18510,7 +18708,7 @@ function validatePatternIds() {
18510
18708
  }
18511
18709
  async function runSynthesis(opts) {
18512
18710
  const standardPath = projectPath(STANDARD_FILE);
18513
- if ((0, import_node_fs26.existsSync)(standardPath) && !opts.force) {
18711
+ if ((0, import_node_fs28.existsSync)(standardPath) && !opts.force) {
18514
18712
  return { refused: `${STANDARD_FILE} already exists \u2014 pass --force to replace it.` };
18515
18713
  }
18516
18714
  const detected = opts.detected ?? detectProject();
@@ -18577,9 +18775,9 @@ async function correctVerityMdVersion(opts) {
18577
18775
  origin: { kind: "synthesized", tools: opts.tools }
18578
18776
  }));
18579
18777
  }
18580
- async function writeFileTo(relative2, body) {
18581
- const target = projectPath(relative2);
18582
- await (0, import_promises10.mkdir)((0, import_node_path24.dirname)(target), { recursive: true });
18778
+ async function writeFileTo(relative3, body) {
18779
+ const target = projectPath(relative3);
18780
+ await (0, import_promises10.mkdir)((0, import_node_path26.dirname)(target), { recursive: true });
18583
18781
  await (0, import_promises10.writeFile)(target, body);
18584
18782
  }
18585
18783
  async function deriveConfigForStandard(standard) {
@@ -18638,11 +18836,11 @@ ${validation.detail}`);
18638
18836
 
18639
18837
  // src/lib/setup-state.ts
18640
18838
  var import_promises11 = require("node:fs/promises");
18641
- var import_node_fs27 = require("node:fs");
18839
+ var import_node_fs29 = require("node:fs");
18642
18840
  var SETUP_STATE_FILE = `${VERITY_DIR}/setup.json`;
18643
18841
  async function readSetupState() {
18644
18842
  const path = projectPath(SETUP_STATE_FILE);
18645
- if (!(0, import_node_fs27.existsSync)(path)) return null;
18843
+ if (!(0, import_node_fs29.existsSync)(path)) return null;
18646
18844
  try {
18647
18845
  const parsed = JSON.parse(await (0, import_promises11.readFile)(path, "utf-8"));
18648
18846
  return parsed && typeof parsed === "object" ? parsed : null;
@@ -18658,12 +18856,12 @@ async function writeSetupState(patch) {
18658
18856
  }
18659
18857
 
18660
18858
  // src/lib/push-setup.ts
18661
- var import_node_fs29 = require("node:fs");
18859
+ var import_node_fs31 = require("node:fs");
18662
18860
  var import_promises12 = require("node:fs/promises");
18663
18861
  var import_yaml2 = __toESM(require_dist());
18664
18862
 
18665
18863
  // src/lib/verityignore.ts
18666
- var import_node_fs28 = require("node:fs");
18864
+ var import_node_fs30 = require("node:fs");
18667
18865
  var EMPTY = { rules: [], securityOverlap: [], problems: [] };
18668
18866
  var SECURITY_PROBES = [
18669
18867
  ".env",
@@ -18756,9 +18954,9 @@ function isIgnored3(ig, path) {
18756
18954
  }
18757
18955
  function loadVerityIgnore() {
18758
18956
  const file = projectPath(VERITYIGNORE_FILE);
18759
- if (!(0, import_node_fs28.existsSync)(file)) return EMPTY;
18957
+ if (!(0, import_node_fs30.existsSync)(file)) return EMPTY;
18760
18958
  try {
18761
- return parseVerityIgnore((0, import_node_fs28.readFileSync)(file, "utf-8"));
18959
+ return parseVerityIgnore((0, import_node_fs30.readFileSync)(file, "utf-8"));
18762
18960
  } catch {
18763
18961
  return EMPTY;
18764
18962
  }
@@ -18796,9 +18994,9 @@ function buildStandardUpload(standard, ignoreRaw) {
18796
18994
  }
18797
18995
  function readVerityIgnoreRaw() {
18798
18996
  const file = projectPath(VERITYIGNORE_FILE);
18799
- if (!(0, import_node_fs28.existsSync)(file)) return null;
18997
+ if (!(0, import_node_fs30.existsSync)(file)) return null;
18800
18998
  try {
18801
- return (0, import_node_fs28.readFileSync)(file, "utf-8");
18999
+ return (0, import_node_fs30.readFileSync)(file, "utf-8");
18802
19000
  } catch {
18803
19001
  return null;
18804
19002
  }
@@ -18826,7 +19024,7 @@ async function pushStandardAndConfig(globals, what = {}) {
18826
19024
  }
18827
19025
  let standardVersion = null;
18828
19026
  const standardPath = projectPath(STANDARD_FILE);
18829
- if (pushStandard && (0, import_node_fs29.existsSync)(standardPath)) {
19027
+ if (pushStandard && (0, import_node_fs31.existsSync)(standardPath)) {
18830
19028
  try {
18831
19029
  const content = (0, import_yaml2.parse)(await (0, import_promises12.readFile)(standardPath, "utf-8"));
18832
19030
  const upload = buildStandardUpload(content, readVerityIgnoreRaw());
@@ -18851,7 +19049,7 @@ async function pushStandardAndConfig(globals, what = {}) {
18851
19049
  }
18852
19050
  let configPushed = false;
18853
19051
  const configPath = projectPath(CODACY_CONFIG_FILE);
18854
- if (pushConfig && (0, import_node_fs29.existsSync)(configPath)) {
19052
+ if (pushConfig && (0, import_node_fs31.existsSync)(configPath)) {
18855
19053
  try {
18856
19054
  const content = JSON.parse(await (0, import_promises12.readFile)(configPath, "utf-8"));
18857
19055
  const result = await apiRequest({
@@ -18883,7 +19081,7 @@ function registerStandardCommands(program2) {
18883
19081
  const state = await readSetupState();
18884
19082
  if (opts.configOnly) {
18885
19083
  const standardPath = projectPath(STANDARD_FILE);
18886
- if (!(0, import_node_fs30.existsSync)(standardPath)) {
19084
+ if (!(0, import_node_fs32.existsSync)(standardPath)) {
18887
19085
  printError(`No ${STANDARD_FILE} here \u2014 run "verity standard synthesize" to create one.`);
18888
19086
  process.exit(1);
18889
19087
  }
@@ -19195,7 +19393,9 @@ function formatRunDetail(run2) {
19195
19393
  if (f.description && f.description !== title) lines.push(` ${f.description}`);
19196
19394
  const fix = f.fix?.description ?? f.suggestion;
19197
19395
  if (fix) lines.push(` \u21B3 fix: ${fix}`);
19198
- if (f.scope === "pre-existing") lines.push(" (pre-existing)");
19396
+ if (f.scope === "pre-existing") {
19397
+ lines.push(f.provenance === "caused-elsewhere" ? " (caused elsewhere \u2014 not by this change)" : " (pre-existing)");
19398
+ }
19199
19399
  }
19200
19400
  }
19201
19401
  const pending = run2.pending_items ?? [];
@@ -19214,10 +19414,10 @@ function formatRunDetail(run2) {
19214
19414
  }
19215
19415
 
19216
19416
  // src/lib/ignore-declaration.ts
19217
- var import_node_fs32 = require("node:fs");
19417
+ var import_node_fs34 = require("node:fs");
19218
19418
 
19219
19419
  // src/lib/debounce.ts
19220
- var import_node_fs31 = require("node:fs");
19420
+ var import_node_fs33 = require("node:fs");
19221
19421
  var import_node_crypto10 = require("node:crypto");
19222
19422
  function scopedFile(base, sessionId) {
19223
19423
  if (!sessionId) return base;
@@ -19225,9 +19425,9 @@ function scopedFile(base, sessionId) {
19225
19425
  }
19226
19426
  function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
19227
19427
  const file = scopedFile(DEBOUNCE_FILE, sessionId);
19228
- if (!(0, import_node_fs31.existsSync)(file)) return null;
19428
+ if (!(0, import_node_fs33.existsSync)(file)) return null;
19229
19429
  try {
19230
- const lastTs = parseInt((0, import_node_fs31.readFileSync)(file, "utf-8").trim(), 10);
19430
+ const lastTs = parseInt((0, import_node_fs33.readFileSync)(file, "utf-8").trim(), 10);
19231
19431
  const nowTs = Math.floor(Date.now() / 1e3);
19232
19432
  const elapsed = nowTs - lastTs;
19233
19433
  if (elapsed < debounceSeconds) {
@@ -19240,10 +19440,10 @@ function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
19240
19440
  function checkMtime(files, bypassForRecentCommits, sessionId) {
19241
19441
  if (bypassForRecentCommits) return null;
19242
19442
  const file = scopedFile(DEBOUNCE_FILE, sessionId);
19243
- if (!(0, import_node_fs31.existsSync)(file)) return null;
19443
+ if (!(0, import_node_fs33.existsSync)(file)) return null;
19244
19444
  let debounceTime;
19245
19445
  try {
19246
- debounceTime = (0, import_node_fs31.statSync)(file).mtimeMs;
19446
+ debounceTime = (0, import_node_fs33.statSync)(file).mtimeMs;
19247
19447
  } catch {
19248
19448
  return null;
19249
19449
  }
@@ -19251,7 +19451,7 @@ function checkMtime(files, bypassForRecentCommits, sessionId) {
19251
19451
  const resolved = resolveFile(f);
19252
19452
  if (!resolved) continue;
19253
19453
  try {
19254
- const stat3 = (0, import_node_fs31.statSync)(resolved);
19454
+ const stat3 = (0, import_node_fs33.statSync)(resolved);
19255
19455
  if (stat3.mtimeMs > debounceTime) {
19256
19456
  return null;
19257
19457
  }
@@ -19267,8 +19467,8 @@ function computeContentHash(files) {
19267
19467
  for (const f of sorted) {
19268
19468
  const resolved = resolveFile(f) ?? f;
19269
19469
  try {
19270
- if ((0, import_node_fs31.existsSync)(resolved)) {
19271
- hash.update((0, import_node_fs31.readFileSync)(resolved));
19470
+ if ((0, import_node_fs33.existsSync)(resolved)) {
19471
+ hash.update((0, import_node_fs33.readFileSync)(resolved));
19272
19472
  }
19273
19473
  } catch {
19274
19474
  }
@@ -19278,9 +19478,9 @@ function computeContentHash(files) {
19278
19478
  function checkContentHash(files, sessionId) {
19279
19479
  const hash = computeContentHash(files);
19280
19480
  const file = scopedFile(HASH_FILE, sessionId);
19281
- if ((0, import_node_fs31.existsSync)(file)) {
19481
+ if ((0, import_node_fs33.existsSync)(file)) {
19282
19482
  try {
19283
- const storedHash = (0, import_node_fs31.readFileSync)(file, "utf-8").trim();
19483
+ const storedHash = (0, import_node_fs33.readFileSync)(file, "utf-8").trim();
19284
19484
  if (hash === storedHash) {
19285
19485
  return { skip: "No source changes since last analysis", hash };
19286
19486
  }
@@ -19290,24 +19490,24 @@ function checkContentHash(files, sessionId) {
19290
19490
  return { skip: null, hash };
19291
19491
  }
19292
19492
  function recordAnalysisStart(sessionId) {
19293
- (0, import_node_fs31.mkdirSync)(VERITY_DIR, { recursive: true });
19294
- (0, import_node_fs31.writeFileSync)(scopedFile(DEBOUNCE_FILE, sessionId), String(Math.floor(Date.now() / 1e3)));
19493
+ (0, import_node_fs33.mkdirSync)(VERITY_DIR, { recursive: true });
19494
+ (0, import_node_fs33.writeFileSync)(scopedFile(DEBOUNCE_FILE, sessionId), String(Math.floor(Date.now() / 1e3)));
19295
19495
  }
19296
19496
  function recordPassHash(hash, sessionId) {
19297
- (0, import_node_fs31.writeFileSync)(scopedFile(HASH_FILE, sessionId), hash);
19497
+ (0, import_node_fs33.writeFileSync)(scopedFile(HASH_FILE, sessionId), hash);
19298
19498
  }
19299
19499
  function narrowToRecent(files, sessionId) {
19300
19500
  const file = scopedFile(DEBOUNCE_FILE, sessionId);
19301
- if (!(0, import_node_fs31.existsSync)(file)) return files;
19501
+ if (!(0, import_node_fs33.existsSync)(file)) return files;
19302
19502
  let debounceTime;
19303
19503
  try {
19304
- debounceTime = (0, import_node_fs31.statSync)(file).mtimeMs;
19504
+ debounceTime = (0, import_node_fs33.statSync)(file).mtimeMs;
19305
19505
  } catch {
19306
19506
  return files;
19307
19507
  }
19308
19508
  const recent = files.filter((f) => {
19309
19509
  try {
19310
- return (0, import_node_fs31.existsSync)(f) && (0, import_node_fs31.statSync)(f).mtimeMs > debounceTime;
19510
+ return (0, import_node_fs33.existsSync)(f) && (0, import_node_fs33.statSync)(f).mtimeMs > debounceTime;
19311
19511
  } catch {
19312
19512
  return false;
19313
19513
  }
@@ -19320,9 +19520,9 @@ function readIteration(currentCommit, _contentHash) {
19320
19520
  var NO_BLOCKS = { attempts: 0, blocks: 0, fingerprint: null };
19321
19521
  function readBlockState(currentCommit, opts) {
19322
19522
  if (opts?.newUserPrompt) return NO_BLOCKS;
19323
- if (!(0, import_node_fs31.existsSync)(ITERATION_FILE)) return NO_BLOCKS;
19523
+ if (!(0, import_node_fs33.existsSync)(ITERATION_FILE)) return NO_BLOCKS;
19324
19524
  try {
19325
- const stored = (0, import_node_fs31.readFileSync)(ITERATION_FILE, "utf-8").trim();
19525
+ const stored = (0, import_node_fs33.readFileSync)(ITERATION_FILE, "utf-8").trim();
19326
19526
  const parsed = stored.startsWith("{") ? parseJsonState(stored) : parseLegacyState(stored);
19327
19527
  if (!parsed) return NO_BLOCKS;
19328
19528
  if (parsed.commit !== currentCommit) return NO_BLOCKS;
@@ -19368,8 +19568,8 @@ function isSameProblem(previous, current) {
19368
19568
  return current.split(",").some((k) => prev.has(k));
19369
19569
  }
19370
19570
  function writeBlockState(commit, state) {
19371
- (0, import_node_fs31.mkdirSync)(VERITY_DIR, { recursive: true });
19372
- (0, import_node_fs31.writeFileSync)(
19571
+ (0, import_node_fs33.mkdirSync)(VERITY_DIR, { recursive: true });
19572
+ (0, import_node_fs33.writeFileSync)(
19373
19573
  ITERATION_FILE,
19374
19574
  JSON.stringify({
19375
19575
  v: 2,
@@ -19474,9 +19674,9 @@ function resolveIgnoreState(keys) {
19474
19674
  }
19475
19675
  function readIgnoreState(sessionId) {
19476
19676
  const file = stateFile(sessionId);
19477
- if (!(0, import_node_fs32.existsSync)(file)) return null;
19677
+ if (!(0, import_node_fs34.existsSync)(file)) return null;
19478
19678
  try {
19479
- const o = JSON.parse((0, import_node_fs32.readFileSync)(file, "utf-8")) ?? {};
19679
+ const o = JSON.parse((0, import_node_fs34.readFileSync)(file, "utf-8")) ?? {};
19480
19680
  const spent = typeof o.spent === "number" ? o.spent : 0;
19481
19681
  const raw = o.active;
19482
19682
  let active = null;
@@ -19500,8 +19700,8 @@ function readIgnoreState(sessionId) {
19500
19700
  }
19501
19701
  function writeIgnoreState(state, sessionId) {
19502
19702
  try {
19503
- (0, import_node_fs32.mkdirSync)(projectPath(VERITY_DIR), { recursive: true });
19504
- (0, import_node_fs32.writeFileSync)(stateFile(sessionId), JSON.stringify({ v: 1, active: state.active, spent: state.spent }));
19703
+ (0, import_node_fs34.mkdirSync)(projectPath(VERITY_DIR), { recursive: true });
19704
+ (0, import_node_fs34.writeFileSync)(stateFile(sessionId), JSON.stringify({ v: 1, active: state.active, spent: state.spent }));
19505
19705
  } catch {
19506
19706
  }
19507
19707
  }
@@ -19884,15 +20084,15 @@ function createRun(opts, globals) {
19884
20084
  }
19885
20085
 
19886
20086
  // src/commands/analyze/index.ts
19887
- var import_node_fs45 = require("node:fs");
20087
+ var import_node_fs47 = require("node:fs");
19888
20088
 
19889
20089
  // src/lib/repo-context.ts
19890
20090
  var import_node_child_process10 = require("node:child_process");
19891
- var import_node_os4 = require("node:os");
20091
+ var import_node_os5 = require("node:os");
19892
20092
  function rgInvocations(env = process.env) {
19893
20093
  const out = [{ cmd: "rg" }];
19894
20094
  if (env.CLAUDE_CODE_EXECPATH) out.push({ cmd: env.CLAUDE_CODE_EXECPATH, argv0: "rg" });
19895
- out.push({ cmd: `${(0, import_node_os4.homedir)()}/.local/bin/claude`, argv0: "rg" });
20095
+ out.push({ cmd: `${(0, import_node_os5.homedir)()}/.local/bin/claude`, argv0: "rg" });
19896
20096
  return out;
19897
20097
  }
19898
20098
  function ripgrepEnv(base = process.env) {
@@ -20395,6 +20595,112 @@ function partitionSites(rgLines, symbols, opts) {
20395
20595
  while (callers.length + tests.length > MAX_SITES) callers.pop();
20396
20596
  return { callers, tests, dropped };
20397
20597
  }
20598
+ var MAX_IMPORTERS = 12;
20599
+ var MAX_IMPORTERS_PER_FILE = 2;
20600
+ function moduleKey(path) {
20601
+ return path.replace(/\.(ts|tsx|js|jsx|mjs|cjs|mts|cts)$/i, "").replace(/\/index$/, "");
20602
+ }
20603
+ function importSpecifier(text) {
20604
+ const m = /(?:\bfrom|\brequire\s*\(|\bimport\s*\(|^\s*import)\s*['"]([^'"\n]+)['"]/.exec(text);
20605
+ return m?.[1] ?? null;
20606
+ }
20607
+ function resolveSpecifier(fromFile, spec) {
20608
+ if (!spec.startsWith(".")) return null;
20609
+ const dir = fromFile.includes("/") ? fromFile.slice(0, fromFile.lastIndexOf("/")) : "";
20610
+ const out = [];
20611
+ for (const part of (dir ? dir.split("/") : []).concat(spec.split("/"))) {
20612
+ if (part === "" || part === ".") continue;
20613
+ if (part === "..") {
20614
+ if (out.length === 0) return null;
20615
+ out.pop();
20616
+ continue;
20617
+ }
20618
+ out.push(part);
20619
+ }
20620
+ return out.length > 0 ? moduleKey(out.join("/")) : null;
20621
+ }
20622
+ function partitionImporters(rgLines, changedPaths, opts) {
20623
+ const changedByKey = /* @__PURE__ */ new Map();
20624
+ for (const p of changedPaths) changedByKey.set(moduleKey(p), p);
20625
+ const hits = rgLines.map(parseRgLine).filter((h) => h !== null);
20626
+ hits.sort((a, b) => a.file < b.file ? -1 : a.file > b.file ? 1 : a.line - b.line);
20627
+ const perFile = /* @__PURE__ */ new Map();
20628
+ const out = [];
20629
+ for (const h of hits) {
20630
+ if (out.length >= MAX_IMPORTERS) break;
20631
+ if (opts.sentPaths.has(h.file)) continue;
20632
+ if (opts.isExcluded(h.file)) continue;
20633
+ if (!isCodeSiteFile(h.file)) continue;
20634
+ const spec = importSpecifier(h.text);
20635
+ if (!spec) continue;
20636
+ const resolved = resolveSpecifier(h.file, spec);
20637
+ if (!resolved) continue;
20638
+ const changed = changedByKey.get(resolved);
20639
+ if (!changed) continue;
20640
+ const used = perFile.get(h.file) ?? 0;
20641
+ if (used >= MAX_IMPORTERS_PER_FILE) continue;
20642
+ perFile.set(h.file, used + 1);
20643
+ out.push({ file: h.file, line: h.line, text: h.text.trim().slice(0, SITE_TEXT_MAX), symbol: changed });
20644
+ }
20645
+ return out;
20646
+ }
20647
+ function runRg(args, cwd, timeoutMs) {
20648
+ let res = null;
20649
+ for (const inv of rgInvocations()) {
20650
+ res = (0, import_node_child_process10.spawnSync)(inv.cmd, args, {
20651
+ ...inv.argv0 ? { argv0: inv.argv0 } : {},
20652
+ cwd,
20653
+ env: ripgrepEnv(),
20654
+ timeout: timeoutMs,
20655
+ maxBuffer: 4 * 1024 * 1024,
20656
+ encoding: "utf8"
20657
+ });
20658
+ if (res.error?.code !== "ENOENT") break;
20659
+ }
20660
+ if (!res || res.error?.code === "ENOENT") {
20661
+ return { ok: false, reason: "no-tool" };
20662
+ }
20663
+ if (res.error) {
20664
+ const code = res.error.code;
20665
+ return { ok: false, reason: code === "ETIMEDOUT" ? "timeout" : "error" };
20666
+ }
20667
+ if (res.signal) return { ok: false, reason: "timeout" };
20668
+ if (res.status !== 0 && res.status !== 1) return { ok: false, reason: "error" };
20669
+ return { ok: true, lines: (res.stdout ?? "").split("\n").map((l) => l.replace(/^\.\//, "")).filter(Boolean) };
20670
+ }
20671
+ function findImporters(input) {
20672
+ const basenames = [
20673
+ ...new Set(input.changedPaths.map((p) => moduleKey(p).split("/").pop() ?? "").filter((b) => b.length > 0))
20674
+ ].slice(0, MAX_SYMBOLS);
20675
+ if (basenames.length === 0) return [];
20676
+ const res = runRg(
20677
+ [
20678
+ "--no-config",
20679
+ "-n",
20680
+ "-w",
20681
+ "-F",
20682
+ "--no-heading",
20683
+ "--color",
20684
+ "never",
20685
+ "-m",
20686
+ "8",
20687
+ "--max-columns",
20688
+ "300",
20689
+ "--max-columns-preview",
20690
+ ...basenames.flatMap((b) => ["-e", b]),
20691
+ "-g",
20692
+ "!**/{dist,build,out,vendor,node_modules,.git,coverage,target,__pycache__}/**",
20693
+ "./"
20694
+ ],
20695
+ input.cwd,
20696
+ input.timeoutMs
20697
+ );
20698
+ if (!res.ok) return [];
20699
+ return partitionImporters(res.lines, input.changedPaths, {
20700
+ sentPaths: input.sentPaths,
20701
+ isExcluded: input.isExcluded
20702
+ });
20703
+ }
20398
20704
  function buildRepoContext(input) {
20399
20705
  const started = Date.now();
20400
20706
  let signalsByPath;
@@ -20429,7 +20735,18 @@ function buildRepoContext(input) {
20429
20735
  const unsupportedExts = [...unsupported].sort().slice(0, 8);
20430
20736
  const audit = unsupportedExts.length > 0 ? { unsupported_exts: unsupportedExts } : {};
20431
20737
  const symbols = rankSymbols([...new Set(collected)]);
20738
+ const changedPaths = [.../* @__PURE__ */ new Set([...signalsByPath.keys(), ...input.deltaFiles.map((f) => f.path)])];
20739
+ const importers = findImporters({
20740
+ changedPaths,
20741
+ sentPaths: input.sentPaths,
20742
+ isExcluded: input.isExcluded,
20743
+ cwd: input.cwd ?? process.cwd(),
20744
+ timeoutMs: input.timeoutMs ?? RG_TIMEOUT_MS
20745
+ });
20432
20746
  if (symbols.length === 0) {
20747
+ if (importers.length > 0) {
20748
+ return { state: "ok", symbols: [], ...audit, callers: [], tests: [], importers, elapsed_ms: Date.now() - started };
20749
+ }
20433
20750
  const everySupportedFileFoundNothing = unsupportedExts.length > 0;
20434
20751
  return {
20435
20752
  state: "absent",
@@ -20468,34 +20785,19 @@ function buildRepoContext(input) {
20468
20785
  "!**/{dist,build,out,vendor,node_modules,.git,coverage,target,__pycache__}/**",
20469
20786
  "./"
20470
20787
  ];
20471
- let res = null;
20472
- for (const inv of rgInvocations()) {
20473
- res = (0, import_node_child_process10.spawnSync)(inv.cmd, args, {
20474
- ...inv.argv0 ? { argv0: inv.argv0 } : {},
20475
- cwd: input.cwd ?? process.cwd(),
20476
- env: ripgrepEnv(),
20477
- timeout: input.timeoutMs ?? RG_TIMEOUT_MS,
20478
- maxBuffer: 4 * 1024 * 1024,
20479
- encoding: "utf8"
20480
- });
20481
- if (res.error?.code !== "ENOENT") break;
20482
- }
20483
- if (!res || res.error?.code === "ENOENT") {
20484
- return { state: "absent", reason: "no-tool", symbols, ...audit };
20485
- }
20486
- if (res.error) {
20487
- const code = res.error.code;
20488
- if (code === "ETIMEDOUT") return { state: "absent", reason: "timeout", symbols, ...audit };
20489
- return { state: "absent", reason: "error", symbols, ...audit };
20788
+ const res = runRg(args, input.cwd ?? process.cwd(), input.timeoutMs ?? RG_TIMEOUT_MS);
20789
+ if (!res.ok) {
20790
+ if (importers.length > 0) {
20791
+ return { state: "ok", symbols, ...audit, callers: [], tests: [], importers, elapsed_ms: Date.now() - started };
20792
+ }
20793
+ return { state: "absent", reason: res.reason, symbols, ...audit };
20490
20794
  }
20491
- if (res.signal) return { state: "absent", reason: "timeout", symbols, ...audit };
20492
- if (res.status !== 0 && res.status !== 1) return { state: "absent", reason: "error", symbols, ...audit };
20493
- const lines = (res.stdout ?? "").split("\n").map((l) => l.replace(/^\.\//, "")).filter(Boolean);
20795
+ const lines = res.lines;
20494
20796
  const { callers, tests, dropped } = partitionSites(lines, symbols, {
20495
20797
  sentPaths: input.sentPaths,
20496
20798
  isExcluded: input.isExcluded
20497
20799
  });
20498
- if (callers.length === 0 && tests.length === 0) {
20800
+ if (callers.length === 0 && tests.length === 0 && importers.length === 0) {
20499
20801
  return {
20500
20802
  state: "absent",
20501
20803
  reason: "no-sites",
@@ -20512,6 +20814,7 @@ function buildRepoContext(input) {
20512
20814
  ...audit,
20513
20815
  callers,
20514
20816
  tests,
20817
+ ...importers.length > 0 ? { importers } : {},
20515
20818
  elapsed_ms: Date.now() - started
20516
20819
  };
20517
20820
  }
@@ -20579,12 +20882,17 @@ function upgradeToExcerpts(rc, opts) {
20579
20882
  }
20580
20883
  function describeRepoContext(rc) {
20581
20884
  if (rc.state !== "ok") {
20582
- const exts = rc.unsupported_exts?.length ? ` \xB7 no rules for: ${rc.unsupported_exts.join(", ")}` : "";
20583
- return `absent (${rc.reason ?? "unknown"})${exts}`;
20885
+ const bits = [
20886
+ rc.symbols?.length ? `searched: ${rc.symbols.join(", ")}` : "",
20887
+ rc.dropped_symbols?.length ? `dropped too-common: ${rc.dropped_symbols.join(", ")}` : "",
20888
+ rc.unsupported_exts?.length ? `no rules for: ${rc.unsupported_exts.join(", ")}` : ""
20889
+ ].filter(Boolean);
20890
+ return `absent (${rc.reason ?? "unknown"})${bits.length > 0 ? ` \xB7 ${bits.join(" \xB7 ")}` : ""}`;
20584
20891
  }
20585
20892
  const parts = [
20586
20893
  `${rc.symbols?.length ?? 0} symbol(s) \u2192 ${rc.callers?.length ?? 0} caller(s) \xB7 ${rc.tests?.length ?? 0} test(s)`
20587
20894
  ];
20895
+ if (rc.importers?.length) parts.push(`${rc.importers.length} importer(s)`);
20588
20896
  if (rc.excerpts?.length) parts.push(`${rc.excerpts.length} excerpt(s)`);
20589
20897
  if (rc.dropped_symbols?.length) parts.push(`dropped too-common: ${rc.dropped_symbols.join(", ")}`);
20590
20898
  if (rc.unsupported_exts?.length) parts.push(`no rules for: ${rc.unsupported_exts.join(", ")}`);
@@ -20712,10 +21020,10 @@ function installRunEvidence(run2) {
20712
21020
  }
20713
21021
 
20714
21022
  // src/lib/git-frame.ts
20715
- var import_node_fs33 = require("node:fs");
20716
- var import_node_os5 = require("node:os");
20717
- var import_node_path25 = require("node:path");
20718
- var import_node_path26 = require("node:path");
21023
+ var import_node_fs35 = require("node:fs");
21024
+ var import_node_os6 = require("node:os");
21025
+ var import_node_path27 = require("node:path");
21026
+ var import_node_path28 = require("node:path");
20719
21027
 
20720
21028
  // src/lib/hardened-git.ts
20721
21029
  var import_node_child_process11 = require("node:child_process");
@@ -20870,15 +21178,15 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
20870
21178
  if (!m) continue;
20871
21179
  named = true;
20872
21180
  if (m[1] === void 0) {
20873
- dir = (0, import_node_os5.homedir)();
21181
+ dir = (0, import_node_os6.homedir)();
20874
21182
  continue;
20875
21183
  }
20876
21184
  const raw = unquote(m[1]);
20877
21185
  if (SHELL_DYNAMIC.test(raw) || raw === "-") {
20878
21186
  return { dir: null, named: true, unresolvable: `cd target not statically resolvable: ${raw}` };
20879
21187
  }
20880
- const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0, import_node_path26.join)((0, import_node_os5.homedir)(), raw.slice(2)) : raw;
20881
- dir = (0, import_node_path25.isAbsolute)(expanded) ? expanded : (0, import_node_path25.resolve)(dir, expanded);
21188
+ const expanded = raw === "~" ? (0, import_node_os6.homedir)() : raw.startsWith("~/") ? (0, import_node_path28.join)((0, import_node_os6.homedir)(), raw.slice(2)) : raw;
21189
+ dir = (0, import_node_path27.isAbsolute)(expanded) ? expanded : (0, import_node_path27.resolve)(dir, expanded);
20882
21190
  }
20883
21191
  const seg = segments[segmentIndex];
20884
21192
  const overrideMatch = /--(?:git-dir|work-tree)(?:=|\s)|\bGIT_(?:DIR|WORK_TREE|INDEX_FILE)=/.exec(seg);
@@ -20896,8 +21204,8 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
20896
21204
  if (SHELL_DYNAMIC.test(raw)) {
20897
21205
  return { dir: null, named: true, unresolvable: `-C target not statically resolvable: ${raw}` };
20898
21206
  }
20899
- const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0, import_node_path26.join)((0, import_node_os5.homedir)(), raw.slice(2)) : raw;
20900
- dir = (0, import_node_path25.isAbsolute)(expanded) ? expanded : (0, import_node_path25.resolve)(dir, expanded);
21207
+ const expanded = raw === "~" ? (0, import_node_os6.homedir)() : raw.startsWith("~/") ? (0, import_node_path28.join)((0, import_node_os6.homedir)(), raw.slice(2)) : raw;
21208
+ dir = (0, import_node_path27.isAbsolute)(expanded) ? expanded : (0, import_node_path27.resolve)(dir, expanded);
20901
21209
  }
20902
21210
  }
20903
21211
  return { dir, named, unresolvable: null };
@@ -20957,14 +21265,14 @@ function gitAt(dir, args) {
20957
21265
  }
20958
21266
  function realpathOr2(p) {
20959
21267
  try {
20960
- return import_node_fs33.realpathSync.native(p);
21268
+ return import_node_fs35.realpathSync.native(p);
20961
21269
  } catch {
20962
- return (0, import_node_path25.resolve)(p);
21270
+ return (0, import_node_path27.resolve)(p);
20963
21271
  }
20964
21272
  }
20965
21273
  function resolveFrame(input) {
20966
21274
  const found = findMomentSegment(input.command, input.on);
20967
- const hookDirUsable = !!input.hookCwd && (0, import_node_fs33.existsSync)(input.hookCwd);
21275
+ const hookDirUsable = !!input.hookCwd && (0, import_node_fs35.existsSync)(input.hookCwd);
20968
21276
  const baseDir = hookDirUsable ? input.hookCwd : process.cwd();
20969
21277
  let anchor = hookDirUsable ? "hook-cwd" : "process-cwd";
20970
21278
  const refuse = (refusal) => ({
@@ -20987,7 +21295,7 @@ function resolveFrame(input) {
20987
21295
  if (dirs.size > 1) return refuse(`target:multiple ${found.moment} targets in one command`);
20988
21296
  const targetDir = dirs.size === 1 ? [...dirs][0] : baseDir;
20989
21297
  if (targetDir !== baseDir) {
20990
- if (!(0, import_node_fs33.existsSync)(targetDir)) return refuse(`target:directory does not exist: ${targetDir}`);
21298
+ if (!(0, import_node_fs35.existsSync)(targetDir)) return refuse(`target:directory does not exist: ${targetDir}`);
20991
21299
  dir = targetDir;
20992
21300
  }
20993
21301
  }
@@ -20998,7 +21306,7 @@ function resolveFrame(input) {
20998
21306
  const gitDirRaw = gitAt(dir, ["rev-parse", "--absolute-git-dir"]);
20999
21307
  const commonRaw = gitAt(dir, ["rev-parse", "--git-common-dir"]);
21000
21308
  const gitDir = gitDirRaw ? realpathOr2(gitDirRaw) : null;
21001
- const commonDir = commonRaw ? realpathOr2((0, import_node_path25.isAbsolute)(commonRaw) ? commonRaw : (0, import_node_path25.resolve)(dir, commonRaw)) : null;
21309
+ const commonDir = commonRaw ? realpathOr2((0, import_node_path27.isAbsolute)(commonRaw) ? commonRaw : (0, import_node_path27.resolve)(dir, commonRaw)) : null;
21002
21310
  const branchRaw = gitAt(dir, ["rev-parse", "--abbrev-ref", "HEAD"]);
21003
21311
  return {
21004
21312
  moment: found?.moment ?? null,
@@ -21173,8 +21481,8 @@ function stagedRange(frame, command) {
21173
21481
  if (plan.kind === "unpredictable") {
21174
21482
  return { kind: "staged", base: "HEAD", head: "INDEX", via: "staged-in-command", refusal: plan.reason };
21175
21483
  }
21176
- const mergeHead = frame.gitDir ? (0, import_node_path26.join)(frame.gitDir, "MERGE_HEAD") : null;
21177
- if (mergeHead && (0, import_node_fs33.existsSync)(mergeHead)) {
21484
+ const mergeHead = frame.gitDir ? (0, import_node_path28.join)(frame.gitDir, "MERGE_HEAD") : null;
21485
+ if (mergeHead && (0, import_node_fs35.existsSync)(mergeHead)) {
21178
21486
  const vsHead = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "HEAD"]).split("\n").filter(Boolean));
21179
21487
  const vsMerge = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "MERGE_HEAD"]).split("\n").filter(Boolean));
21180
21488
  const resolutions = new Set([...vsHead].filter((f) => vsMerge.has(f) && !isVerityOwnedPath(f)));
@@ -21308,7 +21616,7 @@ function truthy(v) {
21308
21616
  }
21309
21617
 
21310
21618
  // src/lib/transcript.ts
21311
- var import_node_fs34 = require("node:fs");
21619
+ var import_node_fs36 = require("node:fs");
21312
21620
  var MAX_READ_BYTES = 256 * 1024;
21313
21621
  var SMALL_FILE_BYTES = 64 * 1024;
21314
21622
  var MAX_FILES_LIST = 20;
@@ -21335,7 +21643,7 @@ async function extractActionSummary(transcriptPath) {
21335
21643
  function readTurnLines(transcriptPath) {
21336
21644
  let size;
21337
21645
  try {
21338
- size = (0, import_node_fs34.statSync)(transcriptPath).size;
21646
+ size = (0, import_node_fs36.statSync)(transcriptPath).size;
21339
21647
  } catch {
21340
21648
  return null;
21341
21649
  }
@@ -21343,7 +21651,7 @@ function readTurnLines(transcriptPath) {
21343
21651
  let raw;
21344
21652
  let windowed = false;
21345
21653
  if (size <= SMALL_FILE_BYTES) {
21346
- raw = (0, import_node_fs34.readFileSync)(transcriptPath, "utf-8");
21654
+ raw = (0, import_node_fs36.readFileSync)(transcriptPath, "utf-8");
21347
21655
  } else {
21348
21656
  windowed = true;
21349
21657
  const buf = Buffer.alloc(Math.min(MAX_READ_BYTES, size));
@@ -21851,7 +22159,7 @@ function channelSilence(input) {
21851
22159
  // src/lib/cli-version.ts
21852
22160
  function cliVersion() {
21853
22161
  try {
21854
- return true ? "0.33.0-experimental.d60f544" : "dev";
22162
+ return true ? "0.33.1-experimental.1378de3" : "dev";
21855
22163
  } catch {
21856
22164
  return "dev";
21857
22165
  }
@@ -21892,7 +22200,7 @@ async function sendSkipBeacon(ctx, reason) {
21892
22200
 
21893
22201
  // src/lib/static-analysis.ts
21894
22202
  var import_node_child_process12 = require("node:child_process");
21895
- var import_node_fs35 = require("node:fs");
22203
+ var import_node_fs37 = require("node:fs");
21896
22204
  var SEVERITY_ORDER = {
21897
22205
  Error: 0,
21898
22206
  Critical: 0,
@@ -21903,12 +22211,10 @@ var SEVERITY_ORDER = {
21903
22211
  Low: 3
21904
22212
  };
21905
22213
  function isCodacyAvailable() {
21906
- try {
21907
- (0, import_node_child_process12.execSync)("which codacy-analysis", { stdio: "pipe" });
21908
- return true;
21909
- } catch {
21910
- return false;
21911
- }
22214
+ return codacyAnalysisPath() !== null;
22215
+ }
22216
+ function codacyAnalysisPath() {
22217
+ return whichSync("codacy-analysis");
21912
22218
  }
21913
22219
  function buildAnalyzerArgv(files) {
21914
22220
  return [
@@ -21935,18 +22241,29 @@ function withFailure(kind, detail) {
21935
22241
  summary: { ...EMPTY_RESULT.summary, failure: { kind, detail: detail.slice(0, 300) } }
21936
22242
  };
21937
22243
  }
22244
+ function runCodacyAnalysisIfAvailable(files) {
22245
+ if (files.length === 0) return EMPTY_RESULT;
22246
+ if (!isCodacyAvailable()) {
22247
+ return withFailure(
22248
+ "analyzer_unavailable",
22249
+ "@codacy/analysis-cli was not found on PATH \u2014 no static analysis ran"
22250
+ );
22251
+ }
22252
+ return runCodacyAnalysis(files);
22253
+ }
21938
22254
  function runCodacyAnalysis(files) {
21939
22255
  const empty = EMPTY_RESULT;
21940
22256
  if (files.length === 0) return empty;
21941
22257
  const existingFiles = files.filter((f) => {
21942
22258
  try {
21943
- return (0, import_node_fs35.existsSync)(f);
22259
+ return (0, import_node_fs37.existsSync)(f);
21944
22260
  } catch {
21945
22261
  return false;
21946
22262
  }
21947
22263
  });
21948
22264
  if (existingFiles.length === 0) return empty;
21949
- const proc = (0, import_node_child_process12.spawnSync)("codacy-analysis", buildAnalyzerArgv(existingFiles), {
22265
+ const analyzer = codacyAnalysisPath() ?? "codacy-analysis";
22266
+ const proc = (0, import_node_child_process12.spawnSync)(analyzer, buildAnalyzerArgv(existingFiles), {
21950
22267
  encoding: "utf-8",
21951
22268
  maxBuffer: 10 * 1024 * 1024
21952
22269
  });
@@ -22114,11 +22431,10 @@ var EMPTY_STATIC = {
22114
22431
  summary: { total_findings: 0, by_severity: {}, tools_run: [] }
22115
22432
  };
22116
22433
  function runLocalStatic(analyzable, securityFiles, baseline, skipStatic) {
22117
- if (skipStatic || !isCodacyAvailable()) return EMPTY_STATIC;
22434
+ if (skipStatic) return EMPTY_STATIC;
22118
22435
  let scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles]));
22119
22436
  if (baseline) scannable = scannable.filter((f) => changedSinceBaseline(f, baseline));
22120
- if (scannable.length === 0) return EMPTY_STATIC;
22121
- return runCodacyAnalysis(scannable);
22437
+ return runCodacyAnalysisIfAvailable(scannable);
22122
22438
  }
22123
22439
  function localOnlyAndExit(staticResults) {
22124
22440
  printJsonCompact({
@@ -22209,8 +22525,8 @@ async function scope(run2) {
22209
22525
  }
22210
22526
 
22211
22527
  // src/lib/specs.ts
22212
- var import_node_fs36 = require("node:fs");
22213
- var import_node_path27 = require("node:path");
22528
+ var import_node_fs38 = require("node:fs");
22529
+ var import_node_path29 = require("node:path");
22214
22530
  var SPEC_CANDIDATES = [
22215
22531
  "CLAUDE.md",
22216
22532
  "AGENTS.md",
@@ -22229,6 +22545,16 @@ var SPEC_CANDIDATES = [
22229
22545
  var DOC_EXT = /\.(md|mdx|ya?ml|txt|rst|adoc)$/i;
22230
22546
  var UNCONSULTED_FILE_BYTES = 10240;
22231
22547
  var UNCONSULTED_TOTAL_BYTES = 30720;
22548
+ function readSpecFiles(specsOpt, root) {
22549
+ const out = [];
22550
+ for (const raw of specsOpt.split(",").map((f) => f.trim()).filter(Boolean)) {
22551
+ const candidate = (0, import_node_path29.isAbsolute)(raw) ? (0, import_node_path29.relative)(root, raw) : raw;
22552
+ const content = readFileInside(root, candidate, MAX_EXPLICIT_SPEC_FILE_BYTES);
22553
+ if (content === null) continue;
22554
+ out.push({ path: raw, content });
22555
+ }
22556
+ return out;
22557
+ }
22232
22558
  function discoverSpecs(consulted = []) {
22233
22559
  const result = [];
22234
22560
  const seen = /* @__PURE__ */ new Set();
@@ -22241,7 +22567,7 @@ function discoverSpecs(consulted = []) {
22241
22567
  const totalCap = relevant ? MAX_TOTAL_SPEC_BYTES : UNCONSULTED_TOTAL_BYTES;
22242
22568
  if (totalBytes >= totalCap) return false;
22243
22569
  if (seen.has(specPath)) return true;
22244
- if (!(0, import_node_fs36.existsSync)(specPath)) return true;
22570
+ if (!(0, import_node_fs38.existsSync)(specPath)) return true;
22245
22571
  seen.add(specPath);
22246
22572
  const remaining = totalCap - totalBytes;
22247
22573
  const fileCap = relevant ? MAX_SPEC_FILE_BYTES : UNCONSULTED_FILE_BYTES;
@@ -22264,7 +22590,7 @@ function discoverSpecs(consulted = []) {
22264
22590
  if (!addSpec(candidate)) break;
22265
22591
  }
22266
22592
  for (const dir of ["spec", "docs"]) {
22267
- if (!(0, import_node_fs36.existsSync)(dir)) continue;
22593
+ if (!(0, import_node_fs38.existsSync)(dir)) continue;
22268
22594
  try {
22269
22595
  const mdFiles = findMdFiles(dir, 2).sort();
22270
22596
  for (const mdFile of mdFiles) {
@@ -22279,9 +22605,9 @@ function findMdFiles(dir, maxDepth, depth = 0) {
22279
22605
  if (depth >= maxDepth) return [];
22280
22606
  const result = [];
22281
22607
  try {
22282
- const entries = (0, import_node_fs36.readdirSync)(dir, { withFileTypes: true });
22608
+ const entries = (0, import_node_fs38.readdirSync)(dir, { withFileTypes: true });
22283
22609
  for (const entry of entries) {
22284
- const fullPath = (0, import_node_path27.join)(dir, entry.name);
22610
+ const fullPath = (0, import_node_path29.join)(dir, entry.name);
22285
22611
  if (entry.isFile() && entry.name.endsWith(".md")) {
22286
22612
  result.push(fullPath);
22287
22613
  } else if (entry.isDirectory() && depth < maxDepth - 1) {
@@ -22294,25 +22620,25 @@ function findMdFiles(dir, maxDepth, depth = 0) {
22294
22620
  }
22295
22621
  function discoverPlans() {
22296
22622
  const home = process.env.HOME ?? "";
22297
- const homePlansDir = (0, import_node_path27.join)(home, ".claude", "plans");
22623
+ const homePlansDir = (0, import_node_path29.join)(home, ".claude", "plans");
22298
22624
  const sources = [];
22299
22625
  if (isRealDirectoryChain(process.cwd(), [".claude", "plans"])) {
22300
- sources.push({ root: process.cwd(), prefix: (0, import_node_path27.join)(".claude", "plans") });
22626
+ sources.push({ root: process.cwd(), prefix: (0, import_node_path29.join)(".claude", "plans") });
22301
22627
  }
22302
- if (home && (0, import_node_fs36.existsSync)(homePlansDir)) sources.push({ root: homePlansDir, prefix: "" });
22628
+ if (home && (0, import_node_fs38.existsSync)(homePlansDir)) sources.push({ root: homePlansDir, prefix: "" });
22303
22629
  const candidates2 = [];
22304
22630
  const seen = /* @__PURE__ */ new Set();
22305
22631
  for (const source of sources) {
22306
22632
  let names2;
22307
22633
  try {
22308
- names2 = (0, import_node_fs36.readdirSync)(source.prefix ? (0, import_node_path27.join)(source.root, source.prefix) : source.root);
22634
+ names2 = (0, import_node_fs38.readdirSync)(source.prefix ? (0, import_node_path29.join)(source.root, source.prefix) : source.root);
22309
22635
  } catch {
22310
22636
  continue;
22311
22637
  }
22312
22638
  for (const f of names2) {
22313
22639
  if (!f.endsWith(".md") || seen.has(f)) continue;
22314
22640
  seen.add(f);
22315
- const relPath = source.prefix ? (0, import_node_path27.join)(source.prefix, f) : f;
22641
+ const relPath = source.prefix ? (0, import_node_path29.join)(source.prefix, f) : f;
22316
22642
  const stat3 = statRegularInRoot(source.root, relPath);
22317
22643
  if (!stat3.ok) continue;
22318
22644
  candidates2.push({ name: f, root: source.root, relPath, mtime: stat3.mtimeMs, size: stat3.size });
@@ -22330,9 +22656,9 @@ function discoverPlans() {
22330
22656
  function isRealDirectoryChain(root, parts) {
22331
22657
  let current = root;
22332
22658
  for (const part of parts) {
22333
- current = (0, import_node_path27.join)(current, part);
22659
+ current = (0, import_node_path29.join)(current, part);
22334
22660
  try {
22335
- if (!(0, import_node_fs36.lstatSync)(current).isDirectory()) return false;
22661
+ if (!(0, import_node_fs38.lstatSync)(current).isDirectory()) return false;
22336
22662
  } catch {
22337
22663
  return false;
22338
22664
  }
@@ -22347,7 +22673,7 @@ function discoverGuardDocs(rangeFiles2) {
22347
22673
  if (result.length >= MAX_SPEC_FILES) break;
22348
22674
  if (!GUARD_DOC_EXT.test(path)) continue;
22349
22675
  if (path.startsWith("/") || path.includes("..")) continue;
22350
- if (!(0, import_node_fs36.existsSync)(path)) continue;
22676
+ if (!(0, import_node_fs38.existsSync)(path)) continue;
22351
22677
  const opened = openRegularInRoot(process.cwd(), path);
22352
22678
  if (!opened.ok) continue;
22353
22679
  if (opened.size > MAX_PLAN_FILE_BYTES || totalBytes + opened.size > MAX_TOTAL_SPEC_BYTES) {
@@ -22533,8 +22859,8 @@ async function mode(run2) {
22533
22859
  }
22534
22860
 
22535
22861
  // src/lib/fold.ts
22536
- var import_node_fs37 = require("node:fs");
22537
- var import_node_path28 = require("node:path");
22862
+ var import_node_fs39 = require("node:fs");
22863
+ var import_node_path30 = require("node:path");
22538
22864
  var KNOWN_RECORD_TYPES = /* @__PURE__ */ new Set([
22539
22865
  "user",
22540
22866
  "assistant",
@@ -22671,7 +22997,7 @@ function candidateRoots(repoRoot2) {
22671
22997
  const norm = repoRoot2.replace(/\\/g, "/").replace(/\/+$/, "");
22672
22998
  const out = [norm];
22673
22999
  try {
22674
- const real = import_node_fs37.realpathSync.native(norm).replace(/\\/g, "/").replace(/\/+$/, "");
23000
+ const real = import_node_fs39.realpathSync.native(norm).replace(/\\/g, "/").replace(/\/+$/, "");
22675
23001
  if (real !== norm) out.push(real);
22676
23002
  } catch {
22677
23003
  }
@@ -22759,31 +23085,31 @@ function fold(transcriptPath, opts = {}) {
22759
23085
  }
22760
23086
  };
22761
23087
  try {
22762
- if (!(0, import_node_fs37.existsSync)(transcriptPath)) return result;
22763
- ingest((0, import_node_fs37.readFileSync)(transcriptPath, "utf8"), "agent");
23088
+ if (!(0, import_node_fs39.existsSync)(transcriptPath)) return result;
23089
+ ingest((0, import_node_fs39.readFileSync)(transcriptPath, "utf8"), "agent");
22764
23090
  result.coverage.complete = true;
22765
23091
  } catch {
22766
23092
  return result;
22767
23093
  }
22768
23094
  try {
22769
- const sidecarDir = (0, import_node_path28.join)(
22770
- (0, import_node_path28.dirname)(transcriptPath),
22771
- (0, import_node_path28.basename)(transcriptPath).replace(/\.jsonl$/, ""),
23095
+ const sidecarDir = (0, import_node_path30.join)(
23096
+ (0, import_node_path30.dirname)(transcriptPath),
23097
+ (0, import_node_path30.basename)(transcriptPath).replace(/\.jsonl$/, ""),
22772
23098
  "subagents"
22773
23099
  );
22774
- if ((0, import_node_fs37.existsSync)(sidecarDir)) {
23100
+ if ((0, import_node_fs39.existsSync)(sidecarDir)) {
22775
23101
  const maxFiles = opts.maxSidecars ?? 200;
22776
23102
  const maxBytes = opts.maxSidecarBytes ?? 16 * 1024 * 1024;
22777
23103
  const found = [];
22778
23104
  const walk2 = (d, depth) => {
22779
23105
  if (depth > 4) return;
22780
- for (const e of (0, import_node_fs37.readdirSync)(d, { withFileTypes: true })) {
22781
- const p = (0, import_node_path28.join)(d, e.name);
23106
+ for (const e of (0, import_node_fs39.readdirSync)(d, { withFileTypes: true })) {
23107
+ const p = (0, import_node_path30.join)(d, e.name);
22782
23108
  if (e.isDirectory()) {
22783
23109
  walk2(p, depth + 1);
22784
23110
  } else if (e.name.startsWith("agent-") && e.name.endsWith(".jsonl")) {
22785
23111
  try {
22786
- const st = (0, import_node_fs37.statSync)(p);
23112
+ const st = (0, import_node_fs39.statSync)(p);
22787
23113
  found.push({ path: p, size: st.size, mtimeMs: st.mtimeMs });
22788
23114
  } catch {
22789
23115
  result.coverage.malformed++;
@@ -22800,7 +23126,7 @@ function fold(transcriptPath, opts = {}) {
22800
23126
  continue;
22801
23127
  }
22802
23128
  try {
22803
- ingest((0, import_node_fs37.readFileSync)(f.path, "utf8"), "subagent");
23129
+ ingest((0, import_node_fs39.readFileSync)(f.path, "utf8"), "subagent");
22804
23130
  bytes += f.size;
22805
23131
  result.coverage.subagentFiles++;
22806
23132
  } catch {
@@ -22835,7 +23161,7 @@ function fold(transcriptPath, opts = {}) {
22835
23161
  }
22836
23162
  function classifyUnobserved(path) {
22837
23163
  try {
22838
- const st = (0, import_node_fs37.statSync)(path);
23164
+ const st = (0, import_node_fs39.statSync)(path);
22839
23165
  if (!st.isFile()) return "unreadable";
22840
23166
  } catch {
22841
23167
  return "unreadable";
@@ -23102,14 +23428,12 @@ async function evidence(run2) {
23102
23428
  authorshipWasObservable
23103
23429
  });
23104
23430
  const recentForReview = narrowToRecent(baseForReview, baselineSessionId);
23105
- if (!opts.skipStatic && isCodacyAvailable()) {
23431
+ if (!opts.skipStatic) {
23106
23432
  let allScannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles]));
23107
23433
  if (baseline) {
23108
23434
  allScannable = allScannable.filter((f) => changedSinceBaseline(f, baseline));
23109
23435
  }
23110
- if (allScannable.length > 0) {
23111
- staticResults = runCodacyAnalysis(allScannable);
23112
- }
23436
+ staticResults = runCodacyAnalysisIfAvailable(allScannable);
23113
23437
  }
23114
23438
  const deltaSet = baseline ? recentForReview.filter((f) => changedSinceBaseline(f, baseline)) : recentForReview;
23115
23439
  codeDelta = collectCodeDelta(deltaSet, {
@@ -23152,20 +23476,20 @@ async function evidence(run2) {
23152
23476
  }
23153
23477
 
23154
23478
  // src/lib/cache-cleanup.ts
23155
- var import_node_fs38 = require("node:fs");
23156
- var import_node_path29 = require("node:path");
23479
+ var import_node_fs40 = require("node:fs");
23480
+ var import_node_path31 = require("node:path");
23157
23481
  var CACHE_TTL_DAYS = 7;
23158
23482
  function pruneStaleCache() {
23159
23483
  try {
23160
23484
  const dir = projectPath(CACHE_DIR);
23161
23485
  const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
23162
- for (const entry of (0, import_node_fs38.readdirSync)(dir)) {
23486
+ for (const entry of (0, import_node_fs40.readdirSync)(dir)) {
23163
23487
  if (!entry.startsWith("pending-")) continue;
23164
- const path = (0, import_node_path29.join)(dir, entry);
23488
+ const path = (0, import_node_path31.join)(dir, entry);
23165
23489
  try {
23166
- const stat3 = (0, import_node_fs38.statSync)(path);
23490
+ const stat3 = (0, import_node_fs40.statSync)(path);
23167
23491
  if (stat3.mtimeMs < cutoff) {
23168
- (0, import_node_fs38.unlinkSync)(path);
23492
+ (0, import_node_fs40.unlinkSync)(path);
23169
23493
  logEvent("cache_entry_pruned", {
23170
23494
  path: entry,
23171
23495
  age_days: Math.round((Date.now() - stat3.mtimeMs) / 864e5)
@@ -23179,8 +23503,8 @@ function pruneStaleCache() {
23179
23503
  }
23180
23504
 
23181
23505
  // src/lib/context-files.ts
23182
- var import_node_fs39 = require("node:fs");
23183
- var import_node_os6 = require("node:os");
23506
+ var import_node_fs41 = require("node:fs");
23507
+ var import_node_os7 = require("node:os");
23184
23508
  var MAX_CONTEXT_FILES = 10;
23185
23509
  var MAX_CONTEXT_FILE_BYTES = 10240;
23186
23510
  var MAX_CONTEXT_TOTAL_BYTES = 24576;
@@ -23188,7 +23512,7 @@ function readSetContextPaths(summary, deltaFiles) {
23188
23512
  const reads = summary?.files_read ?? [];
23189
23513
  if (reads.length === 0) return [];
23190
23514
  const root = process.cwd().replace(/\/+$/, "");
23191
- const home = (0, import_node_os6.homedir)();
23515
+ const home = (0, import_node_os7.homedir)();
23192
23516
  const toRepoRelative2 = (p) => {
23193
23517
  if (!p) return null;
23194
23518
  let abs;
@@ -23237,7 +23561,7 @@ function gatherContextFiles(contextPaths, deltaFiles, opts) {
23237
23561
  continue;
23238
23562
  }
23239
23563
  try {
23240
- const content = (0, import_node_fs39.readFileSync)(safePath, "utf8");
23564
+ const content = (0, import_node_fs41.readFileSync)(safePath, "utf8");
23241
23565
  const bytes = Buffer.byteLength(content);
23242
23566
  if (bytes > MAX_CONTEXT_FILE_BYTES) {
23243
23567
  logEvent("context_file_skipped", { path: filePath, reason: "too_large", bytes });
@@ -23322,14 +23646,15 @@ async function repoContext(run2) {
23322
23646
  dropped: run2.repoContext.dropped_symbols?.length ?? 0,
23323
23647
  callers: run2.repoContext.callers?.length ?? 0,
23324
23648
  tests: run2.repoContext.tests?.length ?? 0,
23649
+ importers: run2.repoContext.importers?.length ?? 0,
23325
23650
  elapsed_ms: run2.repoContext.elapsed_ms ?? null
23326
23651
  });
23327
23652
  }
23328
23653
 
23329
23654
  // src/lib/seed-runner.ts
23330
23655
  var import_promises15 = require("node:fs/promises");
23331
- var import_node_fs40 = require("node:fs");
23332
- var import_node_path30 = require("node:path");
23656
+ var import_node_fs42 = require("node:fs");
23657
+ var import_node_path32 = require("node:path");
23333
23658
  var import_yaml4 = __toESM(require_dist());
23334
23659
 
23335
23660
  // src/lib/seed.ts
@@ -23568,7 +23893,7 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
23568
23893
  return fm;
23569
23894
  }
23570
23895
  async function runSeed(opts) {
23571
- if (!(0, import_node_fs40.existsSync)(STANDARD_FILE)) {
23896
+ if (!(0, import_node_fs42.existsSync)(STANDARD_FILE)) {
23572
23897
  return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
23573
23898
  }
23574
23899
  let standardDoc;
@@ -23580,7 +23905,7 @@ async function runSeed(opts) {
23580
23905
  }
23581
23906
  const knowledgeSpec = standardDoc.knowledge_spec ?? {};
23582
23907
  let readmeContent;
23583
- if ((0, import_node_fs40.existsSync)("README.md")) {
23908
+ if ((0, import_node_fs42.existsSync)("README.md")) {
23584
23909
  try {
23585
23910
  readmeContent = await (0, import_promises15.readFile)("README.md", "utf-8");
23586
23911
  } catch {
@@ -23588,7 +23913,7 @@ async function runSeed(opts) {
23588
23913
  }
23589
23914
  let claudeMdContent;
23590
23915
  for (const p of ["CLAUDE.md", ".claude/CLAUDE.md"]) {
23591
- if ((0, import_node_fs40.existsSync)(p)) {
23916
+ if ((0, import_node_fs42.existsSync)(p)) {
23592
23917
  try {
23593
23918
  claudeMdContent = await (0, import_promises15.readFile)(p, "utf-8");
23594
23919
  break;
@@ -23611,8 +23936,8 @@ async function runSeed(opts) {
23611
23936
  if (candidates2.length === 0) {
23612
23937
  return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
23613
23938
  }
23614
- const overviewPath = (0, import_node_path30.join)(MEMORY_DIR, "domain", "project-overview.md");
23615
- if ((0, import_node_fs40.existsSync)(overviewPath) && !opts.force) {
23939
+ const overviewPath = (0, import_node_path32.join)(MEMORY_DIR, "domain", "project-overview.md");
23940
+ if ((0, import_node_fs42.existsSync)(overviewPath) && !opts.force) {
23616
23941
  return { created: 0, failed: 0, skipped: "already_seeded", candidates: candidates2 };
23617
23942
  }
23618
23943
  if (opts.dryRun) {
@@ -23654,7 +23979,7 @@ async function runSeed(opts) {
23654
23979
  continue;
23655
23980
  }
23656
23981
  try {
23657
- await (0, import_promises15.mkdir)((0, import_node_path30.dirname)(targetPath), { recursive: true });
23982
+ await (0, import_promises15.mkdir)((0, import_node_path32.dirname)(targetPath), { recursive: true });
23658
23983
  await (0, import_promises15.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
23659
23984
  created++;
23660
23985
  opts.onCreated?.(nodeId, filePathRel, c);
@@ -23667,8 +23992,8 @@ async function runSeed(opts) {
23667
23992
  }
23668
23993
 
23669
23994
  // src/commands/analyze/phases/08-memory-manifest.ts
23670
- var import_node_fs41 = require("node:fs");
23671
- var import_node_path31 = require("node:path");
23995
+ var import_node_fs43 = require("node:fs");
23996
+ var import_node_path33 = require("node:path");
23672
23997
  async function memoryManifest(run2) {
23673
23998
  const { globals } = run2;
23674
23999
  const { serviceUrl, token } = run2;
@@ -23678,9 +24003,9 @@ async function memoryManifest(run2) {
23678
24003
  let autoSeedNotice = null;
23679
24004
  try {
23680
24005
  await ensureMemoryDir();
23681
- const seedMarker = (0, import_node_path31.join)(VERITY_DIR, ".seeded");
23682
- const hasStandard = (0, import_node_fs41.existsSync)(STANDARD_FILE);
23683
- const alreadyTried = (0, import_node_fs41.existsSync)(seedMarker);
24006
+ const seedMarker = (0, import_node_path33.join)(VERITY_DIR, ".seeded");
24007
+ const hasStandard = (0, import_node_fs43.existsSync)(STANDARD_FILE);
24008
+ const alreadyTried = (0, import_node_fs43.existsSync)(seedMarker);
23684
24009
  if (hasStandard && !alreadyTried) {
23685
24010
  const preManifest = await buildManifest();
23686
24011
  if (preManifest.nodes.length === 0) {
@@ -23693,7 +24018,7 @@ async function memoryManifest(run2) {
23693
24018
  dryRun: false
23694
24019
  });
23695
24020
  if (seedResult.created > 0) {
23696
- (0, import_node_fs41.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
24021
+ (0, import_node_fs43.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
23697
24022
  `);
23698
24023
  autoSeedNotice = `Seeded ${seedResult.created} knowledge node(s) from your existing Standard (one-time).`;
23699
24024
  logEvent("auto_seed_ran", {
@@ -23701,7 +24026,7 @@ async function memoryManifest(run2) {
23701
24026
  failed: seedResult.failed
23702
24027
  });
23703
24028
  } else if (seedResult.skipped === "already_seeded") {
23704
- (0, import_node_fs41.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
24029
+ (0, import_node_fs43.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
23705
24030
  `);
23706
24031
  } else {
23707
24032
  logEvent("auto_seed_noop", {
@@ -23796,7 +24121,7 @@ function computeIncrement(reviewedPaths, hashOf, priorAuthored) {
23796
24121
  }
23797
24122
 
23798
24123
  // src/commands/analyze/phases/10-working-memory.ts
23799
- var import_node_path32 = require("node:path");
24124
+ var import_node_path34 = require("node:path");
23800
24125
  async function workingMemory(run2) {
23801
24126
  const { opts } = run2;
23802
24127
  const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run2;
@@ -23808,7 +24133,7 @@ async function workingMemory(run2) {
23808
24133
  const priorState = foldForMarks(memorySession.d);
23809
24134
  incrementReport = computeIncrement(
23810
24135
  allForReview,
23811
- (p) => fileHash((0, import_node_path32.join)(repoRoot(), p)),
24136
+ (p) => fileHash((0, import_node_path34.join)(repoRoot(), p)),
23812
24137
  priorState.authored_all.map((a) => ({
23813
24138
  path: a.path,
23814
24139
  hash_at_last_verdict: a.hash_at_last_verdict
@@ -23890,7 +24215,7 @@ async function workingMemory(run2) {
23890
24215
  }
23891
24216
 
23892
24217
  // src/lib/note-budget.ts
23893
- var import_node_fs42 = require("node:fs");
24218
+ var import_node_fs44 = require("node:fs");
23894
24219
  var ADVISORY_BUDGET = { PASS: 1, WARN: 2 };
23895
24220
  var EPISODE_STALE_SECONDS = 30 * 60;
23896
24221
  var FRESH = { delivered: 0, tasksCompleted: 0, ts: 0 };
@@ -23912,9 +24237,9 @@ function advisoryBudgetSpent(episode, rawDecision) {
23912
24237
  }
23913
24238
  function readAdvisoryEpisode(sessionId) {
23914
24239
  const file = scopedFile(ADVISORY_EPISODE_FILE, sessionId);
23915
- if (!(0, import_node_fs42.existsSync)(file)) return null;
24240
+ if (!(0, import_node_fs44.existsSync)(file)) return null;
23916
24241
  try {
23917
- const o = JSON.parse((0, import_node_fs42.readFileSync)(file, "utf-8")) ?? {};
24242
+ const o = JSON.parse((0, import_node_fs44.readFileSync)(file, "utf-8")) ?? {};
23918
24243
  const delivered = typeof o.delivered === "number" ? o.delivered : NaN;
23919
24244
  if (isNaN(delivered)) return null;
23920
24245
  return {
@@ -23928,8 +24253,8 @@ function readAdvisoryEpisode(sessionId) {
23928
24253
  }
23929
24254
  function writeAdvisoryEpisode(episode, sessionId) {
23930
24255
  try {
23931
- (0, import_node_fs42.mkdirSync)(VERITY_DIR, { recursive: true });
23932
- (0, import_node_fs42.writeFileSync)(
24256
+ (0, import_node_fs44.mkdirSync)(VERITY_DIR, { recursive: true });
24257
+ (0, import_node_fs44.writeFileSync)(
23933
24258
  scopedFile(ADVISORY_EPISODE_FILE, sessionId),
23934
24259
  JSON.stringify({ v: 1, ...episode })
23935
24260
  );
@@ -24237,14 +24562,14 @@ async function buildRequest(run2) {
24237
24562
  }
24238
24563
 
24239
24564
  // src/lib/offline.ts
24240
- var import_node_fs43 = require("node:fs");
24565
+ var import_node_fs45 = require("node:fs");
24241
24566
  var import_node_crypto11 = require("node:crypto");
24242
24567
  function cacheRequest(body) {
24243
24568
  try {
24244
- (0, import_node_fs43.mkdirSync)(CACHE_DIR, { recursive: true });
24569
+ (0, import_node_fs45.mkdirSync)(CACHE_DIR, { recursive: true });
24245
24570
  const suffix = (0, import_node_crypto11.randomBytes)(4).toString("hex");
24246
24571
  const filename = `pending-${Math.floor(Date.now() / 1e3)}-${suffix}.json`;
24247
- (0, import_node_fs43.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(redactRequest(body)));
24572
+ (0, import_node_fs45.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(redactRequest(body)));
24248
24573
  } catch {
24249
24574
  }
24250
24575
  }
@@ -24363,8 +24688,8 @@ async function transmit(run2) {
24363
24688
  }
24364
24689
 
24365
24690
  // src/commands/analyze/phases/13-reconcile.ts
24366
- var import_node_fs44 = require("node:fs");
24367
- var import_node_path33 = require("node:path");
24691
+ var import_node_fs46 = require("node:fs");
24692
+ var import_node_path35 = require("node:path");
24368
24693
  async function reconcile(run2) {
24369
24694
  const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run2;
24370
24695
  const sentPaths = codeDelta.files.map((f) => f.path);
@@ -24393,7 +24718,7 @@ async function reconcile(run2) {
24393
24718
  const st = foldDossier(memorySession.d);
24394
24719
  openElsewhere = openBlockingElsewhere(st.statements, sentPaths, (file, line) => {
24395
24720
  try {
24396
- const src = (0, import_node_fs44.readFileSync)((0, import_node_path33.join)(repoRoot(), file), "utf8").split("\n");
24721
+ const src = (0, import_node_fs46.readFileSync)((0, import_node_path35.join)(repoRoot(), file), "utf8").split("\n");
24397
24722
  const at = src[line - 1];
24398
24723
  return at === void 0 ? null : lineSha(at);
24399
24724
  } catch {
@@ -24679,12 +25004,20 @@ async function pullRepoMemory(opts) {
24679
25004
  let version = null;
24680
25005
  let cursor = null;
24681
25006
  let pages = 0;
24682
- const remember = (complete) => writePullState({
24683
- version: complete ? version : null,
24684
- // A complete pull saw every file the server holds, so its ledger replaces the
24685
- // old one (a path that stopped arriving was archived). A partial one only adds.
24686
- served: complete ? served : new Map([...state.served, ...served])
24687
- });
25007
+ const remember = async (complete) => {
25008
+ const onDisk = await readPullState();
25009
+ const meanwhile = /* @__PURE__ */ new Map();
25010
+ for (const [path, hash] of onDisk.served) {
25011
+ if (state.served.get(path) !== hash) meanwhile.set(path, hash);
25012
+ }
25013
+ await writePullState({
25014
+ version: complete ? version : null,
25015
+ // A complete pull saw every file the server holds, so its ledger replaces
25016
+ // the old one (a path that stopped arriving was archived) — except for what
25017
+ // another writer recorded while it ran. A partial one only adds.
25018
+ served: complete ? new Map([...served, ...meanwhile]) : new Map([...state.served, ...served, ...meanwhile])
25019
+ });
25020
+ };
24688
25021
  do {
24689
25022
  const params = new URLSearchParams({ limit: String(PAGE_SIZE) });
24690
25023
  if (cursor) params.set("cursor", cursor);
@@ -24757,7 +25090,7 @@ async function readPullState() {
24757
25090
  async function writePullState(state) {
24758
25091
  try {
24759
25092
  await (0, import_promises16.mkdir)(projectPath(VERITY_DIR), { recursive: true });
24760
- await (0, import_promises16.writeFile)(pullStateFile(), JSON.stringify({
25093
+ await writeFileAtomic(pullStateFile(), JSON.stringify({
24761
25094
  ...state.version ? { version: state.version } : {},
24762
25095
  pulled_at: (/* @__PURE__ */ new Date()).toISOString(),
24763
25096
  served: Object.fromEntries(state.served)
@@ -25200,7 +25533,7 @@ function registerAnalyzeCommand(program2) {
25200
25533
  var tracing = () => process.env.VERITY_TRACE_PHASES === "1";
25201
25534
  async function runAnalyze(opts, globals) {
25202
25535
  if (!verityConfigured()) {
25203
- (0, import_node_fs45.writeSync)(2, '[verity] not set up in this project \u2014 run "verity init" first.\n');
25536
+ (0, import_node_fs47.writeSync)(2, '[verity] not set up in this project \u2014 run "verity init" first.\n');
25204
25537
  process.exit(0);
25205
25538
  }
25206
25539
  const run2 = createRun(opts, globals);
@@ -25221,11 +25554,11 @@ async function runAnalyze(opts, globals) {
25221
25554
  }
25222
25555
 
25223
25556
  // src/commands/baseline.ts
25224
- var import_node_fs47 = require("node:fs");
25557
+ var import_node_fs49 = require("node:fs");
25225
25558
 
25226
25559
  // src/lib/project-skills.ts
25227
- var import_node_fs46 = require("node:fs");
25228
- var import_node_path34 = require("node:path");
25560
+ var import_node_fs48 = require("node:fs");
25561
+ var import_node_path36 = require("node:path");
25229
25562
  var PROJECT_SKILL_NAMES = [
25230
25563
  "verity-setup",
25231
25564
  "verity-analyze",
@@ -25250,14 +25583,14 @@ var LEGACY_SKILL_NAMES = [
25250
25583
  var ALL = [...PROJECT_SKILL_NAMES, ...LEGACY_SKILL_NAMES];
25251
25584
  function staleProjectSkills() {
25252
25585
  const root = projectPath(".claude/skills");
25253
- if (!(0, import_node_fs46.existsSync)(root)) return [];
25254
- return ALL.filter((name) => (0, import_node_fs46.existsSync)((0, import_node_path34.join)(root, name)));
25586
+ if (!(0, import_node_fs48.existsSync)(root)) return [];
25587
+ return ALL.filter((name) => (0, import_node_fs48.existsSync)((0, import_node_path36.join)(root, name)));
25255
25588
  }
25256
25589
  function removeProjectSkills() {
25257
25590
  const root = projectPath(".claude/skills");
25258
25591
  const removed = [];
25259
25592
  for (const name of staleProjectSkills()) {
25260
- (0, import_node_fs46.rmSync)((0, import_node_path34.join)(root, name), { recursive: true, force: true });
25593
+ (0, import_node_fs48.rmSync)((0, import_node_path36.join)(root, name), { recursive: true, force: true });
25261
25594
  removed.push(name);
25262
25595
  }
25263
25596
  return removed;
@@ -25285,10 +25618,10 @@ function registerBaselineCommands(program2) {
25285
25618
  const session = sessionId ?? validSessionId(process.env.CLAUDE_SESSION_ID);
25286
25619
  const cli = pluginCliInvocation();
25287
25620
  const skew = cliVersionSkew();
25288
- const why = skew ? `the \`verity\` on PATH is ${skew.global} but this plugin runs ${skew.plugin}, so it is not the CLI the hooks use` : verityOnPath() ? "the `verity` on PATH is a separate install whose version could not be read" : "this machine has no `verity` on PATH \u2014 the plugin carries its own copy";
25621
+ const why = skew ? `the \`verity\` on PATH is ${skew.global} but the hooks run ${skew.hooks}, so it is not the CLI they use` : verityOnPath() ? "the `verity` on PATH is a separate install whose version could not be read" : "this machine has no `verity` on PATH \u2014 the plugin carries its own copy";
25289
25622
  const cliLine = cli ? `Verity CLI: ${why}. When a Verity skill tells you to run \`verity <args>\`, run \`${cli} <args>\` instead. Everything else about the command is identical.` : null;
25290
- const skewMsg = skew ? `Verity: your global \`verity\` CLI is ${skew.global} but the plugin runs ${skew.plugin}. Update it before using \`verity\` in a terminal: npm install -g @codacy/verity-cli@${skew.plugin}` : null;
25291
- const skewNote = skew ? `Before anything else, including /verity:init's questions, tell the user their global \`verity\` is ${skew.global}, the plugin runs ${skew.plugin}, and \`npm install -g @codacy/verity-cli@${skew.plugin}\` fixes it. Until they have, do not send them to run \`verity login\` in a terminal: that runs the global one, which can sign this machine in to a different server.` : null;
25623
+ const skewMsg = skew ? `Verity: your global \`verity\` CLI is ${skew.global} but the hooks run ${skew.hooks}. Fix it before using \`verity\` in a terminal: ${skew.remedy}` : null;
25624
+ const skewNote = skew ? `Before anything else, including /verity:init's questions, tell the user their global \`verity\` is ${skew.global}, the hooks run ${skew.hooks}, and \`${skew.remedy}\` fixes it. Until they have, do not send them to run \`verity login\` in a terminal: that runs the global one, which can sign this machine in to a different server.` : null;
25292
25625
  if (!verityConfigured()) {
25293
25626
  const how = isPluginInvocation() ? "Tell the user to run /verity:init \u2014 they type it; you cannot invoke it." : "Tell the user to run `verity init` in their terminal.";
25294
25627
  const lines = [
@@ -25322,13 +25655,13 @@ function registerBaselineCommands(program2) {
25322
25655
  let memoryMsg = null;
25323
25656
  let memoryAgentLine = null;
25324
25657
  const memoryNotice = projectPath(`${VERITY_DIR}/.memory-fence-notice`);
25325
- if (realStart && !(0, import_node_fs47.existsSync)(memoryNotice)) {
25658
+ if (realStart && !(0, import_node_fs49.existsSync)(memoryNotice)) {
25326
25659
  const trackedGraph = memoryOptOut() ? 0 : committedMemoryFiles().length;
25327
25660
  if (trackedGraph > 0) {
25328
25661
  memoryMsg = `Verity: this project commits its knowledge base (${trackedGraph} files under .verity/memory/), so Verity's generated notes show up in every diff and pull request. Run \`verity memory untrack\` to keep them on disk but out of git, or \`verity memory track\` to keep committing them on purpose.`;
25329
25662
  memoryAgentLine = `This project has ${trackedGraph} knowledge-graph files tracked in git under .verity/memory/. As of Verity 0.32.6 the graph is machine-local by default \u2014 it is rebuilt from the service, and committing it puts generated notes in every pull request. If the user wants that stopped, run \`verity memory untrack\` for them: it keeps every file on disk and stages their removal from the index, so they only need to commit \u2014 and their teammates' working copies will vanish on the next pull and re-sync from the service, which is expected. If they would rather keep committing it, \`verity memory track\` records that and nothing will offer again.`;
25330
25663
  try {
25331
- (0, import_node_fs47.writeFileSync)(memoryNotice, (/* @__PURE__ */ new Date()).toISOString() + "\n");
25664
+ (0, import_node_fs49.writeFileSync)(memoryNotice, (/* @__PURE__ */ new Date()).toISOString() + "\n");
25332
25665
  } catch {
25333
25666
  }
25334
25667
  }
@@ -25429,7 +25762,7 @@ function hookSource(value) {
25429
25762
  }
25430
25763
 
25431
25764
  // src/commands/review.ts
25432
- var import_node_fs48 = require("node:fs");
25765
+ var import_node_fs50 = require("node:fs");
25433
25766
  function registerReviewCommand(program2) {
25434
25767
  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) => {
25435
25768
  const globals = program2.opts();
@@ -25446,45 +25779,22 @@ async function runReview(opts, globals) {
25446
25779
  const changedFiles = opts.changed ? opts.changed.split(",").map((f) => f.trim()).filter(Boolean) : allFiles;
25447
25780
  const analyzable = filterAnalyzable(allFiles);
25448
25781
  const securityFiles = filterSecurity(allFiles);
25449
- let staticResults;
25450
- if (isCodacyAvailable()) {
25451
- const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs48.existsSync)(f) || resolveFile(f) !== null);
25452
- staticResults = runCodacyAnalysis(scannable);
25453
- } else {
25454
- staticResults = {
25455
- tool: "@codacy/analysis-cli",
25456
- findings: [],
25457
- summary: { total_findings: 0, by_severity: {}, tools_run: [] }
25458
- };
25459
- }
25782
+ const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs50.existsSync)(f) || resolveFile(f) !== null);
25783
+ const staticResults = runCodacyAnalysisIfAvailable(scannable);
25460
25784
  const codeDelta = collectCodeDelta(allFiles);
25461
25785
  const tokenResult = await resolveToken(globals.token);
25462
25786
  const urlResult = await resolveServiceUrl(globals.serviceUrl);
25463
25787
  if (!tokenResult.ok || !urlResult.ok) {
25788
+ const staticFailure = staticResults.summary.failure;
25464
25789
  printJsonCompact({
25465
- gate_decision: "PASS",
25466
- systemMessage: "Verity: not authenticated \u2014 showing local static results only (no deep review, no upload). Run `verity init` to authenticate and unlock the full review.",
25790
+ gate_decision: "WARN",
25791
+ systemMessage: staticFailure ? `Verity: not authenticated, and local static analysis did not run (${staticFailure.kind}) \u2014 nothing was examined. Run \`verity init\` to authenticate and unlock the full review.` : "Verity: not authenticated \u2014 showing local static results only (no deep review, no upload). Run `verity init` to authenticate and unlock the full review.",
25467
25792
  unauthenticated: true,
25468
25793
  static_results: staticResults
25469
25794
  });
25470
25795
  process.exit(0);
25471
25796
  }
25472
- let specs;
25473
- if (opts.specs) {
25474
- const specPaths = opts.specs.split(",").map((f) => f.trim()).filter(Boolean);
25475
- specs = [];
25476
- for (const p of specPaths) {
25477
- if (!(0, import_node_fs48.existsSync)(p)) continue;
25478
- try {
25479
- const { readFileSync: readFileSync26 } = await import("node:fs");
25480
- const content = readFileSync26(p, "utf-8");
25481
- specs.push({ path: p, content: content.slice(0, 10240) });
25482
- } catch {
25483
- }
25484
- }
25485
- } else {
25486
- specs = discoverSpecs();
25487
- }
25797
+ const specs = opts.specs ? readSpecFiles(opts.specs, repoRoot()) : discoverSpecs();
25488
25798
  const plans = discoverPlans();
25489
25799
  const requestBody = {
25490
25800
  static_results: staticResults,
@@ -25517,9 +25827,10 @@ async function runReview(opts, globals) {
25517
25827
  });
25518
25828
  if (!result.ok) {
25519
25829
  printError(`Service error: ${result.error}`);
25830
+ const staticFailure = staticResults.summary.failure;
25520
25831
  printJsonCompact({
25521
- gate_decision: "PASS",
25522
- systemMessage: "Verity: Service unavailable \u2014 showing static results only",
25832
+ gate_decision: "WARN",
25833
+ systemMessage: staticFailure ? `Verity: service unavailable, and local static analysis did not run (${staticFailure.kind}) \u2014 nothing was examined` : "Verity: service unavailable \u2014 showing local static results only",
25523
25834
  offline: true,
25524
25835
  static_results: staticResults
25525
25836
  });
@@ -25534,8 +25845,8 @@ async function runReview(opts, globals) {
25534
25845
  }
25535
25846
 
25536
25847
  // src/commands/guard.ts
25537
- var import_node_fs49 = require("node:fs");
25538
- var import_node_path35 = require("node:path");
25848
+ var import_node_fs51 = require("node:fs");
25849
+ var import_node_path37 = require("node:path");
25539
25850
 
25540
25851
  // src/lib/terminal-text.ts
25541
25852
  var CONTROL = /[\x00-\x08\x0b-\x1f\x7f-\x9f\u061c\u200e\u200f\u2028-\u202e\u2066-\u2069]/g;
@@ -25910,7 +26221,7 @@ async function buildAgentDiffs(ctx, paths, limits = { perFileChars: 24e3, totalC
25910
26221
  // src/commands/guard.ts
25911
26222
  var EXCERPT_SOURCE_MAX_BYTES = 2 * 1024 * 1024;
25912
26223
  var GUARD_BLOCK_CAP = 2;
25913
- var GUARD_ITER_FILE = (0, import_node_path35.join)(VERITY_DIR, ".guard-iteration");
26224
+ var GUARD_ITER_FILE = (0, import_node_path37.join)(VERITY_DIR, ".guard-iteration");
25914
26225
  function readPreToolUseStdin() {
25915
26226
  const empty = { command: "", cwd: null, sessionId: null };
25916
26227
  return new Promise((resolve6) => {
@@ -25955,7 +26266,7 @@ function readPreToolUseStdin() {
25955
26266
  }
25956
26267
  function readIterMap() {
25957
26268
  try {
25958
- const raw = JSON.parse((0, import_node_fs49.readFileSync)(GUARD_ITER_FILE, "utf-8"));
26269
+ const raw = JSON.parse((0, import_node_fs51.readFileSync)(GUARD_ITER_FILE, "utf-8"));
25959
26270
  if (raw && typeof raw === "object") {
25960
26271
  if (typeof raw.moment === "string" && typeof raw.count === "number") {
25961
26272
  return { [raw.moment]: raw.count };
@@ -25975,10 +26286,10 @@ function readIter(moment) {
25975
26286
  }
25976
26287
  function writeIter(moment, count) {
25977
26288
  try {
25978
- (0, import_node_fs49.mkdirSync)(VERITY_DIR, { recursive: true });
26289
+ (0, import_node_fs51.mkdirSync)(VERITY_DIR, { recursive: true });
25979
26290
  const map = readIterMap();
25980
26291
  map[moment] = count;
25981
- (0, import_node_fs49.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
26292
+ (0, import_node_fs51.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
25982
26293
  } catch {
25983
26294
  }
25984
26295
  }
@@ -25988,10 +26299,10 @@ function resetIter(moment) {
25988
26299
  if (!(moment in map)) return;
25989
26300
  delete map[moment];
25990
26301
  if (Object.keys(map).length === 0) {
25991
- if ((0, import_node_fs49.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs49.unlinkSync)(GUARD_ITER_FILE);
26302
+ if ((0, import_node_fs51.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs51.unlinkSync)(GUARD_ITER_FILE);
25992
26303
  } else {
25993
- (0, import_node_fs49.mkdirSync)(VERITY_DIR, { recursive: true });
25994
- (0, import_node_fs49.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
26304
+ (0, import_node_fs51.mkdirSync)(VERITY_DIR, { recursive: true });
26305
+ (0, import_node_fs51.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
25995
26306
  }
25996
26307
  } catch {
25997
26308
  }
@@ -26061,13 +26372,8 @@ function hasBlockingFinding(response, sentFiles) {
26061
26372
  function buildGuardRequest(moment, files, codeDelta, iter, sessionId, statedIntent, coverageTelemetry) {
26062
26373
  const analyzable = filterAnalyzable(files);
26063
26374
  const securityFiles = filterSecurity(files);
26064
- let staticResults;
26065
- if (isCodacyAvailable()) {
26066
- const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs49.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
26067
- staticResults = runCodacyAnalysis(scannable);
26068
- } else {
26069
- staticResults = { tool: "@codacy/analysis-cli", findings: [], summary: { total_findings: 0, by_severity: {}, tools_run: [] } };
26070
- }
26375
+ const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs51.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
26376
+ const staticResults = runCodacyAnalysisIfAvailable(scannable);
26071
26377
  const trigger = moment === "pre-commit" ? "hook:pre-commit" : "hook:pre-push";
26072
26378
  const requestBody = {
26073
26379
  static_results: staticResults,
@@ -26143,6 +26449,9 @@ function worstGate(...gates) {
26143
26449
  };
26144
26450
  return GATES[Math.max(...gates.map(rank2))];
26145
26451
  }
26452
+ function oneShotLostOutcome(input) {
26453
+ return input.agentGate === "FAIL" && input.agentBlocking ? "block" : "allow-without-review";
26454
+ }
26146
26455
  function withAgentVerdict(oneShot, agent) {
26147
26456
  if (agent.one_shot_source === "none" && typeof oneShot.gate_decision === "string") {
26148
26457
  const added = agent.findings.filter((f) => f.agent_added === true);
@@ -26311,6 +26620,7 @@ async function runGuard(opts, globals) {
26311
26620
  symbols: repoContext2.symbols?.length ?? 0,
26312
26621
  callers: repoContext2.callers?.length ?? 0,
26313
26622
  tests: repoContext2.tests?.length ?? 0,
26623
+ importers: repoContext2.importers?.length ?? 0,
26314
26624
  excerpts: repoContext2.excerpts?.length ?? 0,
26315
26625
  elapsed_ms: repoContext2.elapsed_ms ?? null
26316
26626
  });
@@ -26357,13 +26667,6 @@ async function runGuard(opts, globals) {
26357
26667
  const agentOutcome = agent ? await agent : null;
26358
26668
  const agentVerdict = agentOutcome?.kind === "finished" && agentOutcome.response.gate_decision ? agentOutcome.response : null;
26359
26669
  const reviewSecs = Math.max(1, Math.round((Date.now() - reviewStart) / 1e3));
26360
- if (!result.ok && !agentVerdict) {
26361
- const authRemedy = result.error.startsWith("STALE_VERIFICATION") ? " Your GitHub verification expired \u2014 run `verity login` to re-verify." : result.error.startsWith("FORBIDDEN") ? " No access grant for this repository \u2014 run `verity login` to refresh your grants." : result.error.startsWith("INVALID_TOKEN") ? " Your Verity login expired or was revoked \u2014 run `verity login` to sign in again." : "";
26362
- emitAllowNotice(
26363
- `\u26A0 Verity ${moment}: ${authRemedy ? "not authorized" : "service offline"} \u2014 ${verb}ed WITHOUT review${authRemedy}`,
26364
- `Verity ${moment}: ${authRemedy ? "not authorized" : "service unavailable"} (${result.error}); the ${verb} was allowed WITHOUT a Verity review.${authRemedy}`
26365
- );
26366
- }
26367
26670
  const oneShotResponse = result.ok ? result.data : {};
26368
26671
  const response = agentVerdict ? withAgentVerdict(oneShotResponse, agentVerdict) : oneShotResponse;
26369
26672
  if (opts.json) process.stderr.write(JSON.stringify(response) + "\n");
@@ -26375,6 +26678,19 @@ async function runGuard(opts, globals) {
26375
26678
  const covDetail = agentLine ? `${coverageBlock(coverage)}
26376
26679
  ${agentLine}` : coverageBlock(coverage);
26377
26680
  const witnessed = [...codeDelta.files.map((f) => f.path), ...agentVerdict?.witnessed_files ?? []];
26681
+ if (!result.ok) {
26682
+ const authRemedy = result.error.startsWith("STALE_VERIFICATION") ? " Your GitHub verification expired \u2014 run `verity login` to re-verify." : result.error.startsWith("FORBIDDEN") ? " No access grant for this repository \u2014 run `verity login` to refresh your grants." : result.error.startsWith("INVALID_TOKEN") ? " Your Verity login expired or was revoked \u2014 run `verity login` to sign in again." : "";
26683
+ if (oneShotLostOutcome({ agentGate: decision, agentBlocking: hasBlockingFinding(response, witnessed) }) === "block") {
26684
+ writeIter(moment, iter + 1);
26685
+ writeBlockMessage(moment, response, covDetail);
26686
+ process.exit(2);
26687
+ }
26688
+ const agentNote = agentLine ? ` ${agentLine}, but it reviewed only part of the change.` : "";
26689
+ emitAllowNotice(
26690
+ `\u26A0 Verity ${moment}: ${authRemedy ? "not authorized" : "no single-pass review"} \u2014 ${verb}ed WITHOUT review${authRemedy}`,
26691
+ `Verity ${moment}: the single-pass review did not come back (${result.error}); the ${verb} was allowed WITHOUT a Verity review.${agentNote}${authRemedy}`
26692
+ );
26693
+ }
26378
26694
  if (decision === "FAIL" && hasBlockingFinding(response, witnessed)) {
26379
26695
  writeIter(moment, iter + 1);
26380
26696
  writeBlockMessage(moment, response, covDetail);
@@ -26566,7 +26882,7 @@ function registerIgnoreCommand(program2) {
26566
26882
 
26567
26883
  // src/commands/waive.ts
26568
26884
  var import_node_crypto12 = require("node:crypto");
26569
- var import_node_fs50 = require("node:fs");
26885
+ var import_node_fs52 = require("node:fs");
26570
26886
  function registerWaiveCommand(program2) {
26571
26887
  program2.command("waive <pattern-id>").description("Record an accepted-risk disposition for an open finding (voids when the file changes)").option("--file <path>", "File the finding is anchored to, REPO-RELATIVE (recommended \u2014 narrows the waive)").requiredOption("--reason <text>", "The human disposition this records (reviewer finding, ADR, \u2026)").action(async (patternId, opts) => {
26572
26888
  const globals = program2.opts();
@@ -26595,7 +26911,7 @@ function registerWaiveCommand(program2) {
26595
26911
  if (opts.file) {
26596
26912
  body.file = opts.file;
26597
26913
  try {
26598
- body.file_sha256 = (0, import_node_crypto12.createHash)("sha256").update((0, import_node_fs50.readFileSync)(opts.file)).digest("hex");
26914
+ body.file_sha256 = (0, import_node_crypto12.createHash)("sha256").update((0, import_node_fs52.readFileSync)(opts.file)).digest("hex");
26599
26915
  } catch {
26600
26916
  printError(`Cannot read ${opts.file} \u2014 run from the repo root, or omit --file to waive by pattern.`);
26601
26917
  process.exit(1);
@@ -26620,10 +26936,10 @@ function registerWaiveCommand(program2) {
26620
26936
  }
26621
26937
 
26622
26938
  // src/commands/init.ts
26623
- var import_node_fs54 = require("node:fs");
26939
+ var import_node_fs56 = require("node:fs");
26624
26940
  var import_promises19 = require("node:fs/promises");
26625
26941
  var import_yaml6 = __toESM(require_dist());
26626
- var import_node_path38 = require("node:path");
26942
+ var import_node_path40 = require("node:path");
26627
26943
  var import_node_child_process17 = require("node:child_process");
26628
26944
 
26629
26945
  // src/lib/banner.ts
@@ -26702,18 +27018,13 @@ function printPhase(n, of, title, subtitle) {
26702
27018
  }
26703
27019
 
26704
27020
  // src/commands/doctor.ts
26705
- var import_node_fs51 = require("node:fs");
27021
+ var import_node_fs53 = require("node:fs");
26706
27022
 
26707
27023
  // src/lib/prereqs.ts
26708
27024
  var import_node_child_process15 = require("node:child_process");
26709
27025
  var MIN_NODE_MAJOR = 20;
26710
27026
  function which(bin) {
26711
- try {
26712
- const out = (0, import_node_child_process15.execSync)(`command -v ${bin}`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
26713
- return out || null;
26714
- } catch {
26715
- return null;
26716
- }
27027
+ return whichSync(bin, { real: false });
26717
27028
  }
26718
27029
  function checkNode() {
26719
27030
  const version = process.version;
@@ -26913,12 +27224,13 @@ async function buildReport() {
26913
27224
  const state = await readSetupState();
26914
27225
  const wiring = await resolveHookWiring();
26915
27226
  const hooks = wiring.status;
27227
+ const provenance = cliProvenance();
26916
27228
  const telemetry = await checkTelemetry();
26917
- const hasConfig = (0, import_node_fs51.existsSync)(projectPath(CODACY_CONFIG_FILE));
27229
+ const hasConfig = (0, import_node_fs53.existsSync)(projectPath(CODACY_CONFIG_FILE));
26918
27230
  const artifacts = {
26919
- standard: (0, import_node_fs51.existsSync)(projectPath(STANDARD_FILE)),
27231
+ standard: (0, import_node_fs53.existsSync)(projectPath(STANDARD_FILE)),
26920
27232
  analysisConfig: hasConfig,
26921
- verityMd: (0, import_node_fs51.existsSync)(projectPath(VERITY_MD_FILE)),
27233
+ verityMd: (0, import_node_fs53.existsSync)(projectPath(VERITY_MD_FILE)),
26922
27234
  analysisConfigIds: hasConfig ? validatePatternIds().status : "absent"
26923
27235
  };
26924
27236
  const next = [];
@@ -26956,6 +27268,12 @@ async function buildReport() {
26956
27268
  'Duplicate Verity hooks also exist in .claude/settings.json. They stand down at run time under the plugin, but remove them with "verity init --plugin-mode" so the wiring says what it does.'
26957
27269
  );
26958
27270
  }
27271
+ const versions = versionReport(provenance);
27272
+ if (provenance.skew) {
27273
+ next.push(
27274
+ `The \`verity\` on PATH is ${provenance.skew.global}, but the plugin's hooks run ${provenance.skew.hooks} \u2014 so the gate and your terminal are different builds. Fix: ${provenance.skew.remedy}.`
27275
+ );
27276
+ }
26959
27277
  if (state?.telemetry === "deferred") {
26960
27278
  next.push('Telemetry was requested but needs a token \u2014 run "verity login", then "verity telemetry install".');
26961
27279
  }
@@ -26993,7 +27311,8 @@ async function buildReport() {
26993
27311
  source: wiring.source,
26994
27312
  ...hooks,
26995
27313
  duplicateSettingsHooks: wiring.duplicateSettingsHooks,
26996
- noAnalysisMoment
27314
+ noAnalysisMoment,
27315
+ versions
26997
27316
  },
26998
27317
  telemetry: { enabled: telemetry.enabled, endpoint: telemetry.endpoint },
26999
27318
  artifacts,
@@ -27024,6 +27343,9 @@ function registerDoctorCommand(program2) {
27024
27343
  printInfo(` intensity: ${report.answers.intensity ?? "\u2014"} moments: ${report.answers.moments?.join(", ") ?? "\u2014"}`);
27025
27344
  const plugin = report.hooks.source === "plugin";
27026
27345
  printInfo(plugin ? "Hooks: wired by the Verity Claude Code plugin (not .claude/settings.json)" : "Hooks:");
27346
+ const versionOut = versionLines(report.hooks.versions);
27347
+ for (const line of versionOut.info) printInfo(line);
27348
+ for (const line of versionOut.warn) printWarn(line);
27027
27349
  printInfo(` Stop (verity analyze): ${report.hooks.stop ? plugin ? "on (plugin)" : "on" : "off"}`);
27028
27350
  printInfo(` Git-moment gate: ${report.hooks.guardOn.length ? report.hooks.guardOn.join(", ") : "off"}`);
27029
27351
  printInfo(` Infra (intent/baseline/compact/session-end): ${[report.hooks.intent, report.hooks.baseline, report.hooks.compact, report.hooks.sessionEnd].filter(Boolean).length}/4`);
@@ -27049,8 +27371,8 @@ function registerDoctorCommand(program2) {
27049
27371
  }
27050
27372
 
27051
27373
  // src/commands/migrate.ts
27052
- var import_node_fs52 = require("node:fs");
27053
- var import_node_path36 = require("node:path");
27374
+ var import_node_fs54 = require("node:fs");
27375
+ var import_node_path38 = require("node:path");
27054
27376
  var import_node_child_process16 = require("node:child_process");
27055
27377
  var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
27056
27378
  function defaultNpmRemover(pkg) {
@@ -27087,12 +27409,12 @@ async function runMigration(opts = {}) {
27087
27409
  return { actions, migrated: actions.length > 0 };
27088
27410
  }
27089
27411
  function migrateProjectDir(root, actions) {
27090
- const gateDir = (0, import_node_path36.join)(root, ".gate");
27091
- const verityDir = (0, import_node_path36.join)(root, ".verity");
27092
- if ((0, import_node_fs52.existsSync)(gateDir) && !(0, import_node_fs52.existsSync)(verityDir)) {
27412
+ const gateDir = (0, import_node_path38.join)(root, ".gate");
27413
+ const verityDir = (0, import_node_path38.join)(root, ".verity");
27414
+ if ((0, import_node_fs54.existsSync)(gateDir) && !(0, import_node_fs54.existsSync)(verityDir)) {
27093
27415
  return migrateProjectDirRename(root, gateDir, verityDir, actions);
27094
27416
  }
27095
- if ((0, import_node_fs52.existsSync)(gateDir) && (0, import_node_fs52.existsSync)(verityDir)) {
27417
+ if ((0, import_node_fs54.existsSync)(gateDir) && (0, import_node_fs54.existsSync)(verityDir)) {
27096
27418
  return migrateProjectDirCarry(gateDir, verityDir, actions);
27097
27419
  }
27098
27420
  return false;
@@ -27113,13 +27435,13 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
27113
27435
  }
27114
27436
  }
27115
27437
  if (moved) {
27116
- if ((0, import_node_fs52.existsSync)(gateDir)) {
27438
+ if ((0, import_node_fs54.existsSync)(gateDir)) {
27117
27439
  const carried = carryLegacyContents(gateDir, verityDir);
27118
27440
  if (carried > 0) {
27119
27441
  actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
27120
27442
  }
27121
27443
  try {
27122
- (0, import_node_fs52.rmSync)(gateDir, { recursive: true, force: true });
27444
+ (0, import_node_fs54.rmSync)(gateDir, { recursive: true, force: true });
27123
27445
  } catch {
27124
27446
  }
27125
27447
  }
@@ -27135,18 +27457,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
27135
27457
  actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
27136
27458
  }
27137
27459
  try {
27138
- (0, import_node_fs52.rmSync)(gateDir, { recursive: true, force: true });
27460
+ (0, import_node_fs54.rmSync)(gateDir, { recursive: true, force: true });
27139
27461
  } catch {
27140
27462
  }
27141
27463
  return carried > 0;
27142
27464
  }
27143
27465
  function migrateGlobalCredentials(home, actions) {
27144
27466
  if (!home) return;
27145
- const gateCreds = (0, import_node_path36.join)(home, ".gate", "credentials");
27146
- const verityCreds = (0, import_node_path36.join)(home, ".verity", "credentials");
27147
- if (!(0, import_node_fs52.existsSync)(gateCreds)) return;
27148
- if (!(0, import_node_fs52.existsSync)(verityCreds)) {
27149
- (0, import_node_fs52.mkdirSync)((0, import_node_path36.join)(home, ".verity"), { recursive: true });
27467
+ const gateCreds = (0, import_node_path38.join)(home, ".gate", "credentials");
27468
+ const verityCreds = (0, import_node_path38.join)(home, ".verity", "credentials");
27469
+ if (!(0, import_node_fs54.existsSync)(gateCreds)) return;
27470
+ if (!(0, import_node_fs54.existsSync)(verityCreds)) {
27471
+ (0, import_node_fs54.mkdirSync)((0, import_node_path38.join)(home, ".verity"), { recursive: true });
27150
27472
  moveFile(gateCreds, verityCreds);
27151
27473
  actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
27152
27474
  return;
@@ -27168,8 +27490,8 @@ async function migrateLegacyHooks(root, actions) {
27168
27490
  }
27169
27491
  }
27170
27492
  async function migrateClaudeMd(root, actions) {
27171
- const claudeMd = (0, import_node_path36.join)(root, "CLAUDE.md");
27172
- const hadLegacyBlock = (0, import_node_fs52.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
27493
+ const claudeMd = (0, import_node_path38.join)(root, "CLAUDE.md");
27494
+ const hadLegacyBlock = (0, import_node_fs54.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
27173
27495
  if (!hadLegacyBlock) return;
27174
27496
  try {
27175
27497
  await ensureClaudeMdPointer(root);
@@ -27179,9 +27501,9 @@ async function migrateClaudeMd(root, actions) {
27179
27501
  }
27180
27502
  }
27181
27503
  function migrateStandardFile(root, actions) {
27182
- const gateMd = (0, import_node_path36.join)(root, "GATE.md");
27183
- const verityMd = (0, import_node_path36.join)(root, "VERITY.md");
27184
- if (!(0, import_node_fs52.existsSync)(gateMd) || (0, import_node_fs52.existsSync)(verityMd)) return;
27504
+ const gateMd = (0, import_node_path38.join)(root, "GATE.md");
27505
+ const verityMd = (0, import_node_path38.join)(root, "VERITY.md");
27506
+ if (!(0, import_node_fs54.existsSync)(gateMd) || (0, import_node_fs54.existsSync)(verityMd)) return;
27185
27507
  let moved = false;
27186
27508
  if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
27187
27509
  try {
@@ -27193,12 +27515,12 @@ function migrateStandardFile(root, actions) {
27193
27515
  if (!moved) moveFile(gateMd, verityMd);
27194
27516
  const content = readFileSyncSafe(verityMd);
27195
27517
  const refreshed = content.split("GATE.md").join("VERITY.md");
27196
- if (refreshed !== content) (0, import_node_fs52.writeFileSync)(verityMd, refreshed);
27518
+ if (refreshed !== content) (0, import_node_fs54.writeFileSync)(verityMd, refreshed);
27197
27519
  actions.push("Renamed GATE.md \u2192 VERITY.md");
27198
27520
  }
27199
27521
  async function migrateTelemetryHeaders(root, actions) {
27200
- const file = (0, import_node_path36.join)(root, ".claude", "settings.local.json");
27201
- if (!(0, import_node_fs52.existsSync)(file)) return;
27522
+ const file = (0, import_node_path38.join)(root, ".claude", "settings.local.json");
27523
+ if (!(0, import_node_fs54.existsSync)(file)) return;
27202
27524
  let settings;
27203
27525
  try {
27204
27526
  settings = JSON.parse(readFileSyncSafe(file) || "{}");
@@ -27246,14 +27568,14 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
27246
27568
  }
27247
27569
  if (toAppend.length > 0) {
27248
27570
  const sep4 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
27249
- (0, import_node_fs52.writeFileSync)(verityCreds, verityContent + sep4 + toAppend.join("\n") + "\n");
27571
+ (0, import_node_fs54.writeFileSync)(verityCreds, verityContent + sep4 + toAppend.join("\n") + "\n");
27250
27572
  }
27251
- (0, import_node_fs52.rmSync)(gateCreds, { force: true });
27573
+ (0, import_node_fs54.rmSync)(gateCreds, { force: true });
27252
27574
  return toAppend.length;
27253
27575
  }
27254
27576
  function readFileSyncSafe(path) {
27255
27577
  try {
27256
- return (0, import_node_fs52.readFileSync)(path, "utf-8");
27578
+ return (0, import_node_fs54.readFileSync)(path, "utf-8");
27257
27579
  } catch {
27258
27580
  return "";
27259
27581
  }
@@ -27268,35 +27590,35 @@ function hasStagedChanges(root) {
27268
27590
  }
27269
27591
  function moveDir(from, to) {
27270
27592
  try {
27271
- (0, import_node_fs52.renameSync)(from, to);
27593
+ (0, import_node_fs54.renameSync)(from, to);
27272
27594
  } catch (err) {
27273
27595
  if (err.code !== "EXDEV") throw err;
27274
- (0, import_node_fs52.cpSync)(from, to, { recursive: true });
27275
- (0, import_node_fs52.rmSync)(from, { recursive: true, force: true });
27596
+ (0, import_node_fs54.cpSync)(from, to, { recursive: true });
27597
+ (0, import_node_fs54.rmSync)(from, { recursive: true, force: true });
27276
27598
  }
27277
27599
  }
27278
27600
  function moveFile(from, to) {
27279
27601
  try {
27280
- (0, import_node_fs52.renameSync)(from, to);
27602
+ (0, import_node_fs54.renameSync)(from, to);
27281
27603
  } catch (err) {
27282
27604
  if (err.code !== "EXDEV") throw err;
27283
- (0, import_node_fs52.cpSync)(from, to);
27284
- (0, import_node_fs52.rmSync)(from, { force: true });
27605
+ (0, import_node_fs54.cpSync)(from, to);
27606
+ (0, import_node_fs54.rmSync)(from, { force: true });
27285
27607
  }
27286
27608
  }
27287
27609
  function carryLegacyContents(gateDir, verityDir) {
27288
27610
  let copied = 0;
27289
27611
  const walk2 = (relDir) => {
27290
- const srcDir = (0, import_node_path36.join)(gateDir, relDir);
27291
- for (const entry of (0, import_node_fs52.readdirSync)(srcDir)) {
27292
- const rel = relDir ? (0, import_node_path36.join)(relDir, entry) : entry;
27293
- const src = (0, import_node_path36.join)(gateDir, rel);
27294
- const dest = (0, import_node_path36.join)(verityDir, rel);
27295
- if ((0, import_node_fs52.statSync)(src).isDirectory()) {
27612
+ const srcDir = (0, import_node_path38.join)(gateDir, relDir);
27613
+ for (const entry of (0, import_node_fs54.readdirSync)(srcDir)) {
27614
+ const rel = relDir ? (0, import_node_path38.join)(relDir, entry) : entry;
27615
+ const src = (0, import_node_path38.join)(gateDir, rel);
27616
+ const dest = (0, import_node_path38.join)(verityDir, rel);
27617
+ if ((0, import_node_fs54.statSync)(src).isDirectory()) {
27296
27618
  walk2(rel);
27297
- } else if (!(0, import_node_fs52.existsSync)(dest)) {
27298
- (0, import_node_fs52.mkdirSync)((0, import_node_path36.dirname)(dest), { recursive: true });
27299
- (0, import_node_fs52.cpSync)(src, dest);
27619
+ } else if (!(0, import_node_fs54.existsSync)(dest)) {
27620
+ (0, import_node_fs54.mkdirSync)((0, import_node_path38.dirname)(dest), { recursive: true });
27621
+ (0, import_node_fs54.cpSync)(src, dest);
27300
27622
  copied++;
27301
27623
  }
27302
27624
  }
@@ -27305,22 +27627,22 @@ function carryLegacyContents(gateDir, verityDir) {
27305
27627
  return copied;
27306
27628
  }
27307
27629
  async function needsMigration(root = repoRoot()) {
27308
- const gateDir = (0, import_node_path36.join)(root, ".gate");
27309
- const verityDir = (0, import_node_path36.join)(root, ".verity");
27310
- if ((0, import_node_fs52.existsSync)(gateDir) && !(0, import_node_fs52.existsSync)(verityDir)) return true;
27311
- if ((0, import_node_fs52.existsSync)(gateDir) && (0, import_node_fs52.existsSync)(verityDir)) {
27312
- if ((0, import_node_fs52.existsSync)((0, import_node_path36.join)(gateDir, "credentials")) && !(0, import_node_fs52.existsSync)((0, import_node_path36.join)(verityDir, "credentials"))) {
27630
+ const gateDir = (0, import_node_path38.join)(root, ".gate");
27631
+ const verityDir = (0, import_node_path38.join)(root, ".verity");
27632
+ if ((0, import_node_fs54.existsSync)(gateDir) && !(0, import_node_fs54.existsSync)(verityDir)) return true;
27633
+ if ((0, import_node_fs54.existsSync)(gateDir) && (0, import_node_fs54.existsSync)(verityDir)) {
27634
+ if ((0, import_node_fs54.existsSync)((0, import_node_path38.join)(gateDir, "credentials")) && !(0, import_node_fs54.existsSync)((0, import_node_path38.join)(verityDir, "credentials"))) {
27313
27635
  return true;
27314
27636
  }
27315
- if ((0, import_node_fs52.existsSync)((0, import_node_path36.join)(gateDir, "memory")) && !(0, import_node_fs52.existsSync)((0, import_node_path36.join)(verityDir, "memory"))) {
27637
+ if ((0, import_node_fs54.existsSync)((0, import_node_path38.join)(gateDir, "memory")) && !(0, import_node_fs54.existsSync)((0, import_node_path38.join)(verityDir, "memory"))) {
27316
27638
  return true;
27317
27639
  }
27318
27640
  }
27319
- const claudeMd = (0, import_node_path36.join)(root, "CLAUDE.md");
27320
- if ((0, import_node_fs52.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
27641
+ const claudeMd = (0, import_node_path38.join)(root, "CLAUDE.md");
27642
+ if ((0, import_node_fs54.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
27321
27643
  return true;
27322
27644
  }
27323
- if ((0, import_node_fs52.existsSync)((0, import_node_path36.join)(root, "GATE.md")) && !(0, import_node_fs52.existsSync)((0, import_node_path36.join)(root, "VERITY.md"))) {
27645
+ if ((0, import_node_fs54.existsSync)((0, import_node_path38.join)(root, "GATE.md")) && !(0, import_node_fs54.existsSync)((0, import_node_path38.join)(root, "VERITY.md"))) {
27324
27646
  return true;
27325
27647
  }
27326
27648
  if (await hasLegacyHooksAt(root)) return true;
@@ -27601,9 +27923,9 @@ async function promptMultiSelect(question, choices, fallback) {
27601
27923
  }
27602
27924
 
27603
27925
  // src/lib/remote-config.ts
27604
- var import_node_fs53 = require("node:fs");
27926
+ var import_node_fs55 = require("node:fs");
27605
27927
  var import_promises18 = require("node:fs/promises");
27606
- var import_node_path37 = require("node:path");
27928
+ var import_node_path39 = require("node:path");
27607
27929
  var import_yaml5 = __toESM(require_dist());
27608
27930
  var IGNORE_RIDER = "verityignore";
27609
27931
  async function fetchRemoteSetup(opts) {
@@ -27648,7 +27970,7 @@ async function adoptRemoteSetup(found, opts) {
27648
27970
  written.push(STANDARD_FILE);
27649
27971
  if (rider !== null) {
27650
27972
  const localIgnore = projectPath(VERITYIGNORE_FILE);
27651
- if (!(0, import_node_fs53.existsSync)(localIgnore)) {
27973
+ if (!(0, import_node_fs55.existsSync)(localIgnore)) {
27652
27974
  await writeOut(VERITYIGNORE_FILE, rider);
27653
27975
  written.push(VERITYIGNORE_FILE);
27654
27976
  } else {
@@ -27679,9 +28001,9 @@ async function adoptRemoteSetup(found, opts) {
27679
28001
  written.push(VERITY_MD_FILE);
27680
28002
  return { written, notes };
27681
28003
  }
27682
- async function writeOut(relative2, body) {
27683
- const target = projectPath(relative2);
27684
- await (0, import_promises18.mkdir)((0, import_node_path37.dirname)(target), { recursive: true });
28004
+ async function writeOut(relative3, body) {
28005
+ const target = projectPath(relative3);
28006
+ await (0, import_promises18.mkdir)((0, import_node_path39.dirname)(target), { recursive: true });
27685
28007
  await (0, import_promises18.writeFile)(target, body);
27686
28008
  }
27687
28009
  function describeRemote(found) {
@@ -27798,15 +28120,15 @@ async function runOptionalAuth(resolution, opts = {}) {
27798
28120
  }
27799
28121
  function resolveDataDir2() {
27800
28122
  const candidates2 = [
27801
- (0, import_node_path38.join)(__dirname, "..", "data"),
28123
+ (0, import_node_path40.join)(__dirname, "..", "data"),
27802
28124
  // installed: node_modules/@codacy/verity-cli/data
27803
- (0, import_node_path38.join)(__dirname, "..", "..", "data"),
28125
+ (0, import_node_path40.join)(__dirname, "..", "..", "data"),
27804
28126
  // edge case: nested resolution
27805
- (0, import_node_path38.join)(process.cwd(), "cli", "data")
28127
+ (0, import_node_path40.join)(process.cwd(), "cli", "data")
27806
28128
  // local dev: running from repo root
27807
28129
  ];
27808
28130
  for (const candidate of candidates2) {
27809
- if ((0, import_node_fs54.existsSync)((0, import_node_path38.join)(candidate, "skills"))) {
28131
+ if ((0, import_node_fs56.existsSync)((0, import_node_path40.join)(candidate, "skills"))) {
27810
28132
  return candidate;
27811
28133
  }
27812
28134
  }
@@ -27822,9 +28144,9 @@ async function skillIsCurrent(src, dest) {
27822
28144
  const list2 = (dir) => {
27823
28145
  const out = [];
27824
28146
  const walk2 = (d, prefix) => {
27825
- for (const e of (0, import_node_fs54.readdirSync)(d, { withFileTypes: true })) {
28147
+ for (const e of (0, import_node_fs56.readdirSync)(d, { withFileTypes: true })) {
27826
28148
  const rel = prefix ? `${prefix}/${e.name}` : e.name;
27827
- if (e.isDirectory()) walk2((0, import_node_path38.join)(d, e.name), rel);
28149
+ if (e.isDirectory()) walk2((0, import_node_path40.join)(d, e.name), rel);
27828
28150
  else if (e.isFile()) out.push(rel);
27829
28151
  }
27830
28152
  };
@@ -27835,8 +28157,8 @@ async function skillIsCurrent(src, dest) {
27835
28157
  const shipped = list2(src);
27836
28158
  if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
27837
28159
  for (const rel of shipped) {
27838
- const a = await (0, import_promises19.readFile)((0, import_node_path38.join)(src, rel), "utf-8");
27839
- const b = await (0, import_promises19.readFile)((0, import_node_path38.join)(dest, rel), "utf-8");
28160
+ const a = await (0, import_promises19.readFile)((0, import_node_path40.join)(src, rel), "utf-8");
28161
+ const b = await (0, import_promises19.readFile)((0, import_node_path40.join)(dest, rel), "utf-8");
27840
28162
  if (a !== b) return false;
27841
28163
  }
27842
28164
  return true;
@@ -28017,7 +28339,7 @@ async function synthesizeLocally(opts) {
28017
28339
  async function healStaleAnalysisConfig(globals) {
28018
28340
  const configPath = projectPath(CODACY_CONFIG_FILE);
28019
28341
  const standardPath = projectPath(STANDARD_FILE);
28020
- if (!(0, import_node_fs54.existsSync)(configPath) || !(0, import_node_fs54.existsSync)(standardPath)) return;
28342
+ if (!(0, import_node_fs56.existsSync)(configPath) || !(0, import_node_fs56.existsSync)(standardPath)) return;
28021
28343
  const validation = validatePatternIds();
28022
28344
  if (validation.status !== "invalid") return;
28023
28345
  printWarn(" Your analysis config names pattern ids that no longer resolve \u2014 those tools were");
@@ -28114,17 +28436,17 @@ async function handoffToSetup(enabled, claudeInstalled) {
28114
28436
  async function installSkills(force, step) {
28115
28437
  step("Installing skills");
28116
28438
  const dataDir = resolveDataDir2();
28117
- const skillsSource = (0, import_node_path38.join)(dataDir, "skills");
28439
+ const skillsSource = (0, import_node_path40.join)(dataDir, "skills");
28118
28440
  const skillsDest = ".claude/skills";
28119
28441
  let skillsInstalled = 0;
28120
28442
  for (const skill of SKILLS) {
28121
- const src = (0, import_node_path38.join)(skillsSource, skill);
28122
- const dest = (0, import_node_path38.join)(skillsDest, skill);
28123
- if (!(0, import_node_fs54.existsSync)(src)) {
28443
+ const src = (0, import_node_path40.join)(skillsSource, skill);
28444
+ const dest = (0, import_node_path40.join)(skillsDest, skill);
28445
+ if (!(0, import_node_fs56.existsSync)(src)) {
28124
28446
  printWarn(` Skill data not found: ${skill}`);
28125
28447
  continue;
28126
28448
  }
28127
- if ((0, import_node_fs54.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) {
28449
+ if ((0, import_node_fs56.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) {
28128
28450
  skillsInstalled++;
28129
28451
  continue;
28130
28452
  }
@@ -28263,7 +28585,7 @@ function registerInitCommand(program2) {
28263
28585
  const staleMarker = clearStalePluginMarker();
28264
28586
  const pluginMode = opts.plugin === false ? false : opts.pluginMode ?? pluginActiveHere();
28265
28587
  const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
28266
- const isProject = projectMarkers.some((m) => (0, import_node_fs54.existsSync)(m));
28588
+ const isProject = projectMarkers.some((m) => (0, import_node_fs56.existsSync)(m));
28267
28589
  if (!isProject) {
28268
28590
  printError("No project detected in the current directory.");
28269
28591
  printInfo('Run "verity init" from your project root.');
@@ -28353,7 +28675,7 @@ function registerInitCommand(program2) {
28353
28675
  printInfo(` intensity: ${intensity} \xB7 moments: ${moments.join(", ") || "none"} (no questions asked)`);
28354
28676
  }
28355
28677
  await scaffoldProject(step, defaultsOnly);
28356
- const globalVerityDir = (0, import_node_path38.join)(process.env.HOME ?? "", ".verity");
28678
+ const globalVerityDir = (0, import_node_path40.join)(process.env.HOME ?? "", ".verity");
28357
28679
  await (0, import_promises19.mkdir)(globalVerityDir, { recursive: true });
28358
28680
  console.log("");
28359
28681
  step("Wiring Claude Code hooks");
@@ -28422,7 +28744,7 @@ function registerInitCommand(program2) {
28422
28744
  }
28423
28745
  step("Your project's Standard");
28424
28746
  let haveStandard = false;
28425
- if ((0, import_node_fs54.existsSync)(projectPath(STANDARD_FILE))) {
28747
+ if ((0, import_node_fs56.existsSync)(projectPath(STANDARD_FILE))) {
28426
28748
  printInfo(" This project already has .verity/standard.yaml \u2014 keeping it.");
28427
28749
  haveStandard = true;
28428
28750
  } else {
@@ -28452,7 +28774,7 @@ function registerInitCommand(program2) {
28452
28774
  ...telemetryChoice ? { telemetry: telemetryChoice } : {},
28453
28775
  init: {
28454
28776
  completed_at: (/* @__PURE__ */ new Date()).toISOString(),
28455
- cli_version: true ? "0.33.0-experimental.d60f544" : "dev"
28777
+ cli_version: true ? "0.33.1-experimental.1378de3" : "dev"
28456
28778
  }
28457
28779
  });
28458
28780
  } catch (err) {
@@ -28502,8 +28824,8 @@ function registerInitCommand(program2) {
28502
28824
  }
28503
28825
 
28504
28826
  // src/commands/uninstall.ts
28505
- var import_node_fs55 = require("node:fs");
28506
- var import_node_path39 = require("node:path");
28827
+ var import_node_fs57 = require("node:fs");
28828
+ var import_node_path41 = require("node:path");
28507
28829
  function registerUninstallCommand(program2) {
28508
28830
  program2.command("uninstall").description("Remove Verity from this project (skills, hooks, .verity/, VERITY.md)").option("--dry-run", "Show what would be removed without doing it").option("--purge-global", "Also remove ~/.verity/ (deletes saved tokens \u2014 reconnect requires re-registration)").option("--keep-verity-md", "Keep the project root VERITY.md file").action(async (opts) => {
28509
28831
  const dryRun = opts.dryRun ?? false;
@@ -28512,11 +28834,11 @@ function registerUninstallCommand(program2) {
28512
28834
  const actions = [];
28513
28835
  const skillsRoot = projectPath(".claude/skills");
28514
28836
  for (const name of PROJECT_SKILL_NAMES) {
28515
- const dir = (0, import_node_path39.join)(skillsRoot, name);
28516
- if ((0, import_node_fs55.existsSync)(dir)) {
28837
+ const dir = (0, import_node_path41.join)(skillsRoot, name);
28838
+ if ((0, import_node_fs57.existsSync)(dir)) {
28517
28839
  actions.push({
28518
28840
  label: `Remove .claude/skills/${name}/`,
28519
- apply: () => (0, import_node_fs55.rmSync)(dir, { recursive: true, force: true })
28841
+ apply: () => (0, import_node_fs57.rmSync)(dir, { recursive: true, force: true })
28520
28842
  });
28521
28843
  }
28522
28844
  }
@@ -28530,24 +28852,24 @@ function registerUninstallCommand(program2) {
28530
28852
  });
28531
28853
  }
28532
28854
  const verityDir = projectPath(VERITY_DIR);
28533
- if ((0, import_node_fs55.existsSync)(verityDir)) {
28855
+ if ((0, import_node_fs57.existsSync)(verityDir)) {
28534
28856
  actions.push({
28535
28857
  label: `Remove ${VERITY_DIR}/`,
28536
- apply: () => (0, import_node_fs55.rmSync)(verityDir, { recursive: true, force: true })
28858
+ apply: () => (0, import_node_fs57.rmSync)(verityDir, { recursive: true, force: true })
28537
28859
  });
28538
28860
  }
28539
28861
  if (!keepVerityMd) {
28540
28862
  const verityMd = projectPath(VERITY_MD_FILE);
28541
- if ((0, import_node_fs55.existsSync)(verityMd)) {
28863
+ if ((0, import_node_fs57.existsSync)(verityMd)) {
28542
28864
  actions.push({
28543
28865
  label: `Remove ${VERITY_MD_FILE}`,
28544
- apply: () => (0, import_node_fs55.rmSync)(verityMd, { force: true })
28866
+ apply: () => (0, import_node_fs57.rmSync)(verityMd, { force: true })
28545
28867
  });
28546
28868
  }
28547
28869
  }
28548
28870
  const cleanupEmptyDir = (path) => {
28549
- if ((0, import_node_fs55.existsSync)(path) && (0, import_node_fs55.statSync)(path).isDirectory() && (0, import_node_fs55.readdirSync)(path).length === 0) {
28550
- (0, import_node_fs55.rmdirSync)(path);
28871
+ if ((0, import_node_fs57.existsSync)(path) && (0, import_node_fs57.statSync)(path).isDirectory() && (0, import_node_fs57.readdirSync)(path).length === 0) {
28872
+ (0, import_node_fs57.rmdirSync)(path);
28551
28873
  }
28552
28874
  };
28553
28875
  actions.push({
@@ -28558,11 +28880,11 @@ function registerUninstallCommand(program2) {
28558
28880
  }
28559
28881
  });
28560
28882
  const home = process.env.HOME ?? "";
28561
- const globalVerityDir = (0, import_node_path39.join)(home, ".verity");
28562
- if (purgeGlobal && (0, import_node_fs55.existsSync)(globalVerityDir)) {
28883
+ const globalVerityDir = (0, import_node_path41.join)(home, ".verity");
28884
+ if (purgeGlobal && (0, import_node_fs57.existsSync)(globalVerityDir)) {
28563
28885
  actions.push({
28564
28886
  label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
28565
- apply: () => (0, import_node_fs55.rmSync)(globalVerityDir, { recursive: true, force: true })
28887
+ apply: () => (0, import_node_fs57.rmSync)(globalVerityDir, { recursive: true, force: true })
28566
28888
  });
28567
28889
  }
28568
28890
  if (actions.length === 0) {
@@ -28756,8 +29078,8 @@ function registerTaskCommands(program2) {
28756
29078
  }
28757
29079
 
28758
29080
  // src/commands/reset.ts
28759
- var import_node_fs56 = require("node:fs");
28760
- var import_node_path40 = require("node:path");
29081
+ var import_node_fs58 = require("node:fs");
29082
+ var import_node_path42 = require("node:path");
28761
29083
  function registerResetCommand(program2) {
28762
29084
  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) => {
28763
29085
  const globals = program2.opts();
@@ -28794,11 +29116,11 @@ function registerResetCommand(program2) {
28794
29116
  }
28795
29117
  const cacheDir = projectPath(CACHE_DIR);
28796
29118
  let purged = 0;
28797
- if ((0, import_node_fs56.existsSync)(cacheDir)) {
28798
- for (const entry of (0, import_node_fs56.readdirSync)(cacheDir)) {
29119
+ if ((0, import_node_fs58.existsSync)(cacheDir)) {
29120
+ for (const entry of (0, import_node_fs58.readdirSync)(cacheDir)) {
28799
29121
  if (entry.startsWith("pending-")) {
28800
29122
  try {
28801
- (0, import_node_fs56.unlinkSync)((0, import_node_path40.join)(cacheDir, entry));
29123
+ (0, import_node_fs58.unlinkSync)((0, import_node_path42.join)(cacheDir, entry));
28802
29124
  purged++;
28803
29125
  } catch {
28804
29126
  }
@@ -28813,19 +29135,19 @@ function registerResetCommand(program2) {
28813
29135
  projectPath(`${VERITY_DIR}/.last-analysis`)
28814
29136
  ];
28815
29137
  for (const file of filesToClear) {
28816
- if ((0, import_node_fs56.existsSync)(file)) {
29138
+ if ((0, import_node_fs58.existsSync)(file)) {
28817
29139
  try {
28818
- (0, import_node_fs56.writeFileSync)(file, "");
29140
+ (0, import_node_fs58.writeFileSync)(file, "");
28819
29141
  } catch {
28820
29142
  }
28821
29143
  }
28822
29144
  }
28823
29145
  if (opts.all) {
28824
29146
  const logsDir = projectPath(`${VERITY_DIR}/.logs`);
28825
- if ((0, import_node_fs56.existsSync)(logsDir)) {
28826
- for (const entry of (0, import_node_fs56.readdirSync)(logsDir)) {
29147
+ if ((0, import_node_fs58.existsSync)(logsDir)) {
29148
+ for (const entry of (0, import_node_fs58.readdirSync)(logsDir)) {
28827
29149
  try {
28828
- (0, import_node_fs56.unlinkSync)((0, import_node_path40.join)(logsDir, entry));
29150
+ (0, import_node_fs58.unlinkSync)((0, import_node_path42.join)(logsDir, entry));
28829
29151
  } catch {
28830
29152
  }
28831
29153
  }
@@ -28837,7 +29159,7 @@ function registerResetCommand(program2) {
28837
29159
  }
28838
29160
 
28839
29161
  // src/commands/reflect.ts
28840
- var import_node_fs57 = require("node:fs");
29162
+ var import_node_fs59 = require("node:fs");
28841
29163
 
28842
29164
  // src/lib/reflection-globs.ts
28843
29165
  var MAX_GLOBS = 6;
@@ -28875,7 +29197,7 @@ async function writeNodeToDisk(args) {
28875
29197
  { treePaths: listTrackedFiles(), recordBaseline: false }
28876
29198
  );
28877
29199
  if (written === 0) return false;
28878
- return (0, import_node_fs57.existsSync)(projectPath(`${VERITY_DIR}/memory/${args.filePath}`));
29200
+ return (0, import_node_fs59.existsSync)(projectPath(`${VERITY_DIR}/memory/${args.filePath}`));
28879
29201
  } catch {
28880
29202
  return false;
28881
29203
  }
@@ -28954,7 +29276,7 @@ function registerReflectCommand(program2) {
28954
29276
  const fileGlobs = explicitGlobs.length > 0 ? explicitGlobs : derivedGlobs.length > 0 ? derivedGlobs : inheritedGlobs;
28955
29277
  const result = await apiRequest({
28956
29278
  method: "POST",
28957
- path: "/compound/memory/nodes",
29279
+ path: "/compound/reflect",
28958
29280
  serviceUrl,
28959
29281
  token,
28960
29282
  body: {
@@ -28987,6 +29309,8 @@ function registerReflectCommand(program2) {
28987
29309
  const nodeId = result.data.node_id;
28988
29310
  const filePath = result.data.file_path;
28989
29311
  const viewUrl = typeof result.data.view_url === "string" ? result.data.view_url : null;
29312
+ const recordedSource = typeof result.data.source === "string" ? result.data.source : source;
29313
+ const recordedAsUser = recordedSource === "user";
28990
29314
  const content = typeof result.data.content === "string" ? result.data.content : null;
28991
29315
  const synced = content !== null && await writeNodeToDisk({ filePath, content, nodeId });
28992
29316
  printInfo(
@@ -28994,8 +29318,13 @@ function registerReflectCommand(program2) {
28994
29318
  );
28995
29319
  if (viewUrl) printInfo(` ${viewUrl}`);
28996
29320
  printInfo(
28997
- confirmed ? " Recorded as yours (source: user)." : " Auto-recorded from this task \u2014 nobody reviewed it. Edit or delete the file if it is wrong."
29321
+ recordedAsUser ? " Recorded as yours (source: user)." : " Auto-recorded from this task \u2014 nobody reviewed it. Edit or delete the file if it is wrong."
28998
29322
  );
29323
+ if (recordedSource !== source) {
29324
+ printWarn(
29325
+ `Provenance mismatch: sent source "${source}", the service recorded "${recordedSource}". Correct ${nodeId} on the dashboard \u2014 a draft stored as human-authored cannot be told apart later.`
29326
+ );
29327
+ }
28999
29328
  if (fileGlobs.length === 0) {
29000
29329
  printWarn(
29001
29330
  'No files matched \u2014 this reflection will not surface in future reviews. Cite a path in the text, or pass --file-globs "<path or glob>".'
@@ -29367,8 +29696,8 @@ function registerTelemetryCommands(program2) {
29367
29696
  }
29368
29697
 
29369
29698
  // src/cli.ts
29370
- program.name("verity").description("CLI for Verity quality gate service").version("0.33.0-experimental.d60f544").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) => {
29371
- installStderrLog(actionCommand.name(), process.argv.slice(2), "0.33.0-experimental.d60f544");
29699
+ program.name("verity").description("CLI for Verity quality gate service").version("0.33.1-experimental.1378de3").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) => {
29700
+ installStderrLog(actionCommand.name(), process.argv.slice(2), "0.33.1-experimental.1378de3");
29372
29701
  setUserNamedServiceUrl(program.opts().serviceUrl);
29373
29702
  try {
29374
29703
  await foldLegacyLocalCredential();