@codacy/verity-cli 0.32.0-experimental.68ae2ee → 0.32.0-experimental.cc76941

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 +46 -0
  2. package/bin/verity.js +702 -345
  3. package/package.json +1 -1
package/bin/verity.js CHANGED
@@ -911,18 +911,18 @@ var require_suggestSimilar = __commonJS({
911
911
  }
912
912
  return d[a.length][b.length];
913
913
  }
914
- function suggestSimilar(word, candidates) {
915
- if (!candidates || candidates.length === 0) return "";
916
- candidates = Array.from(new Set(candidates));
914
+ function suggestSimilar(word, candidates2) {
915
+ if (!candidates2 || candidates2.length === 0) return "";
916
+ candidates2 = Array.from(new Set(candidates2));
917
917
  const searchingOptions = word.startsWith("--");
918
918
  if (searchingOptions) {
919
919
  word = word.slice(2);
920
- candidates = candidates.map((candidate) => candidate.slice(2));
920
+ candidates2 = candidates2.map((candidate) => candidate.slice(2));
921
921
  }
922
922
  let similar = [];
923
923
  let bestDistance = maxDistance;
924
924
  const minSimilarity = 0.4;
925
- candidates.forEach((candidate) => {
925
+ candidates2.forEach((candidate) => {
926
926
  if (candidate.length <= 1) return;
927
927
  const distance = editDistance(word, candidate);
928
928
  const length = Math.max(word.length, candidate.length);
@@ -6974,10 +6974,10 @@ var require_resolve_block_map = __commonJS({
6974
6974
  let offset = bm.offset;
6975
6975
  let commentEnd = null;
6976
6976
  for (const collItem of bm.items) {
6977
- const { start, key, sep: sep2, value } = collItem;
6977
+ const { start, key, sep: sep3, value } = collItem;
6978
6978
  const keyProps = resolveProps.resolveProps(start, {
6979
6979
  indicator: "explicit-key-ind",
6980
- next: key ?? sep2?.[0],
6980
+ next: key ?? sep3?.[0],
6981
6981
  offset,
6982
6982
  onError,
6983
6983
  parentIndent: bm.indent,
@@ -6991,7 +6991,7 @@ var require_resolve_block_map = __commonJS({
6991
6991
  else if ("indent" in key && key.indent !== bm.indent)
6992
6992
  onError(offset, "BAD_INDENT", startColMsg);
6993
6993
  }
6994
- if (!keyProps.anchor && !keyProps.tag && !sep2) {
6994
+ if (!keyProps.anchor && !keyProps.tag && !sep3) {
6995
6995
  commentEnd = keyProps.end;
6996
6996
  if (keyProps.comment) {
6997
6997
  if (map.comment)
@@ -7015,7 +7015,7 @@ var require_resolve_block_map = __commonJS({
7015
7015
  ctx.atKey = false;
7016
7016
  if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
7017
7017
  onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
7018
- const valueProps = resolveProps.resolveProps(sep2 ?? [], {
7018
+ const valueProps = resolveProps.resolveProps(sep3 ?? [], {
7019
7019
  indicator: "map-value-ind",
7020
7020
  next: value,
7021
7021
  offset: keyNode.range[2],
@@ -7031,7 +7031,7 @@ var require_resolve_block_map = __commonJS({
7031
7031
  if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
7032
7032
  onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
7033
7033
  }
7034
- const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep2, null, valueProps, onError);
7034
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep3, null, valueProps, onError);
7035
7035
  if (ctx.schema.compat)
7036
7036
  utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
7037
7037
  offset = valueNode.range[2];
@@ -7122,7 +7122,7 @@ var require_resolve_end = __commonJS({
7122
7122
  let comment = "";
7123
7123
  if (end) {
7124
7124
  let hasSpace = false;
7125
- let sep2 = "";
7125
+ let sep3 = "";
7126
7126
  for (const token of end) {
7127
7127
  const { source, type } = token;
7128
7128
  switch (type) {
@@ -7136,13 +7136,13 @@ var require_resolve_end = __commonJS({
7136
7136
  if (!comment)
7137
7137
  comment = cb;
7138
7138
  else
7139
- comment += sep2 + cb;
7140
- sep2 = "";
7139
+ comment += sep3 + cb;
7140
+ sep3 = "";
7141
7141
  break;
7142
7142
  }
7143
7143
  case "newline":
7144
7144
  if (comment)
7145
- sep2 += source;
7145
+ sep3 += source;
7146
7146
  hasSpace = true;
7147
7147
  break;
7148
7148
  default:
@@ -7185,18 +7185,18 @@ var require_resolve_flow_collection = __commonJS({
7185
7185
  let offset = fc.offset + fc.start.source.length;
7186
7186
  for (let i = 0; i < fc.items.length; ++i) {
7187
7187
  const collItem = fc.items[i];
7188
- const { start, key, sep: sep2, value } = collItem;
7188
+ const { start, key, sep: sep3, value } = collItem;
7189
7189
  const props = resolveProps.resolveProps(start, {
7190
7190
  flow: fcName,
7191
7191
  indicator: "explicit-key-ind",
7192
- next: key ?? sep2?.[0],
7192
+ next: key ?? sep3?.[0],
7193
7193
  offset,
7194
7194
  onError,
7195
7195
  parentIndent: fc.indent,
7196
7196
  startOnNewline: false
7197
7197
  });
7198
7198
  if (!props.found) {
7199
- if (!props.anchor && !props.tag && !sep2 && !value) {
7199
+ if (!props.anchor && !props.tag && !sep3 && !value) {
7200
7200
  if (i === 0 && props.comma)
7201
7201
  onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
7202
7202
  else if (i < fc.items.length - 1)
@@ -7250,8 +7250,8 @@ var require_resolve_flow_collection = __commonJS({
7250
7250
  }
7251
7251
  }
7252
7252
  }
7253
- if (!isMap && !sep2 && !props.found) {
7254
- const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep2, null, props, onError);
7253
+ if (!isMap && !sep3 && !props.found) {
7254
+ const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep3, null, props, onError);
7255
7255
  coll.items.push(valueNode);
7256
7256
  offset = valueNode.range[2];
7257
7257
  if (isBlock(value))
@@ -7263,7 +7263,7 @@ var require_resolve_flow_collection = __commonJS({
7263
7263
  if (isBlock(key))
7264
7264
  onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
7265
7265
  ctx.atKey = false;
7266
- const valueProps = resolveProps.resolveProps(sep2 ?? [], {
7266
+ const valueProps = resolveProps.resolveProps(sep3 ?? [], {
7267
7267
  flow: fcName,
7268
7268
  indicator: "map-value-ind",
7269
7269
  next: value,
@@ -7274,8 +7274,8 @@ var require_resolve_flow_collection = __commonJS({
7274
7274
  });
7275
7275
  if (valueProps.found) {
7276
7276
  if (!isMap && !props.found && ctx.options.strict) {
7277
- if (sep2)
7278
- for (const st of sep2) {
7277
+ if (sep3)
7278
+ for (const st of sep3) {
7279
7279
  if (st === valueProps.found)
7280
7280
  break;
7281
7281
  if (st.type === "newline") {
@@ -7292,7 +7292,7 @@ var require_resolve_flow_collection = __commonJS({
7292
7292
  else
7293
7293
  onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
7294
7294
  }
7295
- const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep2, null, valueProps, onError) : null;
7295
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep3, null, valueProps, onError) : null;
7296
7296
  if (valueNode) {
7297
7297
  if (isBlock(value))
7298
7298
  onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
@@ -7472,7 +7472,7 @@ var require_resolve_block_scalar = __commonJS({
7472
7472
  chompStart = i + 1;
7473
7473
  }
7474
7474
  let value = "";
7475
- let sep2 = "";
7475
+ let sep3 = "";
7476
7476
  let prevMoreIndented = false;
7477
7477
  for (let i = 0; i < contentStart; ++i)
7478
7478
  value += lines[i][0].slice(trimIndent) + "\n";
@@ -7489,24 +7489,24 @@ var require_resolve_block_scalar = __commonJS({
7489
7489
  indent = "";
7490
7490
  }
7491
7491
  if (type === Scalar.Scalar.BLOCK_LITERAL) {
7492
- value += sep2 + indent.slice(trimIndent) + content;
7493
- sep2 = "\n";
7492
+ value += sep3 + indent.slice(trimIndent) + content;
7493
+ sep3 = "\n";
7494
7494
  } else if (indent.length > trimIndent || content[0] === " ") {
7495
- if (sep2 === " ")
7496
- sep2 = "\n";
7497
- else if (!prevMoreIndented && sep2 === "\n")
7498
- sep2 = "\n\n";
7499
- value += sep2 + indent.slice(trimIndent) + content;
7500
- sep2 = "\n";
7495
+ if (sep3 === " ")
7496
+ sep3 = "\n";
7497
+ else if (!prevMoreIndented && sep3 === "\n")
7498
+ sep3 = "\n\n";
7499
+ value += sep3 + indent.slice(trimIndent) + content;
7500
+ sep3 = "\n";
7501
7501
  prevMoreIndented = true;
7502
7502
  } else if (content === "") {
7503
- if (sep2 === "\n")
7503
+ if (sep3 === "\n")
7504
7504
  value += "\n";
7505
7505
  else
7506
- sep2 = "\n";
7506
+ sep3 = "\n";
7507
7507
  } else {
7508
- value += sep2 + content;
7509
- sep2 = " ";
7508
+ value += sep3 + content;
7509
+ sep3 = " ";
7510
7510
  prevMoreIndented = false;
7511
7511
  }
7512
7512
  }
@@ -7684,25 +7684,25 @@ var require_resolve_flow_scalar = __commonJS({
7684
7684
  if (!match)
7685
7685
  return source;
7686
7686
  let res = match[1];
7687
- let sep2 = " ";
7687
+ let sep3 = " ";
7688
7688
  let pos = first.lastIndex;
7689
7689
  line.lastIndex = pos;
7690
7690
  while (match = line.exec(source)) {
7691
7691
  if (match[1] === "") {
7692
- if (sep2 === "\n")
7693
- res += sep2;
7692
+ if (sep3 === "\n")
7693
+ res += sep3;
7694
7694
  else
7695
- sep2 = "\n";
7695
+ sep3 = "\n";
7696
7696
  } else {
7697
- res += sep2 + match[1];
7698
- sep2 = " ";
7697
+ res += sep3 + match[1];
7698
+ sep3 = " ";
7699
7699
  }
7700
7700
  pos = line.lastIndex;
7701
7701
  }
7702
7702
  const last = /[ \t]*(.*)/sy;
7703
7703
  last.lastIndex = pos;
7704
7704
  match = last.exec(source);
7705
- return res + sep2 + (match?.[1] ?? "");
7705
+ return res + sep3 + (match?.[1] ?? "");
7706
7706
  }
7707
7707
  function doubleQuotedValue(source, onError) {
7708
7708
  let res = "";
@@ -8509,14 +8509,14 @@ var require_cst_stringify = __commonJS({
8509
8509
  }
8510
8510
  }
8511
8511
  }
8512
- function stringifyItem({ start, key, sep: sep2, value }) {
8512
+ function stringifyItem({ start, key, sep: sep3, value }) {
8513
8513
  let res = "";
8514
8514
  for (const st of start)
8515
8515
  res += st.source;
8516
8516
  if (key)
8517
8517
  res += stringifyToken(key);
8518
- if (sep2)
8519
- for (const st of sep2)
8518
+ if (sep3)
8519
+ for (const st of sep3)
8520
8520
  res += st.source;
8521
8521
  if (value)
8522
8522
  res += stringifyToken(value);
@@ -9659,18 +9659,18 @@ var require_parser = __commonJS({
9659
9659
  if (this.type === "map-value-ind") {
9660
9660
  const prev = getPrevProps(this.peek(2));
9661
9661
  const start = getFirstKeyStartProps(prev);
9662
- let sep2;
9662
+ let sep3;
9663
9663
  if (scalar.end) {
9664
- sep2 = scalar.end;
9665
- sep2.push(this.sourceToken);
9664
+ sep3 = scalar.end;
9665
+ sep3.push(this.sourceToken);
9666
9666
  delete scalar.end;
9667
9667
  } else
9668
- sep2 = [this.sourceToken];
9668
+ sep3 = [this.sourceToken];
9669
9669
  const map = {
9670
9670
  type: "block-map",
9671
9671
  offset: scalar.offset,
9672
9672
  indent: scalar.indent,
9673
- items: [{ start, key: scalar, sep: sep2 }]
9673
+ items: [{ start, key: scalar, sep: sep3 }]
9674
9674
  };
9675
9675
  this.onKeyLine = true;
9676
9676
  this.stack[this.stack.length - 1] = map;
@@ -9822,15 +9822,15 @@ var require_parser = __commonJS({
9822
9822
  } else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
9823
9823
  const start2 = getFirstKeyStartProps(it.start);
9824
9824
  const key = it.key;
9825
- const sep2 = it.sep;
9826
- sep2.push(this.sourceToken);
9825
+ const sep3 = it.sep;
9826
+ sep3.push(this.sourceToken);
9827
9827
  delete it.key;
9828
9828
  delete it.sep;
9829
9829
  this.stack.push({
9830
9830
  type: "block-map",
9831
9831
  offset: this.offset,
9832
9832
  indent: this.indent,
9833
- items: [{ start: start2, key, sep: sep2 }]
9833
+ items: [{ start: start2, key, sep: sep3 }]
9834
9834
  });
9835
9835
  } else if (start.length > 0) {
9836
9836
  it.sep = it.sep.concat(start, this.sourceToken);
@@ -10024,13 +10024,13 @@ var require_parser = __commonJS({
10024
10024
  const prev = getPrevProps(parent);
10025
10025
  const start = getFirstKeyStartProps(prev);
10026
10026
  fixFlowSeqItems(fc);
10027
- const sep2 = fc.end.splice(1, fc.end.length);
10028
- sep2.push(this.sourceToken);
10027
+ const sep3 = fc.end.splice(1, fc.end.length);
10028
+ sep3.push(this.sourceToken);
10029
10029
  const map = {
10030
10030
  type: "block-map",
10031
10031
  offset: fc.offset,
10032
10032
  indent: fc.indent,
10033
- items: [{ start, key: fc, sep: sep2 }]
10033
+ items: [{ start, key: fc, sep: sep3 }]
10034
10034
  };
10035
10035
  this.onKeyLine = true;
10036
10036
  this.stack[this.stack.length - 1] = map;
@@ -11519,7 +11519,7 @@ function startSpinner(label2, opts = {}) {
11519
11519
  }
11520
11520
 
11521
11521
  // src/lib/provider-auth.ts
11522
- var sleep = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
11522
+ var sleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
11523
11523
  var form = (fields) => new URLSearchParams(fields).toString();
11524
11524
  async function githubAccountId(owner) {
11525
11525
  try {
@@ -12735,6 +12735,7 @@ async function applyMomentSelection(moments) {
12735
12735
 
12736
12736
  // src/lib/project-config.ts
12737
12737
  var import_node_fs4 = require("node:fs");
12738
+ var import_node_path6 = require("node:path");
12738
12739
  var DEFAULTS = { git_moments: [] };
12739
12740
  function isMoment(value) {
12740
12741
  return value === "commit" || value === "push";
@@ -12742,20 +12743,39 @@ function isMoment(value) {
12742
12743
  function parseMoments(raw) {
12743
12744
  return [...new Set(raw.split(",").map((s) => s.trim()).filter(isMoment))];
12744
12745
  }
12745
- function readProjectConfig() {
12746
+ function readConfigFile(path) {
12746
12747
  try {
12747
- if (!(0, import_node_fs4.existsSync)(PROJECT_CONFIG_FILE)) return DEFAULTS;
12748
- const raw = JSON.parse((0, import_node_fs4.readFileSync)(PROJECT_CONFIG_FILE, "utf-8"));
12748
+ if (!(0, import_node_fs4.existsSync)(path)) return null;
12749
+ const raw = JSON.parse((0, import_node_fs4.readFileSync)(path, "utf-8"));
12749
12750
  const moments = Array.isArray(raw.git_moments) ? raw.git_moments.filter(isMoment) : [];
12750
12751
  return { git_moments: [...new Set(moments)] };
12751
12752
  } catch {
12752
12753
  return DEFAULTS;
12753
12754
  }
12754
12755
  }
12756
+ function candidates() {
12757
+ const local = projectPath(PROJECT_CONFIG_FILE);
12758
+ const out = [{ path: local, source: "local" }];
12759
+ const main = mainWorktreeRoot();
12760
+ if (main) {
12761
+ const inherited = (0, import_node_path6.join)(main, PROJECT_CONFIG_FILE);
12762
+ if (inherited !== local) out.push({ path: inherited, source: "main-worktree" });
12763
+ }
12764
+ return out;
12765
+ }
12766
+ function readProjectConfig() {
12767
+ for (const { path, source } of candidates()) {
12768
+ const cfg = readConfigFile(path);
12769
+ if (cfg) return { ...cfg, source, path };
12770
+ }
12771
+ return { ...DEFAULTS, source: "default" };
12772
+ }
12755
12773
  function writeProjectConfig(patch) {
12756
- const next = { ...readProjectConfig(), ...patch };
12757
- (0, import_node_fs4.mkdirSync)(VERITY_DIR, { recursive: true });
12758
- (0, import_node_fs4.writeFileSync)(PROJECT_CONFIG_FILE, JSON.stringify(next, null, 2) + "\n");
12774
+ const { git_moments } = readProjectConfig();
12775
+ const next = { git_moments, ...patch };
12776
+ const target = projectPath(PROJECT_CONFIG_FILE);
12777
+ (0, import_node_fs4.mkdirSync)((0, import_node_path6.dirname)(target), { recursive: true });
12778
+ (0, import_node_fs4.writeFileSync)(target, JSON.stringify(next, null, 2) + "\n");
12759
12779
  return next;
12760
12780
  }
12761
12781
  function resolveGuardMoments(explicit) {
@@ -12765,6 +12785,8 @@ function resolveGuardMoments(explicit) {
12765
12785
 
12766
12786
  // src/lib/plugin-ownership.ts
12767
12787
  var import_node_fs6 = require("node:fs");
12788
+ var import_node_os2 = require("node:os");
12789
+ var import_node_path7 = require("node:path");
12768
12790
 
12769
12791
  // src/lib/stderr-log.ts
12770
12792
  var import_node_fs5 = require("node:fs");
@@ -12825,10 +12847,13 @@ var MARKER_TTL_SECONDS = 24 * 60 * 60;
12825
12847
  function isPluginInvocation() {
12826
12848
  return !!process.env.VERITY_PLUGIN_ROOT;
12827
12849
  }
12850
+ function markerPath() {
12851
+ return projectPath(PLUGIN_MARKER_FILE);
12852
+ }
12828
12853
  function readMarker() {
12829
12854
  try {
12830
- if (!(0, import_node_fs6.existsSync)(PLUGIN_MARKER_FILE)) return null;
12831
- const raw = JSON.parse((0, import_node_fs6.readFileSync)(PLUGIN_MARKER_FILE, "utf-8"));
12855
+ if (!(0, import_node_fs6.existsSync)(markerPath())) return null;
12856
+ const raw = JSON.parse((0, import_node_fs6.readFileSync)(markerPath(), "utf-8"));
12832
12857
  const pluginRoot = typeof raw.plugin_root === "string" ? raw.plugin_root : "";
12833
12858
  if (!pluginRoot) return null;
12834
12859
  return {
@@ -12845,16 +12870,75 @@ function recordPluginOwnership(sessionId) {
12845
12870
  const pluginRoot = process.env.VERITY_PLUGIN_ROOT;
12846
12871
  if (!pluginRoot) return;
12847
12872
  try {
12848
- (0, import_node_fs6.mkdirSync)(VERITY_DIR, { recursive: true });
12873
+ (0, import_node_fs6.mkdirSync)(projectPath(VERITY_DIR), { recursive: true });
12849
12874
  const marker = {
12850
12875
  session_id: sessionId,
12851
12876
  plugin_root: pluginRoot,
12852
12877
  version: process.env.VERITY_PLUGIN_VERSION || null,
12853
12878
  ts: Math.floor(Date.now() / 1e3)
12854
12879
  };
12855
- (0, import_node_fs6.writeFileSync)(PLUGIN_MARKER_FILE, JSON.stringify(marker));
12880
+ (0, import_node_fs6.writeFileSync)(markerPath(), JSON.stringify(marker));
12881
+ } catch {
12882
+ }
12883
+ }
12884
+ function claudeConfigDir() {
12885
+ return process.env.CLAUDE_CONFIG_DIR || (0, import_node_path7.join)((0, import_node_os2.homedir)(), ".claude");
12886
+ }
12887
+ function readJsonFile(path) {
12888
+ try {
12889
+ const parsed = JSON.parse((0, import_node_fs6.readFileSync)(path, "utf-8"));
12890
+ return parsed && typeof parsed === "object" ? parsed : null;
12891
+ } catch {
12892
+ return null;
12893
+ }
12894
+ }
12895
+ function enabledPluginSetting(key) {
12896
+ const files = [
12897
+ projectPath((0, import_node_path7.join)(".claude", "settings.local.json")),
12898
+ projectPath((0, import_node_path7.join)(".claude", "settings.json")),
12899
+ (0, import_node_path7.join)(claudeConfigDir(), "settings.json")
12900
+ ];
12901
+ for (const file of files) {
12902
+ const map = readJsonFile(file)?.enabledPlugins;
12903
+ if (map && typeof map === "object" && key in map) {
12904
+ return map[key] !== false;
12905
+ }
12906
+ }
12907
+ return void 0;
12908
+ }
12909
+ function registrySays(pluginRoot) {
12910
+ const plugins = readJsonFile((0, import_node_path7.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
12911
+ if (!plugins || typeof plugins !== "object") return "unverified";
12912
+ const want = (0, import_node_path7.resolve)(pluginRoot);
12913
+ for (const [key, value] of Object.entries(plugins)) {
12914
+ for (const entry of Array.isArray(value) ? value : []) {
12915
+ const installPath = entry?.installPath;
12916
+ if (typeof installPath === "string" && (0, import_node_path7.resolve)(installPath) === want) {
12917
+ if (enabledPluginSetting(key) === false) return "gone";
12918
+ return (0, import_node_fs6.existsSync)(pluginRoot) ? "live" : "gone";
12919
+ }
12920
+ }
12921
+ }
12922
+ const managed = (0, import_node_path7.resolve)((0, import_node_path7.join)(claudeConfigDir(), "plugins", "cache"));
12923
+ return want === managed || want.startsWith(managed + import_node_path7.sep) ? "gone" : "unverified";
12924
+ }
12925
+ var _live = /* @__PURE__ */ new Map();
12926
+ function pluginLiveness(pluginRoot) {
12927
+ const cached2 = _live.get(pluginRoot);
12928
+ if (cached2 !== void 0) return cached2;
12929
+ const said = registrySays(pluginRoot);
12930
+ _live.set(pluginRoot, said);
12931
+ return said;
12932
+ }
12933
+ function clearStalePluginMarker() {
12934
+ const marker = readMarker();
12935
+ if (!marker || pluginLiveness(marker.plugin_root) !== "gone") return null;
12936
+ try {
12937
+ (0, import_node_fs6.rmSync)(markerPath(), { force: true });
12856
12938
  } catch {
12939
+ return null;
12857
12940
  }
12941
+ return { pluginRoot: marker.plugin_root, version: marker.version };
12858
12942
  }
12859
12943
  function shouldDeferToPlugin(sessionId) {
12860
12944
  if (isPluginInvocation()) {
@@ -12863,13 +12947,24 @@ function shouldDeferToPlugin(sessionId) {
12863
12947
  }
12864
12948
  const marker = readMarker();
12865
12949
  if (!marker) return false;
12866
- if (!(0, import_node_fs6.existsSync)(marker.plugin_root)) return false;
12950
+ const liveness = pluginLiveness(marker.plugin_root);
12951
+ if (liveness === "gone") return false;
12867
12952
  if (sessionId && marker.session_id) return sessionId === marker.session_id;
12953
+ if (liveness !== "live") {
12954
+ logToFileOnly(
12955
+ `plugin ownership: ignoring an unverified marker for ${marker.plugin_root} \u2014 no session id to match and Claude Code does not list that install.`
12956
+ );
12957
+ return false;
12958
+ }
12868
12959
  return Math.floor(Date.now() / 1e3) - marker.ts < MARKER_TTL_SECONDS;
12869
12960
  }
12870
12961
  function pluginActiveHere() {
12962
+ return activePluginInstall() !== null;
12963
+ }
12964
+ function activePluginInstall() {
12871
12965
  const marker = readMarker();
12872
- return !!marker && (0, import_node_fs6.existsSync)(marker.plugin_root);
12966
+ if (!marker || pluginLiveness(marker.plugin_root) !== "live") return null;
12967
+ return { pluginRoot: marker.plugin_root, version: marker.version };
12873
12968
  }
12874
12969
  function deferredToPlugin(command, sessionId) {
12875
12970
  if (!shouldDeferToPlugin(sessionId)) return false;
@@ -12879,21 +12974,63 @@ function deferredToPlugin(command, sessionId) {
12879
12974
  return true;
12880
12975
  }
12881
12976
 
12977
+ // src/lib/hook-wiring.ts
12978
+ function carriesAnyVerityHook(s) {
12979
+ return s.stop || s.intent || s.baseline || s.compact || s.sessionEnd || s.guard;
12980
+ }
12981
+ async function resolveHookWiring() {
12982
+ const settings = await checkAllVerityHooks();
12983
+ const config = readProjectConfig();
12984
+ const gitMoments = { source: config.source, path: config.path };
12985
+ if (!pluginActiveHere()) {
12986
+ return { source: "settings", status: settings, settings, duplicateSettingsHooks: false, gitMoments };
12987
+ }
12988
+ const status = {
12989
+ stop: true,
12990
+ intent: true,
12991
+ baseline: true,
12992
+ compact: true,
12993
+ sessionEnd: true,
12994
+ guard: true,
12995
+ guardOn: config.git_moments
12996
+ };
12997
+ return {
12998
+ source: "plugin",
12999
+ status,
13000
+ settings,
13001
+ duplicateSettingsHooks: carriesAnyVerityHook(settings),
13002
+ gitMoments
13003
+ };
13004
+ }
13005
+
12882
13006
  // src/commands/hooks.ts
12883
13007
  var ALL_MOMENTS = ["stop", "pre-commit", "pre-push"];
12884
- function parseMoments2(raw) {
12885
- const seen = /* @__PURE__ */ new Set();
12886
- for (const part of raw.split(",").map((s) => s.trim()).filter(Boolean)) {
12887
- if (ALL_MOMENTS.includes(part)) seen.add(part);
13008
+ function parseMomentSelection(raw) {
13009
+ const parts = raw.split(",").map((s) => s.trim()).filter(Boolean);
13010
+ if (parts.length === 1 && parts[0].toLowerCase() === "none") return { moments: [] };
13011
+ if (parts.length === 0) {
13012
+ return { error: `--moments was empty. Pass one or more of ${ALL_MOMENTS.join(", ")} \u2014 or "none" to gate nothing.` };
13013
+ }
13014
+ const unknown = parts.filter((p) => !ALL_MOMENTS.includes(p));
13015
+ if (unknown.length > 0) {
13016
+ return {
13017
+ error: `--moments: unrecognised ${unknown.length === 1 ? "moment" : "moments"} ${unknown.map((u) => `"${u}"`).join(", ")}. Valid: ${ALL_MOMENTS.join(", ")} \u2014 or "none" to gate nothing.`
13018
+ };
12888
13019
  }
12889
- return ALL_MOMENTS.filter((m) => seen.has(m));
13020
+ const seen = new Set(parts);
13021
+ return { moments: ALL_MOMENTS.filter((m) => seen.has(m)) };
12890
13022
  }
12891
13023
  function registerHooksCommands(program2) {
12892
13024
  const hooks = program2.command("hooks").description("Manage Claude Code hook wiring");
12893
13025
  hooks.command("install").description("Install Verity hooks into Claude Code settings").option("--force", "Overwrite existing Verity hooks").option("--moments <list>", "Reconcile to exactly these moments: stop,pre-commit,pre-push").action(async (opts) => {
12894
13026
  const force = opts.force ?? false;
12895
13027
  if (opts.moments != null) {
12896
- const moments = parseMoments2(opts.moments);
13028
+ const parsed = parseMomentSelection(opts.moments);
13029
+ if ("error" in parsed) {
13030
+ printError(parsed.error);
13031
+ process.exit(1);
13032
+ }
13033
+ const moments = parsed.moments;
12897
13034
  const gitMoments = [
12898
13035
  ...moments.includes("pre-commit") ? ["commit"] : [],
12899
13036
  ...moments.includes("pre-push") ? ["push"] : []
@@ -12954,20 +13091,22 @@ function registerHooksCommands(program2) {
12954
13091
  printInfo(" SessionStart hook: verity baseline capture");
12955
13092
  });
12956
13093
  hooks.command("check").description("Check if Verity hooks are installed").action(async () => {
12957
- const status = await checkAllVerityHooks();
12958
- if (pluginActiveHere()) {
12959
- const moments = readProjectConfig().git_moments;
13094
+ const wiring = await resolveHookWiring();
13095
+ const status = wiring.status;
13096
+ if (wiring.source === "plugin") {
13097
+ const moments = status.guardOn;
13098
+ const inherited = wiring.gitMoments.source === "main-worktree" && wiring.gitMoments.path ? ` (inherited from the main worktree: ${wiring.gitMoments.path})` : "";
12960
13099
  printInfo("Wired by the Verity Claude Code plugin (not .claude/settings.json):");
12961
13100
  printInfo(" Stop hook (verity analyze): installed");
12962
13101
  printInfo(" Intent hook (verity intent capture): installed");
12963
13102
  printInfo(" Baseline hook (verity baseline capture): installed");
12964
13103
  printInfo(
12965
- ` Git-moment gate (verity guard): ${moments.length ? `installed [${moments.join(", ")}]` : "wired but gating nothing"}`
13104
+ ` Git-moment gate (verity guard): ${moments.length ? `installed [${moments.join(", ")}]${inherited}` : "wired but gating nothing"}`
12966
13105
  );
12967
13106
  if (!moments.length) {
12968
13107
  printInfo(' Enable it with "verity config git-moments commit,push".');
12969
13108
  }
12970
- if (status.stop || status.intent || status.baseline || status.guard) {
13109
+ if (wiring.duplicateSettingsHooks) {
12971
13110
  printWarn(" Duplicate hooks also exist in .claude/settings.json. They stand down at run time,");
12972
13111
  printWarn(' but remove them with "verity init --plugin-mode" so the wiring says what it does.');
12973
13112
  }
@@ -13352,8 +13491,8 @@ function isCommandOnlyTurn(input) {
13352
13491
  // src/lib/context-identity.ts
13353
13492
  var import_node_crypto2 = require("node:crypto");
13354
13493
  var import_node_fs8 = require("node:fs");
13355
- var import_node_os2 = require("node:os");
13356
- var import_node_path6 = require("node:path");
13494
+ var import_node_os3 = require("node:os");
13495
+ var import_node_path8 = require("node:path");
13357
13496
  var SHARED_SENTINELS = /* @__PURE__ */ new Set([
13358
13497
  "",
13359
13498
  "-",
@@ -13407,13 +13546,13 @@ function contextIdentity(input) {
13407
13546
  }
13408
13547
  function verityHome() {
13409
13548
  const override = process.env.VERITY_HOME;
13410
- return override && override.trim() ? (0, import_node_path6.resolve)(override) : (0, import_node_path6.join)((0, import_node_os2.homedir)(), ".verity");
13549
+ return override && override.trim() ? (0, import_node_path8.resolve)(override) : (0, import_node_path8.join)((0, import_node_os3.homedir)(), ".verity");
13411
13550
  }
13412
13551
  function dossierDir(identity) {
13413
- return (0, import_node_path6.join)(verityHome(), "sessions", identity.userKey, identity.treeKey, identity.sessionKey);
13552
+ return (0, import_node_path8.join)(verityHome(), "sessions", identity.userKey, identity.treeKey, identity.sessionKey);
13414
13553
  }
13415
13554
  function treeDir(identity) {
13416
- return (0, import_node_path6.join)(verityHome(), "sessions", identity.userKey, identity.treeKey);
13555
+ return (0, import_node_path8.join)(verityHome(), "sessions", identity.userKey, identity.treeKey);
13417
13556
  }
13418
13557
  function scopeIdentity(token, sessionId) {
13419
13558
  const t = (token ?? "").trim();
@@ -13429,7 +13568,7 @@ function sessionScopeKey(token, sessionId) {
13429
13568
  // src/lib/task-context-buffer.ts
13430
13569
  var import_promises6 = require("node:fs/promises");
13431
13570
  var import_node_fs9 = require("node:fs");
13432
- var import_node_path7 = require("node:path");
13571
+ var import_node_path9 = require("node:path");
13433
13572
  var TASK_CONTEXT_DIR = `${VERITY_DIR}/.task-context`;
13434
13573
  var MAX_BUFFER_BYTES = 500 * 1024;
13435
13574
  var MAX_PROMPT_CHARS = 2e3;
@@ -13507,7 +13646,7 @@ async function cleanupTaskContextBuffers() {
13507
13646
  const cutoffMs = Date.now() - RETENTION_DAYS * 24 * 60 * 60 * 1e3;
13508
13647
  for (const file of files) {
13509
13648
  if (!file.endsWith(".jsonl")) continue;
13510
- const filePath = (0, import_node_path7.join)(TASK_CONTEXT_DIR, file);
13649
+ const filePath = (0, import_node_path9.join)(TASK_CONTEXT_DIR, file);
13511
13650
  try {
13512
13651
  const stats = await (0, import_promises6.stat)(filePath);
13513
13652
  if (stats.mtimeMs < cutoffMs) {
@@ -13521,7 +13660,7 @@ async function cleanupTaskContextBuffers() {
13521
13660
  }
13522
13661
  function bufferPath(taskId) {
13523
13662
  const safe = taskId.replace(/[^a-zA-Z0-9_-]/g, "");
13524
- return (0, import_node_path7.join)(TASK_CONTEXT_DIR, `${safe}.jsonl`);
13663
+ return (0, import_node_path9.join)(TASK_CONTEXT_DIR, `${safe}.jsonl`);
13525
13664
  }
13526
13665
  async function appendEntry(taskId, entry) {
13527
13666
  try {
@@ -13547,7 +13686,7 @@ async function appendEntry(taskId, entry) {
13547
13686
  // src/lib/memory-retrieval.ts
13548
13687
  var import_promises7 = require("node:fs/promises");
13549
13688
  var import_node_fs10 = require("node:fs");
13550
- var import_node_path8 = require("node:path");
13689
+ var import_node_path10 = require("node:path");
13551
13690
  var memoryDir = () => projectPath(`${VERITY_DIR}/memory`);
13552
13691
  var DOMAINS = ["decisions", "quality", "security", "intent", "gotchas", "patterns", "domain", "integrations"];
13553
13692
  var DEFAULT_BUDGET_TOKENS = 2e3;
@@ -13645,14 +13784,14 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
13645
13784
  const promptTokens = tokenize(promptText);
13646
13785
  const nodes = [];
13647
13786
  for (const domain of DOMAINS) {
13648
- const domainDir = (0, import_node_path8.join)(memoryDir(), domain);
13787
+ const domainDir = (0, import_node_path10.join)(memoryDir(), domain);
13649
13788
  if (!(0, import_node_fs10.existsSync)(domainDir)) continue;
13650
13789
  try {
13651
13790
  const files = await (0, import_promises7.readdir)(domainDir);
13652
13791
  for (const file of files) {
13653
13792
  if (!file.endsWith(".md")) continue;
13654
13793
  try {
13655
- const content = await (0, import_promises7.readFile)((0, import_node_path8.join)(domainDir, file), "utf-8");
13794
+ const content = await (0, import_promises7.readFile)((0, import_node_path10.join)(domainDir, file), "utf-8");
13656
13795
  const { fm, body } = parseFrontmatter(content);
13657
13796
  if (fm.status && fm.status !== "active") continue;
13658
13797
  nodes.push({
@@ -13712,26 +13851,26 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
13712
13851
  // src/lib/memory-sync.ts
13713
13852
  var import_promises8 = require("node:fs/promises");
13714
13853
  var import_node_fs12 = require("node:fs");
13715
- var import_node_path10 = require("node:path");
13854
+ var import_node_path12 = require("node:path");
13716
13855
  var import_node_crypto3 = require("node:crypto");
13717
13856
 
13718
13857
  // src/lib/safe-path.ts
13719
13858
  var import_node_fs11 = require("node:fs");
13720
- var import_node_path9 = require("node:path");
13859
+ var import_node_path11 = require("node:path");
13721
13860
  function resolveInside(baseDir, candidate) {
13722
13861
  if (typeof candidate !== "string" || candidate.length === 0) return null;
13723
- if ((0, import_node_path9.isAbsolute)(candidate)) return null;
13724
- const baseAbs = (0, import_node_path9.resolve)(baseDir);
13725
- const full = (0, import_node_path9.resolve)(baseAbs, candidate);
13726
- const baseSep = baseAbs.endsWith(import_node_path9.sep) ? baseAbs : baseAbs + import_node_path9.sep;
13862
+ if ((0, import_node_path11.isAbsolute)(candidate)) return null;
13863
+ const baseAbs = (0, import_node_path11.resolve)(baseDir);
13864
+ const full = (0, import_node_path11.resolve)(baseAbs, candidate);
13865
+ const baseSep = baseAbs.endsWith(import_node_path11.sep) ? baseAbs : baseAbs + import_node_path11.sep;
13727
13866
  if (full !== baseAbs && !full.startsWith(baseSep)) return null;
13728
13867
  try {
13729
13868
  if ((0, import_node_fs11.existsSync)(baseAbs)) {
13730
13869
  const realBase = (0, import_node_fs11.realpathSync)(baseAbs);
13731
- const realBaseSep = realBase.endsWith(import_node_path9.sep) ? realBase : realBase + import_node_path9.sep;
13870
+ const realBaseSep = realBase.endsWith(import_node_path11.sep) ? realBase : realBase + import_node_path11.sep;
13732
13871
  let probe = full;
13733
13872
  while (!(0, import_node_fs11.existsSync)(probe)) {
13734
- const parent = (0, import_node_path9.dirname)(probe);
13873
+ const parent = (0, import_node_path11.dirname)(probe);
13735
13874
  if (parent === probe) break;
13736
13875
  probe = parent;
13737
13876
  }
@@ -13812,16 +13951,16 @@ var syncStateFile = () => projectPath(`${VERITY_DIR}/.memory-sync-state.json`);
13812
13951
  async function ensureMemoryDir() {
13813
13952
  await (0, import_promises8.mkdir)(memoryDir2(), { recursive: true });
13814
13953
  for (const domain of DOMAINS2) {
13815
- await (0, import_promises8.mkdir)((0, import_node_path10.join)(memoryDir2(), domain), { recursive: true });
13954
+ await (0, import_promises8.mkdir)((0, import_node_path12.join)(memoryDir2(), domain), { recursive: true });
13816
13955
  }
13817
- if (!(0, import_node_fs12.existsSync)((0, import_node_path10.join)(memoryDir2(), "SCHEMA.md"))) {
13818
- await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
13956
+ if (!(0, import_node_fs12.existsSync)((0, import_node_path12.join)(memoryDir2(), "SCHEMA.md"))) {
13957
+ await (0, import_promises8.writeFile)((0, import_node_path12.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
13819
13958
  }
13820
- if (!(0, import_node_fs12.existsSync)((0, import_node_path10.join)(memoryDir2(), "index.md"))) {
13821
- await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
13959
+ if (!(0, import_node_fs12.existsSync)((0, import_node_path12.join)(memoryDir2(), "index.md"))) {
13960
+ await (0, import_promises8.writeFile)((0, import_node_path12.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
13822
13961
  }
13823
- if (!(0, import_node_fs12.existsSync)((0, import_node_path10.join)(memoryDir2(), "log.md"))) {
13824
- await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
13962
+ if (!(0, import_node_fs12.existsSync)((0, import_node_path12.join)(memoryDir2(), "log.md"))) {
13963
+ await (0, import_promises8.writeFile)((0, import_node_path12.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
13825
13964
  }
13826
13965
  }
13827
13966
  async function buildManifest() {
@@ -13830,14 +13969,14 @@ async function buildManifest() {
13830
13969
  }
13831
13970
  const nodes = [];
13832
13971
  for (const domain of DOMAINS2) {
13833
- const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
13972
+ const domainDir = (0, import_node_path12.join)(memoryDir2(), domain);
13834
13973
  if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
13835
13974
  try {
13836
13975
  const files = await (0, import_promises8.readdir)(domainDir);
13837
13976
  for (const file of files) {
13838
13977
  if (!file.endsWith(".md")) continue;
13839
13978
  const filePath = `${domain}/${file}`;
13840
- const fullPath = (0, import_node_path10.join)(memoryDir2(), filePath);
13979
+ const fullPath = (0, import_node_path12.join)(memoryDir2(), filePath);
13841
13980
  try {
13842
13981
  const content = await (0, import_promises8.readFile)(fullPath, "utf-8");
13843
13982
  const hash = (0, import_node_crypto3.createHash)("sha256").update(content).digest("hex").slice(0, 16);
@@ -13850,13 +13989,13 @@ async function buildManifest() {
13850
13989
  }
13851
13990
  let indexHash = null;
13852
13991
  try {
13853
- const indexContent = await (0, import_promises8.readFile)((0, import_node_path10.join)(memoryDir2(), "index.md"), "utf-8");
13992
+ const indexContent = await (0, import_promises8.readFile)((0, import_node_path12.join)(memoryDir2(), "index.md"), "utf-8");
13854
13993
  indexHash = `sha256:${(0, import_node_crypto3.createHash)("sha256").update(indexContent).digest("hex").slice(0, 16)}`;
13855
13994
  } catch {
13856
13995
  }
13857
13996
  let logLength = 0;
13858
13997
  try {
13859
- const logContent = await (0, import_promises8.readFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), "utf-8");
13998
+ const logContent = await (0, import_promises8.readFile)((0, import_node_path12.join)(memoryDir2(), "log.md"), "utf-8");
13860
13999
  logLength = logContent.split("\n").length;
13861
14000
  } catch {
13862
14001
  }
@@ -13869,13 +14008,13 @@ async function readOnDiskNodes() {
13869
14008
  const out = /* @__PURE__ */ new Map();
13870
14009
  if (!(0, import_node_fs12.existsSync)(memoryDir2())) return out;
13871
14010
  for (const domain of DOMAINS2) {
13872
- const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
14011
+ const domainDir = (0, import_node_path12.join)(memoryDir2(), domain);
13873
14012
  if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
13874
14013
  try {
13875
14014
  for (const file of await (0, import_promises8.readdir)(domainDir)) {
13876
14015
  if (!file.endsWith(".md")) continue;
13877
14016
  try {
13878
- out.set(`${domain}/${file}`, hashContent(await (0, import_promises8.readFile)((0, import_node_path10.join)(domainDir, file), "utf-8")));
14017
+ out.set(`${domain}/${file}`, hashContent(await (0, import_promises8.readFile)((0, import_node_path12.join)(domainDir, file), "utf-8")));
13879
14018
  } catch {
13880
14019
  }
13881
14020
  }
@@ -13921,7 +14060,7 @@ async function computeEditedNodeUploads() {
13921
14060
  const uploads = [];
13922
14061
  for (const [path, prevHash] of prev) {
13923
14062
  if (prevHash == null) continue;
13924
- const full = (0, import_node_path10.join)(memoryDir2(), path);
14063
+ const full = (0, import_node_path12.join)(memoryDir2(), path);
13925
14064
  if (!(0, import_node_fs12.existsSync)(full)) continue;
13926
14065
  let content;
13927
14066
  try {
@@ -13958,8 +14097,8 @@ async function applyMemoryWrites(writes, opts = {}) {
13958
14097
  const logLines = [`- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)} \u2014 Applied ${count} write(s) from server`];
13959
14098
  for (const n of notes) logLines.push(` - ${n}`);
13960
14099
  try {
13961
- const existing = (0, import_node_fs12.existsSync)((0, import_node_path10.join)(memoryDir2(), "log.md")) ? await (0, import_promises8.readFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
13962
- await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
14100
+ const existing = (0, import_node_fs12.existsSync)((0, import_node_path12.join)(memoryDir2(), "log.md")) ? await (0, import_promises8.readFile)((0, import_node_path12.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
14101
+ await (0, import_promises8.writeFile)((0, import_node_path12.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
13963
14102
  } catch {
13964
14103
  }
13965
14104
  await recordSyncedNodePaths();
@@ -13991,7 +14130,7 @@ async function applyOneWrite(write, treePaths) {
13991
14130
  return { written: false, notes };
13992
14131
  }
13993
14132
  }
13994
- await (0, import_promises8.mkdir)((0, import_node_path10.dirname)(fullPath), { recursive: true });
14133
+ await (0, import_promises8.mkdir)((0, import_node_path12.dirname)(fullPath), { recursive: true });
13995
14134
  await (0, import_promises8.writeFile)(fullPath, content);
13996
14135
  return { written: true, notes };
13997
14136
  }
@@ -14032,7 +14171,7 @@ async function regenerateIndex() {
14032
14171
  ];
14033
14172
  let totalNodes = 0;
14034
14173
  for (const domain of DOMAINS2.filter((d) => d !== "_archive")) {
14035
- const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
14174
+ const domainDir = (0, import_node_path12.join)(memoryDir2(), domain);
14036
14175
  if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
14037
14176
  try {
14038
14177
  const files = await (0, import_promises8.readdir)(domainDir);
@@ -14043,7 +14182,7 @@ async function regenerateIndex() {
14043
14182
  for (const file of mdFiles.sort()) {
14044
14183
  const slug = file.replace(/\.md$/, "");
14045
14184
  try {
14046
- const content = await (0, import_promises8.readFile)((0, import_node_path10.join)(domainDir, file), "utf-8");
14185
+ const content = await (0, import_promises8.readFile)((0, import_node_path12.join)(domainDir, file), "utf-8");
14047
14186
  const title = pickFrontmatter(content, "title") ?? slug;
14048
14187
  const kind = pickFrontmatter(content, "kind") ?? "-";
14049
14188
  const confidence = pickFrontmatter(content, "confidence");
@@ -14067,7 +14206,7 @@ async function regenerateIndex() {
14067
14206
  lines.push("No nodes yet. Run an analysis to start building the knowledge graph.");
14068
14207
  }
14069
14208
  const next = lines.join("\n") + "\n";
14070
- const indexPath = (0, import_node_path10.join)(memoryDir2(), "index.md");
14209
+ const indexPath = (0, import_node_path12.join)(memoryDir2(), "index.md");
14071
14210
  let existing = null;
14072
14211
  try {
14073
14212
  existing = await (0, import_promises8.readFile)(indexPath, "utf-8");
@@ -14301,7 +14440,7 @@ function hasLegacyMemoryBlock(text) {
14301
14440
  return findMarker(text, LEGACY_MD_START) !== -1;
14302
14441
  }
14303
14442
  async function ensureClaudeMdPointer(cwd = repoRoot()) {
14304
- const claudeMdPath = (0, import_node_path10.join)(cwd, "CLAUDE.md");
14443
+ const claudeMdPath = (0, import_node_path12.join)(cwd, "CLAUDE.md");
14305
14444
  let existing = "";
14306
14445
  if ((0, import_node_fs12.existsSync)(claudeMdPath)) {
14307
14446
  existing = await (0, import_promises8.readFile)(claudeMdPath, "utf-8");
@@ -14441,7 +14580,7 @@ Body content (\u22648KB). Use [[node-id]] wikilinks for cross-references.
14441
14580
  // src/lib/dossier-session.ts
14442
14581
  var import_node_fs17 = require("node:fs");
14443
14582
  var import_node_crypto7 = require("node:crypto");
14444
- var import_node_path13 = require("node:path");
14583
+ var import_node_path15 = require("node:path");
14445
14584
 
14446
14585
  // src/lib/pending-repeat.ts
14447
14586
  var STOP = /* @__PURE__ */ new Set([
@@ -14547,7 +14686,7 @@ function statementAnchorKey(file, patternId) {
14547
14686
  // src/lib/dossier/log.ts
14548
14687
  var import_node_crypto4 = require("node:crypto");
14549
14688
  var import_node_fs13 = require("node:fs");
14550
- var import_node_path11 = require("node:path");
14689
+ var import_node_path13 = require("node:path");
14551
14690
  var CRC_TABLE = (() => {
14552
14691
  const t = new Int32Array(256);
14553
14692
  for (let i = 0; i < 256; i++) {
@@ -14570,9 +14709,9 @@ function openDossier(identity) {
14570
14709
  return {
14571
14710
  dir,
14572
14711
  identity,
14573
- eventsPath: (0, import_node_path11.join)(dir, "events.jsonl"),
14574
- foldPath: (0, import_node_path11.join)(dir, "fold.json"),
14575
- rotatedDir: (0, import_node_path11.join)(dir, "rotated")
14712
+ eventsPath: (0, import_node_path13.join)(dir, "events.jsonl"),
14713
+ foldPath: (0, import_node_path13.join)(dir, "fold.json"),
14714
+ rotatedDir: (0, import_node_path13.join)(dir, "rotated")
14576
14715
  };
14577
14716
  } catch {
14578
14717
  return null;
@@ -14645,11 +14784,11 @@ function rotateIfNeeded2(d) {
14645
14784
  if (!(0, import_node_fs13.existsSync)(d.eventsPath)) return;
14646
14785
  if ((0, import_node_fs13.statSync)(d.eventsPath).size < ROTATE_BYTES) return;
14647
14786
  (0, import_node_fs13.mkdirSync)(d.rotatedDir, { recursive: true, mode: 448 });
14648
- (0, import_node_fs13.renameSync)(d.eventsPath, (0, import_node_path11.join)(d.rotatedDir, `events.${Date.now()}.jsonl`));
14787
+ (0, import_node_fs13.renameSync)(d.eventsPath, (0, import_node_path13.join)(d.rotatedDir, `events.${Date.now()}.jsonl`));
14649
14788
  const kept = (0, import_node_fs13.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
14650
14789
  for (const stale of kept.slice(0, Math.max(0, kept.length - ROTATE_KEEP))) {
14651
14790
  try {
14652
- (0, import_node_fs13.renameSync)((0, import_node_path11.join)(d.rotatedDir, stale), (0, import_node_path11.join)(d.rotatedDir, `${stale}.pruned`));
14791
+ (0, import_node_fs13.renameSync)((0, import_node_path13.join)(d.rotatedDir, stale), (0, import_node_path13.join)(d.rotatedDir, `${stale}.pruned`));
14653
14792
  } catch {
14654
14793
  }
14655
14794
  }
@@ -14660,7 +14799,7 @@ function rotateIfNeeded2(d) {
14660
14799
  // src/lib/dossier/fold-dossier.ts
14661
14800
  var import_node_crypto5 = require("node:crypto");
14662
14801
  var import_node_fs14 = require("node:fs");
14663
- var import_node_path12 = require("node:path");
14802
+ var import_node_path14 = require("node:path");
14664
14803
  var EMPTY_CAPABILITIES = () => ({
14665
14804
  human_reachable: { value: "unknown", tier: "unknown" },
14666
14805
  authorship_observability: { value: "unknown", tier: "unknown" },
@@ -14716,7 +14855,7 @@ function foldDossier(d, opts = {}) {
14716
14855
  state.meta.rotations = files.length;
14717
14856
  for (const f of files) {
14718
14857
  try {
14719
- ingest((0, import_node_fs14.readFileSync)((0, import_node_path12.join)(d.rotatedDir, f), "utf8"));
14858
+ ingest((0, import_node_fs14.readFileSync)((0, import_node_path14.join)(d.rotatedDir, f), "utf8"));
14720
14859
  } catch {
14721
14860
  state.meta.dropped_lines++;
14722
14861
  }
@@ -15573,16 +15712,16 @@ function foreignAuthoredPaths(identity, opts = {}) {
15573
15712
  for (const entry of (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true })) {
15574
15713
  if (!entry.isDirectory()) continue;
15575
15714
  if (entry.name === identity.sessionKey) continue;
15576
- const log = (0, import_node_path13.join)(dir, entry.name, "events.jsonl");
15715
+ const log = (0, import_node_path15.join)(dir, entry.name, "events.jsonl");
15577
15716
  try {
15578
15717
  if (!(0, import_node_fs17.existsSync)(log)) continue;
15579
15718
  if (now - (0, import_node_fs17.statSync)(log).mtimeMs > windowMs) continue;
15580
15719
  const sib = {
15581
- dir: (0, import_node_path13.join)(dir, entry.name),
15720
+ dir: (0, import_node_path15.join)(dir, entry.name),
15582
15721
  identity,
15583
15722
  eventsPath: log,
15584
- foldPath: (0, import_node_path13.join)(dir, entry.name, "fold.json"),
15585
- rotatedDir: (0, import_node_path13.join)(dir, entry.name, "rotated")
15723
+ foldPath: (0, import_node_path15.join)(dir, entry.name, "fold.json"),
15724
+ rotatedDir: (0, import_node_path15.join)(dir, entry.name, "rotated")
15586
15725
  };
15587
15726
  const state = readFoldCache(sib) ?? foldDossier(sib);
15588
15727
  sessions++;
@@ -15610,22 +15749,22 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
15610
15749
  let removed = 0;
15611
15750
  try {
15612
15751
  const mine = dossierDir(identity);
15613
- const userDir = (0, import_node_path13.dirname)((0, import_node_path13.dirname)(mine));
15752
+ const userDir = (0, import_node_path15.dirname)((0, import_node_path15.dirname)(mine));
15614
15753
  if (!(0, import_node_fs17.existsSync)(userDir)) return 0;
15615
15754
  const cutoff = Date.now() - maxAgeMs;
15616
15755
  for (const tree of (0, import_node_fs17.readdirSync)(userDir, { withFileTypes: true })) {
15617
15756
  if (!tree.isDirectory()) continue;
15618
- const treePath = (0, import_node_path13.join)(userDir, tree.name);
15757
+ const treePath = (0, import_node_path15.join)(userDir, tree.name);
15619
15758
  let live = 0;
15620
15759
  for (const entry of (0, import_node_fs17.readdirSync)(treePath, { withFileTypes: true })) {
15621
15760
  if (!entry.isDirectory()) continue;
15622
- const dir = (0, import_node_path13.join)(treePath, entry.name);
15761
+ const dir = (0, import_node_path15.join)(treePath, entry.name);
15623
15762
  if (dir === mine) {
15624
15763
  live++;
15625
15764
  continue;
15626
15765
  }
15627
15766
  try {
15628
- const log = (0, import_node_path13.join)(dir, "events.jsonl");
15767
+ const log = (0, import_node_path15.join)(dir, "events.jsonl");
15629
15768
  const at = (0, import_node_fs17.existsSync)(log) ? (0, import_node_fs17.statSync)(log).mtimeMs : (0, import_node_fs17.statSync)(dir).mtimeMs;
15630
15769
  if (at < cutoff) {
15631
15770
  (0, import_node_fs17.rmSync)(dir, { recursive: true, force: true });
@@ -15680,7 +15819,7 @@ function recordTurn(d, t) {
15680
15819
  for (const a of t.authored) {
15681
15820
  const origin = a.owner === "subagent" ? "subagent" : "edit_tool";
15682
15821
  const prior = t.known?.authored?.get(a.p);
15683
- const hash = fileHash((0, import_node_path13.join)(root, a.p));
15822
+ const hash = fileHash((0, import_node_path15.join)(root, a.p));
15684
15823
  const hunks = Math.max(0, a.h - (prior?.hunks ?? 0));
15685
15824
  const adds = Math.max(0, a.a - (prior?.adds ?? 0));
15686
15825
  const dels = Math.max(0, a.d - (prior?.dels ?? 0));
@@ -15713,7 +15852,7 @@ function recordTurn(d, t) {
15713
15852
  }
15714
15853
  const seenDivergence = t.known?.divergence ?? /* @__PURE__ */ new Set();
15715
15854
  for (const u of t.unobserved) {
15716
- const hash = fileHash((0, import_node_path13.join)(root, u.p));
15855
+ const hash = fileHash((0, import_node_path15.join)(root, u.p));
15717
15856
  if (seenDivergence.has(divergenceKey(u.p, hash))) continue;
15718
15857
  appendEvent(d, { k: "divergence", kind: "external_mutation", path: u.p, hash });
15719
15858
  }
@@ -15748,7 +15887,7 @@ function recordVerdict(d, v) {
15748
15887
  if (!sent.has(f.file)) continue;
15749
15888
  if (!lines.has(f.file)) {
15750
15889
  try {
15751
- const abs = (0, import_node_path13.join)(root, f.file);
15890
+ const abs = (0, import_node_path15.join)(root, f.file);
15752
15891
  lines.set(f.file, (0, import_node_fs17.existsSync)(abs) ? (0, import_node_fs17.readFileSync)(abs, "utf8").split("\n") : null);
15753
15892
  } catch {
15754
15893
  lines.set(f.file, null);
@@ -15849,7 +15988,7 @@ function recallMemory(d, identity, opts) {
15849
15988
  budgetBytes: opts.budgetBytes,
15850
15989
  readFileLines: (file) => {
15851
15990
  try {
15852
- const abs = (0, import_node_path13.join)(root, file);
15991
+ const abs = (0, import_node_path15.join)(root, file);
15853
15992
  return (0, import_node_fs17.existsSync)(abs) ? (0, import_node_fs17.readFileSync)(abs, "utf8").split("\n") : null;
15854
15993
  } catch {
15855
15994
  return null;
@@ -15995,21 +16134,21 @@ async function fireClassify(prompt, sessionId, globals) {
15995
16134
 
15996
16135
  // src/commands/lifecycle.ts
15997
16136
  var import_node_fs21 = require("node:fs");
15998
- var import_node_path17 = require("node:path");
16137
+ var import_node_path19 = require("node:path");
15999
16138
 
16000
16139
  // src/lib/baseline.ts
16001
16140
  var import_node_fs20 = require("node:fs");
16002
- var import_node_path16 = require("node:path");
16141
+ var import_node_path18 = require("node:path");
16003
16142
  var import_node_crypto9 = require("node:crypto");
16004
16143
 
16005
16144
  // src/lib/snapshot.ts
16006
16145
  var import_node_fs19 = require("node:fs");
16007
- var import_node_path15 = require("node:path");
16146
+ var import_node_path17 = require("node:path");
16008
16147
  var import_node_child_process6 = require("node:child_process");
16009
16148
 
16010
16149
  // src/lib/files.ts
16011
16150
  var import_node_fs18 = require("node:fs");
16012
- var import_node_path14 = require("node:path");
16151
+ var import_node_path16 = require("node:path");
16013
16152
  var LANG_MAP = {
16014
16153
  // Analyzable (static analysis + Gemini)
16015
16154
  ts: "typescript",
@@ -16077,7 +16216,7 @@ var LANG_MAP = {
16077
16216
  mk: "make"
16078
16217
  };
16079
16218
  function detectLanguage(filepath) {
16080
- const ext = (0, import_node_path14.extname)(filepath).slice(1);
16219
+ const ext = (0, import_node_path16.extname)(filepath).slice(1);
16081
16220
  return LANG_MAP[ext] ?? ext;
16082
16221
  }
16083
16222
  function sortByMtime(files) {
@@ -16180,7 +16319,7 @@ function generateSnapshotDiffs(files) {
16180
16319
  const diffs = [];
16181
16320
  for (const file of files) {
16182
16321
  if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
16183
- const snapshotPath = (0, import_node_path15.join)(SNAPSHOT_DIR, file.path);
16322
+ const snapshotPath = (0, import_node_path17.join)(SNAPSHOT_DIR, file.path);
16184
16323
  const language = file.language ?? detectLanguage(file.path);
16185
16324
  if ((0, import_node_fs19.existsSync)(snapshotPath)) {
16186
16325
  const oldContent = (0, import_node_fs19.readFileSync)(snapshotPath, "utf-8");
@@ -16208,16 +16347,16 @@ function saveSnapshots(files) {
16208
16347
  const snapshotPaths = /* @__PURE__ */ new Set();
16209
16348
  for (const file of files) {
16210
16349
  if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
16211
- const snapshotPath = (0, import_node_path15.join)(SNAPSHOT_DIR, file.path);
16350
+ const snapshotPath = (0, import_node_path17.join)(SNAPSHOT_DIR, file.path);
16212
16351
  snapshotPaths.add(snapshotPath);
16213
- (0, import_node_fs19.mkdirSync)((0, import_node_path15.dirname)(snapshotPath), { recursive: true });
16352
+ (0, import_node_fs19.mkdirSync)((0, import_node_path17.dirname)(snapshotPath), { recursive: true });
16214
16353
  (0, import_node_fs19.writeFileSync)(snapshotPath, file.content);
16215
16354
  }
16216
16355
  cleanStaleSnapshots(SNAPSHOT_DIR, snapshotPaths);
16217
16356
  }
16218
16357
  function computeDiff(oldContent, newContent, filePath) {
16219
- const tmpOld = (0, import_node_path15.join)(SNAPSHOT_DIR, ".diff-old.tmp");
16220
- const tmpNew = (0, import_node_path15.join)(SNAPSHOT_DIR, ".diff-new.tmp");
16358
+ const tmpOld = (0, import_node_path17.join)(SNAPSHOT_DIR, ".diff-old.tmp");
16359
+ const tmpNew = (0, import_node_path17.join)(SNAPSHOT_DIR, ".diff-new.tmp");
16221
16360
  try {
16222
16361
  (0, import_node_fs19.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
16223
16362
  (0, import_node_fs19.writeFileSync)(tmpOld, oldContent);
@@ -16250,7 +16389,7 @@ function cleanStaleSnapshots(dir, keepSet) {
16250
16389
  const entries = (0, import_node_fs19.readdirSync)(dir, { withFileTypes: true });
16251
16390
  for (const entry of entries) {
16252
16391
  if (dir === SNAPSHOT_DIR && (entry.name === ".diff-old.tmp" || entry.name === ".diff-new.tmp")) continue;
16253
- const fullPath = (0, import_node_path15.join)(dir, entry.name);
16392
+ const fullPath = (0, import_node_path17.join)(dir, entry.name);
16254
16393
  if (entry.isDirectory()) {
16255
16394
  cleanStaleSnapshots(fullPath, keepSet);
16256
16395
  try {
@@ -16279,13 +16418,13 @@ function sessionKey(sessionId) {
16279
16418
  return (0, import_node_crypto9.createHash)("sha256").update(sessionId).digest("hex").slice(0, 16);
16280
16419
  }
16281
16420
  function sessionDir(key) {
16282
- return (0, import_node_path16.join)(projectPath(BASELINE_DIR), key);
16421
+ return (0, import_node_path18.join)(projectPath(BASELINE_DIR), key);
16283
16422
  }
16284
16423
  function manifestPath(dir) {
16285
- return (0, import_node_path16.join)(dir, "manifest.json");
16424
+ return (0, import_node_path18.join)(dir, "manifest.json");
16286
16425
  }
16287
16426
  function mirrorPath(dir, repoRelPath) {
16288
- return (0, import_node_path16.join)(dir, "files", repoRelPath);
16427
+ return (0, import_node_path18.join)(dir, "files", repoRelPath);
16289
16428
  }
16290
16429
  var CARRY_FILE = `${BASELINE_DIR}/.carry`;
16291
16430
  var CARRY_WINDOW_MS = 12e4;
@@ -16347,7 +16486,7 @@ function captureBaseline(opts = {}) {
16347
16486
  (0, import_node_fs20.rmSync)(dir, { recursive: true, force: true });
16348
16487
  } catch {
16349
16488
  }
16350
- const filesDir = (0, import_node_path16.join)(dir, "files");
16489
+ const filesDir = (0, import_node_path18.join)(dir, "files");
16351
16490
  const mirrored = [];
16352
16491
  try {
16353
16492
  (0, import_node_fs20.mkdirSync)(filesDir, { recursive: true });
@@ -16357,7 +16496,7 @@ function captureBaseline(opts = {}) {
16357
16496
  if (content === null) continue;
16358
16497
  const dest = mirrorPath(dir, p);
16359
16498
  try {
16360
- (0, import_node_fs20.mkdirSync)((0, import_node_path16.dirname)(dest), { recursive: true });
16499
+ (0, import_node_fs20.mkdirSync)((0, import_node_path18.dirname)(dest), { recursive: true });
16361
16500
  (0, import_node_fs20.writeFileSync)(dest, content);
16362
16501
  mirrored.push(p);
16363
16502
  } catch {
@@ -16465,7 +16604,7 @@ function absorbIntoBaseline(paths, sessionId) {
16465
16604
  const content = safeReadForMirror(projectPath(p));
16466
16605
  if (content === null) continue;
16467
16606
  const dest = mirrorPath(dir, p);
16468
- (0, import_node_fs20.mkdirSync)((0, import_node_path16.dirname)(dest), { recursive: true });
16607
+ (0, import_node_fs20.mkdirSync)((0, import_node_path18.dirname)(dest), { recursive: true });
16469
16608
  (0, import_node_fs20.writeFileSync)(dest, content);
16470
16609
  dirty.add(p);
16471
16610
  adopted++;
@@ -16513,7 +16652,7 @@ function pruneOldBaselines() {
16513
16652
  }
16514
16653
  const now = Date.now();
16515
16654
  for (const name of entries) {
16516
- const dir = (0, import_node_path16.join)(root, name);
16655
+ const dir = (0, import_node_path18.join)(root, name);
16517
16656
  const manifest = readManifest(dir);
16518
16657
  if (!manifest) {
16519
16658
  try {
@@ -16701,7 +16840,7 @@ function buildCompactionContext(session) {
16701
16840
  commitsSince: commitsSincePaths(watermark, (state.authored ?? []).map((a) => a.path)),
16702
16841
  readFileLines: (file) => {
16703
16842
  try {
16704
- const abs = (0, import_node_path17.join)(root, file);
16843
+ const abs = (0, import_node_path19.join)(root, file);
16705
16844
  return (0, import_node_fs21.existsSync)(abs) ? (0, import_node_fs21.readFileSync)(abs, "utf8").split("\n") : null;
16706
16845
  } catch {
16707
16846
  return null;
@@ -16738,17 +16877,17 @@ async function readHookStdin() {
16738
16877
  try {
16739
16878
  if (process.stdin.isTTY) return {};
16740
16879
  const chunks = [];
16741
- const timeout = new Promise((resolve4) => setTimeout(() => resolve4({}), 500));
16742
- const read = new Promise((resolve4) => {
16880
+ const timeout = new Promise((resolve5) => setTimeout(() => resolve5({}), 500));
16881
+ const read = new Promise((resolve5) => {
16743
16882
  process.stdin.on("data", (c) => chunks.push(c));
16744
16883
  process.stdin.on("end", () => {
16745
16884
  try {
16746
- resolve4(JSON.parse(Buffer.concat(chunks).toString("utf-8").trim() || "{}"));
16885
+ resolve5(JSON.parse(Buffer.concat(chunks).toString("utf-8").trim() || "{}"));
16747
16886
  } catch {
16748
- resolve4({});
16887
+ resolve5({});
16749
16888
  }
16750
16889
  });
16751
- process.stdin.on("error", () => resolve4({}));
16890
+ process.stdin.on("error", () => resolve5({}));
16752
16891
  process.stdin.resume();
16753
16892
  });
16754
16893
  return await Promise.race([read, timeout]);
@@ -16766,17 +16905,17 @@ var import_yaml3 = __toESM(require_dist());
16766
16905
  var import_node_child_process8 = require("node:child_process");
16767
16906
  var import_node_fs24 = require("node:fs");
16768
16907
  var import_promises9 = require("node:fs/promises");
16769
- var import_node_path20 = require("node:path");
16908
+ var import_node_path22 = require("node:path");
16770
16909
  var import_yaml = __toESM(require_dist());
16771
16910
 
16772
16911
  // src/lib/data-dir.ts
16773
16912
  var import_node_fs22 = require("node:fs");
16774
- var import_node_path18 = require("node:path");
16913
+ var import_node_path20 = require("node:path");
16775
16914
  function resolveDataDir() {
16776
- const candidates = [
16777
- (0, import_node_path18.join)(__dirname, "..", "data"),
16915
+ const candidates2 = [
16916
+ (0, import_node_path20.join)(__dirname, "..", "data"),
16778
16917
  // installed: node_modules/@codacy/verity-cli/data
16779
- (0, import_node_path18.join)(__dirname, "..", "..", "data"),
16918
+ (0, import_node_path20.join)(__dirname, "..", "..", "data"),
16780
16919
  // edge case: nested resolution
16781
16920
  // THE COMMITTED SOURCE, for a source checkout that has not been built.
16782
16921
  // cli/data/skills/ is a BUILD ARTIFACT (scripts/build.js copies client/skills
@@ -16785,14 +16924,14 @@ function resolveDataDir() {
16785
16924
  // without this the synthesizer throws "Could not find Verity skill data"
16786
16925
  // for every test and every `verity` run from source. Resolved from this
16787
16926
  // module's own location, never the cwd: see the warning below.
16788
- (0, import_node_path18.join)(__dirname, "..", "..", "client"),
16927
+ (0, import_node_path20.join)(__dirname, "..", "..", "client"),
16789
16928
  // bundled: cli/bin/ → ../../client
16790
- (0, import_node_path18.join)(__dirname, "..", "..", "..", "client"),
16929
+ (0, import_node_path20.join)(__dirname, "..", "..", "..", "client"),
16791
16930
  // tsx: cli/src/lib/ → ../../../client
16792
16931
  ...process.env.VERITY_DEV_DATA_DIR ? [process.env.VERITY_DEV_DATA_DIR] : []
16793
16932
  ];
16794
- for (const candidate of candidates) {
16795
- if ((0, import_node_fs22.existsSync)((0, import_node_path18.join)(candidate, "skills"))) {
16933
+ for (const candidate of candidates2) {
16934
+ if ((0, import_node_fs22.existsSync)((0, import_node_path20.join)(candidate, "skills"))) {
16796
16935
  return candidate;
16797
16936
  }
16798
16937
  }
@@ -16801,13 +16940,13 @@ function resolveDataDir() {
16801
16940
  );
16802
16941
  }
16803
16942
  function setupDataPath(file) {
16804
- return (0, import_node_path18.join)(resolveDataDir(), "skills", "verity-setup", file);
16943
+ return (0, import_node_path20.join)(resolveDataDir(), "skills", "verity-setup", file);
16805
16944
  }
16806
16945
 
16807
16946
  // src/lib/detect.ts
16808
16947
  var import_node_child_process7 = require("node:child_process");
16809
16948
  var import_node_fs23 = require("node:fs");
16810
- var import_node_path19 = require("node:path");
16949
+ var import_node_path21 = require("node:path");
16811
16950
  var TOOLED_LANGUAGES = /* @__PURE__ */ new Set([
16812
16951
  "typescript",
16813
16952
  "javascript",
@@ -16870,18 +17009,18 @@ function walk(root) {
16870
17009
  for (const entry of entries) {
16871
17010
  if (found.length >= WALK_MAX_FILES) return;
16872
17011
  if (IGNORED_SEGMENTS.includes(entry.name)) continue;
16873
- const full = (0, import_node_path19.join)(dir, entry.name);
17012
+ const full = (0, import_node_path21.join)(dir, entry.name);
16874
17013
  if (entry.isDirectory()) visit(full, depth + 1);
16875
- else if (entry.isFile()) found.push((0, import_node_path19.relative)(root, full));
17014
+ else if (entry.isFile()) found.push((0, import_node_path21.relative)(root, full));
16876
17015
  }
16877
17016
  };
16878
17017
  visit(root, 0);
16879
17018
  return found;
16880
17019
  }
16881
17020
  function languageOf(path) {
16882
- const name = (0, import_node_path19.basename)(path);
17021
+ const name = (0, import_node_path21.basename)(path);
16883
17022
  if (/^Dockerfile(\..+)?$/i.test(name)) return "dockerfile";
16884
- if (!(0, import_node_path19.extname)(name)) return null;
17023
+ if (!(0, import_node_path21.extname)(name)) return null;
16885
17024
  const lang = detectLanguage(path);
16886
17025
  return lang || null;
16887
17026
  }
@@ -16963,12 +17102,12 @@ function declaredDependencies(root, files) {
16963
17102
  if (deps && typeof deps === "object") names2.push(...Object.keys(deps));
16964
17103
  }
16965
17104
  };
16966
- readPackageJson((0, import_node_path19.join)(root, "package.json"));
16967
- const nested = files.filter((f) => f.includes("/") && (0, import_node_path19.basename)(f) === "package.json").slice(0, NESTED_MANIFEST_LIMIT);
16968
- for (const rel of nested) readPackageJson((0, import_node_path19.join)(root, rel));
17105
+ readPackageJson((0, import_node_path21.join)(root, "package.json"));
17106
+ const nested = files.filter((f) => f.includes("/") && (0, import_node_path21.basename)(f) === "package.json").slice(0, NESTED_MANIFEST_LIMIT);
17107
+ for (const rel of nested) readPackageJson((0, import_node_path21.join)(root, rel));
16969
17108
  const pythonManifests = [
16970
- ...["pyproject.toml", "requirements.txt", "Pipfile", "setup.py"].map((f) => (0, import_node_path19.join)(root, f)),
16971
- ...files.filter((f) => f.includes("/") && /(^|\/)(pyproject\.toml|requirements\.txt)$/.test(f)).slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path19.join)(root, f))
17109
+ ...["pyproject.toml", "requirements.txt", "Pipfile", "setup.py"].map((f) => (0, import_node_path21.join)(root, f)),
17110
+ ...files.filter((f) => f.includes("/") && /(^|\/)(pyproject\.toml|requirements\.txt)$/.test(f)).slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path21.join)(root, f))
16972
17111
  ];
16973
17112
  for (const path of pythonManifests) {
16974
17113
  if (!(0, import_node_fs23.existsSync)(path)) continue;
@@ -16983,8 +17122,8 @@ function declaredDependencies(root, files) {
16983
17122
  }
16984
17123
  }
16985
17124
  const goMods = [
16986
- (0, import_node_path19.join)(root, "go.mod"),
16987
- ...files.filter((f) => f.includes("/") && (0, import_node_path19.basename)(f) === "go.mod").slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path19.join)(root, f))
17125
+ (0, import_node_path21.join)(root, "go.mod"),
17126
+ ...files.filter((f) => f.includes("/") && (0, import_node_path21.basename)(f) === "go.mod").slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path21.join)(root, f))
16988
17127
  ];
16989
17128
  for (const path of goMods) {
16990
17129
  if (!(0, import_node_fs23.existsSync)(path)) continue;
@@ -16997,7 +17136,7 @@ function declaredDependencies(root, files) {
16997
17136
  }
16998
17137
  }
16999
17138
  for (const file of ["pom.xml", "build.gradle", "build.gradle.kts", "Gemfile", "Cargo.toml"]) {
17000
- const path = (0, import_node_path19.join)(root, file);
17139
+ const path = (0, import_node_path21.join)(root, file);
17001
17140
  if (!(0, import_node_fs23.existsSync)(path)) continue;
17002
17141
  try {
17003
17142
  const text = (0, import_node_fs23.readFileSync)(path, "utf-8");
@@ -17008,7 +17147,7 @@ function declaredDependencies(root, files) {
17008
17147
  return names2;
17009
17148
  }
17010
17149
  function detectBuildSystem(root, files) {
17011
- const has = (f) => (0, import_node_fs23.existsSync)((0, import_node_path19.join)(root, f)) || files.some((p) => (0, import_node_path19.basename)(p) === f);
17150
+ const has = (f) => (0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, f)) || files.some((p) => (0, import_node_path21.basename)(p) === f);
17012
17151
  if (has("pnpm-lock.yaml")) return "pnpm";
17013
17152
  if (has("yarn.lock")) return "yarn";
17014
17153
  if (has("bun.lock") || has("bun.lockb")) return "bun";
@@ -17025,8 +17164,8 @@ function detectBuildSystem(root, files) {
17025
17164
  }
17026
17165
  function detectArchitecture(root, files) {
17027
17166
  const workspaceMarkers = ["lerna.json", "pnpm-workspace.yaml", "nx.json", "turbo.json", "rush.json"];
17028
- if (workspaceMarkers.some((m) => (0, import_node_fs23.existsSync)((0, import_node_path19.join)(root, m)))) return "monorepo";
17029
- const pkg = readJson((0, import_node_path19.join)(root, "package.json"));
17167
+ if (workspaceMarkers.some((m) => (0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, m)))) return "monorepo";
17168
+ const pkg = readJson((0, import_node_path21.join)(root, "package.json"));
17030
17169
  if (pkg && "workspaces" in pkg) return "monorepo";
17031
17170
  const manifests = files.filter((f) => /(^|\/)(package\.json|go\.mod|pyproject\.toml|Cargo\.toml|pom\.xml)$/.test(f));
17032
17171
  const nested = manifests.filter((f) => f.includes("/"));
@@ -17039,16 +17178,16 @@ function detectArchitecture(root, files) {
17039
17178
  var SAMPLE_LIMIT = 300;
17040
17179
  function measureAvgFileLength(root, files, languages) {
17041
17180
  const primary = new Set(languages.slice(0, 2));
17042
- const candidates = files.filter((f) => {
17181
+ const candidates2 = files.filter((f) => {
17043
17182
  const lang = languageOf(f);
17044
17183
  return lang !== null && primary.has(lang);
17045
17184
  });
17046
- if (candidates.length === 0) return null;
17047
- const stride = Math.max(1, Math.floor(candidates.length / SAMPLE_LIMIT));
17185
+ if (candidates2.length === 0) return null;
17186
+ const stride = Math.max(1, Math.floor(candidates2.length / SAMPLE_LIMIT));
17048
17187
  let total = 0;
17049
17188
  let counted = 0;
17050
- for (let i = 0; i < candidates.length; i += stride) {
17051
- const path = (0, import_node_path19.join)(root, candidates[i]);
17189
+ for (let i = 0; i < candidates2.length; i += stride) {
17190
+ const path = (0, import_node_path21.join)(root, candidates2[i]);
17052
17191
  try {
17053
17192
  if ((0, import_node_fs23.statSync)(path).size > 2 * 1024 * 1024) continue;
17054
17193
  total += (0, import_node_fs23.readFileSync)(path, "utf-8").split("\n").length;
@@ -17076,14 +17215,14 @@ function detectProject(root = repoRoot()) {
17076
17215
  const existingToolConfigs = [];
17077
17216
  for (const [tool, markers] of TOOL_CONFIG_MARKERS) {
17078
17217
  for (const marker of markers) {
17079
- if ((0, import_node_fs23.existsSync)((0, import_node_path19.join)(root, marker))) {
17218
+ if ((0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, marker))) {
17080
17219
  existingToolConfigs.push({ tool, path: `./${marker}` });
17081
17220
  break;
17082
17221
  }
17083
17222
  }
17084
17223
  }
17085
17224
  return {
17086
- projectName: (0, import_node_path19.basename)(root),
17225
+ projectName: (0, import_node_path21.basename)(root),
17087
17226
  languages,
17088
17227
  languageCounts,
17089
17228
  frameworks: matchAll(dependencies, FRAMEWORK_BY_DEPENDENCY),
@@ -17529,7 +17668,7 @@ async function correctVerityMdVersion(opts) {
17529
17668
  }
17530
17669
  async function writeFileTo(relative2, body) {
17531
17670
  const target = projectPath(relative2);
17532
- await (0, import_promises9.mkdir)((0, import_node_path20.dirname)(target), { recursive: true });
17671
+ await (0, import_promises9.mkdir)((0, import_node_path22.dirname)(target), { recursive: true });
17533
17672
  await (0, import_promises9.writeFile)(target, body);
17534
17673
  }
17535
17674
  async function deriveConfigForStandard(standard) {
@@ -18004,7 +18143,11 @@ function registerConfigCommands(program2) {
18004
18143
  });
18005
18144
  config.command("git-moments [moments]").description('Get or set the git moments the guard reviews: commit,push \u2014 or "none"').action((moments) => {
18006
18145
  if (moments === void 0) {
18007
- const current = readProjectConfig().git_moments;
18146
+ const config2 = readProjectConfig();
18147
+ const current = config2.git_moments;
18148
+ if (config2.source === "main-worktree" && config2.path) {
18149
+ printInfo(`Inherited from the main worktree: ${config2.path}`);
18150
+ }
18008
18151
  process.stdout.write((current.length ? current.join(",") : "none") + "\n");
18009
18152
  return;
18010
18153
  }
@@ -18474,8 +18617,14 @@ function timeAgo(isoDate) {
18474
18617
  return `${days}d ago`;
18475
18618
  }
18476
18619
  function registerStatusCommand(program2) {
18477
- program2.command("status").description("Show project quality status").option("--history", "Include recent run history").option("--limit <n>", "Number of history entries", "5").option("--json", "Output raw JSON").action(async (opts) => {
18620
+ program2.command("status").description("Show project quality status").option("--history", "Include recent run history").option("--limit <n>", "Number of history entries (1-100)", "5").option("--json", "Output raw JSON").action(async (opts) => {
18478
18621
  const globals = program2.opts();
18622
+ const rawLimit = String(opts.limit).trim();
18623
+ const limit = /^\d{1,3}$/.test(rawLimit) ? Number(rawLimit) : Number.NaN;
18624
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
18625
+ printError(`--limit must be a whole number between 1 and 100 (got "${opts.limit}").`);
18626
+ process.exit(1);
18627
+ }
18479
18628
  const tokenResult = await resolveToken(globals.token);
18480
18629
  if (!tokenResult.ok) {
18481
18630
  printError(tokenResult.error);
@@ -18513,7 +18662,7 @@ function registerStatusCommand(program2) {
18513
18662
  if (opts.history && !denial) {
18514
18663
  const runsResult = await apiRequest({
18515
18664
  method: "GET",
18516
- path: `/runs?limit=${opts.limit}`,
18665
+ path: `/runs?limit=${limit}`,
18517
18666
  serviceUrl,
18518
18667
  token,
18519
18668
  verbose: globals.verbose
@@ -18553,12 +18702,14 @@ function registerStatusCommand(program2) {
18553
18702
  printInfo(`Standard: v${s.version} (${s.quality_dimensions} quality, ${s.security_patterns} security, ${s.custom_patterns} custom)`);
18554
18703
  printInfo(`Languages: ${s.languages.join(", ")}`);
18555
18704
  }
18556
- const hookStatus = await checkAllVerityHooks();
18705
+ const wiring = await resolveHookWiring();
18706
+ const hookStatus = wiring.status;
18557
18707
  const moments = [];
18558
18708
  if (hookStatus.stop) moments.push("stop");
18559
18709
  if (hookStatus.guardOn.includes("commit")) moments.push("pre-commit");
18560
18710
  if (hookStatus.guardOn.includes("push")) moments.push("pre-push/PR");
18561
- printInfo(`Moments: ${moments.length > 0 ? moments.join(", ") : 'none (run "verity init")'}`);
18711
+ const via = wiring.source === "plugin" ? " (wired by the Verity plugin)" : "";
18712
+ printInfo(`Moments: ${moments.length > 0 ? `${moments.join(", ")}${via}` : 'none (run "verity init")'}`);
18562
18713
  if (!mem) return;
18563
18714
  if (mem.recent_runs) {
18564
18715
  const r = mem.recent_runs;
@@ -18635,7 +18786,7 @@ function registerStatusCommand(program2) {
18635
18786
  if (opts.history) {
18636
18787
  const runsResult = await apiRequest({
18637
18788
  method: "GET",
18638
- path: `/runs?limit=${opts.limit}`,
18789
+ path: `/runs?limit=${limit}`,
18639
18790
  serviceUrl,
18640
18791
  token,
18641
18792
  verbose: globals.verbose
@@ -18826,11 +18977,11 @@ var import_node_fs43 = require("node:fs");
18826
18977
 
18827
18978
  // src/lib/repo-context.ts
18828
18979
  var import_node_child_process9 = require("node:child_process");
18829
- var import_node_os3 = require("node:os");
18980
+ var import_node_os4 = require("node:os");
18830
18981
  function rgInvocations(env = process.env) {
18831
18982
  const out = [{ cmd: "rg" }];
18832
18983
  if (env.CLAUDE_CODE_EXECPATH) out.push({ cmd: env.CLAUDE_CODE_EXECPATH, argv0: "rg" });
18833
- out.push({ cmd: `${(0, import_node_os3.homedir)()}/.local/bin/claude`, argv0: "rg" });
18984
+ out.push({ cmd: `${(0, import_node_os4.homedir)()}/.local/bin/claude`, argv0: "rg" });
18834
18985
  return out;
18835
18986
  }
18836
18987
  var MAX_SYMBOLS = 12;
@@ -19644,9 +19795,9 @@ function installRunEvidence(run2) {
19644
19795
  // src/lib/git-frame.ts
19645
19796
  var import_node_child_process10 = require("node:child_process");
19646
19797
  var import_node_fs31 = require("node:fs");
19647
- var import_node_os4 = require("node:os");
19648
- var import_node_path21 = require("node:path");
19649
- var import_node_path22 = require("node:path");
19798
+ var import_node_os5 = require("node:os");
19799
+ var import_node_path23 = require("node:path");
19800
+ var import_node_path24 = require("node:path");
19650
19801
  var VALUE_TOKEN = `(?:'[^']*'|"[^"]*"|\\S+)`;
19651
19802
  var GIT_GLOBAL_OPTS = `(?:\\s+(?:-[Cc]\\s+${VALUE_TOKEN}|--?[\\w-]+(?:=\\S+)?))*`;
19652
19803
  var COMMIT_HEAD = `git${GIT_GLOBAL_OPTS}\\s+commit(?![\\w-])`;
@@ -19692,15 +19843,15 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
19692
19843
  if (!m) continue;
19693
19844
  named = true;
19694
19845
  if (m[1] === void 0) {
19695
- dir = (0, import_node_os4.homedir)();
19846
+ dir = (0, import_node_os5.homedir)();
19696
19847
  continue;
19697
19848
  }
19698
19849
  const raw = unquote(m[1]);
19699
19850
  if (SHELL_DYNAMIC.test(raw) || raw === "-") {
19700
19851
  return { dir: null, named: true, unresolvable: `cd target not statically resolvable: ${raw}` };
19701
19852
  }
19702
- const expanded = raw === "~" ? (0, import_node_os4.homedir)() : raw.startsWith("~/") ? (0, import_node_path22.join)((0, import_node_os4.homedir)(), raw.slice(2)) : raw;
19703
- dir = (0, import_node_path21.isAbsolute)(expanded) ? expanded : (0, import_node_path21.resolve)(dir, expanded);
19853
+ const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0, import_node_path24.join)((0, import_node_os5.homedir)(), raw.slice(2)) : raw;
19854
+ dir = (0, import_node_path23.isAbsolute)(expanded) ? expanded : (0, import_node_path23.resolve)(dir, expanded);
19704
19855
  }
19705
19856
  const seg = segments[segmentIndex];
19706
19857
  const overrideMatch = /--(?:git-dir|work-tree)(?:=|\s)|\bGIT_(?:DIR|WORK_TREE|INDEX_FILE)=/.exec(seg);
@@ -19718,8 +19869,8 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
19718
19869
  if (SHELL_DYNAMIC.test(raw)) {
19719
19870
  return { dir: null, named: true, unresolvable: `-C target not statically resolvable: ${raw}` };
19720
19871
  }
19721
- const expanded = raw === "~" ? (0, import_node_os4.homedir)() : raw.startsWith("~/") ? (0, import_node_path22.join)((0, import_node_os4.homedir)(), raw.slice(2)) : raw;
19722
- dir = (0, import_node_path21.isAbsolute)(expanded) ? expanded : (0, import_node_path21.resolve)(dir, expanded);
19872
+ const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0, import_node_path24.join)((0, import_node_os5.homedir)(), raw.slice(2)) : raw;
19873
+ dir = (0, import_node_path23.isAbsolute)(expanded) ? expanded : (0, import_node_path23.resolve)(dir, expanded);
19723
19874
  }
19724
19875
  }
19725
19876
  return { dir, named, unresolvable: null };
@@ -19784,7 +19935,7 @@ function realpathOr(p) {
19784
19935
  try {
19785
19936
  return import_node_fs31.realpathSync.native(p);
19786
19937
  } catch {
19787
- return (0, import_node_path21.resolve)(p);
19938
+ return (0, import_node_path23.resolve)(p);
19788
19939
  }
19789
19940
  }
19790
19941
  function resolveFrame(input) {
@@ -19823,7 +19974,7 @@ function resolveFrame(input) {
19823
19974
  const gitDirRaw = gitAt(dir, ["rev-parse", "--absolute-git-dir"]);
19824
19975
  const commonRaw = gitAt(dir, ["rev-parse", "--git-common-dir"]);
19825
19976
  const gitDir = gitDirRaw ? realpathOr(gitDirRaw) : null;
19826
- const commonDir = commonRaw ? realpathOr((0, import_node_path21.isAbsolute)(commonRaw) ? commonRaw : (0, import_node_path21.resolve)(dir, commonRaw)) : null;
19977
+ const commonDir = commonRaw ? realpathOr((0, import_node_path23.isAbsolute)(commonRaw) ? commonRaw : (0, import_node_path23.resolve)(dir, commonRaw)) : null;
19827
19978
  const branchRaw = gitAt(dir, ["rev-parse", "--abbrev-ref", "HEAD"]);
19828
19979
  return {
19829
19980
  moment: found?.moment ?? null,
@@ -19848,14 +19999,172 @@ function refResolves(frame, ref) {
19848
19999
  return frameGit(frame, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]) !== "";
19849
20000
  }
19850
20001
  var SHA_RE2 = /^[0-9a-f]{40}$/;
19851
- function stagedRange(frame) {
20002
+ function shellWords(segment) {
20003
+ return segment.match(/'[^']*'|"[^"]*"|\S+/g) ?? [];
20004
+ }
20005
+ var ADD_FLAGS_REPLAYABLE = /* @__PURE__ */ new Set([
20006
+ "-A",
20007
+ "--all",
20008
+ "--no-ignore-removal",
20009
+ "-u",
20010
+ "--update",
20011
+ "--no-all",
20012
+ "--ignore-removal",
20013
+ "-f",
20014
+ "--force",
20015
+ "-v",
20016
+ "--verbose",
20017
+ "-N",
20018
+ "--intent-to-add",
20019
+ "--renormalize",
20020
+ "--sparse",
20021
+ "--ignore-errors",
20022
+ "--refresh"
20023
+ ]);
20024
+ var ADD_FLAGS_INTERACTIVE = /* @__PURE__ */ new Set(["-i", "--interactive", "-p", "--patch", "-e", "--edit"]);
20025
+ var PATHSPEC_UNRESOLVABLE = /[$`\\*?[\]{}~]/;
20026
+ var COMMIT_VALUE_OPTS = /* @__PURE__ */ new Set([
20027
+ "-m",
20028
+ "--message",
20029
+ "-F",
20030
+ "--file",
20031
+ "-C",
20032
+ "--reuse-message",
20033
+ "-c",
20034
+ "--reedit-message",
20035
+ "--author",
20036
+ "--date",
20037
+ "-t",
20038
+ "--template",
20039
+ "--fixup",
20040
+ "--squash",
20041
+ "--trailer",
20042
+ "--cleanup"
20043
+ ]);
20044
+ var ADD_HEAD = `git${GIT_GLOBAL_OPTS}\\s+add(?![\\w-])`;
20045
+ var ADD_RE = new RegExp(`(?:^|[\\s;&|(])${ADD_HEAD}|(?:^|[;&|(])\\s*[^\\s;&|()'"]*\\/${ADD_HEAD}`);
20046
+ function pathspecOf(word) {
20047
+ const raw = unquote(word);
20048
+ if (!raw) return { reason: "an empty pathspec" };
20049
+ if (PATHSPEC_UNRESOLVABLE.test(raw)) {
20050
+ return { reason: `the shell rewrites the pathspec "${raw}" before git sees it` };
20051
+ }
20052
+ return { path: raw };
20053
+ }
20054
+ function parseAddSegment(segment) {
20055
+ const words = shellWords(segment);
20056
+ const at = words.indexOf("add");
20057
+ if (at === -1) return { reason: 'the "git add" arguments could not be read' };
20058
+ const flags = [];
20059
+ const paths = [];
20060
+ let literal = false;
20061
+ for (const word of words.slice(at + 1)) {
20062
+ if (literal || !word.startsWith("-") || word === "-") {
20063
+ if (word === "--" && !literal) {
20064
+ literal = true;
20065
+ continue;
20066
+ }
20067
+ const p = pathspecOf(word);
20068
+ if ("reason" in p) return p;
20069
+ paths.push(p.path);
20070
+ continue;
20071
+ }
20072
+ if (word === "--") {
20073
+ literal = true;
20074
+ continue;
20075
+ }
20076
+ const parts = /^-[A-Za-z]{2,}$/.test(word) ? [...word.slice(1)].map((c) => `-${c}`) : [word];
20077
+ for (const flag of parts) {
20078
+ if (ADD_FLAGS_INTERACTIVE.has(flag)) {
20079
+ return { reason: `"git add ${flag}" stages what a human picks at a prompt` };
20080
+ }
20081
+ if (!ADD_FLAGS_REPLAYABLE.has(flag.split("=")[0])) {
20082
+ return { reason: `unmodelled "git add" option ${flag}` };
20083
+ }
20084
+ flags.push(flag);
20085
+ }
20086
+ }
20087
+ return { flags, paths };
20088
+ }
20089
+ function commitStagesTrackedChanges(segment) {
20090
+ const words = shellWords(segment);
20091
+ const at = words.indexOf("commit");
20092
+ if (at === -1) return false;
20093
+ let skipValue = false;
20094
+ for (const word of words.slice(at + 1)) {
20095
+ if (skipValue) {
20096
+ skipValue = false;
20097
+ continue;
20098
+ }
20099
+ if (word === "--") break;
20100
+ if (!word.startsWith("-") || word === "-") continue;
20101
+ if (word.startsWith("--")) {
20102
+ const name = word.split("=")[0];
20103
+ if (name === "--all") return true;
20104
+ if (COMMIT_VALUE_OPTS.has(name) && !word.includes("=")) skipValue = true;
20105
+ continue;
20106
+ }
20107
+ for (let i = 1; i < word.length; i++) {
20108
+ const flag = `-${word[i]}`;
20109
+ if (flag === "-a") return true;
20110
+ if (COMMIT_VALUE_OPTS.has(flag)) {
20111
+ if (i === word.length - 1) skipValue = true;
20112
+ break;
20113
+ }
20114
+ }
20115
+ }
20116
+ return false;
20117
+ }
20118
+ function planInCommandStaging(frame, command) {
20119
+ const found = findMomentSegment(command, ["commit"]);
20120
+ if (!found) return { kind: "none" };
20121
+ const segments = splitSegments(command);
20122
+ if (commitStagesTrackedChanges(segments[found.segmentIndex])) {
20123
+ return {
20124
+ kind: "files",
20125
+ via: "index+commit-a",
20126
+ files: frameGit(frame, ["diff", "--name-only", "HEAD"]).split("\n").filter(Boolean)
20127
+ };
20128
+ }
20129
+ const addSegments = segments.slice(0, found.segmentIndex).filter((s) => ADD_RE.test(s));
20130
+ if (addSegments.length === 0) return { kind: "none" };
20131
+ const staged = new Set(
20132
+ frameGit(frame, ["diff", "--cached", "--name-only"]).split("\n").filter(Boolean)
20133
+ );
20134
+ for (const segment of addSegments) {
20135
+ const parsed = parseAddSegment(segment);
20136
+ if ("reason" in parsed) return { kind: "unpredictable", reason: parsed.reason };
20137
+ const args = ["add", "--dry-run", "--ignore-missing", ...parsed.flags];
20138
+ if (parsed.paths.length > 0) args.push("--", ...parsed.paths);
20139
+ for (const line of frameGit(frame, args).split("\n")) {
20140
+ const m = line.match(/^(?:add|remove) '(.*)'$/);
20141
+ if (m) staged.add(m[1]);
20142
+ }
20143
+ }
20144
+ return { kind: "files", via: "index+staged-in-command", files: [...staged] };
20145
+ }
20146
+ function stagedRange(frame, command) {
19852
20147
  if (!frame.worktreeRoot) return { kind: "nothing", base: null, head: "INDEX", via: "refused" };
19853
- const mergeHead = frame.gitDir ? (0, import_node_path22.join)(frame.gitDir, "MERGE_HEAD") : null;
20148
+ const plan = command ? planInCommandStaging(frame, command) : { kind: "none" };
20149
+ if (plan.kind === "unpredictable") {
20150
+ return { kind: "staged", base: "HEAD", head: "INDEX", via: "staged-in-command", refusal: plan.reason };
20151
+ }
20152
+ const mergeHead = frame.gitDir ? (0, import_node_path24.join)(frame.gitDir, "MERGE_HEAD") : null;
19854
20153
  if (mergeHead && (0, import_node_fs31.existsSync)(mergeHead)) {
19855
20154
  const vsHead = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "HEAD"]).split("\n").filter(Boolean));
19856
20155
  const vsMerge = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "MERGE_HEAD"]).split("\n").filter(Boolean));
19857
- const resolutions = [...vsHead].filter((f) => vsMerge.has(f) && !isVerityOwnedPath(f));
19858
- return { kind: "merge", base: "HEAD", head: "INDEX", via: "merge-resolutions", files: resolutions };
20156
+ const resolutions = new Set([...vsHead].filter((f) => vsMerge.has(f) && !isVerityOwnedPath(f)));
20157
+ if (plan.kind === "files") {
20158
+ const wtVsHead = new Set(frameGit(frame, ["diff", "--name-only", "HEAD"]).split("\n").filter(Boolean));
20159
+ const wtVsMerge = new Set(frameGit(frame, ["diff", "--name-only", "MERGE_HEAD"]).split("\n").filter(Boolean));
20160
+ for (const f of plan.files) {
20161
+ if (wtVsHead.has(f) && wtVsMerge.has(f) && !isVerityOwnedPath(f)) resolutions.add(f);
20162
+ }
20163
+ }
20164
+ return { kind: "merge", base: "HEAD", head: "INDEX", via: "merge-resolutions", files: [...resolutions] };
20165
+ }
20166
+ if (plan.kind === "files") {
20167
+ return { kind: "staged", base: "HEAD", head: "INDEX", via: plan.via, files: plan.files };
19859
20168
  }
19860
20169
  return { kind: "staged", base: "HEAD", head: "INDEX", via: "index" };
19861
20170
  }
@@ -20247,7 +20556,7 @@ function sanitizeCommandWithLoss(rawCmd) {
20247
20556
  const lost = lines.slice(1).some((l) => l.trim().length > 0);
20248
20557
  const first = lines[0];
20249
20558
  const cmd = sanitizeCommand(first);
20250
- const hadSeparator = SEPARATORS.some((sep2) => first.indexOf(sep2) > 0);
20559
+ const hadSeparator = SEPARATORS.some((sep3) => first.indexOf(sep3) > 0);
20251
20560
  return { cmd, lost: lost || !hadSeparator && first.length > MAX_COMMAND_CHARS };
20252
20561
  }
20253
20562
  var SEPARATORS = [" | ", " > ", " >> ", " 2>", " && ", " ; "];
@@ -20256,11 +20565,11 @@ function sanitizeCommand(rawCmd) {
20256
20565
  let cmd = rawCmd.split("\n")[0];
20257
20566
  let cut = -1;
20258
20567
  let marker = "";
20259
- for (const sep2 of SEPARATORS) {
20260
- const idx = cmd.indexOf(sep2);
20568
+ for (const sep3 of SEPARATORS) {
20569
+ const idx = cmd.indexOf(sep3);
20261
20570
  if (idx > 0 && (cut === -1 || idx < cut)) {
20262
20571
  cut = idx;
20263
- marker = sep2.trim();
20572
+ marker = sep3.trim();
20264
20573
  }
20265
20574
  }
20266
20575
  if (cut > -1) cmd = cmd.slice(0, cut);
@@ -20284,28 +20593,28 @@ async function readStopHookStdin() {
20284
20593
  try {
20285
20594
  if (process.stdin.isTTY) return empty;
20286
20595
  const chunks = [];
20287
- const timeout = new Promise((resolve4) => setTimeout(() => resolve4(empty), 500));
20288
- const read = new Promise((resolve4) => {
20596
+ const timeout = new Promise((resolve5) => setTimeout(() => resolve5(empty), 500));
20597
+ const read = new Promise((resolve5) => {
20289
20598
  process.stdin.on("data", (chunk) => chunks.push(chunk));
20290
20599
  process.stdin.on("end", () => {
20291
20600
  const raw = Buffer.concat(chunks).toString("utf-8").trim();
20292
20601
  if (!raw) {
20293
- resolve4(empty);
20602
+ resolve5(empty);
20294
20603
  return;
20295
20604
  }
20296
20605
  try {
20297
20606
  const data = JSON.parse(raw);
20298
- resolve4({
20607
+ resolve5({
20299
20608
  assistantMessage: typeof data.last_assistant_message === "string" ? data.last_assistant_message : null,
20300
20609
  stopReason: typeof data.stop_reason === "string" ? data.stop_reason : null,
20301
20610
  transcriptPath: typeof data.transcript_path === "string" ? data.transcript_path : null,
20302
20611
  sessionId: typeof data.session_id === "string" ? data.session_id : null
20303
20612
  });
20304
20613
  } catch {
20305
- resolve4(empty);
20614
+ resolve5(empty);
20306
20615
  }
20307
20616
  });
20308
- process.stdin.on("error", () => resolve4(empty));
20617
+ process.stdin.on("error", () => resolve5(empty));
20309
20618
  process.stdin.resume();
20310
20619
  });
20311
20620
  return await Promise.race([read, timeout]);
@@ -20509,7 +20818,7 @@ function channelSilence(input) {
20509
20818
  // src/lib/cli-version.ts
20510
20819
  function cliVersion() {
20511
20820
  try {
20512
- return true ? "0.32.0-experimental.68ae2ee" : "dev";
20821
+ return true ? "0.32.0-experimental.cc76941" : "dev";
20513
20822
  } catch {
20514
20823
  return "dev";
20515
20824
  }
@@ -20868,7 +21177,7 @@ async function scope(run2) {
20868
21177
 
20869
21178
  // src/lib/specs.ts
20870
21179
  var import_node_fs34 = require("node:fs");
20871
- var import_node_path23 = require("node:path");
21180
+ var import_node_path25 = require("node:path");
20872
21181
  var SPEC_CANDIDATES = [
20873
21182
  "CLAUDE.md",
20874
21183
  "AGENTS.md",
@@ -20941,7 +21250,7 @@ function findMdFiles(dir, maxDepth, depth = 0) {
20941
21250
  try {
20942
21251
  const entries = (0, import_node_fs34.readdirSync)(dir, { withFileTypes: true });
20943
21252
  for (const entry of entries) {
20944
- const fullPath = (0, import_node_path23.join)(dir, entry.name);
21253
+ const fullPath = (0, import_node_path25.join)(dir, entry.name);
20945
21254
  if (entry.isFile() && entry.name.endsWith(".md")) {
20946
21255
  result.push(fullPath);
20947
21256
  } else if (entry.isDirectory() && depth < maxDepth - 1) {
@@ -20953,9 +21262,9 @@ function findMdFiles(dir, maxDepth, depth = 0) {
20953
21262
  return result;
20954
21263
  }
20955
21264
  function discoverPlans() {
20956
- const homePlansDir = (0, import_node_path23.join)(process.env.HOME ?? "", ".claude", "plans");
21265
+ const homePlansDir = (0, import_node_path25.join)(process.env.HOME ?? "", ".claude", "plans");
20957
21266
  const localPlansDir = ".claude/plans";
20958
- const candidates = [];
21267
+ const candidates2 = [];
20959
21268
  const seen = /* @__PURE__ */ new Set();
20960
21269
  for (const plansDir of [localPlansDir, homePlansDir]) {
20961
21270
  if (!(0, import_node_fs34.existsSync)(plansDir)) continue;
@@ -20963,19 +21272,19 @@ function discoverPlans() {
20963
21272
  for (const f of (0, import_node_fs34.readdirSync)(plansDir)) {
20964
21273
  if (!f.endsWith(".md") || seen.has(f)) continue;
20965
21274
  seen.add(f);
20966
- const fullPath = (0, import_node_path23.join)(plansDir, f);
21275
+ const fullPath = (0, import_node_path25.join)(plansDir, f);
20967
21276
  try {
20968
21277
  const stat3 = (0, import_node_fs34.statSync)(fullPath);
20969
- candidates.push({ name: f, path: fullPath, mtime: stat3.mtimeMs, size: stat3.size });
21278
+ candidates2.push({ name: f, path: fullPath, mtime: stat3.mtimeMs, size: stat3.size });
20970
21279
  } catch {
20971
21280
  }
20972
21281
  }
20973
21282
  } catch {
20974
21283
  }
20975
21284
  }
20976
- candidates.sort((a, b) => b.mtime - a.mtime);
21285
+ candidates2.sort((a, b) => b.mtime - a.mtime);
20977
21286
  const result = [];
20978
- for (const entry of candidates.slice(0, MAX_PLAN_FILES)) {
21287
+ for (const entry of candidates2.slice(0, MAX_PLAN_FILES)) {
20979
21288
  if (entry.size > MAX_PLAN_FILE_BYTES) continue;
20980
21289
  try {
20981
21290
  const content = (0, import_node_fs34.readFileSync)(entry.path, "utf-8");
@@ -21175,7 +21484,7 @@ async function mode(run2) {
21175
21484
 
21176
21485
  // src/lib/fold.ts
21177
21486
  var import_node_fs35 = require("node:fs");
21178
- var import_node_path24 = require("node:path");
21487
+ var import_node_path26 = require("node:path");
21179
21488
  var KNOWN_RECORD_TYPES = /* @__PURE__ */ new Set([
21180
21489
  "user",
21181
21490
  "assistant",
@@ -21407,9 +21716,9 @@ function fold(transcriptPath, opts = {}) {
21407
21716
  return result;
21408
21717
  }
21409
21718
  try {
21410
- const sidecarDir = (0, import_node_path24.join)(
21411
- (0, import_node_path24.dirname)(transcriptPath),
21412
- (0, import_node_path24.basename)(transcriptPath).replace(/\.jsonl$/, ""),
21719
+ const sidecarDir = (0, import_node_path26.join)(
21720
+ (0, import_node_path26.dirname)(transcriptPath),
21721
+ (0, import_node_path26.basename)(transcriptPath).replace(/\.jsonl$/, ""),
21413
21722
  "subagents"
21414
21723
  );
21415
21724
  if ((0, import_node_fs35.existsSync)(sidecarDir)) {
@@ -21419,7 +21728,7 @@ function fold(transcriptPath, opts = {}) {
21419
21728
  const walk2 = (d, depth) => {
21420
21729
  if (depth > 4) return;
21421
21730
  for (const e of (0, import_node_fs35.readdirSync)(d, { withFileTypes: true })) {
21422
- const p = (0, import_node_path24.join)(d, e.name);
21731
+ const p = (0, import_node_path26.join)(d, e.name);
21423
21732
  if (e.isDirectory()) {
21424
21733
  walk2(p, depth + 1);
21425
21734
  } else if (e.name.startsWith("agent-") && e.name.endsWith(".jsonl")) {
@@ -21794,7 +22103,7 @@ async function evidence(run2) {
21794
22103
 
21795
22104
  // src/lib/cache-cleanup.ts
21796
22105
  var import_node_fs36 = require("node:fs");
21797
- var import_node_path25 = require("node:path");
22106
+ var import_node_path27 = require("node:path");
21798
22107
  var CACHE_TTL_DAYS = 7;
21799
22108
  function pruneStaleCache() {
21800
22109
  try {
@@ -21802,7 +22111,7 @@ function pruneStaleCache() {
21802
22111
  const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
21803
22112
  for (const entry of (0, import_node_fs36.readdirSync)(dir)) {
21804
22113
  if (!entry.startsWith("pending-")) continue;
21805
- const path = (0, import_node_path25.join)(dir, entry);
22114
+ const path = (0, import_node_path27.join)(dir, entry);
21806
22115
  try {
21807
22116
  const stat3 = (0, import_node_fs36.statSync)(path);
21808
22117
  if (stat3.mtimeMs < cutoff) {
@@ -21821,7 +22130,7 @@ function pruneStaleCache() {
21821
22130
 
21822
22131
  // src/lib/context-files.ts
21823
22132
  var import_node_fs37 = require("node:fs");
21824
- var import_node_os5 = require("node:os");
22133
+ var import_node_os6 = require("node:os");
21825
22134
  var MAX_CONTEXT_FILES = 10;
21826
22135
  var MAX_CONTEXT_FILE_BYTES = 10240;
21827
22136
  var MAX_CONTEXT_TOTAL_BYTES = 24576;
@@ -21829,7 +22138,7 @@ function readSetContextPaths(summary, deltaFiles) {
21829
22138
  const reads = summary?.files_read ?? [];
21830
22139
  if (reads.length === 0) return [];
21831
22140
  const root = process.cwd().replace(/\/+$/, "");
21832
- const home = (0, import_node_os5.homedir)();
22141
+ const home = (0, import_node_os6.homedir)();
21833
22142
  const toRepoRelative2 = (p) => {
21834
22143
  if (!p) return null;
21835
22144
  let abs;
@@ -21970,7 +22279,7 @@ async function repoContext(run2) {
21970
22279
  // src/lib/seed-runner.ts
21971
22280
  var import_promises14 = require("node:fs/promises");
21972
22281
  var import_node_fs38 = require("node:fs");
21973
- var import_node_path26 = require("node:path");
22282
+ var import_node_path28 = require("node:path");
21974
22283
  var import_yaml4 = __toESM(require_dist());
21975
22284
 
21976
22285
  // src/lib/seed.ts
@@ -22237,7 +22546,7 @@ async function runSeed(opts) {
22237
22546
  }
22238
22547
  }
22239
22548
  }
22240
- const candidates = deriveSeedNodes({
22549
+ const candidates2 = deriveSeedNodes({
22241
22550
  knowledgeSpec: {
22242
22551
  project_name: knowledgeSpec.project_name,
22243
22552
  languages: knowledgeSpec.languages,
@@ -22249,20 +22558,20 @@ async function runSeed(opts) {
22249
22558
  readmeContent,
22250
22559
  claudeMdContent
22251
22560
  });
22252
- if (candidates.length === 0) {
22561
+ if (candidates2.length === 0) {
22253
22562
  return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
22254
22563
  }
22255
- const overviewPath = (0, import_node_path26.join)(MEMORY_DIR, "domain", "project-overview.md");
22564
+ const overviewPath = (0, import_node_path28.join)(MEMORY_DIR, "domain", "project-overview.md");
22256
22565
  if ((0, import_node_fs38.existsSync)(overviewPath) && !opts.force) {
22257
- return { created: 0, failed: 0, skipped: "already_seeded", candidates };
22566
+ return { created: 0, failed: 0, skipped: "already_seeded", candidates: candidates2 };
22258
22567
  }
22259
22568
  if (opts.dryRun) {
22260
- return { created: 0, failed: 0, skipped: null, candidates };
22569
+ return { created: 0, failed: 0, skipped: null, candidates: candidates2 };
22261
22570
  }
22262
22571
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
22263
22572
  let created = 0;
22264
22573
  let failed = 0;
22265
- for (const c of candidates) {
22574
+ for (const c of candidates2) {
22266
22575
  const res = await apiRequest({
22267
22576
  method: "POST",
22268
22577
  path: "/compound/memory/nodes",
@@ -22295,7 +22604,7 @@ async function runSeed(opts) {
22295
22604
  continue;
22296
22605
  }
22297
22606
  try {
22298
- await (0, import_promises14.mkdir)((0, import_node_path26.dirname)(targetPath), { recursive: true });
22607
+ await (0, import_promises14.mkdir)((0, import_node_path28.dirname)(targetPath), { recursive: true });
22299
22608
  await (0, import_promises14.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
22300
22609
  created++;
22301
22610
  opts.onCreated?.(nodeId, filePathRel, c);
@@ -22304,12 +22613,12 @@ async function runSeed(opts) {
22304
22613
  failed++;
22305
22614
  }
22306
22615
  }
22307
- return { created, failed, skipped: null, candidates };
22616
+ return { created, failed, skipped: null, candidates: candidates2 };
22308
22617
  }
22309
22618
 
22310
22619
  // src/commands/analyze/phases/08-memory-manifest.ts
22311
22620
  var import_node_fs39 = require("node:fs");
22312
- var import_node_path27 = require("node:path");
22621
+ var import_node_path29 = require("node:path");
22313
22622
  async function memoryManifest(run2) {
22314
22623
  const { globals } = run2;
22315
22624
  const { serviceUrl, token } = run2;
@@ -22319,7 +22628,7 @@ async function memoryManifest(run2) {
22319
22628
  let autoSeedNotice = null;
22320
22629
  try {
22321
22630
  await ensureMemoryDir();
22322
- const seedMarker = (0, import_node_path27.join)(VERITY_DIR, ".seeded");
22631
+ const seedMarker = (0, import_node_path29.join)(VERITY_DIR, ".seeded");
22323
22632
  const hasStandard = (0, import_node_fs39.existsSync)(STANDARD_FILE);
22324
22633
  const alreadyTried = (0, import_node_fs39.existsSync)(seedMarker);
22325
22634
  if (hasStandard && !alreadyTried) {
@@ -22437,7 +22746,7 @@ function computeIncrement(reviewedPaths, hashOf, priorAuthored) {
22437
22746
  }
22438
22747
 
22439
22748
  // src/commands/analyze/phases/10-working-memory.ts
22440
- var import_node_path28 = require("node:path");
22749
+ var import_node_path30 = require("node:path");
22441
22750
  async function workingMemory(run2) {
22442
22751
  const { opts } = run2;
22443
22752
  const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run2;
@@ -22449,7 +22758,7 @@ async function workingMemory(run2) {
22449
22758
  const priorState = foldForMarks(memorySession.d);
22450
22759
  incrementReport = computeIncrement(
22451
22760
  allForReview,
22452
- (p) => fileHash((0, import_node_path28.join)(repoRoot(), p)),
22761
+ (p) => fileHash((0, import_node_path30.join)(repoRoot(), p)),
22453
22762
  priorState.authored_all.map((a) => ({
22454
22763
  path: a.path,
22455
22764
  hash_at_last_verdict: a.hash_at_last_verdict
@@ -23014,7 +23323,7 @@ async function transmit(run2) {
23014
23323
 
23015
23324
  // src/commands/analyze/phases/13-reconcile.ts
23016
23325
  var import_node_fs42 = require("node:fs");
23017
- var import_node_path29 = require("node:path");
23326
+ var import_node_path31 = require("node:path");
23018
23327
  async function reconcile(run2) {
23019
23328
  const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run2;
23020
23329
  const sentPaths = codeDelta.files.map((f) => f.path);
@@ -23043,7 +23352,7 @@ async function reconcile(run2) {
23043
23352
  const st = foldDossier(memorySession.d);
23044
23353
  openElsewhere = openBlockingElsewhere(st.statements, sentPaths, (file, line) => {
23045
23354
  try {
23046
- const src = (0, import_node_fs42.readFileSync)((0, import_node_path29.join)(repoRoot(), file), "utf8").split("\n");
23355
+ const src = (0, import_node_fs42.readFileSync)((0, import_node_path31.join)(repoRoot(), file), "utf8").split("\n");
23047
23356
  const at = src[line - 1];
23048
23357
  return at === void 0 ? null : lineSha(at);
23049
23358
  } catch {
@@ -23895,14 +24204,14 @@ async function runReview(opts, globals) {
23895
24204
 
23896
24205
  // src/commands/guard.ts
23897
24206
  var import_node_fs45 = require("node:fs");
23898
- var import_node_path30 = require("node:path");
24207
+ var import_node_path32 = require("node:path");
23899
24208
  var GUARD_BLOCK_CAP = 2;
23900
- var GUARD_ITER_FILE = (0, import_node_path30.join)(VERITY_DIR, ".guard-iteration");
24209
+ var GUARD_ITER_FILE = (0, import_node_path32.join)(VERITY_DIR, ".guard-iteration");
23901
24210
  function readPreToolUseStdin() {
23902
24211
  const empty = { command: "", cwd: null, sessionId: null };
23903
- return new Promise((resolve4) => {
24212
+ return new Promise((resolve5) => {
23904
24213
  try {
23905
- if (process.stdin.isTTY) return resolve4(empty);
24214
+ if (process.stdin.isTTY) return resolve5(empty);
23906
24215
  const chunks = [];
23907
24216
  let timer;
23908
24217
  let settled = false;
@@ -23915,7 +24224,7 @@ function readPreToolUseStdin() {
23915
24224
  process.stdin.removeListener("end", onEnd);
23916
24225
  process.stdin.removeListener("error", onError);
23917
24226
  process.stdin.pause();
23918
- resolve4(value);
24227
+ resolve5(value);
23919
24228
  };
23920
24229
  const onEnd = () => {
23921
24230
  try {
@@ -23936,7 +24245,7 @@ function readPreToolUseStdin() {
23936
24245
  process.stdin.on("error", onError);
23937
24246
  process.stdin.resume();
23938
24247
  } catch {
23939
- resolve4(empty);
24248
+ resolve5(empty);
23940
24249
  }
23941
24250
  });
23942
24251
  }
@@ -23994,7 +24303,7 @@ function registerGuardCommand(program2) {
23994
24303
  });
23995
24304
  }
23996
24305
  function resolveMomentRange(moment, frame, command, on) {
23997
- return moment === "pre-commit" ? stagedRange(frame) : resolvePushRange(frame, command, on);
24306
+ return moment === "pre-commit" ? stagedRange(frame, command) : resolvePushRange(frame, command, on);
23998
24307
  }
23999
24308
  function describeRange(range) {
24000
24309
  if (range.kind === "staged") return "staged";
@@ -24154,6 +24463,13 @@ async function runGuard(opts, globals) {
24154
24463
  );
24155
24464
  }
24156
24465
  const range = resolveMomentRange(moment, frame, command, on);
24466
+ if (range.refusal) {
24467
+ logEvent("guard_frame", { moment, ...frameTelemetry(frame, range) });
24468
+ emitAllowNotice(
24469
+ `\u26A0 Verity ${moment}: could not tell what this ${verb} will include \u2014 ${verb === "commit" ? "committed" : "pushed"} WITHOUT review`,
24470
+ `Verity ${moment}: this command stages files as it runs and the resulting set could not be resolved (${range.refusal}); the ${verb} was allowed WITHOUT a Verity review. Stage first (\`git add \u2026\`) and re-run the ${verb} to have it reviewed.`
24471
+ );
24472
+ }
24157
24473
  const files = rangeFiles(frame, range);
24158
24474
  if (files.length === 0) process.exit(0);
24159
24475
  const tokenResult = await resolveToken(globals.token);
@@ -24189,7 +24505,7 @@ async function runGuard(opts, globals) {
24189
24505
  upgradeToExcerpts(repoContext2, {
24190
24506
  readFile: (rel) => {
24191
24507
  try {
24192
- return (0, import_node_fs45.readFileSync)((0, import_node_path30.join)(frame.worktreeRoot ?? process.cwd(), rel), "utf8");
24508
+ return (0, import_node_fs45.readFileSync)((0, import_node_path32.join)(frame.worktreeRoot ?? process.cwd(), rel), "utf8");
24193
24509
  } catch {
24194
24510
  return null;
24195
24511
  }
@@ -24258,21 +24574,28 @@ async function runGuard(opts, globals) {
24258
24574
  ${covDetail}${viewUrl ? `
24259
24575
  Report: ${viewUrl}` : ""}`
24260
24576
  );
24261
- }
24262
- if (decision === "WARN") {
24577
+ } else if (decision === "WARN") {
24263
24578
  emitAllowNotice(
24264
24579
  `\u26A0 Verity ${moment}: WARN \u2014 proceeding (${covLine})${link}`,
24265
24580
  `Verity ${moment} review: WARN (proceeding).
24266
24581
  ${covDetail}${viewUrl ? `
24267
24582
  Report: ${viewUrl}` : ""}`
24268
24583
  );
24269
- }
24270
- emitAllowNotice(
24271
- `\u2713 Verity ${moment}: PASS (${covLine})${link}`,
24272
- `Verity ${moment} review: PASS.
24584
+ } else if (decision === "PASS") {
24585
+ emitAllowNotice(
24586
+ `\u2713 Verity ${moment}: PASS (${covLine})${link}`,
24587
+ `Verity ${moment} review: PASS.
24273
24588
  ${covDetail}${viewUrl ? `
24274
24589
  Report: ${viewUrl}` : ""}`
24275
- );
24590
+ );
24591
+ } else {
24592
+ emitAllowNotice(
24593
+ `\u26A0 Verity ${moment}: no verdict came back \u2014 ${verb === "commit" ? "committed" : "pushed"} WITHOUT a usable review (${covLine})${link}`,
24594
+ `Verity ${moment}: the service answered with no recognisable gate decision (${decision}); the ${verb} was allowed, but nothing reviewed it. Treat this as unreviewed, not as a pass.
24595
+ ${covDetail}${viewUrl ? `
24596
+ Report: ${viewUrl}` : ""}`
24597
+ );
24598
+ }
24276
24599
  }
24277
24600
  function writeBlockMessage(moment, response, covDetail) {
24278
24601
  const label2 = moment === "pre-commit" ? "pre-commit" : "pre-push";
@@ -24467,7 +24790,7 @@ function registerWaiveCommand(program2) {
24467
24790
  var import_node_fs51 = require("node:fs");
24468
24791
  var import_promises17 = require("node:fs/promises");
24469
24792
  var import_yaml6 = __toESM(require_dist());
24470
- var import_node_path33 = require("node:path");
24793
+ var import_node_path35 = require("node:path");
24471
24794
  var import_node_child_process16 = require("node:child_process");
24472
24795
 
24473
24796
  // src/lib/banner.ts
@@ -24504,8 +24827,8 @@ function printBanner(opts) {
24504
24827
  const dim = (text) => color ? `${DIM3}${text}${RESET2}` : text;
24505
24828
  process.stderr.write("\n");
24506
24829
  if (!art) {
24507
- const candidates = [`Verity ${version}`, "Verity"];
24508
- const text = candidates.find((c) => c.length + INDENT.length <= columns);
24830
+ const candidates2 = [`Verity ${version}`, "Verity"];
24831
+ const text = candidates2.find((c) => c.length + INDENT.length <= columns);
24509
24832
  if (text) process.stderr.write(`${INDENT}${dim(text)}
24510
24833
  `);
24511
24834
  process.stderr.write("\n");
@@ -24612,13 +24935,13 @@ function checkAnalysisCli() {
24612
24935
  }
24613
24936
  var INSTALL_TIMEOUT_MS = 12e4;
24614
24937
  function run(command, args, opts = {}) {
24615
- return new Promise((resolve4) => {
24938
+ return new Promise((resolve5) => {
24616
24939
  const child = (0, import_node_child_process13.spawn)(command, args, {
24617
24940
  stdio: opts.inherit ? "inherit" : "pipe",
24618
24941
  timeout: INSTALL_TIMEOUT_MS
24619
24942
  });
24620
- child.on("error", () => resolve4(false));
24621
- child.on("close", (code) => resolve4(code === 0));
24943
+ child.on("error", () => resolve5(false));
24944
+ child.on("close", (code) => resolve5(code === 0));
24622
24945
  });
24623
24946
  }
24624
24947
  async function installAnalysisCli() {
@@ -24717,8 +25040,8 @@ function ensureVerityGitignore() {
24717
25040
  next = lines.map((l) => BREAKING_ENTRIES.has(l.trim()) ? ".verity/*" : l).join("\n");
24718
25041
  }
24719
25042
  if (!hasMarker) {
24720
- const sep2 = next === "" ? "" : next.endsWith("\n") ? "\n" : "\n\n";
24721
- next = next + sep2 + VERITY_GITIGNORE_BLOCK;
25043
+ const sep3 = next === "" ? "" : next.endsWith("\n") ? "\n" : "\n\n";
25044
+ next = next + sep3 + VERITY_GITIGNORE_BLOCK;
24722
25045
  }
24723
25046
  (0, import_node_fs47.writeFileSync)(".gitignore", next);
24724
25047
  return verified(needsRepair ? "repaired" : "added");
@@ -24845,7 +25168,8 @@ async function uninstallTelemetry() {
24845
25168
  async function buildReport() {
24846
25169
  const prereqs = await checkPrereqs({ install: false });
24847
25170
  const state = await readSetupState();
24848
- const hooks = await checkAllVerityHooks();
25171
+ const wiring = await resolveHookWiring();
25172
+ const hooks = wiring.status;
24849
25173
  const telemetry = await checkTelemetry();
24850
25174
  const hasConfig = (0, import_node_fs48.existsSync)(projectPath(CODACY_CONFIG_FILE));
24851
25175
  const artifacts = {
@@ -24884,6 +25208,11 @@ async function buildReport() {
24884
25208
  'Your analysis config names pattern ids that no longer resolve, so those tools run with nothing enabled and report zero issues. Fix: "verity standard synthesize --config-only" (or re-run "verity init").'
24885
25209
  );
24886
25210
  }
25211
+ if (wiring.duplicateSettingsHooks) {
25212
+ next.push(
25213
+ '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.'
25214
+ );
25215
+ }
24887
25216
  if (state?.telemetry === "deferred") {
24888
25217
  next.push('Telemetry was requested but needs a token \u2014 run "verity login", then "verity telemetry install".');
24889
25218
  }
@@ -24899,7 +25228,12 @@ async function buildReport() {
24899
25228
  moments: state?.moments ?? null,
24900
25229
  telemetry: state?.telemetry ?? null
24901
25230
  },
24902
- hooks: { ...hooks, noAnalysisMoment },
25231
+ hooks: {
25232
+ source: wiring.source,
25233
+ ...hooks,
25234
+ duplicateSettingsHooks: wiring.duplicateSettingsHooks,
25235
+ noAnalysisMoment
25236
+ },
24903
25237
  telemetry: { enabled: telemetry.enabled, endpoint: telemetry.endpoint },
24904
25238
  artifacts,
24905
25239
  next
@@ -24922,8 +25256,9 @@ function registerDoctorCommand(program2) {
24922
25256
  printInfo(` verity init: ${report.phases.init.done ? `done ${report.phases.init.completed_at ?? ""}`.trim() : "NOT run here"}`);
24923
25257
  printInfo(` /verity-setup: ${report.phases.setup.done ? "done" : "not completed"}`);
24924
25258
  printInfo(` intensity: ${report.answers.intensity ?? "\u2014"} moments: ${report.answers.moments?.join(", ") ?? "\u2014"}`);
24925
- printInfo("Hooks:");
24926
- printInfo(` Stop (verity analyze): ${report.hooks.stop ? "on" : "off"}`);
25259
+ const plugin = report.hooks.source === "plugin";
25260
+ printInfo(plugin ? "Hooks: wired by the Verity Claude Code plugin (not .claude/settings.json)" : "Hooks:");
25261
+ printInfo(` Stop (verity analyze): ${report.hooks.stop ? plugin ? "on (plugin)" : "on" : "off"}`);
24927
25262
  printInfo(` Git-moment gate: ${report.hooks.guardOn.length ? report.hooks.guardOn.join(", ") : "off"}`);
24928
25263
  printInfo(` Infra (intent/baseline/compact/session-end): ${[report.hooks.intent, report.hooks.baseline, report.hooks.compact, report.hooks.sessionEnd].filter(Boolean).length}/4`);
24929
25264
  printInfo(`Telemetry: ${report.telemetry.enabled ? `enabled \u2192 ${report.telemetry.endpoint}` : "disabled"}`);
@@ -24946,7 +25281,7 @@ function registerDoctorCommand(program2) {
24946
25281
 
24947
25282
  // src/commands/migrate.ts
24948
25283
  var import_node_fs49 = require("node:fs");
24949
- var import_node_path31 = require("node:path");
25284
+ var import_node_path33 = require("node:path");
24950
25285
  var import_node_child_process15 = require("node:child_process");
24951
25286
  var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
24952
25287
  function defaultNpmRemover(pkg) {
@@ -24983,8 +25318,8 @@ async function runMigration(opts = {}) {
24983
25318
  return { actions, migrated: actions.length > 0 };
24984
25319
  }
24985
25320
  function migrateProjectDir(root, actions) {
24986
- const gateDir = (0, import_node_path31.join)(root, ".gate");
24987
- const verityDir = (0, import_node_path31.join)(root, ".verity");
25321
+ const gateDir = (0, import_node_path33.join)(root, ".gate");
25322
+ const verityDir = (0, import_node_path33.join)(root, ".verity");
24988
25323
  if ((0, import_node_fs49.existsSync)(gateDir) && !(0, import_node_fs49.existsSync)(verityDir)) {
24989
25324
  return migrateProjectDirRename(root, gateDir, verityDir, actions);
24990
25325
  }
@@ -25038,11 +25373,11 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
25038
25373
  }
25039
25374
  function migrateGlobalCredentials(home, actions) {
25040
25375
  if (!home) return;
25041
- const gateCreds = (0, import_node_path31.join)(home, ".gate", "credentials");
25042
- const verityCreds = (0, import_node_path31.join)(home, ".verity", "credentials");
25376
+ const gateCreds = (0, import_node_path33.join)(home, ".gate", "credentials");
25377
+ const verityCreds = (0, import_node_path33.join)(home, ".verity", "credentials");
25043
25378
  if (!(0, import_node_fs49.existsSync)(gateCreds)) return;
25044
25379
  if (!(0, import_node_fs49.existsSync)(verityCreds)) {
25045
- (0, import_node_fs49.mkdirSync)((0, import_node_path31.join)(home, ".verity"), { recursive: true });
25380
+ (0, import_node_fs49.mkdirSync)((0, import_node_path33.join)(home, ".verity"), { recursive: true });
25046
25381
  moveFile(gateCreds, verityCreds);
25047
25382
  actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
25048
25383
  return;
@@ -25064,7 +25399,7 @@ async function migrateLegacyHooks(root, actions) {
25064
25399
  }
25065
25400
  }
25066
25401
  async function migrateClaudeMd(root, actions) {
25067
- const claudeMd = (0, import_node_path31.join)(root, "CLAUDE.md");
25402
+ const claudeMd = (0, import_node_path33.join)(root, "CLAUDE.md");
25068
25403
  const hadLegacyBlock = (0, import_node_fs49.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
25069
25404
  if (!hadLegacyBlock) return;
25070
25405
  try {
@@ -25075,8 +25410,8 @@ async function migrateClaudeMd(root, actions) {
25075
25410
  }
25076
25411
  }
25077
25412
  function migrateStandardFile(root, actions) {
25078
- const gateMd = (0, import_node_path31.join)(root, "GATE.md");
25079
- const verityMd = (0, import_node_path31.join)(root, "VERITY.md");
25413
+ const gateMd = (0, import_node_path33.join)(root, "GATE.md");
25414
+ const verityMd = (0, import_node_path33.join)(root, "VERITY.md");
25080
25415
  if (!(0, import_node_fs49.existsSync)(gateMd) || (0, import_node_fs49.existsSync)(verityMd)) return;
25081
25416
  let moved = false;
25082
25417
  if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
@@ -25093,7 +25428,7 @@ function migrateStandardFile(root, actions) {
25093
25428
  actions.push("Renamed GATE.md \u2192 VERITY.md");
25094
25429
  }
25095
25430
  async function migrateTelemetryHeaders(root, actions) {
25096
- const file = (0, import_node_path31.join)(root, ".claude", "settings.local.json");
25431
+ const file = (0, import_node_path33.join)(root, ".claude", "settings.local.json");
25097
25432
  if (!(0, import_node_fs49.existsSync)(file)) return;
25098
25433
  let settings;
25099
25434
  try {
@@ -25141,8 +25476,8 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
25141
25476
  toAppend.push(line.replace(/\r$/, ""));
25142
25477
  }
25143
25478
  if (toAppend.length > 0) {
25144
- const sep2 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
25145
- (0, import_node_fs49.writeFileSync)(verityCreds, verityContent + sep2 + toAppend.join("\n") + "\n");
25479
+ const sep3 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
25480
+ (0, import_node_fs49.writeFileSync)(verityCreds, verityContent + sep3 + toAppend.join("\n") + "\n");
25146
25481
  }
25147
25482
  (0, import_node_fs49.rmSync)(gateCreds, { force: true });
25148
25483
  return toAppend.length;
@@ -25183,15 +25518,15 @@ function moveFile(from, to) {
25183
25518
  function carryLegacyContents(gateDir, verityDir) {
25184
25519
  let copied = 0;
25185
25520
  const walk2 = (relDir) => {
25186
- const srcDir = (0, import_node_path31.join)(gateDir, relDir);
25521
+ const srcDir = (0, import_node_path33.join)(gateDir, relDir);
25187
25522
  for (const entry of (0, import_node_fs49.readdirSync)(srcDir)) {
25188
- const rel = relDir ? (0, import_node_path31.join)(relDir, entry) : entry;
25189
- const src = (0, import_node_path31.join)(gateDir, rel);
25190
- const dest = (0, import_node_path31.join)(verityDir, rel);
25523
+ const rel = relDir ? (0, import_node_path33.join)(relDir, entry) : entry;
25524
+ const src = (0, import_node_path33.join)(gateDir, rel);
25525
+ const dest = (0, import_node_path33.join)(verityDir, rel);
25191
25526
  if ((0, import_node_fs49.statSync)(src).isDirectory()) {
25192
25527
  walk2(rel);
25193
25528
  } else if (!(0, import_node_fs49.existsSync)(dest)) {
25194
- (0, import_node_fs49.mkdirSync)((0, import_node_path31.dirname)(dest), { recursive: true });
25529
+ (0, import_node_fs49.mkdirSync)((0, import_node_path33.dirname)(dest), { recursive: true });
25195
25530
  (0, import_node_fs49.cpSync)(src, dest);
25196
25531
  copied++;
25197
25532
  }
@@ -25201,22 +25536,22 @@ function carryLegacyContents(gateDir, verityDir) {
25201
25536
  return copied;
25202
25537
  }
25203
25538
  async function needsMigration(root = repoRoot()) {
25204
- const gateDir = (0, import_node_path31.join)(root, ".gate");
25205
- const verityDir = (0, import_node_path31.join)(root, ".verity");
25539
+ const gateDir = (0, import_node_path33.join)(root, ".gate");
25540
+ const verityDir = (0, import_node_path33.join)(root, ".verity");
25206
25541
  if ((0, import_node_fs49.existsSync)(gateDir) && !(0, import_node_fs49.existsSync)(verityDir)) return true;
25207
25542
  if ((0, import_node_fs49.existsSync)(gateDir) && (0, import_node_fs49.existsSync)(verityDir)) {
25208
- if ((0, import_node_fs49.existsSync)((0, import_node_path31.join)(gateDir, "credentials")) && !(0, import_node_fs49.existsSync)((0, import_node_path31.join)(verityDir, "credentials"))) {
25543
+ if ((0, import_node_fs49.existsSync)((0, import_node_path33.join)(gateDir, "credentials")) && !(0, import_node_fs49.existsSync)((0, import_node_path33.join)(verityDir, "credentials"))) {
25209
25544
  return true;
25210
25545
  }
25211
- if ((0, import_node_fs49.existsSync)((0, import_node_path31.join)(gateDir, "memory")) && !(0, import_node_fs49.existsSync)((0, import_node_path31.join)(verityDir, "memory"))) {
25546
+ if ((0, import_node_fs49.existsSync)((0, import_node_path33.join)(gateDir, "memory")) && !(0, import_node_fs49.existsSync)((0, import_node_path33.join)(verityDir, "memory"))) {
25212
25547
  return true;
25213
25548
  }
25214
25549
  }
25215
- const claudeMd = (0, import_node_path31.join)(root, "CLAUDE.md");
25550
+ const claudeMd = (0, import_node_path33.join)(root, "CLAUDE.md");
25216
25551
  if ((0, import_node_fs49.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
25217
25552
  return true;
25218
25553
  }
25219
- if ((0, import_node_fs49.existsSync)((0, import_node_path31.join)(root, "GATE.md")) && !(0, import_node_fs49.existsSync)((0, import_node_path31.join)(root, "VERITY.md"))) {
25554
+ if ((0, import_node_fs49.existsSync)((0, import_node_path33.join)(root, "GATE.md")) && !(0, import_node_fs49.existsSync)((0, import_node_path33.join)(root, "VERITY.md"))) {
25220
25555
  return true;
25221
25556
  }
25222
25557
  if (await hasLegacyHooksAt(root)) return true;
@@ -25339,7 +25674,7 @@ function runSelect(opts) {
25339
25674
  cursor: initialIdx[0] ?? 0,
25340
25675
  chosen: new Set(mode2 === "single" ? [initialIdx[0] ?? 0] : initialIdx)
25341
25676
  };
25342
- return new Promise((resolve4) => {
25677
+ return new Promise((resolve5) => {
25343
25678
  let painted = 0;
25344
25679
  let settled = false;
25345
25680
  const draw = () => {
@@ -25387,7 +25722,7 @@ function runSelect(opts) {
25387
25722
  if (settled) return;
25388
25723
  settled = true;
25389
25724
  restore();
25390
- resolve4(value);
25725
+ resolve5(value);
25391
25726
  };
25392
25727
  readline2.emitKeypressEvents(input);
25393
25728
  input.setRawMode(true);
@@ -25408,9 +25743,9 @@ async function askLine(question, io = {}) {
25408
25743
  output: io.output ?? process.stdout
25409
25744
  });
25410
25745
  try {
25411
- return await new Promise((resolve4) => {
25412
- rl.question(question).then((a) => resolve4(a.trim())).catch(() => resolve4(null));
25413
- rl.once("close", () => setImmediate(() => resolve4(null)));
25746
+ return await new Promise((resolve5) => {
25747
+ rl.question(question).then((a) => resolve5(a.trim())).catch(() => resolve5(null));
25748
+ rl.once("close", () => setImmediate(() => resolve5(null)));
25414
25749
  });
25415
25750
  } finally {
25416
25751
  rl.close();
@@ -25493,7 +25828,7 @@ async function promptMultiSelect(question, choices, fallback) {
25493
25828
  // src/lib/remote-config.ts
25494
25829
  var import_node_fs50 = require("node:fs");
25495
25830
  var import_promises16 = require("node:fs/promises");
25496
- var import_node_path32 = require("node:path");
25831
+ var import_node_path34 = require("node:path");
25497
25832
  var import_yaml5 = __toESM(require_dist());
25498
25833
  var IGNORE_RIDER = "verityignore";
25499
25834
  async function fetchRemoteSetup(opts) {
@@ -25571,7 +25906,7 @@ async function adoptRemoteSetup(found, opts) {
25571
25906
  }
25572
25907
  async function writeOut(relative2, body) {
25573
25908
  const target = projectPath(relative2);
25574
- await (0, import_promises16.mkdir)((0, import_node_path32.dirname)(target), { recursive: true });
25909
+ await (0, import_promises16.mkdir)((0, import_node_path34.dirname)(target), { recursive: true });
25575
25910
  await (0, import_promises16.writeFile)(target, body);
25576
25911
  }
25577
25912
  function describeRemote(found) {
@@ -25687,16 +26022,16 @@ async function runOptionalAuth(resolution, opts = {}) {
25687
26022
  }
25688
26023
  }
25689
26024
  function resolveDataDir2() {
25690
- const candidates = [
25691
- (0, import_node_path33.join)(__dirname, "..", "data"),
26025
+ const candidates2 = [
26026
+ (0, import_node_path35.join)(__dirname, "..", "data"),
25692
26027
  // installed: node_modules/@codacy/verity-cli/data
25693
- (0, import_node_path33.join)(__dirname, "..", "..", "data"),
26028
+ (0, import_node_path35.join)(__dirname, "..", "..", "data"),
25694
26029
  // edge case: nested resolution
25695
- (0, import_node_path33.join)(process.cwd(), "cli", "data")
26030
+ (0, import_node_path35.join)(process.cwd(), "cli", "data")
25696
26031
  // local dev: running from repo root
25697
26032
  ];
25698
- for (const candidate of candidates) {
25699
- if ((0, import_node_fs51.existsSync)((0, import_node_path33.join)(candidate, "skills"))) {
26033
+ for (const candidate of candidates2) {
26034
+ if ((0, import_node_fs51.existsSync)((0, import_node_path35.join)(candidate, "skills"))) {
25700
26035
  return candidate;
25701
26036
  }
25702
26037
  }
@@ -25714,7 +26049,7 @@ async function skillIsCurrent(src, dest) {
25714
26049
  const walk2 = (d, prefix) => {
25715
26050
  for (const e of (0, import_node_fs51.readdirSync)(d, { withFileTypes: true })) {
25716
26051
  const rel = prefix ? `${prefix}/${e.name}` : e.name;
25717
- if (e.isDirectory()) walk2((0, import_node_path33.join)(d, e.name), rel);
26052
+ if (e.isDirectory()) walk2((0, import_node_path35.join)(d, e.name), rel);
25718
26053
  else if (e.isFile()) out.push(rel);
25719
26054
  }
25720
26055
  };
@@ -25725,8 +26060,8 @@ async function skillIsCurrent(src, dest) {
25725
26060
  const shipped = list2(src);
25726
26061
  if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
25727
26062
  for (const rel of shipped) {
25728
- const a = await (0, import_promises17.readFile)((0, import_node_path33.join)(src, rel), "utf-8");
25729
- const b = await (0, import_promises17.readFile)((0, import_node_path33.join)(dest, rel), "utf-8");
26063
+ const a = await (0, import_promises17.readFile)((0, import_node_path35.join)(src, rel), "utf-8");
26064
+ const b = await (0, import_promises17.readFile)((0, import_node_path35.join)(dest, rel), "utf-8");
25730
26065
  if (a !== b) return false;
25731
26066
  }
25732
26067
  return true;
@@ -26001,12 +26336,12 @@ async function handoffToSetup(enabled, claudeInstalled) {
26001
26336
  async function installSkills(force, step) {
26002
26337
  step("Installing skills");
26003
26338
  const dataDir = resolveDataDir2();
26004
- const skillsSource = (0, import_node_path33.join)(dataDir, "skills");
26339
+ const skillsSource = (0, import_node_path35.join)(dataDir, "skills");
26005
26340
  const skillsDest = ".claude/skills";
26006
26341
  let skillsInstalled = 0;
26007
26342
  for (const skill of SKILLS) {
26008
- const src = (0, import_node_path33.join)(skillsSource, skill);
26009
- const dest = (0, import_node_path33.join)(skillsDest, skill);
26343
+ const src = (0, import_node_path35.join)(skillsSource, skill);
26344
+ const dest = (0, import_node_path35.join)(skillsDest, skill);
26010
26345
  if (!(0, import_node_fs51.existsSync)(src)) {
26011
26346
  printWarn(` Skill data not found: ${skill}`);
26012
26347
  continue;
@@ -26109,12 +26444,16 @@ function registerInitCommand(program2) {
26109
26444
  program2.command("init").alias("setup").description("Set up Verity in the current project (asks the setup questions, then hands off to /verity-setup)").option("--force", "Reinstall the skills even when they are already up to date (hooks are always reconciled)").option("-y, --yes", "Take the recommended answer for every question (no prompts)").option("--no-setup", "Skip the /verity-setup handoff at the end").option(
26110
26445
  "--plugin-mode",
26111
26446
  "The Claude Code plugin owns the skills and hooks: install neither, and remove any this project already has"
26447
+ ).option(
26448
+ "--no-plugin",
26449
+ "Ignore any Claude Code plugin here and wire this project's own skills and hooks"
26112
26450
  ).option("--no-adopt", "Don't offer this repository's existing Standard from the service; synthesize a new one").action(async (opts) => {
26113
26451
  const force = opts.force ?? false;
26114
26452
  const wantsHandoff = opts.setup !== false;
26115
26453
  const wantsAdopt = opts.adopt !== false;
26116
26454
  const defaultsOnly = (opts.yes ?? false) || !interactive();
26117
- const pluginMode = opts.pluginMode ?? pluginActiveHere();
26455
+ const staleMarker = clearStalePluginMarker();
26456
+ const pluginMode = opts.plugin === false ? false : opts.pluginMode ?? pluginActiveHere();
26118
26457
  const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
26119
26458
  const isProject = projectMarkers.some((m) => (0, import_node_fs51.existsSync)(m));
26120
26459
  if (!isProject) {
@@ -26131,6 +26470,24 @@ function registerInitCommand(program2) {
26131
26470
  } else {
26132
26471
  printPhase(1, 2, "this machine", "prerequisites \xB7 skills \xB7 hooks \xB7 sign-in");
26133
26472
  }
26473
+ if (staleMarker) {
26474
+ printInfo(`Cleared a stale plugin marker \u2014 ${staleMarker.pluginRoot} is no longer installed.`);
26475
+ }
26476
+ const install = pluginMode ? activePluginInstall() : null;
26477
+ if (pluginMode) {
26478
+ const where = install ? ` \u2014 ${install.pluginRoot}${install.version ? ` (v${install.version})` : ""}` : "";
26479
+ printInfo(`Hooks here: the Verity Claude Code plugin${where}.`);
26480
+ printInfo(" It wires every event for every project, so this one gets no skills or settings.json");
26481
+ printInfo(" hooks of its own, and any left by an earlier npm install are removed below.");
26482
+ printInfo(" Not what you want here? Re-run with --no-plugin.");
26483
+ } else if (opts.plugin === false && pluginActiveHere()) {
26484
+ printWarn("Hooks here: this project's .claude/settings.json (--no-plugin).");
26485
+ printWarn(" The Verity plugin is active on this machine and would otherwise own them. Both sets");
26486
+ printWarn(" will fire; the settings.json copy stands down at run time so each turn is gated once.");
26487
+ } else {
26488
+ printInfo("Hooks here: this project's .claude/settings.json (no Verity Claude Code plugin is active).");
26489
+ }
26490
+ console.log("");
26134
26491
  const TOTAL_STEPS = 9;
26135
26492
  let stepNo = 0;
26136
26493
  const step = (label2) => {
@@ -26162,7 +26519,7 @@ function registerInitCommand(program2) {
26162
26519
  printInfo(` intensity: ${intensity} \xB7 moments: ${moments.join(", ") || "none"} (no questions asked)`);
26163
26520
  }
26164
26521
  await scaffoldProject(step, defaultsOnly);
26165
- const globalVerityDir = (0, import_node_path33.join)(process.env.HOME ?? "", ".verity");
26522
+ const globalVerityDir = (0, import_node_path35.join)(process.env.HOME ?? "", ".verity");
26166
26523
  await (0, import_promises17.mkdir)(globalVerityDir, { recursive: true });
26167
26524
  console.log("");
26168
26525
  step("Wiring Claude Code hooks");
@@ -26244,7 +26601,7 @@ function registerInitCommand(program2) {
26244
26601
  ...telemetryChoice ? { telemetry: telemetryChoice } : {},
26245
26602
  init: {
26246
26603
  completed_at: (/* @__PURE__ */ new Date()).toISOString(),
26247
- cli_version: true ? "0.32.0-experimental.68ae2ee" : "dev"
26604
+ cli_version: true ? "0.32.0-experimental.cc76941" : "dev"
26248
26605
  }
26249
26606
  });
26250
26607
  } catch (err) {
@@ -26284,7 +26641,7 @@ function registerInitCommand(program2) {
26284
26641
 
26285
26642
  // src/commands/uninstall.ts
26286
26643
  var import_node_fs52 = require("node:fs");
26287
- var import_node_path34 = require("node:path");
26644
+ var import_node_path36 = require("node:path");
26288
26645
  var SKILL_NAMES = [
26289
26646
  "verity-setup",
26290
26647
  "verity-analyze",
@@ -26303,7 +26660,7 @@ function registerUninstallCommand(program2) {
26303
26660
  const actions = [];
26304
26661
  const skillsRoot = projectPath(".claude/skills");
26305
26662
  for (const name of SKILL_NAMES) {
26306
- const dir = (0, import_node_path34.join)(skillsRoot, name);
26663
+ const dir = (0, import_node_path36.join)(skillsRoot, name);
26307
26664
  if ((0, import_node_fs52.existsSync)(dir)) {
26308
26665
  actions.push({
26309
26666
  label: `Remove .claude/skills/${name}/`,
@@ -26349,7 +26706,7 @@ function registerUninstallCommand(program2) {
26349
26706
  }
26350
26707
  });
26351
26708
  const home = process.env.HOME ?? "";
26352
- const globalVerityDir = (0, import_node_path34.join)(home, ".verity");
26709
+ const globalVerityDir = (0, import_node_path36.join)(home, ".verity");
26353
26710
  if (purgeGlobal && (0, import_node_fs52.existsSync)(globalVerityDir)) {
26354
26711
  actions.push({
26355
26712
  label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
@@ -26548,7 +26905,7 @@ function registerTaskCommands(program2) {
26548
26905
 
26549
26906
  // src/commands/reset.ts
26550
26907
  var import_node_fs53 = require("node:fs");
26551
- var import_node_path35 = require("node:path");
26908
+ var import_node_path37 = require("node:path");
26552
26909
  function registerResetCommand(program2) {
26553
26910
  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) => {
26554
26911
  const globals = program2.opts();
@@ -26589,7 +26946,7 @@ function registerResetCommand(program2) {
26589
26946
  for (const entry of (0, import_node_fs53.readdirSync)(cacheDir)) {
26590
26947
  if (entry.startsWith("pending-")) {
26591
26948
  try {
26592
- (0, import_node_fs53.unlinkSync)((0, import_node_path35.join)(cacheDir, entry));
26949
+ (0, import_node_fs53.unlinkSync)((0, import_node_path37.join)(cacheDir, entry));
26593
26950
  purged++;
26594
26951
  } catch {
26595
26952
  }
@@ -26616,7 +26973,7 @@ function registerResetCommand(program2) {
26616
26973
  if ((0, import_node_fs53.existsSync)(logsDir)) {
26617
26974
  for (const entry of (0, import_node_fs53.readdirSync)(logsDir)) {
26618
26975
  try {
26619
- (0, import_node_fs53.unlinkSync)((0, import_node_path35.join)(logsDir, entry));
26976
+ (0, import_node_fs53.unlinkSync)((0, import_node_path37.join)(logsDir, entry));
26620
26977
  } catch {
26621
26978
  }
26622
26979
  }
@@ -26924,8 +27281,8 @@ function registerTelemetryCommands(program2) {
26924
27281
  }
26925
27282
 
26926
27283
  // src/cli.ts
26927
- program.name("verity").description("CLI for Verity quality gate service").version("0.32.0-experimental.68ae2ee").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) => {
26928
- installStderrLog(actionCommand.name(), process.argv.slice(2), "0.32.0-experimental.68ae2ee");
27284
+ program.name("verity").description("CLI for Verity quality gate service").version("0.32.0-experimental.cc76941").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) => {
27285
+ installStderrLog(actionCommand.name(), process.argv.slice(2), "0.32.0-experimental.cc76941");
26929
27286
  setUserNamedServiceUrl(program.opts().serviceUrl);
26930
27287
  try {
26931
27288
  await foldLegacyLocalCredential();