@codacy/verity-cli 0.28.0 → 0.28.1-experimental.708d3ae

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/verity.js CHANGED
@@ -10327,10 +10327,6 @@ var {
10327
10327
  // src/commands/auth.ts
10328
10328
  var import_node_child_process4 = require("node:child_process");
10329
10329
 
10330
- // src/lib/auth.ts
10331
- var import_promises2 = require("node:fs/promises");
10332
- var import_node_child_process2 = require("node:child_process");
10333
-
10334
10330
  // src/constants.ts
10335
10331
  var import_node_child_process = require("node:child_process");
10336
10332
  var import_node_path = require("node:path");
@@ -10347,7 +10343,6 @@ function repoRoot() {
10347
10343
  }
10348
10344
  var VERITY_DIR = ".verity";
10349
10345
  var CREDENTIALS_FILE = `${VERITY_DIR}/credentials`;
10350
- var GLOBAL_CREDENTIALS_FILE = `${process.env.HOME}/.verity/credentials`;
10351
10346
  var DEBOUNCE_FILE = `${VERITY_DIR}/.last-analysis`;
10352
10347
  var ITERATION_FILE = `${VERITY_DIR}/.iteration-count`;
10353
10348
  var HASH_FILE = `${VERITY_DIR}/.last-pass-hash`;
@@ -10473,7 +10468,7 @@ var SECURITY_PATTERNS = [
10473
10468
  /Dockerfile/
10474
10469
  ];
10475
10470
  var PROD_SERVICE_URL = "https://ofcamwrjwrkazqvdchko.supabase.co/functions/v1";
10476
- var DEFAULT_SERVICE_URL = "".length > 0 ? "" : PROD_SERVICE_URL;
10471
+ var DEFAULT_SERVICE_URL = "https://wukeddyzpijoegyajtnc.supabase.co/functions/v1".length > 0 ? "https://wukeddyzpijoegyajtnc.supabase.co/functions/v1" : PROD_SERVICE_URL;
10477
10472
  var GITHUB_CLIENT_ID = "Iv23li88HxAi3ZrbYzWh";
10478
10473
  var GITHUB_DEVICE_CODE_URL = "https://github.com/login/device/code";
10479
10474
  var GITHUB_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
@@ -10673,19 +10668,174 @@ function analyzeRequest(options) {
10673
10668
  }
10674
10669
 
10675
10670
  // src/lib/service-url.ts
10671
+ var import_promises2 = require("node:fs/promises");
10672
+
10673
+ // src/lib/credentials.ts
10676
10674
  var import_promises = require("node:fs/promises");
10677
- async function serviceUrlFromCredentials() {
10675
+ var import_node_path2 = require("node:path");
10676
+ var import_node_child_process2 = require("node:child_process");
10677
+ function globalCredentialsPath() {
10678
+ return `${process.env.HOME}/.verity/credentials`;
10679
+ }
10680
+ function currentRemote() {
10681
+ try {
10682
+ return (0, import_node_child_process2.execSync)("git remote get-url origin", {
10683
+ encoding: "utf-8",
10684
+ stdio: ["pipe", "pipe", "pipe"]
10685
+ }).trim();
10686
+ } catch {
10687
+ return "";
10688
+ }
10689
+ }
10690
+ var TOKEN_RE = /token:\s*((?:gate_|verity_)[a-f0-9]+)/;
10691
+ function parseCredentialLine(line) {
10692
+ const idx = line.indexOf(" token:");
10693
+ const remote = idx === -1 ? "" : line.slice(0, idx).trim();
10694
+ const rest = idx === -1 ? line : line.slice(idx);
10695
+ const tokenMatch = rest.match(TOKEN_RE);
10696
+ if (!tokenMatch) return null;
10697
+ const serviceUrl = rest.match(/service_url:\s*(https?:\/\/\S+)/)?.[1];
10698
+ const userIdRaw = rest.match(/user_id:\s*(\d+)/)?.[1];
10699
+ const email = rest.match(/email:\s*(\S+)/)?.[1];
10700
+ return {
10701
+ remote,
10702
+ rec: {
10703
+ token: tokenMatch[1],
10704
+ serviceUrl,
10705
+ userId: userIdRaw != null ? Number(userIdRaw) : void 0,
10706
+ email
10707
+ }
10708
+ };
10709
+ }
10710
+ function encodeRemoteKey(remote) {
10711
+ return remote.replace(
10712
+ /[%\x00-\x20\x7f]/g,
10713
+ (c) => "%" + c.charCodeAt(0).toString(16).padStart(2, "0").toUpperCase()
10714
+ );
10715
+ }
10716
+ function serializeCredential(remote, rec) {
10717
+ const key = encodeRemoteKey(remote);
10718
+ const out = [key ? `${key} token: ${rec.token}` : `token: ${rec.token}`];
10719
+ if (rec.serviceUrl) out.push(`service_url: ${rec.serviceUrl}`);
10720
+ if (rec.userId != null) out.push(`user_id: ${rec.userId}`);
10721
+ if (rec.email) out.push(`email: ${rec.email}`);
10722
+ return out.join(" ");
10723
+ }
10724
+ async function readGlobalCredential(remote) {
10725
+ let content;
10678
10726
  try {
10679
- const creds = await (0, import_promises.readFile)(projectPath(CREDENTIALS_FILE), "utf-8");
10680
- const match = creds.match(/service_url:\s*(https?:\/\/[^\s]+)/);
10681
- return match ? match[1] : null;
10727
+ content = await (0, import_promises.readFile)(globalCredentialsPath(), "utf-8");
10682
10728
  } catch {
10683
10729
  return null;
10684
10730
  }
10731
+ const lines = content.split("\n");
10732
+ const key = encodeRemoteKey(remote);
10733
+ if (key) {
10734
+ let last = null;
10735
+ for (const line of lines) {
10736
+ const parsed = parseCredentialLine(line);
10737
+ if (parsed && parsed.remote === key) last = parsed.rec;
10738
+ }
10739
+ if (last) return last;
10740
+ }
10741
+ let plain = null;
10742
+ for (const line of lines) {
10743
+ const parsed = parseCredentialLine(line);
10744
+ if (parsed && parsed.remote === "") plain = parsed.rec;
10745
+ }
10746
+ return plain;
10747
+ }
10748
+ async function upsertGlobalCredential(remote, rec) {
10749
+ const path = globalCredentialsPath();
10750
+ await (0, import_promises.mkdir)((0, import_node_path2.dirname)(path), { recursive: true });
10751
+ let content = "";
10752
+ try {
10753
+ content = await (0, import_promises.readFile)(path, "utf-8");
10754
+ } catch {
10755
+ }
10756
+ const line = serializeCredential(remote, rec);
10757
+ const key = encodeRemoteKey(remote);
10758
+ const kept = [];
10759
+ let replaced = false;
10760
+ for (const existing of content ? content.split("\n") : []) {
10761
+ const parsed = parseCredentialLine(existing);
10762
+ const matches = parsed !== null && parsed.remote === key;
10763
+ if (matches) {
10764
+ if (!replaced) {
10765
+ kept.push(line);
10766
+ replaced = true;
10767
+ }
10768
+ continue;
10769
+ }
10770
+ kept.push(existing);
10771
+ }
10772
+ while (kept.length && kept[kept.length - 1].trim() === "") kept.pop();
10773
+ if (!replaced) kept.push(line);
10774
+ const body = kept.join("\n") + "\n";
10775
+ await (0, import_promises.writeFile)(path, body, { mode: 384 });
10776
+ await (0, import_promises.chmod)(path, 384).catch(() => {
10777
+ });
10778
+ }
10779
+ function parseLocalCredentialFile(content) {
10780
+ const tokenMatch = content.match(/token:\s*((?:gate_|verity_)[a-f0-9]+)/);
10781
+ if (!tokenMatch) return null;
10782
+ const userIdMatch = content.match(/^user_id:\s*(\d+)/m);
10783
+ return {
10784
+ token: tokenMatch[1],
10785
+ serviceUrl: content.match(/service_url:\s*(https?:\/\/\S+)/)?.[1],
10786
+ userId: userIdMatch ? Number(userIdMatch[1]) : void 0,
10787
+ email: content.match(/^email:\s*(\S+)/m)?.[1]
10788
+ };
10789
+ }
10790
+ async function readLegacyLocalCredential() {
10791
+ try {
10792
+ return parseLocalCredentialFile(await (0, import_promises.readFile)(projectPath(CREDENTIALS_FILE), "utf-8"));
10793
+ } catch {
10794
+ return null;
10795
+ }
10796
+ }
10797
+ async function foldLegacyLocalCredential(remoteArg) {
10798
+ let content;
10799
+ try {
10800
+ content = await (0, import_promises.readFile)(projectPath(CREDENTIALS_FILE), "utf-8");
10801
+ } catch {
10802
+ return false;
10803
+ }
10804
+ const local = parseLocalCredentialFile(content);
10805
+ if (!local) {
10806
+ await (0, import_promises.unlink)(projectPath(CREDENTIALS_FILE)).catch(() => {
10807
+ });
10808
+ return false;
10809
+ }
10810
+ const remote = remoteArg ?? currentRemote();
10811
+ if (!remote) {
10812
+ return false;
10813
+ }
10814
+ const existing = await readGlobalCredential(remote);
10815
+ const merged = {
10816
+ token: existing?.token ?? local.token,
10817
+ serviceUrl: existing?.serviceUrl ?? local.serviceUrl,
10818
+ userId: existing?.userId ?? local.userId,
10819
+ email: existing?.email ?? local.email
10820
+ };
10821
+ try {
10822
+ await upsertGlobalCredential(remote, merged);
10823
+ } catch {
10824
+ return false;
10825
+ }
10826
+ await (0, import_promises.unlink)(projectPath(CREDENTIALS_FILE)).catch(() => {
10827
+ });
10828
+ return true;
10829
+ }
10830
+
10831
+ // src/lib/service-url.ts
10832
+ async function serviceUrlFromCredentials() {
10833
+ const rec = await readGlobalCredential(currentRemote());
10834
+ return rec?.serviceUrl ?? null;
10685
10835
  }
10686
10836
  async function serviceUrlFromVerityMd() {
10687
10837
  try {
10688
- const content = await (0, import_promises.readFile)(projectPath(VERITY_MD_FILE), "utf-8");
10838
+ const content = await (0, import_promises2.readFile)(projectPath(VERITY_MD_FILE), "utf-8");
10689
10839
  const boldLine = content.split("\n").find((l) => /\*\*url\*\*/i.test(l));
10690
10840
  if (boldLine) {
10691
10841
  const urlMatch = boldLine.match(/https:\/\/[^\s]+/);
@@ -10727,14 +10877,6 @@ function isHealCandidate(resolved) {
10727
10877
  }
10728
10878
 
10729
10879
  // src/lib/auth.ts
10730
- function parseIdentity(content) {
10731
- const idMatch = content.match(/^user_id:\s*(\d+)/m);
10732
- const emailMatch = content.match(/^email:\s*(\S+)/m);
10733
- return {
10734
- userId: idMatch ? Number(idMatch[1]) : void 0,
10735
- email: emailMatch ? emailMatch[1] : void 0
10736
- };
10737
- }
10738
10880
  async function resolveToken(flagToken) {
10739
10881
  if (flagToken) {
10740
10882
  return { ok: true, data: { token: flagToken, source: "flag" } };
@@ -10743,36 +10885,19 @@ async function resolveToken(flagToken) {
10743
10885
  if (envToken) {
10744
10886
  return { ok: true, data: { token: envToken, source: "env" } };
10745
10887
  }
10746
- try {
10747
- const content = await (0, import_promises2.readFile)(projectPath(CREDENTIALS_FILE), "utf-8");
10748
- const match = content.match(/token:\s*((?:gate_|verity_)[a-f0-9]+)/);
10749
- if (match) {
10750
- return { ok: true, data: { token: match[1], source: "local", ...parseIdentity(content) } };
10751
- }
10752
- } catch {
10888
+ const rec = await readGlobalCredential(currentRemote());
10889
+ if (rec) {
10890
+ return {
10891
+ ok: true,
10892
+ data: { token: rec.token, source: "global", userId: rec.userId, email: rec.email }
10893
+ };
10753
10894
  }
10754
- const globalCredentials = `${process.env.HOME}/.verity/credentials`;
10755
- try {
10756
- const content = await (0, import_promises2.readFile)(globalCredentials, "utf-8");
10757
- let remote = "";
10758
- try {
10759
- remote = (0, import_node_child_process2.execSync)("git remote get-url origin", { encoding: "utf-8" }).trim();
10760
- } catch {
10761
- }
10762
- if (remote) {
10763
- const remoteLine = content.split("\n").find((l) => l.includes(remote));
10764
- if (remoteLine) {
10765
- const match = remoteLine.match(/token:\s*((?:gate_|verity_)[a-f0-9]+)/);
10766
- if (match) {
10767
- return { ok: true, data: { token: match[1], source: "global" } };
10768
- }
10769
- }
10770
- }
10771
- const plainMatch = content.match(/^token:\s*((?:gate_|verity_)[a-f0-9]+)/m);
10772
- if (plainMatch) {
10773
- return { ok: true, data: { token: plainMatch[1], source: "global" } };
10774
- }
10775
- } catch {
10895
+ const local = await readLegacyLocalCredential();
10896
+ if (local) {
10897
+ return {
10898
+ ok: true,
10899
+ data: { token: local.token, source: "local", userId: local.userId, email: local.email }
10900
+ };
10776
10901
  }
10777
10902
  return { ok: false, error: "No Verity token found. Run /verity-setup to configure." };
10778
10903
  }
@@ -10806,7 +10931,7 @@ async function maybeHealServiceUrl(resolution, verbose) {
10806
10931
  if (probe.reachable) {
10807
10932
  return { serviceUrl: resolution.url, healed: false };
10808
10933
  }
10809
- const from = resolution.source === "credentials" ? ".verity/credentials" : "VERITY.md";
10934
+ const from = resolution.source === "credentials" ? "~/.verity/credentials" : "VERITY.md";
10810
10935
  printWarn(`Your configured Verity service URL is unreachable: ${resolution.url}`);
10811
10936
  printInfo(` (${probe.error})`);
10812
10937
  if (probe.dnsDead && (await probeService(DEFAULT_SERVICE_URL, verbose)).reachable) {
@@ -10823,8 +10948,6 @@ async function maybeHealServiceUrl(resolution, verbose) {
10823
10948
  }
10824
10949
 
10825
10950
  // src/lib/register.ts
10826
- var import_promises3 = require("node:fs/promises");
10827
- var import_node_path3 = require("node:path");
10828
10951
  var readline = __toESM(require("node:readline/promises"));
10829
10952
 
10830
10953
  // src/lib/provider-auth.ts
@@ -10934,7 +11057,7 @@ async function githubDeviceFlow() {
10934
11057
  // src/lib/git.ts
10935
11058
  var import_node_child_process3 = require("node:child_process");
10936
11059
  var import_node_fs2 = require("node:fs");
10937
- var import_node_path2 = require("node:path");
11060
+ var import_node_path3 = require("node:path");
10938
11061
  function resolveFile(relpath) {
10939
11062
  if ((0, import_node_fs2.existsSync)(relpath)) return relpath;
10940
11063
  if ((0, import_node_fs2.existsSync)(".claude/worktrees")) {
@@ -10942,7 +11065,7 @@ function resolveFile(relpath) {
10942
11065
  const entries = (0, import_node_fs2.readdirSync)(".claude/worktrees", { withFileTypes: true });
10943
11066
  for (const entry of entries) {
10944
11067
  if (!entry.isDirectory()) continue;
10945
- const candidate = (0, import_node_path2.join)(".claude/worktrees", entry.name, relpath);
11068
+ const candidate = (0, import_node_path3.join)(".claude/worktrees", entry.name, relpath);
10946
11069
  if ((0, import_node_fs2.existsSync)(candidate)) return candidate;
10947
11070
  }
10948
11071
  } catch {
@@ -10983,7 +11106,7 @@ function readBaselineSha() {
10983
11106
  function writeBaselineSha(sha) {
10984
11107
  if (!SHA_RE.test(sha)) return;
10985
11108
  try {
10986
- (0, import_node_fs2.mkdirSync)((0, import_node_path2.dirname)(BASELINE_SHA_FILE), { recursive: true });
11109
+ (0, import_node_fs2.mkdirSync)((0, import_node_path3.dirname)(BASELINE_SHA_FILE), { recursive: true });
10987
11110
  (0, import_node_fs2.writeFileSync)(BASELINE_SHA_FILE, sha);
10988
11111
  } catch {
10989
11112
  }
@@ -11077,7 +11200,7 @@ function getWorktreeFiles() {
11077
11200
  const entries = (0, import_node_fs2.readdirSync)(worktreeDir, { withFileTypes: true });
11078
11201
  for (const entry of entries) {
11079
11202
  if (!entry.isDirectory()) continue;
11080
- const wtDir = (0, import_node_path2.join)(worktreeDir, entry.name);
11203
+ const wtDir = (0, import_node_path3.join)(worktreeDir, entry.name);
11081
11204
  scanDir(wtDir, wtDir, fiveMinAgo, result);
11082
11205
  }
11083
11206
  } catch {
@@ -11088,12 +11211,12 @@ function scanDir(baseDir, dir, minMtime, result) {
11088
11211
  try {
11089
11212
  const entries = (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true });
11090
11213
  for (const entry of entries) {
11091
- const fullPath = (0, import_node_path2.join)(dir, entry.name);
11214
+ const fullPath = (0, import_node_path3.join)(dir, entry.name);
11092
11215
  if (entry.isDirectory()) {
11093
11216
  if (entry.name === "node_modules" || entry.name === ".git") continue;
11094
11217
  scanDir(baseDir, fullPath, minMtime, result);
11095
11218
  } else if (entry.isFile()) {
11096
- const ext = (0, import_node_path2.extname)(entry.name).slice(1);
11219
+ const ext = (0, import_node_path3.extname)(entry.name).slice(1);
11097
11220
  if (!ANALYZABLE_EXTENSIONS.has(ext)) continue;
11098
11221
  try {
11099
11222
  const stat3 = (0, import_node_fs2.statSync)(fullPath);
@@ -11110,13 +11233,13 @@ function scanDir(baseDir, dir, minMtime, result) {
11110
11233
  }
11111
11234
  function filterAnalyzable(files) {
11112
11235
  return files.filter((f) => {
11113
- const ext = (0, import_node_path2.extname)(f).slice(1);
11236
+ const ext = (0, import_node_path3.extname)(f).slice(1);
11114
11237
  return ANALYZABLE_EXTENSIONS.has(ext);
11115
11238
  });
11116
11239
  }
11117
11240
  function filterReviewable(files) {
11118
11241
  return files.filter((f) => {
11119
- const ext = (0, import_node_path2.extname)(f).slice(1);
11242
+ const ext = (0, import_node_path3.extname)(f).slice(1);
11120
11243
  if (ANALYZABLE_EXTENSIONS.has(ext)) return false;
11121
11244
  if (REVIEWABLE_EXTENSIONS.has(ext)) return true;
11122
11245
  const basename4 = f.split("/").pop() ?? "";
@@ -11249,38 +11372,19 @@ async function registerProject(opts) {
11249
11372
  const { project_id, token, service_url, user } = result.data;
11250
11373
  const userId = result.data.user_id ?? user?.id;
11251
11374
  const email = user?.email;
11252
- const identityLines = (userId != null ? `user_id: ${userId}
11253
- ` : "") + (email ? `email: ${email}
11254
- ` : "");
11255
11375
  try {
11256
- await (0, import_promises3.mkdir)(VERITY_DIR, { recursive: true });
11257
- await (0, import_promises3.writeFile)(
11258
- CREDENTIALS_FILE,
11259
- `token: ${token}
11260
- service_url: ${service_url}
11261
- ${identityLines}`,
11262
- { mode: 384 }
11263
- );
11264
- await (0, import_promises3.chmod)(CREDENTIALS_FILE, 384).catch(() => {
11376
+ await upsertGlobalCredential(opts.remote, {
11377
+ token,
11378
+ serviceUrl: service_url,
11379
+ userId: userId ?? void 0,
11380
+ email
11265
11381
  });
11266
11382
  } catch (err) {
11267
11383
  return {
11268
11384
  ok: false,
11269
- error: `Registered with the Verity service, but could not save credentials to ${CREDENTIALS_FILE}: ${err.message}. Check filesystem permissions and re-run "verity auth register".`
11385
+ error: `Registered with the Verity service, but could not save credentials to ~/.verity/credentials: ${err.message}. Check filesystem permissions and re-run "verity auth register".`
11270
11386
  };
11271
11387
  }
11272
- try {
11273
- await (0, import_promises3.mkdir)((0, import_node_path3.dirname)(GLOBAL_CREDENTIALS_FILE), { recursive: true });
11274
- await (0, import_promises3.appendFile)(
11275
- GLOBAL_CREDENTIALS_FILE,
11276
- `${opts.remote} token: ${token}
11277
- `,
11278
- { mode: 384 }
11279
- );
11280
- await (0, import_promises3.chmod)(GLOBAL_CREDENTIALS_FILE, 384).catch(() => {
11281
- });
11282
- } catch {
11283
- }
11284
11388
  return { ok: true, data: { projectId: project_id, serviceUrl: service_url, email, userId } };
11285
11389
  }
11286
11390
 
@@ -11385,7 +11489,7 @@ function registerLoginCommand(program2) {
11385
11489
  const heal = await maybeHealServiceUrl(urlResult.data, globals.verbose);
11386
11490
  const serviceUrl = heal.serviceUrl;
11387
11491
  if (heal.healed) {
11388
- printInfo(" Completing login re-registers this project and updates .verity/credentials.");
11492
+ printInfo(" Completing login re-registers this project and updates ~/.verity/credentials.");
11389
11493
  }
11390
11494
  const existing = await resolveToken(globals.token);
11391
11495
  if (existing.ok && !opts.force && !heal.healed) {
@@ -11433,11 +11537,11 @@ function registerLoginCommand(program2) {
11433
11537
  }
11434
11538
 
11435
11539
  // src/lib/hooks.ts
11436
- var import_promises5 = require("node:fs/promises");
11540
+ var import_promises4 = require("node:fs/promises");
11437
11541
  var import_node_path6 = require("node:path");
11438
11542
 
11439
11543
  // src/lib/json-file.ts
11440
- var import_promises4 = require("node:fs/promises");
11544
+ var import_promises3 = require("node:fs/promises");
11441
11545
  var import_node_path5 = require("node:path");
11442
11546
  function jsonSemanticEqual(a, b) {
11443
11547
  if (a === b) return true;
@@ -11471,7 +11575,7 @@ function detectJsonIndent(raw) {
11471
11575
  async function writeJsonFilePreservingStyle(file, value) {
11472
11576
  let currentRaw = null;
11473
11577
  try {
11474
- currentRaw = await (0, import_promises4.readFile)(file, "utf-8");
11578
+ currentRaw = await (0, import_promises3.readFile)(file, "utf-8");
11475
11579
  } catch {
11476
11580
  currentRaw = null;
11477
11581
  }
@@ -11484,8 +11588,8 @@ async function writeJsonFilePreservingStyle(file, value) {
11484
11588
  const indent = currentRaw !== null ? detectJsonIndent(currentRaw) : 2;
11485
11589
  const next = JSON.stringify(value, null, indent) + "\n";
11486
11590
  if (next === currentRaw) return false;
11487
- await (0, import_promises4.mkdir)((0, import_node_path5.dirname)(file), { recursive: true });
11488
- await (0, import_promises4.writeFile)(file, next);
11591
+ await (0, import_promises3.mkdir)((0, import_node_path5.dirname)(file), { recursive: true });
11592
+ await (0, import_promises3.writeFile)(file, next);
11489
11593
  return true;
11490
11594
  }
11491
11595
 
@@ -11567,7 +11671,7 @@ function globalSettingsFile() {
11567
11671
  }
11568
11672
  async function readSettings() {
11569
11673
  try {
11570
- const content = await (0, import_promises5.readFile)(CLAUDE_SETTINGS_FILE, "utf-8");
11674
+ const content = await (0, import_promises4.readFile)(CLAUDE_SETTINGS_FILE, "utf-8");
11571
11675
  return JSON.parse(content);
11572
11676
  } catch {
11573
11677
  return {};
@@ -11578,7 +11682,7 @@ async function readAllSettings() {
11578
11682
  const out = [];
11579
11683
  for (const f of files) {
11580
11684
  try {
11581
- out.push(JSON.parse(await (0, import_promises5.readFile)(f, "utf-8")));
11685
+ out.push(JSON.parse(await (0, import_promises4.readFile)(f, "utf-8")));
11582
11686
  } catch {
11583
11687
  }
11584
11688
  }
@@ -11607,7 +11711,7 @@ async function checkExternalVerityHooks() {
11607
11711
  for (const f of [SETTINGS_LOCAL_FILE, globalSettingsFile()]) {
11608
11712
  let settings;
11609
11713
  try {
11610
- settings = JSON.parse(await (0, import_promises5.readFile)(f, "utf-8"));
11714
+ settings = JSON.parse(await (0, import_promises4.readFile)(f, "utf-8"));
11611
11715
  } catch {
11612
11716
  continue;
11613
11717
  }
@@ -11645,7 +11749,7 @@ async function writeSettings(settings) {
11645
11749
  }
11646
11750
  async function readSettingsAt(root) {
11647
11751
  try {
11648
- return JSON.parse(await (0, import_promises5.readFile)((0, import_node_path6.join)(root, CLAUDE_SETTINGS_FILE), "utf-8"));
11752
+ return JSON.parse(await (0, import_promises4.readFile)((0, import_node_path6.join)(root, CLAUDE_SETTINGS_FILE), "utf-8"));
11649
11753
  } catch {
11650
11754
  return {};
11651
11755
  }
@@ -11890,7 +11994,7 @@ function registerHooksCommands(program2) {
11890
11994
  var import_node_crypto4 = require("node:crypto");
11891
11995
 
11892
11996
  // src/lib/conversation-buffer.ts
11893
- var import_promises6 = require("node:fs/promises");
11997
+ var import_promises5 = require("node:fs/promises");
11894
11998
  var import_node_fs3 = require("node:fs");
11895
11999
  var import_node_child_process6 = require("node:child_process");
11896
12000
  var import_node_crypto = require("node:crypto");
@@ -11902,7 +12006,7 @@ function bufferTmpPath() {
11902
12006
  }
11903
12007
  async function appendToConversationBuffer(prompt, sessionId) {
11904
12008
  try {
11905
- await (0, import_promises6.mkdir)(VERITY_DIR, { recursive: true });
12009
+ await (0, import_promises5.mkdir)(VERITY_DIR, { recursive: true });
11906
12010
  let sanitized = prompt.length > MAX_INTENT_CHARS ? prompt.slice(0, MAX_INTENT_CHARS) : prompt;
11907
12011
  sanitized = stripImageReferences(sanitized);
11908
12012
  const entry = {
@@ -11920,8 +12024,8 @@ async function appendToConversationBuffer(prompt, sessionId) {
11920
12024
  const capped = recent.slice(-CONVERSATION_MAX_ENTRIES);
11921
12025
  const content = capped.map((e) => JSON.stringify(e)).join("\n") + "\n";
11922
12026
  const tmpFile = bufferTmpPath();
11923
- await (0, import_promises6.writeFile)(tmpFile, content);
11924
- await (0, import_promises6.rename)(tmpFile, CONVERSATION_BUFFER_FILE);
12027
+ await (0, import_promises5.writeFile)(tmpFile, content);
12028
+ await (0, import_promises5.rename)(tmpFile, CONVERSATION_BUFFER_FILE);
11925
12029
  } catch {
11926
12030
  }
11927
12031
  }
@@ -11938,10 +12042,10 @@ async function readAndClearConversationBuffer(currentSessionId) {
11938
12042
  if (others.length > 0) {
11939
12043
  const remaining = others.map((e) => JSON.stringify(e)).join("\n") + "\n";
11940
12044
  const tmpFile = bufferTmpPath();
11941
- await (0, import_promises6.writeFile)(tmpFile, remaining);
11942
- await (0, import_promises6.rename)(tmpFile, CONVERSATION_BUFFER_FILE);
12045
+ await (0, import_promises5.writeFile)(tmpFile, remaining);
12046
+ await (0, import_promises5.rename)(tmpFile, CONVERSATION_BUFFER_FILE);
11943
12047
  } else {
11944
- await (0, import_promises6.unlink)(CONVERSATION_BUFFER_FILE).catch(() => {
12048
+ await (0, import_promises5.unlink)(CONVERSATION_BUFFER_FILE).catch(() => {
11945
12049
  });
11946
12050
  }
11947
12051
  if (mine.length > 0) {
@@ -11953,8 +12057,8 @@ async function readAndClearConversationBuffer(currentSessionId) {
11953
12057
  }
11954
12058
  if ((0, import_node_fs3.existsSync)(INTENT_FILE)) {
11955
12059
  try {
11956
- const content = await (0, import_promises6.readFile)(INTENT_FILE, "utf-8");
11957
- await (0, import_promises6.unlink)(INTENT_FILE).catch(() => {
12060
+ const content = await (0, import_promises5.readFile)(INTENT_FILE, "utf-8");
12061
+ await (0, import_promises5.unlink)(INTENT_FILE).catch(() => {
11958
12062
  });
11959
12063
  const data = JSON.parse(content);
11960
12064
  if (data.prompt) {
@@ -11977,7 +12081,7 @@ async function readAndClearConversationBuffer(currentSessionId) {
11977
12081
  }
11978
12082
  async function readBufferEntries() {
11979
12083
  try {
11980
- const content = await (0, import_promises6.readFile)(CONVERSATION_BUFFER_FILE, "utf-8");
12084
+ const content = await (0, import_promises5.readFile)(CONVERSATION_BUFFER_FILE, "utf-8");
11981
12085
  const entries = [];
11982
12086
  for (const line of content.split("\n")) {
11983
12087
  const trimmed = line.trim();
@@ -12020,7 +12124,7 @@ function sessionScopeKey(token, sessionId) {
12020
12124
  }
12021
12125
 
12022
12126
  // src/lib/task-context-buffer.ts
12023
- var import_promises7 = require("node:fs/promises");
12127
+ var import_promises6 = require("node:fs/promises");
12024
12128
  var import_node_fs4 = require("node:fs");
12025
12129
  var import_node_path7 = require("node:path");
12026
12130
  var TASK_CONTEXT_DIR = `${VERITY_DIR}/.task-context`;
@@ -12063,7 +12167,7 @@ async function readTaskContextBuffer(taskId) {
12063
12167
  const filePath = bufferPath(taskId);
12064
12168
  if (!(0, import_node_fs4.existsSync)(filePath)) return null;
12065
12169
  try {
12066
- const content = await (0, import_promises7.readFile)(filePath, "utf-8");
12170
+ const content = await (0, import_promises6.readFile)(filePath, "utf-8");
12067
12171
  if (!content.trim()) return null;
12068
12172
  const lines = content.split("\n").filter((l) => l.trim());
12069
12173
  const formatted = [];
@@ -12096,15 +12200,15 @@ async function readTaskContextBuffer(taskId) {
12096
12200
  async function cleanupTaskContextBuffers() {
12097
12201
  try {
12098
12202
  if (!(0, import_node_fs4.existsSync)(TASK_CONTEXT_DIR)) return;
12099
- const files = await (0, import_promises7.readdir)(TASK_CONTEXT_DIR);
12203
+ const files = await (0, import_promises6.readdir)(TASK_CONTEXT_DIR);
12100
12204
  const cutoffMs = Date.now() - RETENTION_DAYS * 24 * 60 * 60 * 1e3;
12101
12205
  for (const file of files) {
12102
12206
  if (!file.endsWith(".jsonl")) continue;
12103
12207
  const filePath = (0, import_node_path7.join)(TASK_CONTEXT_DIR, file);
12104
12208
  try {
12105
- const stats = await (0, import_promises7.stat)(filePath);
12209
+ const stats = await (0, import_promises6.stat)(filePath);
12106
12210
  if (stats.mtimeMs < cutoffMs) {
12107
- await (0, import_promises7.unlink)(filePath);
12211
+ await (0, import_promises6.unlink)(filePath);
12108
12212
  }
12109
12213
  } catch {
12110
12214
  }
@@ -12118,27 +12222,27 @@ function bufferPath(taskId) {
12118
12222
  }
12119
12223
  async function appendEntry(taskId, entry) {
12120
12224
  try {
12121
- await (0, import_promises7.mkdir)(TASK_CONTEXT_DIR, { recursive: true });
12225
+ await (0, import_promises6.mkdir)(TASK_CONTEXT_DIR, { recursive: true });
12122
12226
  const filePath = bufferPath(taskId);
12123
12227
  if ((0, import_node_fs4.existsSync)(filePath)) {
12124
- const stats = await (0, import_promises7.stat)(filePath);
12228
+ const stats = await (0, import_promises6.stat)(filePath);
12125
12229
  if (stats.size >= MAX_BUFFER_BYTES) {
12126
- const content = await (0, import_promises7.readFile)(filePath, "utf-8");
12230
+ const content = await (0, import_promises6.readFile)(filePath, "utf-8");
12127
12231
  const lines = content.split("\n").filter((l) => l.trim());
12128
12232
  const keepFrom = Math.floor(lines.length * 0.25);
12129
12233
  const pruned = lines.slice(keepFrom).join("\n") + "\n";
12130
- await (0, import_promises7.writeFile)(filePath, pruned);
12234
+ await (0, import_promises6.writeFile)(filePath, pruned);
12131
12235
  }
12132
12236
  }
12133
12237
  const line = JSON.stringify(entry) + "\n";
12134
- const existing = (0, import_node_fs4.existsSync)(filePath) ? await (0, import_promises7.readFile)(filePath, "utf-8") : "";
12135
- await (0, import_promises7.writeFile)(filePath, existing + line);
12238
+ const existing = (0, import_node_fs4.existsSync)(filePath) ? await (0, import_promises6.readFile)(filePath, "utf-8") : "";
12239
+ await (0, import_promises6.writeFile)(filePath, existing + line);
12136
12240
  } catch {
12137
12241
  }
12138
12242
  }
12139
12243
 
12140
12244
  // src/lib/memory-retrieval.ts
12141
- var import_promises8 = require("node:fs/promises");
12245
+ var import_promises7 = require("node:fs/promises");
12142
12246
  var import_node_fs5 = require("node:fs");
12143
12247
  var import_node_path8 = require("node:path");
12144
12248
  var memoryDir = () => projectPath(`${VERITY_DIR}/memory`);
@@ -12241,11 +12345,11 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
12241
12345
  const domainDir = (0, import_node_path8.join)(memoryDir(), domain);
12242
12346
  if (!(0, import_node_fs5.existsSync)(domainDir)) continue;
12243
12347
  try {
12244
- const files = await (0, import_promises8.readdir)(domainDir);
12348
+ const files = await (0, import_promises7.readdir)(domainDir);
12245
12349
  for (const file of files) {
12246
12350
  if (!file.endsWith(".md")) continue;
12247
12351
  try {
12248
- const content = await (0, import_promises8.readFile)((0, import_node_path8.join)(domainDir, file), "utf-8");
12352
+ const content = await (0, import_promises7.readFile)((0, import_node_path8.join)(domainDir, file), "utf-8");
12249
12353
  const { fm, body } = parseFrontmatter(content);
12250
12354
  if (fm.status && fm.status !== "active") continue;
12251
12355
  nodes.push({
@@ -12303,7 +12407,7 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
12303
12407
  }
12304
12408
 
12305
12409
  // src/lib/memory-sync.ts
12306
- var import_promises9 = require("node:fs/promises");
12410
+ var import_promises8 = require("node:fs/promises");
12307
12411
  var import_node_fs6 = require("node:fs");
12308
12412
  var import_node_path9 = require("node:path");
12309
12413
  var import_node_crypto3 = require("node:crypto");
@@ -12374,18 +12478,18 @@ var memoryDir2 = () => projectPath(`${VERITY_DIR}/memory`);
12374
12478
  var DOMAINS2 = ["decisions", "quality", "security", "intent", "gotchas", "patterns", "domain", "integrations", "_archive"];
12375
12479
  var syncStateFile = () => projectPath(`${VERITY_DIR}/.memory-sync-state.json`);
12376
12480
  async function ensureMemoryDir() {
12377
- await (0, import_promises9.mkdir)(memoryDir2(), { recursive: true });
12481
+ await (0, import_promises8.mkdir)(memoryDir2(), { recursive: true });
12378
12482
  for (const domain of DOMAINS2) {
12379
- await (0, import_promises9.mkdir)((0, import_node_path9.join)(memoryDir2(), domain), { recursive: true });
12483
+ await (0, import_promises8.mkdir)((0, import_node_path9.join)(memoryDir2(), domain), { recursive: true });
12380
12484
  }
12381
12485
  if (!(0, import_node_fs6.existsSync)((0, import_node_path9.join)(memoryDir2(), "SCHEMA.md"))) {
12382
- await (0, import_promises9.writeFile)((0, import_node_path9.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
12486
+ await (0, import_promises8.writeFile)((0, import_node_path9.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
12383
12487
  }
12384
12488
  if (!(0, import_node_fs6.existsSync)((0, import_node_path9.join)(memoryDir2(), "index.md"))) {
12385
- await (0, import_promises9.writeFile)((0, import_node_path9.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
12489
+ await (0, import_promises8.writeFile)((0, import_node_path9.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
12386
12490
  }
12387
12491
  if (!(0, import_node_fs6.existsSync)((0, import_node_path9.join)(memoryDir2(), "log.md"))) {
12388
- await (0, import_promises9.writeFile)((0, import_node_path9.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
12492
+ await (0, import_promises8.writeFile)((0, import_node_path9.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
12389
12493
  }
12390
12494
  }
12391
12495
  async function buildManifest() {
@@ -12397,13 +12501,13 @@ async function buildManifest() {
12397
12501
  const domainDir = (0, import_node_path9.join)(memoryDir2(), domain);
12398
12502
  if (!(0, import_node_fs6.existsSync)(domainDir)) continue;
12399
12503
  try {
12400
- const files = await (0, import_promises9.readdir)(domainDir);
12504
+ const files = await (0, import_promises8.readdir)(domainDir);
12401
12505
  for (const file of files) {
12402
12506
  if (!file.endsWith(".md")) continue;
12403
12507
  const filePath = `${domain}/${file}`;
12404
12508
  const fullPath = (0, import_node_path9.join)(memoryDir2(), filePath);
12405
12509
  try {
12406
- const content = await (0, import_promises9.readFile)(fullPath, "utf-8");
12510
+ const content = await (0, import_promises8.readFile)(fullPath, "utf-8");
12407
12511
  const hash = (0, import_node_crypto3.createHash)("sha256").update(content).digest("hex").slice(0, 16);
12408
12512
  nodes.push({ path: filePath, content_hash: `sha256:${hash}` });
12409
12513
  } catch {
@@ -12414,13 +12518,13 @@ async function buildManifest() {
12414
12518
  }
12415
12519
  let indexHash = null;
12416
12520
  try {
12417
- const indexContent = await (0, import_promises9.readFile)((0, import_node_path9.join)(memoryDir2(), "index.md"), "utf-8");
12521
+ const indexContent = await (0, import_promises8.readFile)((0, import_node_path9.join)(memoryDir2(), "index.md"), "utf-8");
12418
12522
  indexHash = `sha256:${(0, import_node_crypto3.createHash)("sha256").update(indexContent).digest("hex").slice(0, 16)}`;
12419
12523
  } catch {
12420
12524
  }
12421
12525
  let logLength = 0;
12422
12526
  try {
12423
- const logContent = await (0, import_promises9.readFile)((0, import_node_path9.join)(memoryDir2(), "log.md"), "utf-8");
12527
+ const logContent = await (0, import_promises8.readFile)((0, import_node_path9.join)(memoryDir2(), "log.md"), "utf-8");
12424
12528
  logLength = logContent.split("\n").length;
12425
12529
  } catch {
12426
12530
  }
@@ -12436,10 +12540,10 @@ async function readOnDiskNodes() {
12436
12540
  const domainDir = (0, import_node_path9.join)(memoryDir2(), domain);
12437
12541
  if (!(0, import_node_fs6.existsSync)(domainDir)) continue;
12438
12542
  try {
12439
- for (const file of await (0, import_promises9.readdir)(domainDir)) {
12543
+ for (const file of await (0, import_promises8.readdir)(domainDir)) {
12440
12544
  if (!file.endsWith(".md")) continue;
12441
12545
  try {
12442
- out.set(`${domain}/${file}`, hashContent(await (0, import_promises9.readFile)((0, import_node_path9.join)(domainDir, file), "utf-8")));
12546
+ out.set(`${domain}/${file}`, hashContent(await (0, import_promises8.readFile)((0, import_node_path9.join)(domainDir, file), "utf-8")));
12443
12547
  } catch {
12444
12548
  }
12445
12549
  }
@@ -12451,7 +12555,7 @@ async function readOnDiskNodes() {
12451
12555
  async function readSyncBaseline() {
12452
12556
  const out = /* @__PURE__ */ new Map();
12453
12557
  try {
12454
- const parsed = JSON.parse(await (0, import_promises9.readFile)(syncStateFile(), "utf-8"));
12558
+ const parsed = JSON.parse(await (0, import_promises8.readFile)(syncStateFile(), "utf-8"));
12455
12559
  if (Array.isArray(parsed?.nodes)) {
12456
12560
  for (const n of parsed.nodes) if (n?.path) out.set(n.path, n.hash ?? null);
12457
12561
  } else if (Array.isArray(parsed?.paths)) {
@@ -12467,12 +12571,12 @@ async function recordSyncedNodePaths() {
12467
12571
  const next = JSON.stringify({ schema: 2, nodes }) + "\n";
12468
12572
  let existing = "";
12469
12573
  try {
12470
- existing = await (0, import_promises9.readFile)(syncStateFile(), "utf-8");
12574
+ existing = await (0, import_promises8.readFile)(syncStateFile(), "utf-8");
12471
12575
  } catch {
12472
12576
  }
12473
12577
  if (existing === next) return;
12474
- await (0, import_promises9.mkdir)(projectPath(VERITY_DIR), { recursive: true });
12475
- await (0, import_promises9.writeFile)(syncStateFile(), next);
12578
+ await (0, import_promises8.mkdir)(projectPath(VERITY_DIR), { recursive: true });
12579
+ await (0, import_promises8.writeFile)(syncStateFile(), next);
12476
12580
  } catch {
12477
12581
  }
12478
12582
  }
@@ -12489,7 +12593,7 @@ async function computeEditedNodeUploads() {
12489
12593
  if (!(0, import_node_fs6.existsSync)(full)) continue;
12490
12594
  let content;
12491
12595
  try {
12492
- content = await (0, import_promises9.readFile)(full, "utf-8");
12596
+ content = await (0, import_promises8.readFile)(full, "utf-8");
12493
12597
  } catch {
12494
12598
  continue;
12495
12599
  }
@@ -12522,8 +12626,8 @@ async function applyMemoryWrites(writes, opts = {}) {
12522
12626
  const logLines = [`- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)} \u2014 Applied ${count} write(s) from server`];
12523
12627
  for (const n of notes) logLines.push(` - ${n}`);
12524
12628
  try {
12525
- const existing = (0, import_node_fs6.existsSync)((0, import_node_path9.join)(memoryDir2(), "log.md")) ? await (0, import_promises9.readFile)((0, import_node_path9.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
12526
- await (0, import_promises9.writeFile)((0, import_node_path9.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
12629
+ const existing = (0, import_node_fs6.existsSync)((0, import_node_path9.join)(memoryDir2(), "log.md")) ? await (0, import_promises8.readFile)((0, import_node_path9.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
12630
+ await (0, import_promises8.writeFile)((0, import_node_path9.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
12527
12631
  } catch {
12528
12632
  }
12529
12633
  await recordSyncedNodePaths();
@@ -12543,7 +12647,7 @@ async function applyOneWrite(write, treePaths) {
12543
12647
  if ((0, import_node_fs6.existsSync)(fullPath)) {
12544
12648
  let existing = "";
12545
12649
  try {
12546
- existing = await (0, import_promises9.readFile)(fullPath, "utf-8");
12650
+ existing = await (0, import_promises8.readFile)(fullPath, "utf-8");
12547
12651
  } catch {
12548
12652
  }
12549
12653
  if (existing === content) return { written: false, notes };
@@ -12552,8 +12656,8 @@ async function applyOneWrite(write, treePaths) {
12552
12656
  return { written: false, notes };
12553
12657
  }
12554
12658
  }
12555
- await (0, import_promises9.mkdir)((0, import_node_path9.dirname)(fullPath), { recursive: true });
12556
- await (0, import_promises9.writeFile)(fullPath, content);
12659
+ await (0, import_promises8.mkdir)((0, import_node_path9.dirname)(fullPath), { recursive: true });
12660
+ await (0, import_promises8.writeFile)(fullPath, content);
12557
12661
  return { written: true, notes };
12558
12662
  }
12559
12663
  function groundFileGlobs(content, treePaths) {
@@ -12596,7 +12700,7 @@ async function regenerateIndex() {
12596
12700
  const domainDir = (0, import_node_path9.join)(memoryDir2(), domain);
12597
12701
  if (!(0, import_node_fs6.existsSync)(domainDir)) continue;
12598
12702
  try {
12599
- const files = await (0, import_promises9.readdir)(domainDir);
12703
+ const files = await (0, import_promises8.readdir)(domainDir);
12600
12704
  const mdFiles = files.filter((f) => f.endsWith(".md"));
12601
12705
  if (mdFiles.length === 0) continue;
12602
12706
  lines.push(`## ${domain}/ (${mdFiles.length})`);
@@ -12604,7 +12708,7 @@ async function regenerateIndex() {
12604
12708
  for (const file of mdFiles.sort()) {
12605
12709
  const slug = file.replace(/\.md$/, "");
12606
12710
  try {
12607
- const content = await (0, import_promises9.readFile)((0, import_node_path9.join)(domainDir, file), "utf-8");
12711
+ const content = await (0, import_promises8.readFile)((0, import_node_path9.join)(domainDir, file), "utf-8");
12608
12712
  const title = pickFrontmatter(content, "title") ?? slug;
12609
12713
  const kind = pickFrontmatter(content, "kind") ?? "-";
12610
12714
  const confidence = pickFrontmatter(content, "confidence");
@@ -12631,11 +12735,11 @@ async function regenerateIndex() {
12631
12735
  const indexPath = (0, import_node_path9.join)(memoryDir2(), "index.md");
12632
12736
  let existing = null;
12633
12737
  try {
12634
- existing = await (0, import_promises9.readFile)(indexPath, "utf-8");
12738
+ existing = await (0, import_promises8.readFile)(indexPath, "utf-8");
12635
12739
  } catch {
12636
12740
  }
12637
12741
  if (existing === next) return;
12638
- await (0, import_promises9.writeFile)(indexPath, next);
12742
+ await (0, import_promises8.writeFile)(indexPath, next);
12639
12743
  }
12640
12744
  function pickFrontmatter(content, key) {
12641
12745
  const re = new RegExp(`^${key}:\\s*"?([^"\\n]+?)"?\\s*$`, "m");
@@ -12713,7 +12817,7 @@ async function ensureClaudeMdPointer(cwd = repoRoot()) {
12713
12817
  const claudeMdPath = (0, import_node_path9.join)(cwd, "CLAUDE.md");
12714
12818
  let existing = "";
12715
12819
  if ((0, import_node_fs6.existsSync)(claudeMdPath)) {
12716
- existing = await (0, import_promises9.readFile)(claudeMdPath, "utf-8");
12820
+ existing = await (0, import_promises8.readFile)(claudeMdPath, "utf-8");
12717
12821
  }
12718
12822
  let startTag = CLAUDE_MD_START;
12719
12823
  let endTag = CLAUDE_MD_END;
@@ -12769,7 +12873,7 @@ async function ensureClaudeMdPointer(cwd = repoRoot()) {
12769
12873
  next = existing.replace(/\n*$/, "") + "\n\n" + block + "\n";
12770
12874
  }
12771
12875
  if (next === existing) return;
12772
- await (0, import_promises9.writeFile)(claudeMdPath, next);
12876
+ await (0, import_promises8.writeFile)(claudeMdPath, next);
12773
12877
  }
12774
12878
  function extractPreserveContent(interior) {
12775
12879
  for (const [start, end] of [
@@ -12955,7 +13059,7 @@ async function fireClassify(prompt, sessionId) {
12955
13059
  }
12956
13060
 
12957
13061
  // src/commands/standard.ts
12958
- var import_promises10 = require("node:fs/promises");
13062
+ var import_promises9 = require("node:fs/promises");
12959
13063
  var import_yaml = __toESM(require_dist());
12960
13064
  function registerStandardCommands(program2) {
12961
13065
  const standard = program2.command("standard").description("Manage the project Standard");
@@ -12973,7 +13077,7 @@ function registerStandardCommands(program2) {
12973
13077
  }
12974
13078
  let yamlContent;
12975
13079
  try {
12976
- yamlContent = await (0, import_promises10.readFile)(opts.file, "utf-8");
13080
+ yamlContent = await (0, import_promises9.readFile)(opts.file, "utf-8");
12977
13081
  } catch {
12978
13082
  printError(`Cannot read ${opts.file}`);
12979
13083
  process.exit(1);
@@ -13064,7 +13168,7 @@ function registerStandardCommands(program2) {
13064
13168
  }
13065
13169
 
13066
13170
  // src/commands/config.ts
13067
- var import_promises11 = require("node:fs/promises");
13171
+ var import_promises10 = require("node:fs/promises");
13068
13172
  function registerConfigCommands(program2) {
13069
13173
  const config = program2.command("config").description("Manage analysis configuration");
13070
13174
  config.command("push").description("Upload the analysis config to the service").option("--file <path>", "Path to config file", CODACY_CONFIG_FILE).action(async (opts) => {
@@ -13081,7 +13185,7 @@ function registerConfigCommands(program2) {
13081
13185
  }
13082
13186
  let content;
13083
13187
  try {
13084
- const raw = await (0, import_promises11.readFile)(opts.file, "utf-8");
13188
+ const raw = await (0, import_promises10.readFile)(opts.file, "utf-8");
13085
13189
  content = JSON.parse(raw);
13086
13190
  } catch {
13087
13191
  printError(`Cannot read or parse ${opts.file}`);
@@ -14773,7 +14877,7 @@ function isExplicitlyAutonomous(env = process.env) {
14773
14877
  }
14774
14878
 
14775
14879
  // src/lib/seed-runner.ts
14776
- var import_promises12 = require("node:fs/promises");
14880
+ var import_promises11 = require("node:fs/promises");
14777
14881
  var import_node_fs18 = require("node:fs");
14778
14882
  var import_node_path15 = require("node:path");
14779
14883
  var import_yaml2 = __toESM(require_dist());
@@ -15019,7 +15123,7 @@ async function runSeed(opts) {
15019
15123
  }
15020
15124
  let standardDoc;
15021
15125
  try {
15022
- const raw = await (0, import_promises12.readFile)(STANDARD_FILE, "utf-8");
15126
+ const raw = await (0, import_promises11.readFile)(STANDARD_FILE, "utf-8");
15023
15127
  standardDoc = (0, import_yaml2.parse)(raw);
15024
15128
  } catch {
15025
15129
  return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
@@ -15028,7 +15132,7 @@ async function runSeed(opts) {
15028
15132
  let readmeContent;
15029
15133
  if ((0, import_node_fs18.existsSync)("README.md")) {
15030
15134
  try {
15031
- readmeContent = await (0, import_promises12.readFile)("README.md", "utf-8");
15135
+ readmeContent = await (0, import_promises11.readFile)("README.md", "utf-8");
15032
15136
  } catch {
15033
15137
  }
15034
15138
  }
@@ -15036,7 +15140,7 @@ async function runSeed(opts) {
15036
15140
  for (const p of ["CLAUDE.md", ".claude/CLAUDE.md"]) {
15037
15141
  if ((0, import_node_fs18.existsSync)(p)) {
15038
15142
  try {
15039
- claudeMdContent = await (0, import_promises12.readFile)(p, "utf-8");
15143
+ claudeMdContent = await (0, import_promises11.readFile)(p, "utf-8");
15040
15144
  break;
15041
15145
  } catch {
15042
15146
  }
@@ -15095,8 +15199,8 @@ async function runSeed(opts) {
15095
15199
  const filePathRel = res.data.file_path;
15096
15200
  const targetPath = (0, import_node_path15.join)(MEMORY_DIR, filePathRel);
15097
15201
  try {
15098
- await (0, import_promises12.mkdir)((0, import_node_path15.dirname)(targetPath), { recursive: true });
15099
- await (0, import_promises12.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
15202
+ await (0, import_promises11.mkdir)((0, import_node_path15.dirname)(targetPath), { recursive: true });
15203
+ await (0, import_promises11.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
15100
15204
  created++;
15101
15205
  opts.onCreated?.(nodeId, filePathRel, c);
15102
15206
  } catch (err) {
@@ -16217,6 +16321,98 @@ var readline2 = __toESM(require("node:readline/promises"));
16217
16321
  var import_node_fs23 = require("node:fs");
16218
16322
  var import_node_path18 = require("node:path");
16219
16323
  var import_node_child_process10 = require("node:child_process");
16324
+
16325
+ // src/lib/telemetry.ts
16326
+ var import_promises12 = require("node:fs/promises");
16327
+ var SETTINGS_LOCAL_FILE2 = ".claude/settings.local.json";
16328
+ var GITIGNORE_FILE = ".gitignore";
16329
+ var GITIGNORE_ENTRY = ".claude/settings.local.json";
16330
+ var OTEL_HEADERS_HELPER_CMD = "verity telemetry headers";
16331
+ var LEGACY_TELEMETRY_ENV_KEYS = ["OTEL_EXPORTER_OTLP_HEADERS"];
16332
+ function deriveOtlpEndpoint(serviceUrl) {
16333
+ return serviceUrl.replace(/\/+$/, "").replace(/\/v1$/, "") + "/v1/otlp";
16334
+ }
16335
+ function buildTelemetryEnv(serviceUrl) {
16336
+ return {
16337
+ CLAUDE_CODE_ENABLE_TELEMETRY: "1",
16338
+ OTEL_METRICS_EXPORTER: "otlp",
16339
+ OTEL_TRACES_EXPORTER: "otlp",
16340
+ CLAUDE_CODE_ENHANCED_TELEMETRY_BETA: "1",
16341
+ OTEL_EXPORTER_OTLP_PROTOCOL: "http/json",
16342
+ OTEL_EXPORTER_OTLP_ENDPOINT: deriveOtlpEndpoint(serviceUrl),
16343
+ OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: "delta",
16344
+ OTEL_LOG_USER_PROMPTS: "0",
16345
+ OTEL_LOG_TOOL_DETAILS: "0",
16346
+ OTEL_LOG_TOOL_CONTENT: "0",
16347
+ OTEL_METRICS_INCLUDE_SESSION_ID: "true",
16348
+ OTEL_METRICS_INCLUDE_ACCOUNT_UUID: "false",
16349
+ OTEL_METRICS_INCLUDE_VERSION: "false",
16350
+ OTEL_METRIC_EXPORT_INTERVAL: "60000"
16351
+ };
16352
+ }
16353
+ var VERITY_TELEMETRY_KEYS = Object.keys(buildTelemetryEnv(""));
16354
+ async function readSettingsLocal() {
16355
+ try {
16356
+ return JSON.parse(await (0, import_promises12.readFile)(projectPath(SETTINGS_LOCAL_FILE2), "utf-8"));
16357
+ } catch {
16358
+ return {};
16359
+ }
16360
+ }
16361
+ async function writeSettingsLocal(settings) {
16362
+ await writeJsonFilePreservingStyle(projectPath(SETTINGS_LOCAL_FILE2), settings);
16363
+ }
16364
+ async function ensureGitignore() {
16365
+ const file = projectPath(GITIGNORE_FILE);
16366
+ let content = "";
16367
+ try {
16368
+ content = await (0, import_promises12.readFile)(file, "utf-8");
16369
+ } catch {
16370
+ }
16371
+ const lines = content.split("\n").map((l) => l.trim());
16372
+ if (lines.includes(GITIGNORE_ENTRY) || lines.includes(".claude/") || lines.includes(".claude")) {
16373
+ return;
16374
+ }
16375
+ const block = "# Verity telemetry \u2014 machine-local Claude Code settings\n" + GITIGNORE_ENTRY + "\n";
16376
+ const next = content ? content + (content.endsWith("\n") ? "" : "\n") + "\n" + block : block;
16377
+ await (0, import_promises12.writeFile)(file, next);
16378
+ }
16379
+ async function installTelemetry(serviceUrl) {
16380
+ const env = buildTelemetryEnv(serviceUrl);
16381
+ const settings = await readSettingsLocal();
16382
+ settings.env = { ...settings.env ?? {}, ...env };
16383
+ for (const key of LEGACY_TELEMETRY_ENV_KEYS) delete settings.env[key];
16384
+ settings.otelHeadersHelper = OTEL_HEADERS_HELPER_CMD;
16385
+ await writeSettingsLocal(settings);
16386
+ await ensureGitignore();
16387
+ return { ok: true, data: { endpoint: env.OTEL_EXPORTER_OTLP_ENDPOINT } };
16388
+ }
16389
+ async function checkTelemetry() {
16390
+ const env = (await readSettingsLocal()).env ?? {};
16391
+ const enabled = env.CLAUDE_CODE_ENABLE_TELEMETRY === "1" && !!env.OTEL_EXPORTER_OTLP_ENDPOINT;
16392
+ return { enabled, endpoint: env.OTEL_EXPORTER_OTLP_ENDPOINT ?? null, settingsPath: SETTINGS_LOCAL_FILE2 };
16393
+ }
16394
+ async function uninstallTelemetry() {
16395
+ const settings = await readSettingsLocal();
16396
+ const hadHelper = settings.otelHeadersHelper === OTEL_HEADERS_HELPER_CMD;
16397
+ if (hadHelper) delete settings.otelHeadersHelper;
16398
+ if (!settings.env) {
16399
+ if (hadHelper) await writeSettingsLocal(settings);
16400
+ return { ok: true, data: { removed: 0 } };
16401
+ }
16402
+ let removed = 0;
16403
+ for (const key of VERITY_TELEMETRY_KEYS) {
16404
+ if (key in settings.env) {
16405
+ delete settings.env[key];
16406
+ removed++;
16407
+ }
16408
+ }
16409
+ for (const key of LEGACY_TELEMETRY_ENV_KEYS) delete settings.env[key];
16410
+ if (Object.keys(settings.env).length === 0) delete settings.env;
16411
+ await writeSettingsLocal(settings);
16412
+ return { ok: true, data: { removed } };
16413
+ }
16414
+
16415
+ // src/commands/migrate.ts
16220
16416
  var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
16221
16417
  function defaultNpmRemover(pkg) {
16222
16418
  (0, import_node_child_process10.execSync)(`npm rm -g ${pkg}`, { stdio: "pipe", timeout: 12e4 });
@@ -16247,6 +16443,7 @@ async function runMigration(opts = {}) {
16247
16443
  await migrateLegacyHooks(root, actions);
16248
16444
  await migrateClaudeMd(root, actions);
16249
16445
  migrateStandardFile(root, actions);
16446
+ await migrateTelemetryHeaders(root, actions);
16250
16447
  removeLegacyPackage(movedProjectDir, npmRemover, actions);
16251
16448
  return { actions, migrated: actions.length > 0 };
16252
16449
  }
@@ -16360,6 +16557,25 @@ function migrateStandardFile(root, actions) {
16360
16557
  if (refreshed !== content) (0, import_node_fs23.writeFileSync)(verityMd, refreshed);
16361
16558
  actions.push("Renamed GATE.md \u2192 VERITY.md");
16362
16559
  }
16560
+ async function migrateTelemetryHeaders(root, actions) {
16561
+ const file = (0, import_node_path18.join)(root, ".claude", "settings.local.json");
16562
+ if (!(0, import_node_fs23.existsSync)(file)) return;
16563
+ let settings;
16564
+ try {
16565
+ settings = JSON.parse(readFileSyncSafe(file) || "{}");
16566
+ } catch {
16567
+ return;
16568
+ }
16569
+ const env = settings.env;
16570
+ const hasInlineHeader = !!env && "OTEL_EXPORTER_OTLP_HEADERS" in env;
16571
+ const telemetryEnabled = env?.CLAUDE_CODE_ENABLE_TELEMETRY === "1";
16572
+ const needsHelper = telemetryEnabled && settings.otelHeadersHelper !== OTEL_HEADERS_HELPER_CMD;
16573
+ if (!hasInlineHeader && !needsHelper) return;
16574
+ if (hasInlineHeader && env) delete env["OTEL_EXPORTER_OTLP_HEADERS"];
16575
+ if (telemetryEnabled) settings.otelHeadersHelper = OTEL_HEADERS_HELPER_CMD;
16576
+ await writeJsonFilePreservingStyle(file, settings);
16577
+ actions.push("Moved the telemetry token out of .claude/settings.local.json (now resolved at runtime)");
16578
+ }
16363
16579
  function removeLegacyPackage(movedProjectDir, npmRemover, actions) {
16364
16580
  if (!movedProjectDir) return;
16365
16581
  try {
@@ -16532,7 +16748,7 @@ async function runOptionalAuth(resolution, opts = {}) {
16532
16748
  serviceUrl = heal.serviceUrl;
16533
16749
  healed = heal.healed;
16534
16750
  if (healed) {
16535
- printInfo(" Log in below to re-register this project and repair .verity/credentials.");
16751
+ printInfo(" Log in below to re-register this project and repair ~/.verity/credentials.");
16536
16752
  }
16537
16753
  }
16538
16754
  if (!healed) {
@@ -17330,89 +17546,6 @@ function registerRunCommand(program2) {
17330
17546
  });
17331
17547
  }
17332
17548
 
17333
- // src/lib/telemetry.ts
17334
- var import_promises14 = require("node:fs/promises");
17335
- var SETTINGS_LOCAL_FILE2 = ".claude/settings.local.json";
17336
- var GITIGNORE_FILE = ".gitignore";
17337
- var GITIGNORE_ENTRY = ".claude/settings.local.json";
17338
- function deriveOtlpEndpoint(serviceUrl) {
17339
- return serviceUrl.replace(/\/+$/, "").replace(/\/v1$/, "") + "/v1/otlp";
17340
- }
17341
- function buildTelemetryEnv(serviceUrl, token) {
17342
- return {
17343
- CLAUDE_CODE_ENABLE_TELEMETRY: "1",
17344
- OTEL_METRICS_EXPORTER: "otlp",
17345
- OTEL_TRACES_EXPORTER: "otlp",
17346
- CLAUDE_CODE_ENHANCED_TELEMETRY_BETA: "1",
17347
- OTEL_EXPORTER_OTLP_PROTOCOL: "http/json",
17348
- OTEL_EXPORTER_OTLP_ENDPOINT: deriveOtlpEndpoint(serviceUrl),
17349
- // <token> is whatever is in .verity/credentials — verity_ OR legacy gate_.
17350
- // The server hashes the raw token regardless of prefix.
17351
- OTEL_EXPORTER_OTLP_HEADERS: `Authorization=Bearer ${token}`,
17352
- OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: "delta",
17353
- OTEL_LOG_USER_PROMPTS: "0",
17354
- OTEL_LOG_TOOL_DETAILS: "0",
17355
- OTEL_LOG_TOOL_CONTENT: "0",
17356
- OTEL_METRICS_INCLUDE_SESSION_ID: "true",
17357
- OTEL_METRICS_INCLUDE_ACCOUNT_UUID: "false",
17358
- OTEL_METRICS_INCLUDE_VERSION: "false",
17359
- OTEL_METRIC_EXPORT_INTERVAL: "60000"
17360
- };
17361
- }
17362
- var VERITY_TELEMETRY_KEYS = Object.keys(buildTelemetryEnv("", ""));
17363
- async function readSettingsLocal() {
17364
- try {
17365
- return JSON.parse(await (0, import_promises14.readFile)(projectPath(SETTINGS_LOCAL_FILE2), "utf-8"));
17366
- } catch {
17367
- return {};
17368
- }
17369
- }
17370
- async function writeSettingsLocal(settings) {
17371
- await writeJsonFilePreservingStyle(projectPath(SETTINGS_LOCAL_FILE2), settings);
17372
- }
17373
- async function ensureGitignore() {
17374
- const file = projectPath(GITIGNORE_FILE);
17375
- let content = "";
17376
- try {
17377
- content = await (0, import_promises14.readFile)(file, "utf-8");
17378
- } catch {
17379
- }
17380
- const lines = content.split("\n").map((l) => l.trim());
17381
- if (lines.includes(GITIGNORE_ENTRY) || lines.includes(".claude/") || lines.includes(".claude")) {
17382
- return;
17383
- }
17384
- const block = "# Verity telemetry \u2014 holds your project token\n" + GITIGNORE_ENTRY + "\n";
17385
- const next = content ? content + (content.endsWith("\n") ? "" : "\n") + "\n" + block : block;
17386
- await (0, import_promises14.writeFile)(file, next);
17387
- }
17388
- async function installTelemetry(serviceUrl, token) {
17389
- const env = buildTelemetryEnv(serviceUrl, token);
17390
- const settings = await readSettingsLocal();
17391
- settings.env = { ...settings.env ?? {}, ...env };
17392
- await writeSettingsLocal(settings);
17393
- await ensureGitignore();
17394
- return { ok: true, data: { endpoint: env.OTEL_EXPORTER_OTLP_ENDPOINT } };
17395
- }
17396
- async function checkTelemetry() {
17397
- const env = (await readSettingsLocal()).env ?? {};
17398
- const enabled = env.CLAUDE_CODE_ENABLE_TELEMETRY === "1" && !!env.OTEL_EXPORTER_OTLP_ENDPOINT;
17399
- return { enabled, endpoint: env.OTEL_EXPORTER_OTLP_ENDPOINT ?? null, settingsPath: SETTINGS_LOCAL_FILE2 };
17400
- }
17401
- async function uninstallTelemetry() {
17402
- const settings = await readSettingsLocal();
17403
- if (!settings.env) return { ok: true, data: { removed: 0 } };
17404
- let removed = 0;
17405
- for (const key of VERITY_TELEMETRY_KEYS) {
17406
- if (key in settings.env) {
17407
- delete settings.env[key];
17408
- removed++;
17409
- }
17410
- }
17411
- if (Object.keys(settings.env).length === 0) delete settings.env;
17412
- await writeSettingsLocal(settings);
17413
- return { ok: true, data: { removed } };
17414
- }
17415
-
17416
17549
  // src/commands/telemetry.ts
17417
17550
  function registerTelemetryCommands(program2) {
17418
17551
  const telemetry = program2.command("telemetry").description("Manage Claude Code OpenTelemetry export to Verity (cost & usage)");
@@ -17428,16 +17561,25 @@ function registerTelemetryCommands(program2) {
17428
17561
  printError(urlResult.error);
17429
17562
  process.exit(1);
17430
17563
  }
17431
- const result = await installTelemetry(urlResult.data, tokenResult.data.token);
17564
+ const result = await installTelemetry(urlResult.data);
17432
17565
  if (!result.ok) {
17433
17566
  printError(result.error);
17434
17567
  process.exit(1);
17435
17568
  }
17436
17569
  printInfo(`Telemetry enabled \u2192 ${result.data.endpoint}`);
17437
- printInfo(` wrote ${SETTINGS_LOCAL_FILE2} (gitignored \u2014 it holds your project token)`);
17570
+ printInfo(` wrote ${SETTINGS_LOCAL_FILE2} (no token stored \u2014 resolved at runtime via otelHeadersHelper)`);
17438
17571
  printInfo(" takes effect on your NEXT Claude Code session; first metrics appear within ~60s of activity");
17439
17572
  printInfo(" view cost & usage at /usage");
17440
17573
  });
17574
+ telemetry.command("headers").description("Print the OTLP Authorization header as JSON (used by Claude Code otelHeadersHelper)").action(async () => {
17575
+ const globals = program2.opts();
17576
+ const tokenResult = await resolveToken(globals.token);
17577
+ if (tokenResult.ok) {
17578
+ printJsonCompact({ Authorization: `Bearer ${tokenResult.data.token}` });
17579
+ } else {
17580
+ printJsonCompact({});
17581
+ }
17582
+ });
17441
17583
  telemetry.command("check").description("Show whether Claude Code telemetry export to Verity is enabled").option("--json", "Output status as JSON").action(async (opts) => {
17442
17584
  const status = await checkTelemetry();
17443
17585
  if (opts.json) {
@@ -17463,7 +17605,12 @@ function registerTelemetryCommands(program2) {
17463
17605
  }
17464
17606
 
17465
17607
  // src/cli.ts
17466
- program.name("verity").description("CLI for Verity quality gate service").version("0.28.0").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr");
17608
+ program.name("verity").description("CLI for Verity quality gate service").version("0.28.1-experimental.708d3ae").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr").hook("preAction", async () => {
17609
+ try {
17610
+ await foldLegacyLocalCredential();
17611
+ } catch {
17612
+ }
17613
+ });
17467
17614
  registerAuthCommands(program);
17468
17615
  registerLoginCommand(program);
17469
17616
  registerHooksCommands(program);
@@ -17485,4 +17632,8 @@ registerMemoryCommand(program);
17485
17632
  registerRunCommand(program);
17486
17633
  registerMigrateCommand(program);
17487
17634
  registerTelemetryCommands(program);
17488
- program.parse();
17635
+ program.parseAsync().catch((err) => {
17636
+ process.stderr.write(`[verity] ${err instanceof Error ? err.message : String(err)}
17637
+ `);
17638
+ process.exit(1);
17639
+ });
@@ -353,8 +353,9 @@ verity auth verify
353
353
  (Metadata + Email addresses); the resulting token is used once server-side to
354
354
  check repo access and is never persisted.
355
355
 
356
- When authenticated, `.verity/credentials` contains `token` and `service_url`
357
- all subsequent `verity` upload commands work.
356
+ When authenticated, the project's `token` and `service_url` are stored in the
357
+ single global credentials file `~/.verity/credentials` (keyed by git remote) —
358
+ nothing secret is written into the repo. All subsequent `verity` upload commands work.
358
359
 
359
360
  ---
360
361
 
@@ -407,10 +408,12 @@ now (the token from Step 6 must already exist):
407
408
  verity telemetry install
408
409
  ```
409
410
 
410
- This writes the `OTEL_*` env block to the gitignored `.claude/settings.local.json` (which
411
- holds your token) and points Claude Code's OpenTelemetry exporter at Verity's OTLP endpoint.
412
- Tell the user it takes effect on their **next** Claude Code session, that first metrics appear
413
- within ~60s of activity, and point them at `/usage`.
411
+ This writes the `OTEL_*` env block plus an `otelHeadersHelper` to `.claude/settings.local.json`
412
+ and points Claude Code's OpenTelemetry exporter at Verity's OTLP endpoint. No token is written to
413
+ the file the helper (`verity telemetry headers`) resolves the project token from
414
+ `~/.verity/credentials` at session start, so the secret never lands in the repo. Tell the user it
415
+ takes effect on their **next** Claude Code session, that first metrics appear within ~60s of
416
+ activity, and point them at `/usage`.
414
417
 
415
418
  If the user declined, skip this step and note that `/usage` will stay empty until they run
416
419
  `verity telemetry install`.
@@ -534,7 +537,6 @@ Add these entries to `.gitignore` (create it if it doesn't exist, append if it d
534
537
 
535
538
  ```
536
539
  # Verity
537
- .verity/credentials
538
540
  .verity/.cache/
539
541
  .verity/.logs/
540
542
  .verity/.last-analysis
@@ -546,14 +548,18 @@ Add these entries to `.gitignore` (create it if it doesn't exist, append if it d
546
548
  .claude/settings.local.json
547
549
  ```
548
550
 
549
- `.claude/settings.local.json` holds the telemetry env block **including your token**, so it
550
- must never be committed (`verity telemetry install` also adds this entry automatically).
551
+ `.claude/settings.local.json` is machine-local Claude Code config (telemetry endpoint + an
552
+ `otelHeadersHelper` reference no token). `verity telemetry install` adds this entry
553
+ automatically.
551
554
 
552
555
  Do NOT gitignore `.verity/standard.yaml` or `VERITY.md` — those should be committed.
553
556
 
554
557
  **Commit the knowledge graph, but not its log.** The nodes under `.verity/memory/<domain>/` and `.verity/memory/index.md` are durable project knowledge meant to be committed and reviewed. But `.verity/memory/log.md` is an append-only, per-run timestamped activity log — it churns on every analysis and carries no reviewable content, so it is gitignored above. If a project already committed it, untrack it once with `git rm --cached .verity/memory/log.md`.
555
558
 
556
- The `.verity/credentials` file contains the project token and MUST be gitignored.
559
+ **No secrets live in the repo anymore.** The project token is stored only in the single global
560
+ file `~/.verity/credentials` (outside the repo, keyed by git remote), so there is no
561
+ `.verity/credentials` to ignore. If an older install left one behind, the CLI folds it into the
562
+ global store and removes it automatically on the next `verity` command.
557
563
 
558
564
  ---
559
565
 
package/package.json CHANGED
@@ -1,12 +1,8 @@
1
1
  {
2
2
  "name": "@codacy/verity-cli",
3
- "version": "0.28.0",
3
+ "version": "0.28.1-experimental.708d3ae",
4
4
  "description": "CLI for Verity quality gate service",
5
5
  "homepage": "https://verity.md",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://github.com/codacy/verity.git"
9
- },
10
6
  "bugs": {
11
7
  "url": "https://github.com/codacy/verity/issues"
12
8
  },