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

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
@@ -675,8 +675,8 @@ var require_option = __commonJS({
675
675
  * @param {(string | string[])} names
676
676
  * @return {Option}
677
677
  */
678
- conflicts(names) {
679
- this.conflictsWith = this.conflictsWith.concat(names);
678
+ conflicts(names2) {
679
+ this.conflictsWith = this.conflictsWith.concat(names2);
680
680
  return this;
681
681
  }
682
682
  /**
@@ -1249,8 +1249,8 @@ var require_command = __commonJS({
1249
1249
  * @param {string} names
1250
1250
  * @return {Command} `this` command for chaining
1251
1251
  */
1252
- arguments(names) {
1253
- names.trim().split(/ +/).forEach((detail) => {
1252
+ arguments(names2) {
1253
+ names2.trim().split(/ +/).forEach((detail) => {
1254
1254
  this.argument(detail);
1255
1255
  });
1256
1256
  return this;
@@ -10509,7 +10509,7 @@ var SECURITY_PATTERNS = [
10509
10509
  /Dockerfile/
10510
10510
  ];
10511
10511
  var PROD_SERVICE_URL = "https://ofcamwrjwrkazqvdchko.supabase.co/functions/v1";
10512
- var DEFAULT_SERVICE_URL = "".length > 0 ? "" : PROD_SERVICE_URL;
10512
+ var DEFAULT_SERVICE_URL = "https://wukeddyzpijoegyajtnc.supabase.co/functions/v1".length > 0 ? "https://wukeddyzpijoegyajtnc.supabase.co/functions/v1" : PROD_SERVICE_URL;
10513
10513
  var GITHUB_CLIENT_ID = "Iv23li88HxAi3ZrbYzWh";
10514
10514
  var GITHUB_DEVICE_CODE_URL = "https://github.com/login/device/code";
10515
10515
  var GITHUB_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
@@ -10955,8 +10955,8 @@ function filterReviewable(files) {
10955
10955
  const ext = (0, import_node_path3.extname)(f).slice(1);
10956
10956
  if (ANALYZABLE_EXTENSIONS.has(ext)) return false;
10957
10957
  if (REVIEWABLE_EXTENSIONS.has(ext)) return true;
10958
- const basename3 = f.split("/").pop() ?? "";
10959
- if (REVIEWABLE_FILENAMES.has(basename3)) return true;
10958
+ const basename4 = f.split("/").pop() ?? "";
10959
+ if (REVIEWABLE_FILENAMES.has(basename4)) return true;
10960
10960
  if (REVIEWABLE_PATH_PATTERNS.some((p) => p.test(f))) return true;
10961
10961
  return false;
10962
10962
  });
@@ -16758,12 +16758,862 @@ async function readHookStdin() {
16758
16758
  }
16759
16759
 
16760
16760
  // src/commands/standard.ts
16761
+ var import_promises12 = require("node:fs/promises");
16762
+ var import_node_fs28 = require("node:fs");
16763
+ var import_yaml3 = __toESM(require_dist());
16764
+
16765
+ // src/lib/synthesize.ts
16766
+ var import_node_child_process8 = require("node:child_process");
16767
+ var import_node_fs24 = require("node:fs");
16761
16768
  var import_promises9 = require("node:fs/promises");
16762
- var import_node_fs23 = require("node:fs");
16769
+ var import_node_path20 = require("node:path");
16763
16770
  var import_yaml = __toESM(require_dist());
16764
16771
 
16765
- // src/lib/verityignore.ts
16772
+ // src/lib/data-dir.ts
16766
16773
  var import_node_fs22 = require("node:fs");
16774
+ var import_node_path18 = require("node:path");
16775
+ function resolveDataDir() {
16776
+ const candidates = [
16777
+ (0, import_node_path18.join)(__dirname, "..", "data"),
16778
+ // installed: node_modules/@codacy/verity-cli/data
16779
+ (0, import_node_path18.join)(__dirname, "..", "..", "data"),
16780
+ // edge case: nested resolution
16781
+ // THE COMMITTED SOURCE, for a source checkout that has not been built.
16782
+ // cli/data/skills/ is a BUILD ARTIFACT (scripts/build.js copies client/skills
16783
+ // into it) and is gitignored, because skills have one committed source — so
16784
+ // in a fresh clone the packaged candidates above do not exist at all, and
16785
+ // without this the synthesizer throws "Could not find Verity skill data"
16786
+ // for every test and every `verity` run from source. Resolved from this
16787
+ // module's own location, never the cwd: see the warning below.
16788
+ (0, import_node_path18.join)(__dirname, "..", "..", "client"),
16789
+ // bundled: cli/bin/ → ../../client
16790
+ (0, import_node_path18.join)(__dirname, "..", "..", "..", "client"),
16791
+ // tsx: cli/src/lib/ → ../../../client
16792
+ ...process.env.VERITY_DEV_DATA_DIR ? [process.env.VERITY_DEV_DATA_DIR] : []
16793
+ ];
16794
+ for (const candidate of candidates) {
16795
+ if ((0, import_node_fs22.existsSync)((0, import_node_path18.join)(candidate, "skills"))) {
16796
+ return candidate;
16797
+ }
16798
+ }
16799
+ throw new Error(
16800
+ "Could not find Verity skill data. Reinstall: npm install -g @codacy/verity-cli"
16801
+ );
16802
+ }
16803
+ function setupDataPath(file) {
16804
+ return (0, import_node_path18.join)(resolveDataDir(), "skills", "verity-setup", file);
16805
+ }
16806
+
16807
+ // src/lib/detect.ts
16808
+ var import_node_child_process7 = require("node:child_process");
16809
+ var import_node_fs23 = require("node:fs");
16810
+ var import_node_path19 = require("node:path");
16811
+ var TOOLED_LANGUAGES = /* @__PURE__ */ new Set([
16812
+ "typescript",
16813
+ "javascript",
16814
+ "python",
16815
+ "go",
16816
+ "java",
16817
+ "kotlin",
16818
+ "ruby",
16819
+ "rust",
16820
+ "c",
16821
+ "cpp",
16822
+ "shell",
16823
+ "dockerfile"
16824
+ ]);
16825
+ var MIN_FILES_FOR_LANGUAGE = 3;
16826
+ var IGNORED_SEGMENTS = [
16827
+ "node_modules",
16828
+ "dist",
16829
+ "build",
16830
+ "vendor",
16831
+ "coverage",
16832
+ ".git",
16833
+ "__pycache__",
16834
+ ".next",
16835
+ ".venv",
16836
+ "target",
16837
+ ".verity",
16838
+ ".codacy"
16839
+ ];
16840
+ function isIgnored(path) {
16841
+ const parts = path.split("/");
16842
+ return parts.some((p) => IGNORED_SEGMENTS.includes(p));
16843
+ }
16844
+ function listProjectFiles(root) {
16845
+ try {
16846
+ const out = (0, import_node_child_process7.execSync)("git ls-files -z", {
16847
+ cwd: root,
16848
+ encoding: "utf-8",
16849
+ maxBuffer: 32 * 1024 * 1024,
16850
+ stdio: ["pipe", "pipe", "pipe"]
16851
+ });
16852
+ const tracked = out.split("\0").filter(Boolean).filter((p) => !isIgnored(p));
16853
+ if (tracked.length > 0) return tracked;
16854
+ } catch {
16855
+ }
16856
+ return walk(root);
16857
+ }
16858
+ var WALK_MAX_FILES = 2e4;
16859
+ var WALK_MAX_DEPTH = 8;
16860
+ function walk(root) {
16861
+ const found = [];
16862
+ const visit = (dir, depth) => {
16863
+ if (depth > WALK_MAX_DEPTH || found.length >= WALK_MAX_FILES) return;
16864
+ let entries;
16865
+ try {
16866
+ entries = (0, import_node_fs23.readdirSync)(dir, { withFileTypes: true });
16867
+ } catch {
16868
+ return;
16869
+ }
16870
+ for (const entry of entries) {
16871
+ if (found.length >= WALK_MAX_FILES) return;
16872
+ if (IGNORED_SEGMENTS.includes(entry.name)) continue;
16873
+ const full = (0, import_node_path19.join)(dir, entry.name);
16874
+ if (entry.isDirectory()) visit(full, depth + 1);
16875
+ else if (entry.isFile()) found.push((0, import_node_path19.relative)(root, full));
16876
+ }
16877
+ };
16878
+ visit(root, 0);
16879
+ return found;
16880
+ }
16881
+ function languageOf(path) {
16882
+ const name = (0, import_node_path19.basename)(path);
16883
+ if (/^Dockerfile(\..+)?$/i.test(name)) return "dockerfile";
16884
+ if (!(0, import_node_path19.extname)(name)) return null;
16885
+ const lang = detectLanguage(path);
16886
+ return lang || null;
16887
+ }
16888
+ var FRAMEWORK_BY_DEPENDENCY = [
16889
+ [/^react$/, "react"],
16890
+ [/^react-native$/, "react-native"],
16891
+ [/^next$/, "next.js"],
16892
+ [/^vue$/, "vue"],
16893
+ [/^@angular\/core$/, "angular"],
16894
+ [/^svelte$/, "svelte"],
16895
+ [/^express$/, "express"],
16896
+ [/^fastify$/, "fastify"],
16897
+ [/^@nestjs\/core$/, "nestjs"],
16898
+ [/^koa$/, "koa"],
16899
+ [/^hono$/, "hono"],
16900
+ [/^@supabase\/supabase-js$/, "supabase"],
16901
+ [/^prisma$|^@prisma\/client$/, "prisma"],
16902
+ [/^drizzle-orm$/, "drizzle"],
16903
+ [/^django$/i, "django"],
16904
+ [/^flask$/i, "flask"],
16905
+ [/^fastapi$/i, "fastapi"],
16906
+ [/^sqlalchemy$/i, "sqlalchemy"],
16907
+ [/^pydantic$/i, "pydantic"],
16908
+ [/^celery$/i, "celery"],
16909
+ [/^gin-gonic\/gin$/, "gin"],
16910
+ [/^labstack\/echo/, "echo"],
16911
+ [/^gofiber\/fiber/, "fiber"],
16912
+ [/^spring-boot|springframework/, "spring"],
16913
+ [/^rails$/, "rails"],
16914
+ [/^sinatra$/, "sinatra"],
16915
+ [/^actix-web$/, "actix"],
16916
+ [/^axum$/, "axum"],
16917
+ [/^rocket$/, "rocket"]
16918
+ ];
16919
+ var TEST_FRAMEWORK_BY_DEPENDENCY = [
16920
+ [/^vitest$/, "vitest"],
16921
+ [/^jest$/, "jest"],
16922
+ [/^mocha$/, "mocha"],
16923
+ [/^@playwright\/test$/, "playwright"],
16924
+ [/^cypress$/, "cypress"],
16925
+ [/^pytest$/i, "pytest"],
16926
+ [/^unittest2$/i, "unittest"],
16927
+ [/^rspec$/, "rspec"],
16928
+ [/^junit$|^junit-jupiter/, "junit"]
16929
+ ];
16930
+ var TOOL_CONFIG_MARKERS = [
16931
+ ["ESLint9", ["eslint.config.js", "eslint.config.mjs", "eslint.config.cjs", ".eslintrc", ".eslintrc.js", ".eslintrc.json", ".eslintrc.yml"]],
16932
+ ["Semgrep", [".semgrep.yml", ".semgrep.yaml", "semgrep.yml", "semgrep.yaml"]],
16933
+ ["Trivy", ["trivy.yaml", "trivy.yml"]],
16934
+ ["Ruff", ["ruff.toml", ".ruff.toml"]],
16935
+ ["PMD7", ["pmd.xml", "ruleset.xml"]],
16936
+ ["detekt", ["detekt.yml", "detekt.yaml"]],
16937
+ ["Hadolint", [".hadolint.yaml", ".hadolint.yml"]]
16938
+ ];
16939
+ function readJson(path) {
16940
+ try {
16941
+ return JSON.parse((0, import_node_fs23.readFileSync)(path, "utf-8"));
16942
+ } catch {
16943
+ return null;
16944
+ }
16945
+ }
16946
+ function matchAll(names2, table) {
16947
+ const hits = /* @__PURE__ */ new Set();
16948
+ for (const name of names2) {
16949
+ for (const [pattern, label2] of table) {
16950
+ if (pattern.test(name)) hits.add(label2);
16951
+ }
16952
+ }
16953
+ return [...hits];
16954
+ }
16955
+ var NESTED_MANIFEST_LIMIT = 25;
16956
+ function declaredDependencies(root, files) {
16957
+ const names2 = [];
16958
+ const readPackageJson = (path) => {
16959
+ const pkg = readJson(path);
16960
+ if (!pkg) return;
16961
+ for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
16962
+ const deps = pkg[field];
16963
+ if (deps && typeof deps === "object") names2.push(...Object.keys(deps));
16964
+ }
16965
+ };
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));
16969
+ 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))
16972
+ ];
16973
+ for (const path of pythonManifests) {
16974
+ if (!(0, import_node_fs23.existsSync)(path)) continue;
16975
+ try {
16976
+ const text = (0, import_node_fs23.readFileSync)(path, "utf-8");
16977
+ for (const m of text.matchAll(/^\s*["']?([A-Za-z][A-Za-z0-9._-]+)/gm)) names2.push(m[1]);
16978
+ for (const line of text.split("\n")) {
16979
+ if (!/dependencies\s*=/.test(line)) continue;
16980
+ for (const m of line.matchAll(/["']([A-Za-z][A-Za-z0-9._-]+)/g)) names2.push(m[1]);
16981
+ }
16982
+ } catch {
16983
+ }
16984
+ }
16985
+ 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))
16988
+ ];
16989
+ for (const path of goMods) {
16990
+ if (!(0, import_node_fs23.existsSync)(path)) continue;
16991
+ try {
16992
+ const text = (0, import_node_fs23.readFileSync)(path, "utf-8");
16993
+ for (const m of text.matchAll(/^\s+([\w.-]+\/[\w./-]+)\s+v/gm)) {
16994
+ names2.push(m[1].replace(/^github\.com\//, ""));
16995
+ }
16996
+ } catch {
16997
+ }
16998
+ }
16999
+ for (const file of ["pom.xml", "build.gradle", "build.gradle.kts", "Gemfile", "Cargo.toml"]) {
17000
+ const path = (0, import_node_path19.join)(root, file);
17001
+ if (!(0, import_node_fs23.existsSync)(path)) continue;
17002
+ try {
17003
+ const text = (0, import_node_fs23.readFileSync)(path, "utf-8");
17004
+ for (const m of text.matchAll(/["'<]([A-Za-z][A-Za-z0-9._-]{2,})["'>]/g)) names2.push(m[1]);
17005
+ } catch {
17006
+ }
17007
+ }
17008
+ return names2;
17009
+ }
17010
+ 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);
17012
+ if (has("pnpm-lock.yaml")) return "pnpm";
17013
+ if (has("yarn.lock")) return "yarn";
17014
+ if (has("bun.lock") || has("bun.lockb")) return "bun";
17015
+ if (has("package-lock.json") || has("package.json")) return "npm";
17016
+ if (has("poetry.lock")) return "poetry";
17017
+ if (has("uv.lock")) return "uv";
17018
+ if (has("pyproject.toml") || has("requirements.txt")) return "pip";
17019
+ if (has("go.mod")) return "go";
17020
+ if (has("pom.xml")) return "maven";
17021
+ if (has("build.gradle") || has("build.gradle.kts")) return "gradle";
17022
+ if (has("Cargo.toml")) return "cargo";
17023
+ if (has("Gemfile")) return "bundler";
17024
+ return null;
17025
+ }
17026
+ function detectArchitecture(root, files) {
17027
+ 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"));
17030
+ if (pkg && "workspaces" in pkg) return "monorepo";
17031
+ const manifests = files.filter((f) => /(^|\/)(package\.json|go\.mod|pyproject\.toml|Cargo\.toml|pom\.xml)$/.test(f));
17032
+ const nested = manifests.filter((f) => f.includes("/"));
17033
+ if (nested.length >= 2) {
17034
+ const underServices = nested.filter((f) => /^(services|apps)\//.test(f));
17035
+ return underServices.length >= 2 ? "microservices" : "monorepo";
17036
+ }
17037
+ return "monolith";
17038
+ }
17039
+ var SAMPLE_LIMIT = 300;
17040
+ function measureAvgFileLength(root, files, languages) {
17041
+ const primary = new Set(languages.slice(0, 2));
17042
+ const candidates = files.filter((f) => {
17043
+ const lang = languageOf(f);
17044
+ return lang !== null && primary.has(lang);
17045
+ });
17046
+ if (candidates.length === 0) return null;
17047
+ const stride = Math.max(1, Math.floor(candidates.length / SAMPLE_LIMIT));
17048
+ let total = 0;
17049
+ let counted = 0;
17050
+ for (let i = 0; i < candidates.length; i += stride) {
17051
+ const path = (0, import_node_path19.join)(root, candidates[i]);
17052
+ try {
17053
+ if ((0, import_node_fs23.statSync)(path).size > 2 * 1024 * 1024) continue;
17054
+ total += (0, import_node_fs23.readFileSync)(path, "utf-8").split("\n").length;
17055
+ counted++;
17056
+ } catch {
17057
+ }
17058
+ }
17059
+ return counted > 0 ? Math.round(total / counted) : null;
17060
+ }
17061
+ function tunedFileLengthThreshold(avgFileLength, floor = 300) {
17062
+ if (avgFileLength === null || avgFileLength <= 0) return floor;
17063
+ const scaled = Math.round(avgFileLength * 0.8 / 50) * 50;
17064
+ return Math.max(floor, scaled);
17065
+ }
17066
+ function detectProject(root = repoRoot()) {
17067
+ const files = listProjectFiles(root);
17068
+ const languageCounts = {};
17069
+ for (const file of files) {
17070
+ const lang = languageOf(file);
17071
+ if (!lang) continue;
17072
+ languageCounts[lang] = (languageCounts[lang] ?? 0) + 1;
17073
+ }
17074
+ const languages = Object.entries(languageCounts).filter(([lang, count]) => TOOLED_LANGUAGES.has(lang) && count >= MIN_FILES_FOR_LANGUAGE).sort((a, b) => b[1] - a[1]).map(([lang]) => lang);
17075
+ const dependencies = declaredDependencies(root, files);
17076
+ const existingToolConfigs = [];
17077
+ for (const [tool, markers] of TOOL_CONFIG_MARKERS) {
17078
+ for (const marker of markers) {
17079
+ if ((0, import_node_fs23.existsSync)((0, import_node_path19.join)(root, marker))) {
17080
+ existingToolConfigs.push({ tool, path: `./${marker}` });
17081
+ break;
17082
+ }
17083
+ }
17084
+ }
17085
+ return {
17086
+ projectName: (0, import_node_path19.basename)(root),
17087
+ languages,
17088
+ languageCounts,
17089
+ frameworks: matchAll(dependencies, FRAMEWORK_BY_DEPENDENCY),
17090
+ architecture: detectArchitecture(root, files),
17091
+ buildSystem: detectBuildSystem(root, files),
17092
+ testFramework: matchAll(dependencies, TEST_FRAMEWORK_BY_DEPENDENCY)[0] ?? null,
17093
+ existingToolConfigs,
17094
+ avgFileLength: measureAvgFileLength(root, files, languages),
17095
+ filesScanned: files.length
17096
+ };
17097
+ }
17098
+ function describeDetected(d) {
17099
+ const langs = d.languages.length > 0 ? d.languages.map((l) => `${l} (${d.languageCounts[l]} files)`).join(", ") : "no code languages detected";
17100
+ const parts = [langs];
17101
+ if (d.frameworks.length > 0) parts.push(d.frameworks.join(", "));
17102
+ parts.push(d.architecture);
17103
+ if (d.buildSystem) parts.push(d.buildSystem);
17104
+ if (d.testFramework) parts.push(d.testFramework);
17105
+ return parts.join(" \xB7 ");
17106
+ }
17107
+
17108
+ // src/lib/verity-md.ts
17109
+ function names(content, key) {
17110
+ const raw = content[key];
17111
+ if (!Array.isArray(raw)) return [];
17112
+ return raw.map((entry) => {
17113
+ if (typeof entry === "string") return entry;
17114
+ if (entry && typeof entry === "object") {
17115
+ const rec = entry;
17116
+ const label2 = rec.name ?? rec.id ?? rec.dimension ?? rec.pattern;
17117
+ return typeof label2 === "string" ? label2 : null;
17118
+ }
17119
+ return null;
17120
+ }).filter((x) => !!x);
17121
+ }
17122
+ var DEFAULT_DIMENSIONS = ["comprehensibility", "modularity", "type_safety", "test_adequacy"];
17123
+ var DEFAULT_SECURITY = [
17124
+ "No hardcoded secrets (CWE-798)",
17125
+ "Input sanitization (CWE-20)",
17126
+ "Parameterized queries (CWE-89)",
17127
+ "Dependency verification (CWE-1395)",
17128
+ "No unsafe deserialization (CWE-502)",
17129
+ "Access control checks (CWE-639)",
17130
+ "Config file integrity (CWE-15)"
17131
+ ];
17132
+ function describeOrigin(origin) {
17133
+ if (origin.kind === "adopted") {
17134
+ return `adopted from the service${origin.createdBy ? `, created by ${origin.createdBy}` : ""}`;
17135
+ }
17136
+ return `derived from this codebase${origin.tools.length > 0 ? ` \xB7 ${origin.tools.join(", ")}` : ""}`;
17137
+ }
17138
+ function closingNote(origin) {
17139
+ if (origin.kind === "adopted") {
17140
+ return `_This Standard came from the service \u2014 the team's shared version. To change it,
17141
+ edit \`.verity/standard.yaml\` and run \`verity standard push\`, or re-synthesize
17142
+ from the codebase with \`verity standard synthesize --force\`._`;
17143
+ }
17144
+ return `_This Standard was derived from the codebase: languages, frameworks and
17145
+ architecture were detected, and the rules come from Verity's research-backed
17146
+ patterns reference. Project-specific patterns are not part of it yet \u2014 add them
17147
+ to \`custom_patterns\` in \`.verity/standard.yaml\` and run \`verity standard push\`._`;
17148
+ }
17149
+ function renderVerityMd(input) {
17150
+ const dimensions = names(input.content, "quality_dimensions");
17151
+ const patterns = names(input.content, "security_patterns");
17152
+ const custom = names(input.content, "custom_patterns");
17153
+ const list2 = (items, fallback) => (items.length > 0 ? items : fallback).map((i) => `- ${i}`).join("\n");
17154
+ return `# VERITY.md \u2014 Quality Gate
17155
+
17156
+ > This project uses [Verity](https://verity.md) to enforce quality and security standards on AI-generated code.
17157
+
17158
+ **URL:** ${input.serviceUrl}
17159
+ **Project:** ${input.projectId ?? "this repository"}
17160
+ **Standard:** v${input.version} (${describeOrigin(input.origin)})
17161
+
17162
+ ## Quality Dimensions
17163
+ ${list2(dimensions, DEFAULT_DIMENSIONS)}
17164
+
17165
+ ## Security Patterns
17166
+ ${list2(patterns, DEFAULT_SECURITY)}
17167
+ ${custom.length > 0 ? `
17168
+ ## Project Patterns
17169
+ ${list2(custom, [])}
17170
+ ` : ""}
17171
+ ## How It Works
17172
+ Every time the coding agent stops, the Verity hook:
17173
+ 1. Runs static analysis via @codacy/analysis-cli
17174
+ 2. Sends results + code to the Verity service
17175
+ 3. An independent model reviews the code
17176
+ 4. Returns PASS / WARN / FAIL with actionable findings
17177
+
17178
+ ${closingNote(input.origin)}
17179
+ `;
17180
+ }
17181
+
17182
+ // src/lib/synthesize.ts
17183
+ function loadCatalog() {
17184
+ const catalog = (0, import_yaml.parse)((0, import_node_fs24.readFileSync)(setupDataPath("patterns-reference.yaml"), "utf-8"));
17185
+ const template = (0, import_yaml.parse)((0, import_node_fs24.readFileSync)(setupDataPath("standard-template.yaml"), "utf-8"));
17186
+ return { catalog, template };
17187
+ }
17188
+ function selectTools(languages, intensity, catalog) {
17189
+ const recommended = /* @__PURE__ */ new Set();
17190
+ for (const language of languages) {
17191
+ for (const tool of catalog.tool_recommendations?.[language]?.[intensity] ?? []) {
17192
+ recommended.add(tool);
17193
+ }
17194
+ }
17195
+ const tools = [];
17196
+ const skipped = [];
17197
+ for (const tool of recommended) {
17198
+ if (tool === "Trivy") {
17199
+ tools.push(tool);
17200
+ continue;
17201
+ }
17202
+ const curated = catalog.curated_patterns?.[tool]?.patterns;
17203
+ if (curated && curated.length > 0) tools.push(tool);
17204
+ else skipped.push(tool);
17205
+ }
17206
+ return { tools: tools.sort(), skipped: skipped.sort() };
17207
+ }
17208
+ var TRIVY_BY_INTENSITY = {
17209
+ lightweight: {
17210
+ emit: "^Trivy_(secret|vulnerability_(critical|high))$",
17211
+ fallback: ["Trivy_secret", "Trivy_vulnerability_critical", "Trivy_vulnerability_high"]
17212
+ },
17213
+ balanced: {
17214
+ emit: "^Trivy_(secret|malicious_packages|vulnerability_(critical|high))$",
17215
+ fallback: [
17216
+ "Trivy_secret",
17217
+ "Trivy_malicious_packages",
17218
+ "Trivy_vulnerability_critical",
17219
+ "Trivy_vulnerability_high"
17220
+ ]
17221
+ },
17222
+ thorough: {
17223
+ // `medium` is emitted when the adapter has it; the fallback stays at the
17224
+ // four ids that are known to exist rather than guessing a fifth.
17225
+ emit: "^Trivy_(secret|malicious_packages|vulnerability_(critical|high|medium))$",
17226
+ fallback: [
17227
+ "Trivy_secret",
17228
+ "Trivy_malicious_packages",
17229
+ "Trivy_vulnerability_critical",
17230
+ "Trivy_vulnerability_high"
17231
+ ]
17232
+ }
17233
+ };
17234
+ function adapterPatternIds(toolId) {
17235
+ try {
17236
+ const out = (0, import_node_child_process8.execFileSync)(
17237
+ process.execPath,
17238
+ [setupDataPath("validate-patterns.mjs"), "--list", toolId],
17239
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
17240
+ );
17241
+ const ids = out.split("\n").map((l) => l.trim()).filter(Boolean);
17242
+ return ids.length > 0 ? new Set(ids) : null;
17243
+ } catch {
17244
+ return null;
17245
+ }
17246
+ }
17247
+ function resolvePatternId(toolId, curatedId, adapterIds) {
17248
+ if (adapterIds.has(curatedId)) return { id: curatedId, resolved: false };
17249
+ const prefixed = `${toolId}_${curatedId}`;
17250
+ if (adapterIds.has(prefixed)) return { id: prefixed, resolved: true };
17251
+ for (const base of [curatedId, prefixed]) {
17252
+ const matches = [...adapterIds].filter((id) => id.startsWith(`${base}_`));
17253
+ if (matches.length === 1) return { id: matches[0], resolved: true };
17254
+ if (matches.length > 1) return null;
17255
+ }
17256
+ const segments = curatedId.split("_");
17257
+ if (segments.length >= 3) {
17258
+ const head = segments.slice(0, 2).join("_");
17259
+ const matches = [...adapterIds].filter((id) => id.startsWith(`${head}_`));
17260
+ if (matches.length === 1) return { id: matches[0], resolved: true };
17261
+ }
17262
+ return null;
17263
+ }
17264
+ function trivyPatterns(intensity) {
17265
+ try {
17266
+ const out = (0, import_node_child_process8.execFileSync)(
17267
+ process.execPath,
17268
+ [setupDataPath("validate-patterns.mjs"), "--emit", "Trivy", TRIVY_BY_INTENSITY[intensity].emit],
17269
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
17270
+ );
17271
+ const parsed = JSON.parse(out);
17272
+ const patterns = parsed.map((p) => p.patternId).filter(Boolean);
17273
+ if (patterns.length > 0) return { patterns, derived: true };
17274
+ } catch {
17275
+ }
17276
+ return { patterns: [...TRIVY_BY_INTENSITY[intensity].fallback], derived: false };
17277
+ }
17278
+ function buildStandard(input, loaded) {
17279
+ const { detected, intensity, tools } = input;
17280
+ const { catalog, template } = loaded;
17281
+ const standard = structuredClone(template);
17282
+ const selected = new Set(tools);
17283
+ standard.created_by = input.createdBy ?? "verity-cli";
17284
+ standard.knowledge_spec = {
17285
+ project_name: detected.projectName,
17286
+ languages: detected.languages,
17287
+ frameworks: detected.frameworks,
17288
+ architecture: detected.architecture,
17289
+ build_system: detected.buildSystem ?? "",
17290
+ test_framework: detected.testFramework ?? ""
17291
+ };
17292
+ const dimensions = Array.isArray(standard.quality_dimensions) ? standard.quality_dimensions : [];
17293
+ for (const dimension of dimensions) {
17294
+ if (dimension.id === "comprehensibility") {
17295
+ for (const signal of dimension.signals ?? []) {
17296
+ if (signal.metric === "file_length") {
17297
+ signal.threshold = tunedFileLengthThreshold(detected.avgFileLength);
17298
+ if (detected.avgFileLength !== null) {
17299
+ signal.measured_project_average = detected.avgFileLength;
17300
+ }
17301
+ }
17302
+ }
17303
+ }
17304
+ if (dimension.id === "type_safety") {
17305
+ dimension.signals = typeSafetySignals(detected.languages, catalog);
17306
+ }
17307
+ }
17308
+ const patterns = Array.isArray(standard.security_patterns) ? standard.security_patterns : [];
17309
+ const catalogById = new Map((catalog.security_patterns ?? []).map((p) => [p.id, p]));
17310
+ for (const pattern of patterns) {
17311
+ const fromCatalog = catalogById.get(String(pattern.id));
17312
+ const enforcers = (fromCatalog?.enforced_by ?? []).filter((e) => e.tool && selected.has(e.tool)).map((e) => ({ tool: e.tool }));
17313
+ pattern.enforced_by = enforcers;
17314
+ }
17315
+ standard.custom_patterns = [];
17316
+ const constraints = standard.process_constraints ?? {};
17317
+ constraints.analysis_mode = intensity;
17318
+ standard.process_constraints = constraints;
17319
+ standard.tool_configuration = Object.fromEntries(
17320
+ tools.map((tool) => {
17321
+ const existing = detected.existingToolConfigs.find((c) => c.tool === tool);
17322
+ return [tool, existing ? { enabled: true, project_config_detected: existing.path } : { enabled: true }];
17323
+ })
17324
+ );
17325
+ return standard;
17326
+ }
17327
+ function typeSafetySignals(languages, catalog) {
17328
+ const template = (catalog.quality_dimensions ?? []).find((d) => d.id === "type_safety");
17329
+ const signals = [];
17330
+ for (const signal of template?.signals ?? []) {
17331
+ const byLanguage = signal.rules_by_language;
17332
+ if (!byLanguage) continue;
17333
+ for (const language of languages) {
17334
+ const entry = byLanguage[language];
17335
+ if (!entry) continue;
17336
+ signals.push({
17337
+ metric: signal.metric,
17338
+ language,
17339
+ tool: entry.tool,
17340
+ rules: entry.rules ?? [],
17341
+ rationale: signal.rationale
17342
+ });
17343
+ }
17344
+ }
17345
+ return signals;
17346
+ }
17347
+ function standardToYaml(standard) {
17348
+ return (0, import_yaml.stringify)(standard, { lineWidth: 100 });
17349
+ }
17350
+ var VERITY_ESLINT_CONFIG_PATH = "./.codacy/tools-configs/eslint.config.mjs";
17351
+ function resolveToolPatterns(toolId, curated) {
17352
+ const real = adapterPatternIds(toolId);
17353
+ if (!real) return { patterns: curated, notes: [] };
17354
+ const notes = [];
17355
+ const kept = [];
17356
+ const lost = [];
17357
+ let renamed = 0;
17358
+ for (const { patternId } of curated) {
17359
+ const match = resolvePatternId(toolId, patternId, real);
17360
+ if (!match) {
17361
+ lost.push(patternId);
17362
+ continue;
17363
+ }
17364
+ if (match.resolved) renamed++;
17365
+ kept.push({ patternId: match.id });
17366
+ }
17367
+ if (renamed > 0) {
17368
+ notes.push(`${toolId}: ${renamed} of ${curated.length} pattern ids resolved to your adapter's spelling.`);
17369
+ }
17370
+ if (lost.length > 0) {
17371
+ notes.push(
17372
+ `${toolId}: ${lost.length} of ${curated.length} curated pattern ids match nothing in your installed adapter and were dropped${kept.length === 0 ? ` \u2014 ${toolId} is not configured at all` : ""} (${lost.slice(0, 3).join(", ")}${lost.length > 3 ? ", \u2026" : ""}). Re-derive them with: validate-patterns.mjs --list ${toolId}`
17373
+ );
17374
+ }
17375
+ return { patterns: kept, notes };
17376
+ }
17377
+ function buildCodacyConfig(input, loaded, trivy, verifyAgainstAdapter = true) {
17378
+ const tools = [];
17379
+ const notes = [];
17380
+ for (const toolId of input.tools) {
17381
+ const curated = toolId === "Trivy" ? trivy.patterns.map((patternId) => ({ patternId })) : (loaded.catalog.curated_patterns?.[toolId]?.patterns ?? []).map((p) => ({ patternId: p.patternId }));
17382
+ const resolved = verifyAgainstAdapter && toolId !== "Trivy" ? resolveToolPatterns(toolId, curated) : { patterns: curated, notes: [] };
17383
+ const patterns = resolved.patterns;
17384
+ notes.push(...resolved.notes);
17385
+ if (patterns.length === 0) continue;
17386
+ const tool = { toolId, patterns };
17387
+ if (toolId === "ESLint9") {
17388
+ tool.useLocalConfigurationFile = false;
17389
+ tool.localConfigurationFile = VERITY_ESLINT_CONFIG_PATH;
17390
+ }
17391
+ tools.push(tool);
17392
+ }
17393
+ return {
17394
+ config: {
17395
+ version: 1,
17396
+ metadata: {
17397
+ source: "local",
17398
+ languages: input.detected.languages.map(capitalizeLanguage)
17399
+ },
17400
+ tools
17401
+ },
17402
+ notes
17403
+ };
17404
+ }
17405
+ function capitalizeLanguage(language) {
17406
+ const special = {
17407
+ typescript: "TypeScript",
17408
+ javascript: "JavaScript",
17409
+ cpp: "CPP",
17410
+ c: "C",
17411
+ csharp: "CSharp",
17412
+ php: "PHP",
17413
+ shell: "Shell",
17414
+ dockerfile: "Dockerfile"
17415
+ };
17416
+ return special[language] ?? language.charAt(0).toUpperCase() + language.slice(1);
17417
+ }
17418
+ var VERITY_ESLINT_CONFIG = `// Verity-owned ESLint config for the quality gate. Generated by \`verity init\`.
17419
+ //
17420
+ // Deliberately SEPARATE from the project's ./eslint.config.js. Pointing the gate at
17421
+ // the project config makes Verity's pattern list a FILTER over rules the project
17422
+ // enabled, so any rule the project disables becomes unreachable (VRT-108).
17423
+ //
17424
+ // The enabled rules come from .codacy/codacy.config.json; this file supplies only
17425
+ // the parser, the globals and the ignores ESLint needs to run at all.
17426
+ import js from "@eslint/js";
17427
+ import globals from "globals";
17428
+ import tseslint from "typescript-eslint";
17429
+
17430
+ export default tseslint.config(
17431
+ { ignores: ["dist/**", "build/**", "node_modules/**", "coverage/**", ".codacy/**"] },
17432
+ {
17433
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
17434
+ files: ["**/*.{ts,tsx,js,jsx}"],
17435
+ languageOptions: {
17436
+ ecmaVersion: 2022,
17437
+ sourceType: "module",
17438
+ globals: { ...globals.browser, ...globals.node },
17439
+ },
17440
+ },
17441
+ );
17442
+ `;
17443
+ function validatePatternIds() {
17444
+ const configPath = projectPath(CODACY_CONFIG_FILE);
17445
+ try {
17446
+ (0, import_node_child_process8.execFileSync)(process.execPath, [setupDataPath("validate-patterns.mjs"), configPath], {
17447
+ encoding: "utf-8",
17448
+ stdio: ["pipe", "pipe", "pipe"],
17449
+ timeout: 6e4
17450
+ });
17451
+ return { status: "valid" };
17452
+ } catch (err) {
17453
+ const e = err;
17454
+ const raw = (e.stderr || e.stdout || e.message || "").trim();
17455
+ const detail = raw.split("\n").slice(0, 6).join("\n");
17456
+ if (/^\s*SKIP:/m.test(raw)) return { status: "unchecked", detail };
17457
+ if (/^\s*FAIL:/m.test(raw)) return { status: "invalid", detail };
17458
+ return { status: "unchecked", detail };
17459
+ }
17460
+ }
17461
+ async function runSynthesis(opts) {
17462
+ const standardPath = projectPath(STANDARD_FILE);
17463
+ if ((0, import_node_fs24.existsSync)(standardPath) && !opts.force) {
17464
+ return { refused: `${STANDARD_FILE} already exists \u2014 pass --force to replace it.` };
17465
+ }
17466
+ const detected = opts.detected ?? detectProject();
17467
+ const loaded = loadCatalog();
17468
+ const { tools, skipped } = selectTools(detected.languages, opts.intensity, loaded.catalog);
17469
+ const trivy = trivyPatterns(opts.intensity);
17470
+ const input = { detected, intensity: opts.intensity, tools };
17471
+ const built = buildCodacyConfig(input, loaded, trivy);
17472
+ const config = built.config;
17473
+ const configuredTools = config.tools.map((t) => t.toolId);
17474
+ const standard = buildStandard({ ...input, tools: configuredTools }, loaded);
17475
+ const written = [];
17476
+ const notes = [...built.notes];
17477
+ await writeFileTo(STANDARD_FILE, standardToYaml(standard));
17478
+ written.push(STANDARD_FILE);
17479
+ if (config.tools.length > 0) {
17480
+ await writeFileTo(CODACY_CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
17481
+ written.push(CODACY_CONFIG_FILE);
17482
+ if (config.tools.some((t) => t.toolId === "ESLint9")) {
17483
+ await writeFileTo(VERITY_ESLINT_CONFIG_PATH.replace(/^\.\//, ""), VERITY_ESLINT_CONFIG);
17484
+ written.push(VERITY_ESLINT_CONFIG_PATH.replace(/^\.\//, ""));
17485
+ }
17486
+ } else {
17487
+ notes.push(
17488
+ "No static-analysis tool matched this codebase, so the gate runs on AI review alone. Static findings would need a supported language (TypeScript, JavaScript, Python, Go, Java, Kotlin, Ruby, Rust, C/C++, shell, Dockerfile)."
17489
+ );
17490
+ }
17491
+ await writeFileTo(VERITY_MD_FILE, renderVerityMd({
17492
+ content: standard,
17493
+ version: 1,
17494
+ serviceUrl: opts.serviceUrl ?? "https://verity.md",
17495
+ projectId: opts.projectId,
17496
+ origin: { kind: "synthesized", tools }
17497
+ }));
17498
+ written.push(VERITY_MD_FILE);
17499
+ if (skipped.length > 0) {
17500
+ notes.push(
17501
+ `Not configured: ${skipped.join(", ")} \u2014 the patterns reference has no derived rule ids for ${skipped.length === 1 ? "it" : "them"} yet, and a wrong id disables a tool silently.`
17502
+ );
17503
+ }
17504
+ if (!trivy.derived && config.tools.some((t) => t.toolId === "Trivy")) {
17505
+ notes.push(
17506
+ "Trivy pattern ids came from the documented fallback, not from your installed adapter (@codacy/analysis-cli was not found). Re-run after installing it to derive them."
17507
+ );
17508
+ }
17509
+ if (config.tools.length > 0) {
17510
+ const validation = validatePatternIds();
17511
+ if (validation.status === "invalid") {
17512
+ notes.push(`\u26A0 Pattern-id validation FAILED \u2014 a tool may be silently disabled:
17513
+ ${validation.detail}`);
17514
+ } else if (validation.status === "unchecked") {
17515
+ notes.push("Pattern ids could not be validated (no analysis adapter installed on this machine).");
17516
+ }
17517
+ }
17518
+ return { written, notes, standard, tools, intensity: opts.intensity, detected };
17519
+ }
17520
+ async function correctVerityMdVersion(opts) {
17521
+ if (opts.version === 1) return;
17522
+ await writeFileTo(VERITY_MD_FILE, renderVerityMd({
17523
+ content: opts.standard,
17524
+ version: opts.version,
17525
+ serviceUrl: opts.serviceUrl ?? "https://verity.md",
17526
+ projectId: opts.projectId,
17527
+ origin: { kind: "synthesized", tools: opts.tools }
17528
+ }));
17529
+ }
17530
+ async function writeFileTo(relative2, body) {
17531
+ const target = projectPath(relative2);
17532
+ await (0, import_promises9.mkdir)((0, import_node_path20.dirname)(target), { recursive: true });
17533
+ await (0, import_promises9.writeFile)(target, body);
17534
+ }
17535
+ async function deriveConfigForStandard(standard) {
17536
+ const spec = standard.knowledge_spec ?? {};
17537
+ const constraints = standard.process_constraints ?? {};
17538
+ const languages = Array.isArray(spec.languages) ? spec.languages.filter((l) => typeof l === "string").map((l) => l.toLowerCase()) : [];
17539
+ const mode2 = constraints.analysis_mode;
17540
+ const intensity = mode2 === "lightweight" || mode2 === "thorough" ? mode2 : "balanced";
17541
+ const written = [];
17542
+ const notes = [];
17543
+ if (languages.length === 0) {
17544
+ notes.push(
17545
+ "The adopted Standard names no languages, so no analysis config could be derived from it. Static analysis will run nothing until one exists."
17546
+ );
17547
+ return { written, notes, tools: [] };
17548
+ }
17549
+ const loaded = loadCatalog();
17550
+ const { tools, skipped } = selectTools(languages, intensity, loaded.catalog);
17551
+ const trivy = trivyPatterns(intensity);
17552
+ const stub = {
17553
+ projectName: "",
17554
+ languages,
17555
+ languageCounts: {},
17556
+ frameworks: [],
17557
+ architecture: "monolith",
17558
+ buildSystem: null,
17559
+ testFramework: null,
17560
+ existingToolConfigs: [],
17561
+ avgFileLength: null,
17562
+ filesScanned: 0
17563
+ };
17564
+ const built = buildCodacyConfig({ detected: stub, intensity, tools }, loaded, trivy);
17565
+ const config = built.config;
17566
+ notes.push(...built.notes);
17567
+ if (config.tools.length === 0) {
17568
+ notes.push("No static-analysis tool matches the adopted Standard's languages \u2014 the gate runs on AI review alone.");
17569
+ return { written, notes, tools: [] };
17570
+ }
17571
+ await writeFileTo(CODACY_CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
17572
+ written.push(CODACY_CONFIG_FILE);
17573
+ if (config.tools.some((t) => t.toolId === "ESLint9")) {
17574
+ const path = VERITY_ESLINT_CONFIG_PATH.replace(/^\.\//, "");
17575
+ await writeFileTo(path, VERITY_ESLINT_CONFIG);
17576
+ written.push(path);
17577
+ }
17578
+ if (skipped.length > 0) {
17579
+ notes.push(`Not configured: ${skipped.join(", ")} \u2014 no derived rule ids for ${skipped.length === 1 ? "it" : "them"} yet.`);
17580
+ }
17581
+ const validation = validatePatternIds();
17582
+ if (validation.status === "invalid") {
17583
+ notes.push(`\u26A0 Pattern-id validation FAILED \u2014 a tool may be silently disabled:
17584
+ ${validation.detail}`);
17585
+ }
17586
+ return { written, notes, tools };
17587
+ }
17588
+
17589
+ // src/lib/setup-state.ts
17590
+ var import_promises10 = require("node:fs/promises");
17591
+ var import_node_fs25 = require("node:fs");
17592
+ var SETUP_STATE_FILE = `${VERITY_DIR}/setup.json`;
17593
+ async function readSetupState() {
17594
+ const path = projectPath(SETUP_STATE_FILE);
17595
+ if (!(0, import_node_fs25.existsSync)(path)) return null;
17596
+ try {
17597
+ const parsed = JSON.parse(await (0, import_promises10.readFile)(path, "utf-8"));
17598
+ return parsed && typeof parsed === "object" ? parsed : null;
17599
+ } catch {
17600
+ return null;
17601
+ }
17602
+ }
17603
+ async function writeSetupState(patch) {
17604
+ const current = await readSetupState() ?? { version: 1 };
17605
+ const next = { ...current, ...patch, version: 1 };
17606
+ await writeJsonFilePreservingStyle(projectPath(SETUP_STATE_FILE), next);
17607
+ return next;
17608
+ }
17609
+
17610
+ // src/lib/push-setup.ts
17611
+ var import_node_fs27 = require("node:fs");
17612
+ var import_promises11 = require("node:fs/promises");
17613
+ var import_yaml2 = __toESM(require_dist());
17614
+
17615
+ // src/lib/verityignore.ts
17616
+ var import_node_fs26 = require("node:fs");
16767
17617
  var EMPTY = { rules: [], securityOverlap: [], problems: [] };
16768
17618
  var SECURITY_PROBES = [
16769
17619
  ".env",
@@ -16851,14 +17701,14 @@ function decide(rules, path) {
16851
17701
  }
16852
17702
  return excluded;
16853
17703
  }
16854
- function isIgnored(ig, path) {
17704
+ function isIgnored2(ig, path) {
16855
17705
  return decide(ig.rules, path);
16856
17706
  }
16857
17707
  function loadVerityIgnore() {
16858
17708
  const file = projectPath(VERITYIGNORE_FILE);
16859
- if (!(0, import_node_fs22.existsSync)(file)) return EMPTY;
17709
+ if (!(0, import_node_fs26.existsSync)(file)) return EMPTY;
16860
17710
  try {
16861
- return parseVerityIgnore((0, import_node_fs22.readFileSync)(file, "utf-8"));
17711
+ return parseVerityIgnore((0, import_node_fs26.readFileSync)(file, "utf-8"));
16862
17712
  } catch {
16863
17713
  return EMPTY;
16864
17714
  }
@@ -16871,7 +17721,7 @@ function partitionIgnored(paths, ig) {
16871
17721
  const kept = [];
16872
17722
  const ignored = [];
16873
17723
  for (const p of paths) {
16874
- if (p !== VERITYIGNORE_FILE && isIgnored(ig, p)) ignored.push(p);
17724
+ if (p !== VERITYIGNORE_FILE && isIgnored2(ig, p)) ignored.push(p);
16875
17725
  else kept.push(p);
16876
17726
  }
16877
17727
  return {
@@ -16887,6 +17737,22 @@ function ignoreShare(kept, ignored) {
16887
17737
  if (total === 0) return 0;
16888
17738
  return Math.round(ignored / total * 1e3) / 1e3;
16889
17739
  }
17740
+ function buildStandardUpload(standard, ignoreRaw) {
17741
+ if (ignoreRaw === null) return { content: standard, warning: null };
17742
+ return {
17743
+ content: { ...standard, verityignore: ignoreRaw },
17744
+ warning: describeSecurityOverlap(parseVerityIgnore(ignoreRaw))
17745
+ };
17746
+ }
17747
+ function readVerityIgnoreRaw() {
17748
+ const file = projectPath(VERITYIGNORE_FILE);
17749
+ if (!(0, import_node_fs26.existsSync)(file)) return null;
17750
+ try {
17751
+ return (0, import_node_fs26.readFileSync)(file, "utf-8");
17752
+ } catch {
17753
+ return null;
17754
+ }
17755
+ }
16890
17756
  function describeSecurityOverlap(ig) {
16891
17757
  if (ig.securityOverlap.length === 0) return null;
16892
17758
  const lines = ig.securityOverlap.map(
@@ -16897,9 +17763,122 @@ ${lines.join("\n")}
16897
17763
  These are still excluded \u2014 this is a warning, not a refusal. Add a \`!\` rule to keep one in scope, e.g. \`!.env*\`.`;
16898
17764
  }
16899
17765
 
17766
+ // src/lib/push-setup.ts
17767
+ async function pushStandardAndConfig(globals, what = {}) {
17768
+ const pushStandard = what.standard ?? true;
17769
+ const pushConfig = what.config ?? true;
17770
+ const lines = [];
17771
+ const token = await resolveToken(globals.token);
17772
+ const url = await resolveServiceUrl(globals.serviceUrl);
17773
+ if (!token.ok || !url.ok) {
17774
+ lines.push('Not signed in \u2014 the Standard stays local until you run "verity login" and "verity standard push".');
17775
+ return { lines, standardVersion: null, configPushed: false };
17776
+ }
17777
+ let standardVersion = null;
17778
+ const standardPath = projectPath(STANDARD_FILE);
17779
+ if (pushStandard && (0, import_node_fs27.existsSync)(standardPath)) {
17780
+ try {
17781
+ const content = (0, import_yaml2.parse)(await (0, import_promises11.readFile)(standardPath, "utf-8"));
17782
+ const upload = buildStandardUpload(content, readVerityIgnoreRaw());
17783
+ if (upload.warning) lines.push(upload.warning);
17784
+ const result = await apiRequest({
17785
+ method: "POST",
17786
+ path: "/standards",
17787
+ serviceUrl: url.data,
17788
+ token: token.data.token,
17789
+ body: { content: upload.content, created_by: "verity-cli" },
17790
+ verbose: globals.verbose
17791
+ });
17792
+ if (result.ok) {
17793
+ standardVersion = result.data.version;
17794
+ lines.push(`Standard pushed to Verity (v${result.data.version}) \u2713`);
17795
+ } else {
17796
+ lines.push(`Could not push the Standard: ${result.error} \u2014 run "verity standard push" later.`);
17797
+ }
17798
+ } catch (err) {
17799
+ lines.push(`Could not read ${STANDARD_FILE}: ${err.message}`);
17800
+ }
17801
+ }
17802
+ let configPushed = false;
17803
+ const configPath = projectPath(CODACY_CONFIG_FILE);
17804
+ if (pushConfig && (0, import_node_fs27.existsSync)(configPath)) {
17805
+ try {
17806
+ const content = JSON.parse(await (0, import_promises11.readFile)(configPath, "utf-8"));
17807
+ const result = await apiRequest({
17808
+ method: "POST",
17809
+ path: "/analysis-configs",
17810
+ serviceUrl: url.data,
17811
+ token: token.data.token,
17812
+ body: { content },
17813
+ verbose: globals.verbose
17814
+ });
17815
+ if (result.ok) {
17816
+ configPushed = true;
17817
+ lines.push("Analysis config pushed \u2713");
17818
+ } else {
17819
+ lines.push(`Could not push the analysis config: ${result.error} \u2014 run "verity config push" later.`);
17820
+ }
17821
+ } catch (err) {
17822
+ lines.push(`Could not read ${CODACY_CONFIG_FILE}: ${err.message}`);
17823
+ }
17824
+ }
17825
+ return { lines, standardVersion, configPushed };
17826
+ }
17827
+
16900
17828
  // src/commands/standard.ts
16901
17829
  function registerStandardCommands(program2) {
16902
17830
  const standard = program2.command("standard").description("Manage the project Standard");
17831
+ standard.command("synthesize").description("Derive the Standard and analysis config from this codebase (no model required)").option("--intensity <mode>", "lightweight | balanced | thorough (default: your recorded answer)").option("--force", "Replace an existing .verity/standard.yaml").option("--config-only", "Rewrite only the analysis config, from the Standard already here").option("--push", "Upload the Standard and config after writing them").action(async (opts) => {
17832
+ const globals = program2.opts();
17833
+ const state = await readSetupState();
17834
+ if (opts.configOnly) {
17835
+ const standardPath = projectPath(STANDARD_FILE);
17836
+ if (!(0, import_node_fs28.existsSync)(standardPath)) {
17837
+ printError(`No ${STANDARD_FILE} here \u2014 run "verity standard synthesize" to create one.`);
17838
+ process.exit(1);
17839
+ }
17840
+ const content = (0, import_yaml3.parse)(await (0, import_promises12.readFile)(standardPath, "utf-8"));
17841
+ const derived = await deriveConfigForStandard(content);
17842
+ for (const path of derived.written) printInfo(` ${path} \u2713`);
17843
+ for (const note of derived.notes) printWarn(` ${note}`);
17844
+ if (derived.written.length === 0) printWarn(" Nothing written.");
17845
+ if (opts.push) {
17846
+ const pushed = await pushStandardAndConfig(globals, { standard: false });
17847
+ for (const line of pushed.lines) printInfo(` ${line}`);
17848
+ }
17849
+ return;
17850
+ }
17851
+ if (opts.intensity && !parseIntensity(opts.intensity)) {
17852
+ printError(`Unknown intensity "${opts.intensity}" \u2014 use lightweight, balanced or thorough.`);
17853
+ process.exit(1);
17854
+ }
17855
+ const intensity = parseIntensity(opts.intensity) ?? state?.intensity ?? "balanced";
17856
+ const urlResult = await resolveServiceUrl(globals.serviceUrl);
17857
+ const result = await runSynthesis({
17858
+ intensity,
17859
+ force: opts.force ?? false,
17860
+ serviceUrl: urlResult.ok ? urlResult.data : void 0
17861
+ });
17862
+ if ("refused" in result) {
17863
+ printWarn(result.refused);
17864
+ process.exit(1);
17865
+ }
17866
+ printInfo(` ${describeDetected(result.detected)}`);
17867
+ for (const path of result.written) printInfo(` ${path} \u2713`);
17868
+ for (const note of result.notes) printWarn(` ${note}`);
17869
+ if (opts.push) {
17870
+ const pushed = await pushStandardAndConfig(globals);
17871
+ for (const line of pushed.lines) printInfo(` ${line}`);
17872
+ if (pushed.standardVersion !== null) {
17873
+ await correctVerityMdVersion({
17874
+ standard: result.standard,
17875
+ version: pushed.standardVersion,
17876
+ tools: result.tools,
17877
+ serviceUrl: urlResult.ok ? urlResult.data : void 0
17878
+ });
17879
+ }
17880
+ }
17881
+ });
16903
17882
  standard.command("push").description("Upload the project Standard to the service").option("--file <path>", "Path to standard YAML file", STANDARD_FILE).option("--created-by <name>", "Who created this version", "claude-code").action(async (opts) => {
16904
17883
  const globals = program2.opts();
16905
17884
  const tokenResult = await resolveToken(globals.token);
@@ -16914,37 +17893,26 @@ function registerStandardCommands(program2) {
16914
17893
  }
16915
17894
  let yamlContent;
16916
17895
  try {
16917
- yamlContent = await (0, import_promises9.readFile)(opts.file, "utf-8");
17896
+ yamlContent = await (0, import_promises12.readFile)(opts.file, "utf-8");
16918
17897
  } catch {
16919
17898
  printError(`Cannot read ${opts.file}`);
16920
17899
  process.exit(1);
16921
17900
  }
16922
17901
  let content;
16923
17902
  try {
16924
- content = (0, import_yaml.parse)(yamlContent);
17903
+ content = (0, import_yaml3.parse)(yamlContent);
16925
17904
  } catch (err) {
16926
17905
  printError(`Invalid YAML in ${opts.file}: ${err.message}`);
16927
17906
  process.exit(1);
16928
17907
  }
16929
- let ignoreRaw = null;
16930
- const ignorePath = projectPath(VERITYIGNORE_FILE);
16931
- if ((0, import_node_fs23.existsSync)(ignorePath)) {
16932
- try {
16933
- ignoreRaw = (0, import_node_fs23.readFileSync)(ignorePath, "utf-8");
16934
- const overlap = describeSecurityOverlap(parseVerityIgnore(ignoreRaw));
16935
- if (overlap) printWarn(overlap);
16936
- } catch {
16937
- }
16938
- }
17908
+ const upload = buildStandardUpload(content, readVerityIgnoreRaw());
17909
+ if (upload.warning) printWarn(upload.warning);
16939
17910
  const result = await apiRequest({
16940
17911
  method: "POST",
16941
17912
  path: "/standards",
16942
17913
  serviceUrl: urlResult.data,
16943
17914
  token: tokenResult.data.token,
16944
- body: {
16945
- content: ignoreRaw === null ? content : { ...content, verityignore: ignoreRaw },
16946
- created_by: opts.createdBy
16947
- },
17915
+ body: { content: upload.content, created_by: opts.createdBy },
16948
17916
  verbose: globals.verbose
16949
17917
  });
16950
17918
  if (!result.ok) {
@@ -17016,9 +17984,13 @@ function registerStandardCommands(program2) {
17016
17984
  }
17017
17985
  });
17018
17986
  }
17987
+ function parseIntensity(value) {
17988
+ if (value === "lightweight" || value === "balanced" || value === "thorough") return value;
17989
+ return null;
17990
+ }
17019
17991
 
17020
17992
  // src/commands/config.ts
17021
- var import_promises10 = require("node:fs/promises");
17993
+ var import_promises13 = require("node:fs/promises");
17022
17994
  function registerConfigCommands(program2) {
17023
17995
  const config = program2.command("config").description("Manage analysis configuration");
17024
17996
  config.command("service-url").description("Print the resolved service URL (used by the shipped skills)").action(async () => {
@@ -17060,7 +18032,7 @@ function registerConfigCommands(program2) {
17060
18032
  }
17061
18033
  let content;
17062
18034
  try {
17063
- const raw = await (0, import_promises10.readFile)(opts.file, "utf-8");
18035
+ const raw = await (0, import_promises13.readFile)(opts.file, "utf-8");
17064
18036
  content = JSON.parse(raw);
17065
18037
  } catch {
17066
18038
  printError(`Cannot read or parse ${opts.file}`);
@@ -17188,10 +18160,10 @@ function formatRunDetail(run2) {
17188
18160
  }
17189
18161
 
17190
18162
  // src/lib/ignore-declaration.ts
17191
- var import_node_fs25 = require("node:fs");
18163
+ var import_node_fs30 = require("node:fs");
17192
18164
 
17193
18165
  // src/lib/debounce.ts
17194
- var import_node_fs24 = require("node:fs");
18166
+ var import_node_fs29 = require("node:fs");
17195
18167
  var import_node_crypto10 = require("node:crypto");
17196
18168
  function scopedFile(base, sessionId) {
17197
18169
  if (!sessionId) return base;
@@ -17199,9 +18171,9 @@ function scopedFile(base, sessionId) {
17199
18171
  }
17200
18172
  function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
17201
18173
  const file = scopedFile(DEBOUNCE_FILE, sessionId);
17202
- if (!(0, import_node_fs24.existsSync)(file)) return null;
18174
+ if (!(0, import_node_fs29.existsSync)(file)) return null;
17203
18175
  try {
17204
- const lastTs = parseInt((0, import_node_fs24.readFileSync)(file, "utf-8").trim(), 10);
18176
+ const lastTs = parseInt((0, import_node_fs29.readFileSync)(file, "utf-8").trim(), 10);
17205
18177
  const nowTs = Math.floor(Date.now() / 1e3);
17206
18178
  const elapsed = nowTs - lastTs;
17207
18179
  if (elapsed < debounceSeconds) {
@@ -17214,10 +18186,10 @@ function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
17214
18186
  function checkMtime(files, bypassForRecentCommits, sessionId) {
17215
18187
  if (bypassForRecentCommits) return null;
17216
18188
  const file = scopedFile(DEBOUNCE_FILE, sessionId);
17217
- if (!(0, import_node_fs24.existsSync)(file)) return null;
18189
+ if (!(0, import_node_fs29.existsSync)(file)) return null;
17218
18190
  let debounceTime;
17219
18191
  try {
17220
- debounceTime = (0, import_node_fs24.statSync)(file).mtimeMs;
18192
+ debounceTime = (0, import_node_fs29.statSync)(file).mtimeMs;
17221
18193
  } catch {
17222
18194
  return null;
17223
18195
  }
@@ -17225,7 +18197,7 @@ function checkMtime(files, bypassForRecentCommits, sessionId) {
17225
18197
  const resolved = resolveFile(f);
17226
18198
  if (!resolved) continue;
17227
18199
  try {
17228
- const stat3 = (0, import_node_fs24.statSync)(resolved);
18200
+ const stat3 = (0, import_node_fs29.statSync)(resolved);
17229
18201
  if (stat3.mtimeMs > debounceTime) {
17230
18202
  return null;
17231
18203
  }
@@ -17241,8 +18213,8 @@ function computeContentHash(files) {
17241
18213
  for (const f of sorted) {
17242
18214
  const resolved = resolveFile(f) ?? f;
17243
18215
  try {
17244
- if ((0, import_node_fs24.existsSync)(resolved)) {
17245
- hash.update((0, import_node_fs24.readFileSync)(resolved));
18216
+ if ((0, import_node_fs29.existsSync)(resolved)) {
18217
+ hash.update((0, import_node_fs29.readFileSync)(resolved));
17246
18218
  }
17247
18219
  } catch {
17248
18220
  }
@@ -17252,9 +18224,9 @@ function computeContentHash(files) {
17252
18224
  function checkContentHash(files, sessionId) {
17253
18225
  const hash = computeContentHash(files);
17254
18226
  const file = scopedFile(HASH_FILE, sessionId);
17255
- if ((0, import_node_fs24.existsSync)(file)) {
18227
+ if ((0, import_node_fs29.existsSync)(file)) {
17256
18228
  try {
17257
- const storedHash = (0, import_node_fs24.readFileSync)(file, "utf-8").trim();
18229
+ const storedHash = (0, import_node_fs29.readFileSync)(file, "utf-8").trim();
17258
18230
  if (hash === storedHash) {
17259
18231
  return { skip: "No source changes since last analysis", hash };
17260
18232
  }
@@ -17264,24 +18236,24 @@ function checkContentHash(files, sessionId) {
17264
18236
  return { skip: null, hash };
17265
18237
  }
17266
18238
  function recordAnalysisStart(sessionId) {
17267
- (0, import_node_fs24.mkdirSync)(VERITY_DIR, { recursive: true });
17268
- (0, import_node_fs24.writeFileSync)(scopedFile(DEBOUNCE_FILE, sessionId), String(Math.floor(Date.now() / 1e3)));
18239
+ (0, import_node_fs29.mkdirSync)(VERITY_DIR, { recursive: true });
18240
+ (0, import_node_fs29.writeFileSync)(scopedFile(DEBOUNCE_FILE, sessionId), String(Math.floor(Date.now() / 1e3)));
17269
18241
  }
17270
18242
  function recordPassHash(hash, sessionId) {
17271
- (0, import_node_fs24.writeFileSync)(scopedFile(HASH_FILE, sessionId), hash);
18243
+ (0, import_node_fs29.writeFileSync)(scopedFile(HASH_FILE, sessionId), hash);
17272
18244
  }
17273
18245
  function narrowToRecent(files, sessionId) {
17274
18246
  const file = scopedFile(DEBOUNCE_FILE, sessionId);
17275
- if (!(0, import_node_fs24.existsSync)(file)) return files;
18247
+ if (!(0, import_node_fs29.existsSync)(file)) return files;
17276
18248
  let debounceTime;
17277
18249
  try {
17278
- debounceTime = (0, import_node_fs24.statSync)(file).mtimeMs;
18250
+ debounceTime = (0, import_node_fs29.statSync)(file).mtimeMs;
17279
18251
  } catch {
17280
18252
  return files;
17281
18253
  }
17282
18254
  const recent = files.filter((f) => {
17283
18255
  try {
17284
- return (0, import_node_fs24.existsSync)(f) && (0, import_node_fs24.statSync)(f).mtimeMs > debounceTime;
18256
+ return (0, import_node_fs29.existsSync)(f) && (0, import_node_fs29.statSync)(f).mtimeMs > debounceTime;
17285
18257
  } catch {
17286
18258
  return false;
17287
18259
  }
@@ -17294,9 +18266,9 @@ function readIteration(currentCommit, _contentHash) {
17294
18266
  var NO_BLOCKS = { attempts: 0, blocks: 0, fingerprint: null };
17295
18267
  function readBlockState(currentCommit, opts) {
17296
18268
  if (opts?.newUserPrompt) return NO_BLOCKS;
17297
- if (!(0, import_node_fs24.existsSync)(ITERATION_FILE)) return NO_BLOCKS;
18269
+ if (!(0, import_node_fs29.existsSync)(ITERATION_FILE)) return NO_BLOCKS;
17298
18270
  try {
17299
- const stored = (0, import_node_fs24.readFileSync)(ITERATION_FILE, "utf-8").trim();
18271
+ const stored = (0, import_node_fs29.readFileSync)(ITERATION_FILE, "utf-8").trim();
17300
18272
  const parsed = stored.startsWith("{") ? parseJsonState(stored) : parseLegacyState(stored);
17301
18273
  if (!parsed) return NO_BLOCKS;
17302
18274
  if (parsed.commit !== currentCommit) return NO_BLOCKS;
@@ -17342,8 +18314,8 @@ function isSameProblem(previous, current) {
17342
18314
  return current.split(",").some((k) => prev.has(k));
17343
18315
  }
17344
18316
  function writeBlockState(commit, state) {
17345
- (0, import_node_fs24.mkdirSync)(VERITY_DIR, { recursive: true });
17346
- (0, import_node_fs24.writeFileSync)(
18317
+ (0, import_node_fs29.mkdirSync)(VERITY_DIR, { recursive: true });
18318
+ (0, import_node_fs29.writeFileSync)(
17347
18319
  ITERATION_FILE,
17348
18320
  JSON.stringify({
17349
18321
  v: 2,
@@ -17448,9 +18420,9 @@ function resolveIgnoreState(keys) {
17448
18420
  }
17449
18421
  function readIgnoreState(sessionId) {
17450
18422
  const file = stateFile(sessionId);
17451
- if (!(0, import_node_fs25.existsSync)(file)) return null;
18423
+ if (!(0, import_node_fs30.existsSync)(file)) return null;
17452
18424
  try {
17453
- const o = JSON.parse((0, import_node_fs25.readFileSync)(file, "utf-8")) ?? {};
18425
+ const o = JSON.parse((0, import_node_fs30.readFileSync)(file, "utf-8")) ?? {};
17454
18426
  const spent = typeof o.spent === "number" ? o.spent : 0;
17455
18427
  const raw = o.active;
17456
18428
  let active = null;
@@ -17474,8 +18446,8 @@ function readIgnoreState(sessionId) {
17474
18446
  }
17475
18447
  function writeIgnoreState(state, sessionId) {
17476
18448
  try {
17477
- (0, import_node_fs25.mkdirSync)(projectPath(VERITY_DIR), { recursive: true });
17478
- (0, import_node_fs25.writeFileSync)(stateFile(sessionId), JSON.stringify({ v: 1, active: state.active, spent: state.spent }));
18449
+ (0, import_node_fs30.mkdirSync)(projectPath(VERITY_DIR), { recursive: true });
18450
+ (0, import_node_fs30.writeFileSync)(stateFile(sessionId), JSON.stringify({ v: 1, active: state.active, spent: state.spent }));
17479
18451
  } catch {
17480
18452
  }
17481
18453
  }
@@ -17850,10 +18822,10 @@ function createRun(opts, globals) {
17850
18822
  }
17851
18823
 
17852
18824
  // src/commands/analyze/index.ts
17853
- var import_node_fs38 = require("node:fs");
18825
+ var import_node_fs43 = require("node:fs");
17854
18826
 
17855
18827
  // src/lib/repo-context.ts
17856
- var import_node_child_process7 = require("node:child_process");
18828
+ var import_node_child_process9 = require("node:child_process");
17857
18829
  var import_node_os3 = require("node:os");
17858
18830
  function rgInvocations(env = process.env) {
17859
18831
  const out = [{ cmd: "rg" }];
@@ -18429,7 +19401,7 @@ function buildRepoContext(input) {
18429
19401
  ];
18430
19402
  let res = null;
18431
19403
  for (const inv of rgInvocations()) {
18432
- res = (0, import_node_child_process7.spawnSync)(inv.cmd, args, {
19404
+ res = (0, import_node_child_process9.spawnSync)(inv.cmd, args, {
18433
19405
  ...inv.argv0 ? { argv0: inv.argv0 } : {},
18434
19406
  cwd: input.cwd ?? process.cwd(),
18435
19407
  timeout: input.timeoutMs ?? RG_TIMEOUT_MS,
@@ -18670,11 +19642,11 @@ function installRunEvidence(run2) {
18670
19642
  }
18671
19643
 
18672
19644
  // src/lib/git-frame.ts
18673
- var import_node_child_process8 = require("node:child_process");
18674
- var import_node_fs26 = require("node:fs");
19645
+ var import_node_child_process10 = require("node:child_process");
19646
+ var import_node_fs31 = require("node:fs");
18675
19647
  var import_node_os4 = require("node:os");
18676
- var import_node_path18 = require("node:path");
18677
- var import_node_path19 = require("node:path");
19648
+ var import_node_path21 = require("node:path");
19649
+ var import_node_path22 = require("node:path");
18678
19650
  var VALUE_TOKEN = `(?:'[^']*'|"[^"]*"|\\S+)`;
18679
19651
  var GIT_GLOBAL_OPTS = `(?:\\s+(?:-[Cc]\\s+${VALUE_TOKEN}|--?[\\w-]+(?:=\\S+)?))*`;
18680
19652
  var COMMIT_HEAD = `git${GIT_GLOBAL_OPTS}\\s+commit(?![\\w-])`;
@@ -18727,8 +19699,8 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
18727
19699
  if (SHELL_DYNAMIC.test(raw) || raw === "-") {
18728
19700
  return { dir: null, named: true, unresolvable: `cd target not statically resolvable: ${raw}` };
18729
19701
  }
18730
- const expanded = raw === "~" ? (0, import_node_os4.homedir)() : raw.startsWith("~/") ? (0, import_node_path19.join)((0, import_node_os4.homedir)(), raw.slice(2)) : raw;
18731
- dir = (0, import_node_path18.isAbsolute)(expanded) ? expanded : (0, import_node_path18.resolve)(dir, expanded);
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);
18732
19704
  }
18733
19705
  const seg = segments[segmentIndex];
18734
19706
  const overrideMatch = /--(?:git-dir|work-tree)(?:=|\s)|\bGIT_(?:DIR|WORK_TREE|INDEX_FILE)=/.exec(seg);
@@ -18746,8 +19718,8 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
18746
19718
  if (SHELL_DYNAMIC.test(raw)) {
18747
19719
  return { dir: null, named: true, unresolvable: `-C target not statically resolvable: ${raw}` };
18748
19720
  }
18749
- const expanded = raw === "~" ? (0, import_node_os4.homedir)() : raw.startsWith("~/") ? (0, import_node_path19.join)((0, import_node_os4.homedir)(), raw.slice(2)) : raw;
18750
- dir = (0, import_node_path18.isAbsolute)(expanded) ? expanded : (0, import_node_path18.resolve)(dir, expanded);
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);
18751
19723
  }
18752
19724
  }
18753
19725
  return { dir, named, unresolvable: null };
@@ -18803,21 +19775,21 @@ function parsePushTarget(segment) {
18803
19775
  }
18804
19776
  function gitAt(dir, args) {
18805
19777
  try {
18806
- return (0, import_node_child_process8.execFileSync)("git", args, { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
19778
+ return (0, import_node_child_process10.execFileSync)("git", args, { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
18807
19779
  } catch {
18808
19780
  return "";
18809
19781
  }
18810
19782
  }
18811
19783
  function realpathOr(p) {
18812
19784
  try {
18813
- return import_node_fs26.realpathSync.native(p);
19785
+ return import_node_fs31.realpathSync.native(p);
18814
19786
  } catch {
18815
- return (0, import_node_path18.resolve)(p);
19787
+ return (0, import_node_path21.resolve)(p);
18816
19788
  }
18817
19789
  }
18818
19790
  function resolveFrame(input) {
18819
19791
  const found = findMomentSegment(input.command, input.on);
18820
- const hookDirUsable = !!input.hookCwd && (0, import_node_fs26.existsSync)(input.hookCwd);
19792
+ const hookDirUsable = !!input.hookCwd && (0, import_node_fs31.existsSync)(input.hookCwd);
18821
19793
  const baseDir = hookDirUsable ? input.hookCwd : process.cwd();
18822
19794
  let anchor = hookDirUsable ? "hook-cwd" : "process-cwd";
18823
19795
  const refuse = (refusal) => ({
@@ -18840,7 +19812,7 @@ function resolveFrame(input) {
18840
19812
  if (dirs.size > 1) return refuse(`target:multiple ${found.moment} targets in one command`);
18841
19813
  const targetDir = dirs.size === 1 ? [...dirs][0] : baseDir;
18842
19814
  if (targetDir !== baseDir) {
18843
- if (!(0, import_node_fs26.existsSync)(targetDir)) return refuse(`target:directory does not exist: ${targetDir}`);
19815
+ if (!(0, import_node_fs31.existsSync)(targetDir)) return refuse(`target:directory does not exist: ${targetDir}`);
18844
19816
  dir = targetDir;
18845
19817
  }
18846
19818
  }
@@ -18851,7 +19823,7 @@ function resolveFrame(input) {
18851
19823
  const gitDirRaw = gitAt(dir, ["rev-parse", "--absolute-git-dir"]);
18852
19824
  const commonRaw = gitAt(dir, ["rev-parse", "--git-common-dir"]);
18853
19825
  const gitDir = gitDirRaw ? realpathOr(gitDirRaw) : null;
18854
- const commonDir = commonRaw ? realpathOr((0, import_node_path18.isAbsolute)(commonRaw) ? commonRaw : (0, import_node_path18.resolve)(dir, commonRaw)) : null;
19826
+ const commonDir = commonRaw ? realpathOr((0, import_node_path21.isAbsolute)(commonRaw) ? commonRaw : (0, import_node_path21.resolve)(dir, commonRaw)) : null;
18855
19827
  const branchRaw = gitAt(dir, ["rev-parse", "--abbrev-ref", "HEAD"]);
18856
19828
  return {
18857
19829
  moment: found?.moment ?? null,
@@ -18878,8 +19850,8 @@ function refResolves(frame, ref) {
18878
19850
  var SHA_RE2 = /^[0-9a-f]{40}$/;
18879
19851
  function stagedRange(frame) {
18880
19852
  if (!frame.worktreeRoot) return { kind: "nothing", base: null, head: "INDEX", via: "refused" };
18881
- const mergeHead = frame.gitDir ? (0, import_node_path19.join)(frame.gitDir, "MERGE_HEAD") : null;
18882
- if (mergeHead && (0, import_node_fs26.existsSync)(mergeHead)) {
19853
+ const mergeHead = frame.gitDir ? (0, import_node_path22.join)(frame.gitDir, "MERGE_HEAD") : null;
19854
+ if (mergeHead && (0, import_node_fs31.existsSync)(mergeHead)) {
18883
19855
  const vsHead = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "HEAD"]).split("\n").filter(Boolean));
18884
19856
  const vsMerge = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "MERGE_HEAD"]).split("\n").filter(Boolean));
18885
19857
  const resolutions = [...vsHead].filter((f) => vsMerge.has(f) && !isVerityOwnedPath(f));
@@ -19003,7 +19975,7 @@ function truthy(v) {
19003
19975
  }
19004
19976
 
19005
19977
  // src/lib/transcript.ts
19006
- var import_node_fs27 = require("node:fs");
19978
+ var import_node_fs32 = require("node:fs");
19007
19979
  var MAX_READ_BYTES = 256 * 1024;
19008
19980
  var SMALL_FILE_BYTES = 64 * 1024;
19009
19981
  var MAX_FILES_LIST = 20;
@@ -19030,7 +20002,7 @@ async function extractActionSummary(transcriptPath) {
19030
20002
  function readTurnLines(transcriptPath) {
19031
20003
  let size;
19032
20004
  try {
19033
- size = (0, import_node_fs27.statSync)(transcriptPath).size;
20005
+ size = (0, import_node_fs32.statSync)(transcriptPath).size;
19034
20006
  } catch {
19035
20007
  return null;
19036
20008
  }
@@ -19038,7 +20010,7 @@ function readTurnLines(transcriptPath) {
19038
20010
  let raw;
19039
20011
  let windowed = false;
19040
20012
  if (size <= SMALL_FILE_BYTES) {
19041
- raw = (0, import_node_fs27.readFileSync)(transcriptPath, "utf-8");
20013
+ raw = (0, import_node_fs32.readFileSync)(transcriptPath, "utf-8");
19042
20014
  } else {
19043
20015
  windowed = true;
19044
20016
  const buf = Buffer.alloc(Math.min(MAX_READ_BYTES, size));
@@ -19537,7 +20509,7 @@ function channelSilence(input) {
19537
20509
  // src/lib/cli-version.ts
19538
20510
  function cliVersion() {
19539
20511
  try {
19540
- return true ? "0.31.4" : "dev";
20512
+ return true ? "0.32.0-experimental.68ae2ee" : "dev";
19541
20513
  } catch {
19542
20514
  return "dev";
19543
20515
  }
@@ -19577,8 +20549,8 @@ async function sendSkipBeacon(ctx, reason) {
19577
20549
  }
19578
20550
 
19579
20551
  // src/lib/static-analysis.ts
19580
- var import_node_child_process9 = require("node:child_process");
19581
- var import_node_fs28 = require("node:fs");
20552
+ var import_node_child_process11 = require("node:child_process");
20553
+ var import_node_fs33 = require("node:fs");
19582
20554
  var SEVERITY_ORDER = {
19583
20555
  Error: 0,
19584
20556
  Critical: 0,
@@ -19590,7 +20562,7 @@ var SEVERITY_ORDER = {
19590
20562
  };
19591
20563
  function isCodacyAvailable() {
19592
20564
  try {
19593
- (0, import_node_child_process9.execSync)("which codacy-analysis", { stdio: "pipe" });
20565
+ (0, import_node_child_process11.execSync)("which codacy-analysis", { stdio: "pipe" });
19594
20566
  return true;
19595
20567
  } catch {
19596
20568
  return false;
@@ -19626,13 +20598,13 @@ function runCodacyAnalysis(files) {
19626
20598
  if (files.length === 0) return empty;
19627
20599
  const existingFiles = files.filter((f) => {
19628
20600
  try {
19629
- return (0, import_node_fs28.existsSync)(f);
20601
+ return (0, import_node_fs33.existsSync)(f);
19630
20602
  } catch {
19631
20603
  return false;
19632
20604
  }
19633
20605
  });
19634
20606
  if (existingFiles.length === 0) return empty;
19635
- const proc = (0, import_node_child_process9.spawnSync)("codacy-analysis", buildAnalyzerArgv(existingFiles), {
20607
+ const proc = (0, import_node_child_process11.spawnSync)("codacy-analysis", buildAnalyzerArgv(existingFiles), {
19636
20608
  encoding: "utf-8",
19637
20609
  maxBuffer: 10 * 1024 * 1024
19638
20610
  });
@@ -19895,8 +20867,8 @@ async function scope(run2) {
19895
20867
  }
19896
20868
 
19897
20869
  // src/lib/specs.ts
19898
- var import_node_fs29 = require("node:fs");
19899
- var import_node_path20 = require("node:path");
20870
+ var import_node_fs34 = require("node:fs");
20871
+ var import_node_path23 = require("node:path");
19900
20872
  var SPEC_CANDIDATES = [
19901
20873
  "CLAUDE.md",
19902
20874
  "AGENTS.md",
@@ -19927,16 +20899,16 @@ function discoverSpecs(consulted = []) {
19927
20899
  const totalCap = relevant ? MAX_TOTAL_SPEC_BYTES : UNCONSULTED_TOTAL_BYTES;
19928
20900
  if (totalBytes >= totalCap) return false;
19929
20901
  if (seen.has(specPath)) return true;
19930
- if (!(0, import_node_fs29.existsSync)(specPath)) return true;
20902
+ if (!(0, import_node_fs34.existsSync)(specPath)) return true;
19931
20903
  seen.add(specPath);
19932
20904
  const remaining = totalCap - totalBytes;
19933
20905
  const fileCap = relevant ? MAX_SPEC_FILE_BYTES : UNCONSULTED_FILE_BYTES;
19934
20906
  const readBytes = Math.min(fileCap, remaining);
19935
20907
  try {
19936
20908
  const buf = Buffer.alloc(readBytes);
19937
- const fd = (0, import_node_fs29.openSync)(specPath, "r");
19938
- const bytesRead = (0, import_node_fs29.readSync)(fd, buf, 0, readBytes, 0);
19939
- (0, import_node_fs29.closeSync)(fd);
20909
+ const fd = (0, import_node_fs34.openSync)(specPath, "r");
20910
+ const bytesRead = (0, import_node_fs34.readSync)(fd, buf, 0, readBytes, 0);
20911
+ (0, import_node_fs34.closeSync)(fd);
19940
20912
  const content = buf.slice(0, bytesRead).toString("utf-8");
19941
20913
  if (!content) return true;
19942
20914
  result.push({ path: specPath, content });
@@ -19952,7 +20924,7 @@ function discoverSpecs(consulted = []) {
19952
20924
  if (!addSpec(candidate)) break;
19953
20925
  }
19954
20926
  for (const dir of ["spec", "docs"]) {
19955
- if (!(0, import_node_fs29.existsSync)(dir)) continue;
20927
+ if (!(0, import_node_fs34.existsSync)(dir)) continue;
19956
20928
  try {
19957
20929
  const mdFiles = findMdFiles(dir, 2).sort();
19958
20930
  for (const mdFile of mdFiles) {
@@ -19967,9 +20939,9 @@ function findMdFiles(dir, maxDepth, depth = 0) {
19967
20939
  if (depth >= maxDepth) return [];
19968
20940
  const result = [];
19969
20941
  try {
19970
- const entries = (0, import_node_fs29.readdirSync)(dir, { withFileTypes: true });
20942
+ const entries = (0, import_node_fs34.readdirSync)(dir, { withFileTypes: true });
19971
20943
  for (const entry of entries) {
19972
- const fullPath = (0, import_node_path20.join)(dir, entry.name);
20944
+ const fullPath = (0, import_node_path23.join)(dir, entry.name);
19973
20945
  if (entry.isFile() && entry.name.endsWith(".md")) {
19974
20946
  result.push(fullPath);
19975
20947
  } else if (entry.isDirectory() && depth < maxDepth - 1) {
@@ -19981,19 +20953,19 @@ function findMdFiles(dir, maxDepth, depth = 0) {
19981
20953
  return result;
19982
20954
  }
19983
20955
  function discoverPlans() {
19984
- const homePlansDir = (0, import_node_path20.join)(process.env.HOME ?? "", ".claude", "plans");
20956
+ const homePlansDir = (0, import_node_path23.join)(process.env.HOME ?? "", ".claude", "plans");
19985
20957
  const localPlansDir = ".claude/plans";
19986
20958
  const candidates = [];
19987
20959
  const seen = /* @__PURE__ */ new Set();
19988
20960
  for (const plansDir of [localPlansDir, homePlansDir]) {
19989
- if (!(0, import_node_fs29.existsSync)(plansDir)) continue;
20961
+ if (!(0, import_node_fs34.existsSync)(plansDir)) continue;
19990
20962
  try {
19991
- for (const f of (0, import_node_fs29.readdirSync)(plansDir)) {
20963
+ for (const f of (0, import_node_fs34.readdirSync)(plansDir)) {
19992
20964
  if (!f.endsWith(".md") || seen.has(f)) continue;
19993
20965
  seen.add(f);
19994
- const fullPath = (0, import_node_path20.join)(plansDir, f);
20966
+ const fullPath = (0, import_node_path23.join)(plansDir, f);
19995
20967
  try {
19996
- const stat3 = (0, import_node_fs29.statSync)(fullPath);
20968
+ const stat3 = (0, import_node_fs34.statSync)(fullPath);
19997
20969
  candidates.push({ name: f, path: fullPath, mtime: stat3.mtimeMs, size: stat3.size });
19998
20970
  } catch {
19999
20971
  }
@@ -20006,7 +20978,7 @@ function discoverPlans() {
20006
20978
  for (const entry of candidates.slice(0, MAX_PLAN_FILES)) {
20007
20979
  if (entry.size > MAX_PLAN_FILE_BYTES) continue;
20008
20980
  try {
20009
- const content = (0, import_node_fs29.readFileSync)(entry.path, "utf-8");
20981
+ const content = (0, import_node_fs34.readFileSync)(entry.path, "utf-8");
20010
20982
  result.push({ name: entry.name, content });
20011
20983
  } catch {
20012
20984
  }
@@ -20021,12 +20993,12 @@ function discoverGuardDocs(rangeFiles2) {
20021
20993
  if (result.length >= MAX_SPEC_FILES) break;
20022
20994
  if (!GUARD_DOC_EXT.test(path)) continue;
20023
20995
  if (path.startsWith("/") || path.includes("..")) continue;
20024
- if (!(0, import_node_fs29.existsSync)(path)) continue;
20996
+ if (!(0, import_node_fs34.existsSync)(path)) continue;
20025
20997
  try {
20026
- const stat3 = (0, import_node_fs29.statSync)(path);
20998
+ const stat3 = (0, import_node_fs34.statSync)(path);
20027
20999
  if (stat3.size > MAX_PLAN_FILE_BYTES) continue;
20028
21000
  if (totalBytes + stat3.size > MAX_TOTAL_SPEC_BYTES) continue;
20029
- const content = (0, import_node_fs29.readFileSync)(path, "utf-8");
21001
+ const content = (0, import_node_fs34.readFileSync)(path, "utf-8");
20030
21002
  if (!content) continue;
20031
21003
  result.push({ name: path, content });
20032
21004
  totalBytes += content.length;
@@ -20202,8 +21174,8 @@ async function mode(run2) {
20202
21174
  }
20203
21175
 
20204
21176
  // src/lib/fold.ts
20205
- var import_node_fs30 = require("node:fs");
20206
- var import_node_path21 = require("node:path");
21177
+ var import_node_fs35 = require("node:fs");
21178
+ var import_node_path24 = require("node:path");
20207
21179
  var KNOWN_RECORD_TYPES = /* @__PURE__ */ new Set([
20208
21180
  "user",
20209
21181
  "assistant",
@@ -20340,7 +21312,7 @@ function candidateRoots(repoRoot2) {
20340
21312
  const norm = repoRoot2.replace(/\\/g, "/").replace(/\/+$/, "");
20341
21313
  const out = [norm];
20342
21314
  try {
20343
- const real = import_node_fs30.realpathSync.native(norm).replace(/\\/g, "/").replace(/\/+$/, "");
21315
+ const real = import_node_fs35.realpathSync.native(norm).replace(/\\/g, "/").replace(/\/+$/, "");
20344
21316
  if (real !== norm) out.push(real);
20345
21317
  } catch {
20346
21318
  }
@@ -20428,31 +21400,31 @@ function fold(transcriptPath, opts = {}) {
20428
21400
  }
20429
21401
  };
20430
21402
  try {
20431
- if (!(0, import_node_fs30.existsSync)(transcriptPath)) return result;
20432
- ingest((0, import_node_fs30.readFileSync)(transcriptPath, "utf8"), "agent");
21403
+ if (!(0, import_node_fs35.existsSync)(transcriptPath)) return result;
21404
+ ingest((0, import_node_fs35.readFileSync)(transcriptPath, "utf8"), "agent");
20433
21405
  result.coverage.complete = true;
20434
21406
  } catch {
20435
21407
  return result;
20436
21408
  }
20437
21409
  try {
20438
- const sidecarDir = (0, import_node_path21.join)(
20439
- (0, import_node_path21.dirname)(transcriptPath),
20440
- (0, import_node_path21.basename)(transcriptPath).replace(/\.jsonl$/, ""),
21410
+ const sidecarDir = (0, import_node_path24.join)(
21411
+ (0, import_node_path24.dirname)(transcriptPath),
21412
+ (0, import_node_path24.basename)(transcriptPath).replace(/\.jsonl$/, ""),
20441
21413
  "subagents"
20442
21414
  );
20443
- if ((0, import_node_fs30.existsSync)(sidecarDir)) {
21415
+ if ((0, import_node_fs35.existsSync)(sidecarDir)) {
20444
21416
  const maxFiles = opts.maxSidecars ?? 200;
20445
21417
  const maxBytes = opts.maxSidecarBytes ?? 16 * 1024 * 1024;
20446
21418
  const found = [];
20447
- const walk = (d, depth) => {
21419
+ const walk2 = (d, depth) => {
20448
21420
  if (depth > 4) return;
20449
- for (const e of (0, import_node_fs30.readdirSync)(d, { withFileTypes: true })) {
20450
- const p = (0, import_node_path21.join)(d, e.name);
21421
+ for (const e of (0, import_node_fs35.readdirSync)(d, { withFileTypes: true })) {
21422
+ const p = (0, import_node_path24.join)(d, e.name);
20451
21423
  if (e.isDirectory()) {
20452
- walk(p, depth + 1);
21424
+ walk2(p, depth + 1);
20453
21425
  } else if (e.name.startsWith("agent-") && e.name.endsWith(".jsonl")) {
20454
21426
  try {
20455
- const st = (0, import_node_fs30.statSync)(p);
21427
+ const st = (0, import_node_fs35.statSync)(p);
20456
21428
  found.push({ path: p, size: st.size, mtimeMs: st.mtimeMs });
20457
21429
  } catch {
20458
21430
  result.coverage.malformed++;
@@ -20460,7 +21432,7 @@ function fold(transcriptPath, opts = {}) {
20460
21432
  }
20461
21433
  }
20462
21434
  };
20463
- walk(sidecarDir, 0);
21435
+ walk2(sidecarDir, 0);
20464
21436
  found.sort((a, b) => b.mtimeMs - a.mtimeMs);
20465
21437
  let bytes = 0;
20466
21438
  for (const f of found) {
@@ -20469,7 +21441,7 @@ function fold(transcriptPath, opts = {}) {
20469
21441
  continue;
20470
21442
  }
20471
21443
  try {
20472
- ingest((0, import_node_fs30.readFileSync)(f.path, "utf8"), "subagent");
21444
+ ingest((0, import_node_fs35.readFileSync)(f.path, "utf8"), "subagent");
20473
21445
  bytes += f.size;
20474
21446
  result.coverage.subagentFiles++;
20475
21447
  } catch {
@@ -20504,7 +21476,7 @@ function fold(transcriptPath, opts = {}) {
20504
21476
  }
20505
21477
  function classifyUnobserved(path) {
20506
21478
  try {
20507
- const st = (0, import_node_fs30.statSync)(path);
21479
+ const st = (0, import_node_fs35.statSync)(path);
20508
21480
  if (!st.isFile()) return "unreadable";
20509
21481
  } catch {
20510
21482
  return "unreadable";
@@ -20821,20 +21793,20 @@ async function evidence(run2) {
20821
21793
  }
20822
21794
 
20823
21795
  // src/lib/cache-cleanup.ts
20824
- var import_node_fs31 = require("node:fs");
20825
- var import_node_path22 = require("node:path");
21796
+ var import_node_fs36 = require("node:fs");
21797
+ var import_node_path25 = require("node:path");
20826
21798
  var CACHE_TTL_DAYS = 7;
20827
21799
  function pruneStaleCache() {
20828
21800
  try {
20829
21801
  const dir = projectPath(CACHE_DIR);
20830
21802
  const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
20831
- for (const entry of (0, import_node_fs31.readdirSync)(dir)) {
21803
+ for (const entry of (0, import_node_fs36.readdirSync)(dir)) {
20832
21804
  if (!entry.startsWith("pending-")) continue;
20833
- const path = (0, import_node_path22.join)(dir, entry);
21805
+ const path = (0, import_node_path25.join)(dir, entry);
20834
21806
  try {
20835
- const stat3 = (0, import_node_fs31.statSync)(path);
21807
+ const stat3 = (0, import_node_fs36.statSync)(path);
20836
21808
  if (stat3.mtimeMs < cutoff) {
20837
- (0, import_node_fs31.unlinkSync)(path);
21809
+ (0, import_node_fs36.unlinkSync)(path);
20838
21810
  logEvent("cache_entry_pruned", {
20839
21811
  path: entry,
20840
21812
  age_days: Math.round((Date.now() - stat3.mtimeMs) / 864e5)
@@ -20848,7 +21820,7 @@ function pruneStaleCache() {
20848
21820
  }
20849
21821
 
20850
21822
  // src/lib/context-files.ts
20851
- var import_node_fs32 = require("node:fs");
21823
+ var import_node_fs37 = require("node:fs");
20852
21824
  var import_node_os5 = require("node:os");
20853
21825
  var MAX_CONTEXT_FILES = 10;
20854
21826
  var MAX_CONTEXT_FILE_BYTES = 10240;
@@ -20906,7 +21878,7 @@ function gatherContextFiles(contextPaths, deltaFiles, opts) {
20906
21878
  continue;
20907
21879
  }
20908
21880
  try {
20909
- const content = (0, import_node_fs32.readFileSync)(safePath, "utf8");
21881
+ const content = (0, import_node_fs37.readFileSync)(safePath, "utf8");
20910
21882
  const bytes = Buffer.byteLength(content);
20911
21883
  if (bytes > MAX_CONTEXT_FILE_BYTES) {
20912
21884
  logEvent("context_file_skipped", { path: filePath, reason: "too_large", bytes });
@@ -20956,7 +21928,7 @@ async function contextFiles(run2) {
20956
21928
  const readSet = readSetContextPaths(run2.actionSummary, codeDelta.files);
20957
21929
  const { kept: externalContext } = partitionVerityOwned(readSet);
20958
21930
  const ig = loadVerityIgnore();
20959
- const unfenced = run2.verityIgnored.suspended ? externalContext : externalContext.filter((p) => !isIgnored(ig, p));
21931
+ const unfenced = run2.verityIgnored.suspended ? externalContext : externalContext.filter((p) => !isIgnored2(ig, p));
20960
21932
  const contextFiles2 = gatherContextFiles(unfenced, codeDelta.files, {
20961
21933
  maxFiles: MAX_FILES - codeDelta.files.length
20962
21934
  });
@@ -20977,7 +21949,7 @@ async function repoContext(run2) {
20977
21949
  const deltaFiles = codeDelta.files.filter((f) => f.role !== "context");
20978
21950
  const sentPaths = new Set(codeDelta.files.map((f) => f.path));
20979
21951
  const ig = loadVerityIgnore();
20980
- const isExcluded = (p) => isVerityOwnedPath(p) || !run2.verityIgnored.suspended && isIgnored(ig, p);
21952
+ const isExcluded = (p) => isVerityOwnedPath(p) || !run2.verityIgnored.suspended && isIgnored2(ig, p);
20981
21953
  run2.repoContext = buildRepoContext({
20982
21954
  deltaFiles,
20983
21955
  diffs: snapshotResult.diffs,
@@ -20996,10 +21968,10 @@ async function repoContext(run2) {
20996
21968
  }
20997
21969
 
20998
21970
  // src/lib/seed-runner.ts
20999
- var import_promises11 = require("node:fs/promises");
21000
- var import_node_fs33 = require("node:fs");
21001
- var import_node_path23 = require("node:path");
21002
- var import_yaml2 = __toESM(require_dist());
21971
+ var import_promises14 = require("node:fs/promises");
21972
+ var import_node_fs38 = require("node:fs");
21973
+ var import_node_path26 = require("node:path");
21974
+ var import_yaml4 = __toESM(require_dist());
21003
21975
 
21004
21976
  // src/lib/seed.ts
21005
21977
  function extractReadmeIntro(content) {
@@ -21237,29 +22209,29 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
21237
22209
  return fm;
21238
22210
  }
21239
22211
  async function runSeed(opts) {
21240
- if (!(0, import_node_fs33.existsSync)(STANDARD_FILE)) {
22212
+ if (!(0, import_node_fs38.existsSync)(STANDARD_FILE)) {
21241
22213
  return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
21242
22214
  }
21243
22215
  let standardDoc;
21244
22216
  try {
21245
- const raw = await (0, import_promises11.readFile)(STANDARD_FILE, "utf-8");
21246
- standardDoc = (0, import_yaml2.parse)(raw);
22217
+ const raw = await (0, import_promises14.readFile)(STANDARD_FILE, "utf-8");
22218
+ standardDoc = (0, import_yaml4.parse)(raw);
21247
22219
  } catch {
21248
22220
  return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
21249
22221
  }
21250
22222
  const knowledgeSpec = standardDoc.knowledge_spec ?? {};
21251
22223
  let readmeContent;
21252
- if ((0, import_node_fs33.existsSync)("README.md")) {
22224
+ if ((0, import_node_fs38.existsSync)("README.md")) {
21253
22225
  try {
21254
- readmeContent = await (0, import_promises11.readFile)("README.md", "utf-8");
22226
+ readmeContent = await (0, import_promises14.readFile)("README.md", "utf-8");
21255
22227
  } catch {
21256
22228
  }
21257
22229
  }
21258
22230
  let claudeMdContent;
21259
22231
  for (const p of ["CLAUDE.md", ".claude/CLAUDE.md"]) {
21260
- if ((0, import_node_fs33.existsSync)(p)) {
22232
+ if ((0, import_node_fs38.existsSync)(p)) {
21261
22233
  try {
21262
- claudeMdContent = await (0, import_promises11.readFile)(p, "utf-8");
22234
+ claudeMdContent = await (0, import_promises14.readFile)(p, "utf-8");
21263
22235
  break;
21264
22236
  } catch {
21265
22237
  }
@@ -21280,8 +22252,8 @@ async function runSeed(opts) {
21280
22252
  if (candidates.length === 0) {
21281
22253
  return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
21282
22254
  }
21283
- const overviewPath = (0, import_node_path23.join)(MEMORY_DIR, "domain", "project-overview.md");
21284
- if ((0, import_node_fs33.existsSync)(overviewPath) && !opts.force) {
22255
+ const overviewPath = (0, import_node_path26.join)(MEMORY_DIR, "domain", "project-overview.md");
22256
+ if ((0, import_node_fs38.existsSync)(overviewPath) && !opts.force) {
21285
22257
  return { created: 0, failed: 0, skipped: "already_seeded", candidates };
21286
22258
  }
21287
22259
  if (opts.dryRun) {
@@ -21323,8 +22295,8 @@ async function runSeed(opts) {
21323
22295
  continue;
21324
22296
  }
21325
22297
  try {
21326
- await (0, import_promises11.mkdir)((0, import_node_path23.dirname)(targetPath), { recursive: true });
21327
- await (0, import_promises11.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
22298
+ await (0, import_promises14.mkdir)((0, import_node_path26.dirname)(targetPath), { recursive: true });
22299
+ await (0, import_promises14.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
21328
22300
  created++;
21329
22301
  opts.onCreated?.(nodeId, filePathRel, c);
21330
22302
  } catch (err) {
@@ -21336,8 +22308,8 @@ async function runSeed(opts) {
21336
22308
  }
21337
22309
 
21338
22310
  // src/commands/analyze/phases/08-memory-manifest.ts
21339
- var import_node_fs34 = require("node:fs");
21340
- var import_node_path24 = require("node:path");
22311
+ var import_node_fs39 = require("node:fs");
22312
+ var import_node_path27 = require("node:path");
21341
22313
  async function memoryManifest(run2) {
21342
22314
  const { globals } = run2;
21343
22315
  const { serviceUrl, token } = run2;
@@ -21347,9 +22319,9 @@ async function memoryManifest(run2) {
21347
22319
  let autoSeedNotice = null;
21348
22320
  try {
21349
22321
  await ensureMemoryDir();
21350
- const seedMarker = (0, import_node_path24.join)(VERITY_DIR, ".seeded");
21351
- const hasStandard = (0, import_node_fs34.existsSync)(STANDARD_FILE);
21352
- const alreadyTried = (0, import_node_fs34.existsSync)(seedMarker);
22322
+ const seedMarker = (0, import_node_path27.join)(VERITY_DIR, ".seeded");
22323
+ const hasStandard = (0, import_node_fs39.existsSync)(STANDARD_FILE);
22324
+ const alreadyTried = (0, import_node_fs39.existsSync)(seedMarker);
21353
22325
  if (hasStandard && !alreadyTried) {
21354
22326
  const preManifest = await buildManifest();
21355
22327
  if (preManifest.nodes.length === 0) {
@@ -21362,7 +22334,7 @@ async function memoryManifest(run2) {
21362
22334
  dryRun: false
21363
22335
  });
21364
22336
  if (seedResult.created > 0) {
21365
- (0, import_node_fs34.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
22337
+ (0, import_node_fs39.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
21366
22338
  `);
21367
22339
  autoSeedNotice = `Seeded ${seedResult.created} knowledge node(s) from your existing Standard (one-time).`;
21368
22340
  logEvent("auto_seed_ran", {
@@ -21370,7 +22342,7 @@ async function memoryManifest(run2) {
21370
22342
  failed: seedResult.failed
21371
22343
  });
21372
22344
  } else if (seedResult.skipped === "already_seeded") {
21373
- (0, import_node_fs34.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
22345
+ (0, import_node_fs39.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
21374
22346
  `);
21375
22347
  } else {
21376
22348
  logEvent("auto_seed_noop", {
@@ -21465,7 +22437,7 @@ function computeIncrement(reviewedPaths, hashOf, priorAuthored) {
21465
22437
  }
21466
22438
 
21467
22439
  // src/commands/analyze/phases/10-working-memory.ts
21468
- var import_node_path25 = require("node:path");
22440
+ var import_node_path28 = require("node:path");
21469
22441
  async function workingMemory(run2) {
21470
22442
  const { opts } = run2;
21471
22443
  const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run2;
@@ -21477,7 +22449,7 @@ async function workingMemory(run2) {
21477
22449
  const priorState = foldForMarks(memorySession.d);
21478
22450
  incrementReport = computeIncrement(
21479
22451
  allForReview,
21480
- (p) => fileHash((0, import_node_path25.join)(repoRoot(), p)),
22452
+ (p) => fileHash((0, import_node_path28.join)(repoRoot(), p)),
21481
22453
  priorState.authored_all.map((a) => ({
21482
22454
  path: a.path,
21483
22455
  hash_at_last_verdict: a.hash_at_last_verdict
@@ -21559,7 +22531,7 @@ async function workingMemory(run2) {
21559
22531
  }
21560
22532
 
21561
22533
  // src/lib/note-budget.ts
21562
- var import_node_fs35 = require("node:fs");
22534
+ var import_node_fs40 = require("node:fs");
21563
22535
  var ADVISORY_BUDGET = { PASS: 1, WARN: 2 };
21564
22536
  var EPISODE_STALE_SECONDS = 30 * 60;
21565
22537
  var FRESH = { delivered: 0, tasksCompleted: 0, ts: 0 };
@@ -21581,9 +22553,9 @@ function advisoryBudgetSpent(episode, rawDecision) {
21581
22553
  }
21582
22554
  function readAdvisoryEpisode(sessionId) {
21583
22555
  const file = scopedFile(ADVISORY_EPISODE_FILE, sessionId);
21584
- if (!(0, import_node_fs35.existsSync)(file)) return null;
22556
+ if (!(0, import_node_fs40.existsSync)(file)) return null;
21585
22557
  try {
21586
- const o = JSON.parse((0, import_node_fs35.readFileSync)(file, "utf-8")) ?? {};
22558
+ const o = JSON.parse((0, import_node_fs40.readFileSync)(file, "utf-8")) ?? {};
21587
22559
  const delivered = typeof o.delivered === "number" ? o.delivered : NaN;
21588
22560
  if (isNaN(delivered)) return null;
21589
22561
  return {
@@ -21597,8 +22569,8 @@ function readAdvisoryEpisode(sessionId) {
21597
22569
  }
21598
22570
  function writeAdvisoryEpisode(episode, sessionId) {
21599
22571
  try {
21600
- (0, import_node_fs35.mkdirSync)(VERITY_DIR, { recursive: true });
21601
- (0, import_node_fs35.writeFileSync)(
22572
+ (0, import_node_fs40.mkdirSync)(VERITY_DIR, { recursive: true });
22573
+ (0, import_node_fs40.writeFileSync)(
21602
22574
  scopedFile(ADVISORY_EPISODE_FILE, sessionId),
21603
22575
  JSON.stringify({ v: 1, ...episode })
21604
22576
  );
@@ -21628,7 +22600,7 @@ function isExplicitlyAutonomous(env = process.env) {
21628
22600
  }
21629
22601
 
21630
22602
  // src/lib/task-context.ts
21631
- var import_node_child_process10 = require("node:child_process");
22603
+ var import_node_child_process12 = require("node:child_process");
21632
22604
  var CLOSING_RE = /\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?)\b[\s:]*#(\d+)/i;
21633
22605
  var BRANCH_RE = /(?:^|[/_-])(?:issue|gh|fix)[-_/]?(\d+)\b/i;
21634
22606
  function parseLinkedIssue(sources) {
@@ -21644,7 +22616,7 @@ function parseLinkedIssue(sources) {
21644
22616
  }
21645
22617
  function safeExec(cmd, timeout) {
21646
22618
  try {
21647
- return (0, import_node_child_process10.execSync)(cmd, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout }).trim();
22619
+ return (0, import_node_child_process12.execSync)(cmd, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout }).trim();
21648
22620
  } catch {
21649
22621
  return "";
21650
22622
  }
@@ -21915,14 +22887,14 @@ async function buildRequest(run2) {
21915
22887
  }
21916
22888
 
21917
22889
  // src/lib/offline.ts
21918
- var import_node_fs36 = require("node:fs");
22890
+ var import_node_fs41 = require("node:fs");
21919
22891
  var import_node_crypto11 = require("node:crypto");
21920
22892
  function cacheRequest(body) {
21921
22893
  try {
21922
- (0, import_node_fs36.mkdirSync)(CACHE_DIR, { recursive: true });
22894
+ (0, import_node_fs41.mkdirSync)(CACHE_DIR, { recursive: true });
21923
22895
  const suffix = (0, import_node_crypto11.randomBytes)(4).toString("hex");
21924
22896
  const filename = `pending-${Math.floor(Date.now() / 1e3)}-${suffix}.json`;
21925
- (0, import_node_fs36.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(redactRequest(body)));
22897
+ (0, import_node_fs41.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(redactRequest(body)));
21926
22898
  } catch {
21927
22899
  }
21928
22900
  }
@@ -22041,8 +23013,8 @@ async function transmit(run2) {
22041
23013
  }
22042
23014
 
22043
23015
  // src/commands/analyze/phases/13-reconcile.ts
22044
- var import_node_fs37 = require("node:fs");
22045
- var import_node_path26 = require("node:path");
23016
+ var import_node_fs42 = require("node:fs");
23017
+ var import_node_path29 = require("node:path");
22046
23018
  async function reconcile(run2) {
22047
23019
  const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run2;
22048
23020
  const sentPaths = codeDelta.files.map((f) => f.path);
@@ -22071,7 +23043,7 @@ async function reconcile(run2) {
22071
23043
  const st = foldDossier(memorySession.d);
22072
23044
  openElsewhere = openBlockingElsewhere(st.statements, sentPaths, (file, line) => {
22073
23045
  try {
22074
- const src = (0, import_node_fs37.readFileSync)((0, import_node_path26.join)(repoRoot(), file), "utf8").split("\n");
23046
+ const src = (0, import_node_fs42.readFileSync)((0, import_node_path29.join)(repoRoot(), file), "utf8").split("\n");
22075
23047
  const at = src[line - 1];
22076
23048
  return at === void 0 ? null : lineSha(at);
22077
23049
  } catch {
@@ -22736,7 +23708,7 @@ function registerAnalyzeCommand(program2) {
22736
23708
  var tracing = () => process.env.VERITY_TRACE_PHASES === "1";
22737
23709
  async function runAnalyze(opts, globals) {
22738
23710
  if (!verityConfigured()) {
22739
- (0, import_node_fs38.writeSync)(2, '[verity] not set up in this project \u2014 run "verity init" first.\n');
23711
+ (0, import_node_fs43.writeSync)(2, '[verity] not set up in this project \u2014 run "verity init" first.\n');
22740
23712
  process.exit(0);
22741
23713
  }
22742
23714
  const run2 = createRun(opts, globals);
@@ -22817,7 +23789,7 @@ async function readStdin() {
22817
23789
  }
22818
23790
 
22819
23791
  // src/commands/review.ts
22820
- var import_node_fs39 = require("node:fs");
23792
+ var import_node_fs44 = require("node:fs");
22821
23793
  function registerReviewCommand(program2) {
22822
23794
  program2.command("review").description("Run on-demand Verity analysis (advisory, never blocks)").requiredOption("--files <paths>", "Comma-separated file list").option("--changed <paths>", "Subset of --files that were modified").option("--intent <text>", "User intent description (max 2000 chars)").option("--specs <paths>", "Comma-separated spec file paths").option("--json", "Output raw JSON response").action(async (opts) => {
22823
23795
  const globals = program2.opts();
@@ -22836,7 +23808,7 @@ async function runReview(opts, globals) {
22836
23808
  const securityFiles = filterSecurity(allFiles);
22837
23809
  let staticResults;
22838
23810
  if (isCodacyAvailable()) {
22839
- const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs39.existsSync)(f) || resolveFile(f) !== null);
23811
+ const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs44.existsSync)(f) || resolveFile(f) !== null);
22840
23812
  staticResults = runCodacyAnalysis(scannable);
22841
23813
  } else {
22842
23814
  staticResults = {
@@ -22862,10 +23834,10 @@ async function runReview(opts, globals) {
22862
23834
  const specPaths = opts.specs.split(",").map((f) => f.trim()).filter(Boolean);
22863
23835
  specs = [];
22864
23836
  for (const p of specPaths) {
22865
- if (!(0, import_node_fs39.existsSync)(p)) continue;
23837
+ if (!(0, import_node_fs44.existsSync)(p)) continue;
22866
23838
  try {
22867
- const { readFileSync: readFileSync26 } = await import("node:fs");
22868
- const content = readFileSync26(p, "utf-8");
23839
+ const { readFileSync: readFileSync27 } = await import("node:fs");
23840
+ const content = readFileSync27(p, "utf-8");
22869
23841
  specs.push({ path: p, content: content.slice(0, 10240) });
22870
23842
  } catch {
22871
23843
  }
@@ -22922,10 +23894,10 @@ async function runReview(opts, globals) {
22922
23894
  }
22923
23895
 
22924
23896
  // src/commands/guard.ts
22925
- var import_node_fs40 = require("node:fs");
22926
- var import_node_path27 = require("node:path");
23897
+ var import_node_fs45 = require("node:fs");
23898
+ var import_node_path30 = require("node:path");
22927
23899
  var GUARD_BLOCK_CAP = 2;
22928
- var GUARD_ITER_FILE = (0, import_node_path27.join)(VERITY_DIR, ".guard-iteration");
23900
+ var GUARD_ITER_FILE = (0, import_node_path30.join)(VERITY_DIR, ".guard-iteration");
22929
23901
  function readPreToolUseStdin() {
22930
23902
  const empty = { command: "", cwd: null, sessionId: null };
22931
23903
  return new Promise((resolve4) => {
@@ -22970,7 +23942,7 @@ function readPreToolUseStdin() {
22970
23942
  }
22971
23943
  function readIterMap() {
22972
23944
  try {
22973
- const raw = JSON.parse((0, import_node_fs40.readFileSync)(GUARD_ITER_FILE, "utf-8"));
23945
+ const raw = JSON.parse((0, import_node_fs45.readFileSync)(GUARD_ITER_FILE, "utf-8"));
22974
23946
  if (raw && typeof raw === "object") {
22975
23947
  if (typeof raw.moment === "string" && typeof raw.count === "number") {
22976
23948
  return { [raw.moment]: raw.count };
@@ -22990,10 +23962,10 @@ function readIter(moment) {
22990
23962
  }
22991
23963
  function writeIter(moment, count) {
22992
23964
  try {
22993
- (0, import_node_fs40.mkdirSync)(VERITY_DIR, { recursive: true });
23965
+ (0, import_node_fs45.mkdirSync)(VERITY_DIR, { recursive: true });
22994
23966
  const map = readIterMap();
22995
23967
  map[moment] = count;
22996
- (0, import_node_fs40.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
23968
+ (0, import_node_fs45.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
22997
23969
  } catch {
22998
23970
  }
22999
23971
  }
@@ -23003,10 +23975,10 @@ function resetIter(moment) {
23003
23975
  if (!(moment in map)) return;
23004
23976
  delete map[moment];
23005
23977
  if (Object.keys(map).length === 0) {
23006
- if ((0, import_node_fs40.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs40.unlinkSync)(GUARD_ITER_FILE);
23978
+ if ((0, import_node_fs45.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs45.unlinkSync)(GUARD_ITER_FILE);
23007
23979
  } else {
23008
- (0, import_node_fs40.mkdirSync)(VERITY_DIR, { recursive: true });
23009
- (0, import_node_fs40.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
23980
+ (0, import_node_fs45.mkdirSync)(VERITY_DIR, { recursive: true });
23981
+ (0, import_node_fs45.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
23010
23982
  }
23011
23983
  } catch {
23012
23984
  }
@@ -23078,7 +24050,7 @@ function buildGuardRequest(moment, files, codeDelta, iter, sessionId, statedInte
23078
24050
  const securityFiles = filterSecurity(files);
23079
24051
  let staticResults;
23080
24052
  if (isCodacyAvailable()) {
23081
- const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs40.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
24053
+ const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs45.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
23082
24054
  staticResults = runCodacyAnalysis(scannable);
23083
24055
  } else {
23084
24056
  staticResults = { tool: "@codacy/analysis-cli", findings: [], summary: { total_findings: 0, by_severity: {}, tools_run: [] } };
@@ -23211,13 +24183,13 @@ async function runGuard(opts, globals) {
23211
24183
  diffs: [],
23212
24184
  signalsByPath: rangeChangeSignals(frame, range, codeDelta.files.map((f) => f.path)),
23213
24185
  sentPaths: new Set(codeDelta.files.map((f) => f.path)),
23214
- isExcluded: (p) => isVerityOwnedPath(p) || isIgnored(ig, p),
24186
+ isExcluded: (p) => isVerityOwnedPath(p) || isIgnored2(ig, p),
23215
24187
  cwd: frame.worktreeRoot ?? process.cwd()
23216
24188
  });
23217
24189
  upgradeToExcerpts(repoContext2, {
23218
24190
  readFile: (rel) => {
23219
24191
  try {
23220
- return (0, import_node_fs40.readFileSync)((0, import_node_path27.join)(frame.worktreeRoot ?? process.cwd(), rel), "utf8");
24192
+ return (0, import_node_fs45.readFileSync)((0, import_node_path30.join)(frame.worktreeRoot ?? process.cwd(), rel), "utf8");
23221
24193
  } catch {
23222
24194
  return null;
23223
24195
  }
@@ -23438,7 +24410,7 @@ function registerIgnoreCommand(program2) {
23438
24410
 
23439
24411
  // src/commands/waive.ts
23440
24412
  var import_node_crypto12 = require("node:crypto");
23441
- var import_node_fs41 = require("node:fs");
24413
+ var import_node_fs46 = require("node:fs");
23442
24414
  function registerWaiveCommand(program2) {
23443
24415
  program2.command("waive <pattern-id>").description("Record an accepted-risk disposition for an open finding (voids when the file changes)").option("--file <path>", "File the finding is anchored to, REPO-RELATIVE (recommended \u2014 narrows the waive)").requiredOption("--reason <text>", "The human disposition this records (reviewer finding, ADR, \u2026)").action(async (patternId, opts) => {
23444
24416
  const globals = program2.opts();
@@ -23467,7 +24439,7 @@ function registerWaiveCommand(program2) {
23467
24439
  if (opts.file) {
23468
24440
  body.file = opts.file;
23469
24441
  try {
23470
- body.file_sha256 = (0, import_node_crypto12.createHash)("sha256").update((0, import_node_fs41.readFileSync)(opts.file)).digest("hex");
24442
+ body.file_sha256 = (0, import_node_crypto12.createHash)("sha256").update((0, import_node_fs46.readFileSync)(opts.file)).digest("hex");
23471
24443
  } catch {
23472
24444
  printError(`Cannot read ${opts.file} \u2014 run from the repo root, or omit --file to waive by pattern.`);
23473
24445
  process.exit(1);
@@ -23492,10 +24464,11 @@ function registerWaiveCommand(program2) {
23492
24464
  }
23493
24465
 
23494
24466
  // src/commands/init.ts
23495
- var import_node_fs46 = require("node:fs");
23496
- var import_promises14 = require("node:fs/promises");
23497
- var import_node_path29 = require("node:path");
23498
- var import_node_child_process14 = require("node:child_process");
24467
+ var import_node_fs51 = require("node:fs");
24468
+ var import_promises17 = require("node:fs/promises");
24469
+ var import_yaml6 = __toESM(require_dist());
24470
+ var import_node_path33 = require("node:path");
24471
+ var import_node_child_process16 = require("node:child_process");
23499
24472
 
23500
24473
  // src/lib/banner.ts
23501
24474
  var WORDMARK = [
@@ -23573,14 +24546,14 @@ function printPhase(n, of, title, subtitle) {
23573
24546
  }
23574
24547
 
23575
24548
  // src/commands/doctor.ts
23576
- var import_node_fs44 = require("node:fs");
24549
+ var import_node_fs48 = require("node:fs");
23577
24550
 
23578
24551
  // src/lib/prereqs.ts
23579
- var import_node_child_process11 = require("node:child_process");
24552
+ var import_node_child_process13 = require("node:child_process");
23580
24553
  var MIN_NODE_MAJOR = 20;
23581
24554
  function which(bin) {
23582
24555
  try {
23583
- const out = (0, import_node_child_process11.execSync)(`command -v ${bin}`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
24556
+ const out = (0, import_node_child_process13.execSync)(`command -v ${bin}`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
23584
24557
  return out || null;
23585
24558
  } catch {
23586
24559
  return null;
@@ -23602,7 +24575,7 @@ function checkNode() {
23602
24575
  function checkGit() {
23603
24576
  let detail = "";
23604
24577
  try {
23605
- detail = (0, import_node_child_process11.execSync)("git --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
24578
+ detail = (0, import_node_child_process13.execSync)("git --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
23606
24579
  } catch {
23607
24580
  return {
23608
24581
  id: "git",
@@ -23640,7 +24613,7 @@ function checkAnalysisCli() {
23640
24613
  var INSTALL_TIMEOUT_MS = 12e4;
23641
24614
  function run(command, args, opts = {}) {
23642
24615
  return new Promise((resolve4) => {
23643
- const child = (0, import_node_child_process11.spawn)(command, args, {
24616
+ const child = (0, import_node_child_process13.spawn)(command, args, {
23644
24617
  stdio: opts.inherit ? "inherit" : "pipe",
23645
24618
  timeout: INSTALL_TIMEOUT_MS
23646
24619
  });
@@ -23689,11 +24662,11 @@ async function checkPrereqs(opts = {}) {
23689
24662
  }
23690
24663
 
23691
24664
  // src/lib/telemetry.ts
23692
- var import_promises12 = require("node:fs/promises");
24665
+ var import_promises15 = require("node:fs/promises");
23693
24666
 
23694
24667
  // src/lib/gitignore.ts
23695
- var import_node_child_process12 = require("node:child_process");
23696
- var import_node_fs42 = require("node:fs");
24668
+ var import_node_child_process14 = require("node:child_process");
24669
+ var import_node_fs47 = require("node:fs");
23697
24670
  var VERITY_GITIGNORE_MARKER = "# Verity \u2014 machine-local state.";
23698
24671
  var SETTINGS_LOCAL_IGNORE_ENTRY = ".claude/settings.local.json";
23699
24672
  var VERITY_GITIGNORE_BLOCK = [
@@ -23707,26 +24680,26 @@ var VERITY_GITIGNORE_BLOCK = [
23707
24680
  ""
23708
24681
  ].join("\n");
23709
24682
  var BREAKING_ENTRIES = /* @__PURE__ */ new Set([".verity/", ".verity"]);
23710
- function isIgnored2(path) {
24683
+ function isIgnored3(path) {
23711
24684
  try {
23712
- (0, import_node_child_process12.execSync)(`git check-ignore -q -- "${path}"`, { stdio: "pipe" });
24685
+ (0, import_node_child_process14.execSync)(`git check-ignore -q -- "${path}"`, { stdio: "pipe" });
23713
24686
  return true;
23714
24687
  } catch (err) {
23715
24688
  return err.status === 1 ? false : null;
23716
24689
  }
23717
24690
  }
23718
24691
  function semanticsHold() {
23719
- const snapshot = isIgnored2(".verity/.snapshot/__probe__");
23720
- const standard = isIgnored2(".verity/standard.yaml");
23721
- const node = isIgnored2(".verity/memory/domain/__probe__.md");
23722
- const futureState = isIgnored2(".verity/.__probe-future-state__");
24692
+ const snapshot = isIgnored3(".verity/.snapshot/__probe__");
24693
+ const standard = isIgnored3(".verity/standard.yaml");
24694
+ const node = isIgnored3(".verity/memory/domain/__probe__.md");
24695
+ const futureState = isIgnored3(".verity/.__probe-future-state__");
23723
24696
  if (snapshot === null || standard === null || node === null || futureState === null) return null;
23724
24697
  return snapshot === true && futureState === true && standard === false && node === false;
23725
24698
  }
23726
24699
  function ensureVerityGitignore() {
23727
24700
  let content = "";
23728
24701
  try {
23729
- content = (0, import_node_fs42.readFileSync)(".gitignore", "utf-8");
24702
+ content = (0, import_node_fs47.readFileSync)(".gitignore", "utf-8");
23730
24703
  } catch {
23731
24704
  }
23732
24705
  const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
@@ -23747,7 +24720,7 @@ function ensureVerityGitignore() {
23747
24720
  const sep2 = next === "" ? "" : next.endsWith("\n") ? "\n" : "\n\n";
23748
24721
  next = next + sep2 + VERITY_GITIGNORE_BLOCK;
23749
24722
  }
23750
- (0, import_node_fs42.writeFileSync)(".gitignore", next);
24723
+ (0, import_node_fs47.writeFileSync)(".gitignore", next);
23751
24724
  return verified(needsRepair ? "repaired" : "added");
23752
24725
  } catch {
23753
24726
  return "failed";
@@ -23756,7 +24729,7 @@ function ensureVerityGitignore() {
23756
24729
  function committedVerityState() {
23757
24730
  let out = "";
23758
24731
  try {
23759
- out = (0, import_node_child_process12.execSync)("git ls-files -z -- .verity", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
24732
+ out = (0, import_node_child_process14.execSync)("git ls-files -z -- .verity", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
23760
24733
  } catch {
23761
24734
  return [];
23762
24735
  }
@@ -23766,10 +24739,10 @@ function untrackVerityState() {
23766
24739
  const tracked = committedVerityState();
23767
24740
  if (tracked.length === 0) return "none";
23768
24741
  try {
23769
- (0, import_node_child_process12.execSync)("git rm -r --cached --quiet -- .verity", { stdio: "pipe" });
24742
+ (0, import_node_child_process14.execSync)("git rm -r --cached --quiet -- .verity", { stdio: "pipe" });
23770
24743
  for (const keep of [".verity/standard.yaml", ".verity/memory"]) {
23771
24744
  try {
23772
- (0, import_node_child_process12.execSync)(`git add -- "${keep}"`, { stdio: "pipe" });
24745
+ (0, import_node_child_process14.execSync)(`git add -- "${keep}"`, { stdio: "pipe" });
23773
24746
  } catch {
23774
24747
  }
23775
24748
  }
@@ -23809,7 +24782,7 @@ function buildTelemetryEnv(serviceUrl) {
23809
24782
  var VERITY_TELEMETRY_KEYS = Object.keys(buildTelemetryEnv(""));
23810
24783
  async function readSettingsLocal() {
23811
24784
  try {
23812
- return JSON.parse(await (0, import_promises12.readFile)(projectPath(SETTINGS_LOCAL_FILE2), "utf-8"));
24785
+ return JSON.parse(await (0, import_promises15.readFile)(projectPath(SETTINGS_LOCAL_FILE2), "utf-8"));
23813
24786
  } catch {
23814
24787
  return {};
23815
24788
  }
@@ -23821,7 +24794,7 @@ async function ensureGitignore() {
23821
24794
  const file = projectPath(GITIGNORE_FILE);
23822
24795
  let content = "";
23823
24796
  try {
23824
- content = await (0, import_promises12.readFile)(file, "utf-8");
24797
+ content = await (0, import_promises15.readFile)(file, "utf-8");
23825
24798
  } catch {
23826
24799
  }
23827
24800
  const lines = content.split("\n").map((l) => l.trim());
@@ -23830,7 +24803,7 @@ async function ensureGitignore() {
23830
24803
  }
23831
24804
  const block = "# Verity telemetry \u2014 machine-local Claude Code settings\n" + GITIGNORE_ENTRY + "\n";
23832
24805
  const next = content ? content + (content.endsWith("\n") ? "" : "\n") + "\n" + block : block;
23833
- await (0, import_promises12.writeFile)(file, next);
24806
+ await (0, import_promises15.writeFile)(file, next);
23834
24807
  }
23835
24808
  async function installTelemetry(serviceUrl) {
23836
24809
  const env = buildTelemetryEnv(serviceUrl);
@@ -23868,50 +24841,49 @@ async function uninstallTelemetry() {
23868
24841
  return { ok: true, data: { removed } };
23869
24842
  }
23870
24843
 
23871
- // src/lib/setup-state.ts
23872
- var import_promises13 = require("node:fs/promises");
23873
- var import_node_fs43 = require("node:fs");
23874
- var SETUP_STATE_FILE = `${VERITY_DIR}/setup.json`;
23875
- async function readSetupState() {
23876
- const path = projectPath(SETUP_STATE_FILE);
23877
- if (!(0, import_node_fs43.existsSync)(path)) return null;
23878
- try {
23879
- const parsed = JSON.parse(await (0, import_promises13.readFile)(path, "utf-8"));
23880
- return parsed && typeof parsed === "object" ? parsed : null;
23881
- } catch {
23882
- return null;
23883
- }
23884
- }
23885
- async function writeSetupState(patch) {
23886
- const current = await readSetupState() ?? { version: 1 };
23887
- const next = { ...current, ...patch, version: 1 };
23888
- await writeJsonFilePreservingStyle(projectPath(SETUP_STATE_FILE), next);
23889
- return next;
23890
- }
23891
-
23892
24844
  // src/commands/doctor.ts
23893
24845
  async function buildReport() {
23894
24846
  const prereqs = await checkPrereqs({ install: false });
23895
24847
  const state = await readSetupState();
23896
24848
  const hooks = await checkAllVerityHooks();
23897
24849
  const telemetry = await checkTelemetry();
24850
+ const hasConfig = (0, import_node_fs48.existsSync)(projectPath(CODACY_CONFIG_FILE));
23898
24851
  const artifacts = {
23899
- standard: (0, import_node_fs44.existsSync)(projectPath(STANDARD_FILE)),
23900
- analysisConfig: (0, import_node_fs44.existsSync)(projectPath(CODACY_CONFIG_FILE)),
23901
- verityMd: (0, import_node_fs44.existsSync)(projectPath(VERITY_MD_FILE))
24852
+ standard: (0, import_node_fs48.existsSync)(projectPath(STANDARD_FILE)),
24853
+ analysisConfig: hasConfig,
24854
+ verityMd: (0, import_node_fs48.existsSync)(projectPath(VERITY_MD_FILE)),
24855
+ analysisConfigIds: hasConfig ? validatePatternIds().status : "absent"
23902
24856
  };
23903
24857
  const next = [];
23904
24858
  for (const c of prereqs.checks) {
23905
24859
  if (c.status !== "ok" && c.remedy) next.push(c.remedy);
23906
24860
  }
23907
24861
  if (!state?.init) next.push('Run "verity init" \u2014 the deterministic setup phase has not completed here.');
23908
- if (!artifacts.standard || !artifacts.analysisConfig || !artifacts.verityMd) {
23909
- next.push("Run /verity-setup in Claude Code \u2014 the Standard, analysis config, and VERITY.md are synthesized there.");
24862
+ const missing = [
24863
+ !artifacts.standard && ".verity/standard.yaml",
24864
+ !artifacts.analysisConfig && ".codacy/codacy.config.json",
24865
+ !artifacts.verityMd && "VERITY.md"
24866
+ ].filter((x) => !!x);
24867
+ if (missing.length === 3) {
24868
+ next.push('Run "verity standard synthesize --push" \u2014 it derives the Standard, the analysis config and VERITY.md from this codebase.');
24869
+ } else if (missing.length === 1 && !artifacts.analysisConfig) {
24870
+ next.push(
24871
+ 'No analysis config, so static analysis runs nothing. Run "verity standard synthesize --config-only" to derive one from the Standard you already have (--force would REPLACE that Standard), or have a teammate run "verity config push".'
24872
+ );
24873
+ } else if (missing.length > 0) {
24874
+ next.push(
24875
+ `Missing ${missing.join(" and ")}. Run "verity standard synthesize --force" to regenerate \u2014 note that replaces the Standard; use --config-only if only the analysis config is missing.`
24876
+ );
23910
24877
  }
23911
24878
  const noAnalysisMoment = !hooks.stop && hooks.guardOn.length === 0;
23912
24879
  if (noAnalysisMoment) {
23913
24880
  next.push('No analysis moment is active \u2014 run "verity hooks install --moments stop" or re-run "verity init".');
23914
24881
  }
24882
+ if (artifacts.analysisConfigIds === "invalid") {
24883
+ next.push(
24884
+ '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
+ );
24886
+ }
23915
24887
  if (state?.telemetry === "deferred") {
23916
24888
  next.push('Telemetry was requested but needs a token \u2014 run "verity login", then "verity telemetry install".');
23917
24889
  }
@@ -23957,7 +24929,9 @@ function registerDoctorCommand(program2) {
23957
24929
  printInfo(`Telemetry: ${report.telemetry.enabled ? `enabled \u2192 ${report.telemetry.endpoint}` : "disabled"}`);
23958
24930
  printInfo("Artifacts:");
23959
24931
  printInfo(` .verity/standard.yaml: ${report.artifacts.standard ? "\u2713" : "missing"}`);
23960
- printInfo(` .codacy/codacy.config.json: ${report.artifacts.analysisConfig ? "\u2713" : "missing"}`);
24932
+ const idState = report.artifacts.analysisConfigIds;
24933
+ const idNote = idState === "valid" ? "\u2713" : idState === "invalid" ? "\u26A0 ids do not resolve" : idState === "unchecked" ? "\u2713 (ids unverified \u2014 no adapter)" : "";
24934
+ printInfo(` .codacy/codacy.config.json: ${report.artifacts.analysisConfig ? idNote : "missing"}`);
23961
24935
  printInfo(` VERITY.md: ${report.artifacts.verityMd ? "\u2713" : "missing"}`);
23962
24936
  if (report.next.length > 0) {
23963
24937
  console.log("");
@@ -23971,16 +24945,16 @@ function registerDoctorCommand(program2) {
23971
24945
  }
23972
24946
 
23973
24947
  // src/commands/migrate.ts
23974
- var import_node_fs45 = require("node:fs");
23975
- var import_node_path28 = require("node:path");
23976
- var import_node_child_process13 = require("node:child_process");
24948
+ var import_node_fs49 = require("node:fs");
24949
+ var import_node_path31 = require("node:path");
24950
+ var import_node_child_process15 = require("node:child_process");
23977
24951
  var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
23978
24952
  function defaultNpmRemover(pkg) {
23979
- (0, import_node_child_process13.execSync)(`npm rm -g ${pkg}`, { stdio: "pipe", timeout: 12e4 });
24953
+ (0, import_node_child_process15.execSync)(`npm rm -g ${pkg}`, { stdio: "pipe", timeout: 12e4 });
23980
24954
  }
23981
24955
  function isGitTracked(cwd, relPath) {
23982
24956
  try {
23983
- (0, import_node_child_process13.execSync)(`git ls-files --error-unmatch ${relPath}`, { cwd, stdio: "pipe" });
24957
+ (0, import_node_child_process15.execSync)(`git ls-files --error-unmatch ${relPath}`, { cwd, stdio: "pipe" });
23984
24958
  return true;
23985
24959
  } catch {
23986
24960
  return false;
@@ -23988,7 +24962,7 @@ function isGitTracked(cwd, relPath) {
23988
24962
  }
23989
24963
  function isGitRepo(cwd) {
23990
24964
  try {
23991
- (0, import_node_child_process13.execSync)("git rev-parse --is-inside-work-tree", { cwd, stdio: "pipe" });
24965
+ (0, import_node_child_process15.execSync)("git rev-parse --is-inside-work-tree", { cwd, stdio: "pipe" });
23992
24966
  return true;
23993
24967
  } catch {
23994
24968
  return false;
@@ -24009,12 +24983,12 @@ async function runMigration(opts = {}) {
24009
24983
  return { actions, migrated: actions.length > 0 };
24010
24984
  }
24011
24985
  function migrateProjectDir(root, actions) {
24012
- const gateDir = (0, import_node_path28.join)(root, ".gate");
24013
- const verityDir = (0, import_node_path28.join)(root, ".verity");
24014
- if ((0, import_node_fs45.existsSync)(gateDir) && !(0, import_node_fs45.existsSync)(verityDir)) {
24986
+ const gateDir = (0, import_node_path31.join)(root, ".gate");
24987
+ const verityDir = (0, import_node_path31.join)(root, ".verity");
24988
+ if ((0, import_node_fs49.existsSync)(gateDir) && !(0, import_node_fs49.existsSync)(verityDir)) {
24015
24989
  return migrateProjectDirRename(root, gateDir, verityDir, actions);
24016
24990
  }
24017
- if ((0, import_node_fs45.existsSync)(gateDir) && (0, import_node_fs45.existsSync)(verityDir)) {
24991
+ if ((0, import_node_fs49.existsSync)(gateDir) && (0, import_node_fs49.existsSync)(verityDir)) {
24018
24992
  return migrateProjectDirCarry(gateDir, verityDir, actions);
24019
24993
  }
24020
24994
  return false;
@@ -24028,20 +25002,20 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
24028
25002
  );
24029
25003
  }
24030
25004
  try {
24031
- (0, import_node_child_process13.execSync)("git mv .gate .verity", { cwd: root, stdio: "pipe" });
25005
+ (0, import_node_child_process15.execSync)("git mv .gate .verity", { cwd: root, stdio: "pipe" });
24032
25006
  actions.push("Moved .gate/ \u2192 .verity/ (git mv, staged)");
24033
25007
  moved = true;
24034
25008
  } catch {
24035
25009
  }
24036
25010
  }
24037
25011
  if (moved) {
24038
- if ((0, import_node_fs45.existsSync)(gateDir)) {
25012
+ if ((0, import_node_fs49.existsSync)(gateDir)) {
24039
25013
  const carried = carryLegacyContents(gateDir, verityDir);
24040
25014
  if (carried > 0) {
24041
25015
  actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
24042
25016
  }
24043
25017
  try {
24044
- (0, import_node_fs45.rmSync)(gateDir, { recursive: true, force: true });
25018
+ (0, import_node_fs49.rmSync)(gateDir, { recursive: true, force: true });
24045
25019
  } catch {
24046
25020
  }
24047
25021
  }
@@ -24057,18 +25031,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
24057
25031
  actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
24058
25032
  }
24059
25033
  try {
24060
- (0, import_node_fs45.rmSync)(gateDir, { recursive: true, force: true });
25034
+ (0, import_node_fs49.rmSync)(gateDir, { recursive: true, force: true });
24061
25035
  } catch {
24062
25036
  }
24063
25037
  return carried > 0;
24064
25038
  }
24065
25039
  function migrateGlobalCredentials(home, actions) {
24066
25040
  if (!home) return;
24067
- const gateCreds = (0, import_node_path28.join)(home, ".gate", "credentials");
24068
- const verityCreds = (0, import_node_path28.join)(home, ".verity", "credentials");
24069
- if (!(0, import_node_fs45.existsSync)(gateCreds)) return;
24070
- if (!(0, import_node_fs45.existsSync)(verityCreds)) {
24071
- (0, import_node_fs45.mkdirSync)((0, import_node_path28.join)(home, ".verity"), { recursive: true });
25041
+ const gateCreds = (0, import_node_path31.join)(home, ".gate", "credentials");
25042
+ const verityCreds = (0, import_node_path31.join)(home, ".verity", "credentials");
25043
+ if (!(0, import_node_fs49.existsSync)(gateCreds)) return;
25044
+ if (!(0, import_node_fs49.existsSync)(verityCreds)) {
25045
+ (0, import_node_fs49.mkdirSync)((0, import_node_path31.join)(home, ".verity"), { recursive: true });
24072
25046
  moveFile(gateCreds, verityCreds);
24073
25047
  actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
24074
25048
  return;
@@ -24090,8 +25064,8 @@ async function migrateLegacyHooks(root, actions) {
24090
25064
  }
24091
25065
  }
24092
25066
  async function migrateClaudeMd(root, actions) {
24093
- const claudeMd = (0, import_node_path28.join)(root, "CLAUDE.md");
24094
- const hadLegacyBlock = (0, import_node_fs45.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
25067
+ const claudeMd = (0, import_node_path31.join)(root, "CLAUDE.md");
25068
+ const hadLegacyBlock = (0, import_node_fs49.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
24095
25069
  if (!hadLegacyBlock) return;
24096
25070
  try {
24097
25071
  await ensureClaudeMdPointer(root);
@@ -24101,13 +25075,13 @@ async function migrateClaudeMd(root, actions) {
24101
25075
  }
24102
25076
  }
24103
25077
  function migrateStandardFile(root, actions) {
24104
- const gateMd = (0, import_node_path28.join)(root, "GATE.md");
24105
- const verityMd = (0, import_node_path28.join)(root, "VERITY.md");
24106
- if (!(0, import_node_fs45.existsSync)(gateMd) || (0, import_node_fs45.existsSync)(verityMd)) return;
25078
+ const gateMd = (0, import_node_path31.join)(root, "GATE.md");
25079
+ const verityMd = (0, import_node_path31.join)(root, "VERITY.md");
25080
+ if (!(0, import_node_fs49.existsSync)(gateMd) || (0, import_node_fs49.existsSync)(verityMd)) return;
24107
25081
  let moved = false;
24108
25082
  if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
24109
25083
  try {
24110
- (0, import_node_child_process13.execSync)("git mv GATE.md VERITY.md", { cwd: root, stdio: "pipe" });
25084
+ (0, import_node_child_process15.execSync)("git mv GATE.md VERITY.md", { cwd: root, stdio: "pipe" });
24111
25085
  moved = true;
24112
25086
  } catch {
24113
25087
  }
@@ -24115,12 +25089,12 @@ function migrateStandardFile(root, actions) {
24115
25089
  if (!moved) moveFile(gateMd, verityMd);
24116
25090
  const content = readFileSyncSafe(verityMd);
24117
25091
  const refreshed = content.split("GATE.md").join("VERITY.md");
24118
- if (refreshed !== content) (0, import_node_fs45.writeFileSync)(verityMd, refreshed);
25092
+ if (refreshed !== content) (0, import_node_fs49.writeFileSync)(verityMd, refreshed);
24119
25093
  actions.push("Renamed GATE.md \u2192 VERITY.md");
24120
25094
  }
24121
25095
  async function migrateTelemetryHeaders(root, actions) {
24122
- const file = (0, import_node_path28.join)(root, ".claude", "settings.local.json");
24123
- if (!(0, import_node_fs45.existsSync)(file)) return;
25096
+ const file = (0, import_node_path31.join)(root, ".claude", "settings.local.json");
25097
+ if (!(0, import_node_fs49.existsSync)(file)) return;
24124
25098
  let settings;
24125
25099
  try {
24126
25100
  settings = JSON.parse(readFileSyncSafe(file) || "{}");
@@ -24168,21 +25142,21 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
24168
25142
  }
24169
25143
  if (toAppend.length > 0) {
24170
25144
  const sep2 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
24171
- (0, import_node_fs45.writeFileSync)(verityCreds, verityContent + sep2 + toAppend.join("\n") + "\n");
25145
+ (0, import_node_fs49.writeFileSync)(verityCreds, verityContent + sep2 + toAppend.join("\n") + "\n");
24172
25146
  }
24173
- (0, import_node_fs45.rmSync)(gateCreds, { force: true });
25147
+ (0, import_node_fs49.rmSync)(gateCreds, { force: true });
24174
25148
  return toAppend.length;
24175
25149
  }
24176
25150
  function readFileSyncSafe(path) {
24177
25151
  try {
24178
- return (0, import_node_fs45.readFileSync)(path, "utf-8");
25152
+ return (0, import_node_fs49.readFileSync)(path, "utf-8");
24179
25153
  } catch {
24180
25154
  return "";
24181
25155
  }
24182
25156
  }
24183
25157
  function hasStagedChanges(root) {
24184
25158
  try {
24185
- (0, import_node_child_process13.execSync)("git diff --cached --quiet", { cwd: root, stdio: "pipe" });
25159
+ (0, import_node_child_process15.execSync)("git diff --cached --quiet", { cwd: root, stdio: "pipe" });
24186
25160
  return false;
24187
25161
  } catch {
24188
25162
  return true;
@@ -24190,59 +25164,59 @@ function hasStagedChanges(root) {
24190
25164
  }
24191
25165
  function moveDir(from, to) {
24192
25166
  try {
24193
- (0, import_node_fs45.renameSync)(from, to);
25167
+ (0, import_node_fs49.renameSync)(from, to);
24194
25168
  } catch (err) {
24195
25169
  if (err.code !== "EXDEV") throw err;
24196
- (0, import_node_fs45.cpSync)(from, to, { recursive: true });
24197
- (0, import_node_fs45.rmSync)(from, { recursive: true, force: true });
25170
+ (0, import_node_fs49.cpSync)(from, to, { recursive: true });
25171
+ (0, import_node_fs49.rmSync)(from, { recursive: true, force: true });
24198
25172
  }
24199
25173
  }
24200
25174
  function moveFile(from, to) {
24201
25175
  try {
24202
- (0, import_node_fs45.renameSync)(from, to);
25176
+ (0, import_node_fs49.renameSync)(from, to);
24203
25177
  } catch (err) {
24204
25178
  if (err.code !== "EXDEV") throw err;
24205
- (0, import_node_fs45.cpSync)(from, to);
24206
- (0, import_node_fs45.rmSync)(from, { force: true });
25179
+ (0, import_node_fs49.cpSync)(from, to);
25180
+ (0, import_node_fs49.rmSync)(from, { force: true });
24207
25181
  }
24208
25182
  }
24209
25183
  function carryLegacyContents(gateDir, verityDir) {
24210
25184
  let copied = 0;
24211
- const walk = (relDir) => {
24212
- const srcDir = (0, import_node_path28.join)(gateDir, relDir);
24213
- for (const entry of (0, import_node_fs45.readdirSync)(srcDir)) {
24214
- const rel = relDir ? (0, import_node_path28.join)(relDir, entry) : entry;
24215
- const src = (0, import_node_path28.join)(gateDir, rel);
24216
- const dest = (0, import_node_path28.join)(verityDir, rel);
24217
- if ((0, import_node_fs45.statSync)(src).isDirectory()) {
24218
- walk(rel);
24219
- } else if (!(0, import_node_fs45.existsSync)(dest)) {
24220
- (0, import_node_fs45.mkdirSync)((0, import_node_path28.dirname)(dest), { recursive: true });
24221
- (0, import_node_fs45.cpSync)(src, dest);
25185
+ const walk2 = (relDir) => {
25186
+ const srcDir = (0, import_node_path31.join)(gateDir, relDir);
25187
+ 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);
25191
+ if ((0, import_node_fs49.statSync)(src).isDirectory()) {
25192
+ walk2(rel);
25193
+ } else if (!(0, import_node_fs49.existsSync)(dest)) {
25194
+ (0, import_node_fs49.mkdirSync)((0, import_node_path31.dirname)(dest), { recursive: true });
25195
+ (0, import_node_fs49.cpSync)(src, dest);
24222
25196
  copied++;
24223
25197
  }
24224
25198
  }
24225
25199
  };
24226
- walk("");
25200
+ walk2("");
24227
25201
  return copied;
24228
25202
  }
24229
25203
  async function needsMigration(root = repoRoot()) {
24230
- const gateDir = (0, import_node_path28.join)(root, ".gate");
24231
- const verityDir = (0, import_node_path28.join)(root, ".verity");
24232
- if ((0, import_node_fs45.existsSync)(gateDir) && !(0, import_node_fs45.existsSync)(verityDir)) return true;
24233
- if ((0, import_node_fs45.existsSync)(gateDir) && (0, import_node_fs45.existsSync)(verityDir)) {
24234
- if ((0, import_node_fs45.existsSync)((0, import_node_path28.join)(gateDir, "credentials")) && !(0, import_node_fs45.existsSync)((0, import_node_path28.join)(verityDir, "credentials"))) {
25204
+ const gateDir = (0, import_node_path31.join)(root, ".gate");
25205
+ const verityDir = (0, import_node_path31.join)(root, ".verity");
25206
+ if ((0, import_node_fs49.existsSync)(gateDir) && !(0, import_node_fs49.existsSync)(verityDir)) return true;
25207
+ 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"))) {
24235
25209
  return true;
24236
25210
  }
24237
- if ((0, import_node_fs45.existsSync)((0, import_node_path28.join)(gateDir, "memory")) && !(0, import_node_fs45.existsSync)((0, import_node_path28.join)(verityDir, "memory"))) {
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"))) {
24238
25212
  return true;
24239
25213
  }
24240
25214
  }
24241
- const claudeMd = (0, import_node_path28.join)(root, "CLAUDE.md");
24242
- if ((0, import_node_fs45.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
25215
+ const claudeMd = (0, import_node_path31.join)(root, "CLAUDE.md");
25216
+ if ((0, import_node_fs49.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
24243
25217
  return true;
24244
25218
  }
24245
- if ((0, import_node_fs45.existsSync)((0, import_node_path28.join)(root, "GATE.md")) && !(0, import_node_fs45.existsSync)((0, import_node_path28.join)(root, "VERITY.md"))) {
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"))) {
24246
25220
  return true;
24247
25221
  }
24248
25222
  if (await hasLegacyHooksAt(root)) return true;
@@ -24268,12 +25242,168 @@ function registerMigrateCommand(program2) {
24268
25242
  }
24269
25243
 
24270
25244
  // src/lib/prompt.ts
24271
- var readline2 = __toESM(require("node:readline/promises"));
25245
+ var readline3 = __toESM(require("node:readline/promises"));
25246
+
25247
+ // src/lib/select.ts
25248
+ var readline2 = __toESM(require("node:readline"));
25249
+ function keyToAction(str, key) {
25250
+ const name = key?.name;
25251
+ if (key?.ctrl && (name === "c" || str === "")) return { type: "interrupt" };
25252
+ if (key?.ctrl && (name === "d" || str === "")) return { type: "eof" };
25253
+ switch (name) {
25254
+ case "up":
25255
+ return { type: "move", delta: -1 };
25256
+ case "down":
25257
+ return { type: "move", delta: 1 };
25258
+ case "k":
25259
+ return key?.ctrl ? null : { type: "move", delta: -1 };
25260
+ case "j":
25261
+ return key?.ctrl ? null : { type: "move", delta: 1 };
25262
+ case "space":
25263
+ return { type: "toggle" };
25264
+ case "return":
25265
+ case "enter":
25266
+ return { type: "confirm" };
25267
+ default:
25268
+ break;
25269
+ }
25270
+ if (str === " ") return { type: "toggle" };
25271
+ if (str === "\r" || str === "\n") return { type: "confirm" };
25272
+ if (str && /^[1-9]$/.test(str)) return { type: "jump", index: Number(str) - 1 };
25273
+ return null;
25274
+ }
25275
+ function applyKey(state, action, count, mode2) {
25276
+ switch (action.type) {
25277
+ case "move": {
25278
+ const cursor = (state.cursor + action.delta + count) % count;
25279
+ return { status: "open", state: { cursor, chosen: state.chosen } };
25280
+ }
25281
+ case "jump": {
25282
+ if (action.index >= count) return { status: "open", state };
25283
+ return { status: "open", state: { cursor: action.index, chosen: state.chosen } };
25284
+ }
25285
+ case "toggle": {
25286
+ if (mode2 === "single") {
25287
+ return { status: "open", state: { cursor: state.cursor, chosen: /* @__PURE__ */ new Set([state.cursor]) } };
25288
+ }
25289
+ const chosen = new Set(state.chosen);
25290
+ if (chosen.has(state.cursor)) chosen.delete(state.cursor);
25291
+ else chosen.add(state.cursor);
25292
+ return { status: "open", state: { cursor: state.cursor, chosen } };
25293
+ }
25294
+ case "confirm": {
25295
+ if (mode2 === "single") return { status: "confirmed", indices: [state.cursor] };
25296
+ if (state.chosen.size === 0) {
25297
+ return {
25298
+ status: "open",
25299
+ state: { ...state, hint: "Select at least one \u2014 space toggles the option under the cursor." }
25300
+ };
25301
+ }
25302
+ return { status: "confirmed", indices: [...state.chosen].sort((a, b) => a - b) };
25303
+ }
25304
+ case "interrupt":
25305
+ return { status: "interrupt" };
25306
+ case "eof":
25307
+ return { status: "eof" };
25308
+ }
25309
+ }
25310
+ var GREEN3 = "\x1B[0;32m";
25311
+ var DIM4 = "\x1B[2m";
25312
+ var BOLD2 = "\x1B[1m";
25313
+ var RESET3 = "\x1B[0m";
25314
+ function renderSelect(question, choices, state, mode2, color = colorEnabled()) {
25315
+ const paint = (text, code) => color ? `${code}${text}${RESET3}` : text;
25316
+ const lines = ["", ` ${question}`];
25317
+ const labelOf = (c) => `${c.label}${c.recommended ? " (recommended)" : ""}`;
25318
+ const gutter = Math.max(...choices.map((c) => labelOf(c).length));
25319
+ choices.forEach((choice, i) => {
25320
+ const here = i === state.cursor;
25321
+ const marker = state.chosen.has(i) ? "\u25C9" : "\u25CB";
25322
+ const cursor = here ? "\u276F" : " ";
25323
+ const label2 = labelOf(choice);
25324
+ const pad = choice.hint ? " ".repeat(gutter - label2.length) : "";
25325
+ const hint = choice.hint ? `${pad} ${paint(choice.hint, DIM4)}` : "";
25326
+ lines.push(` ${cursor} ${marker} ${here ? paint(label2, BOLD2) : label2}${hint}`);
25327
+ });
25328
+ const keys = mode2 === "multi" ? "\u2191\u2193 move \xB7 space toggle \xB7 enter confirm" : "\u2191\u2193 move \xB7 enter confirm";
25329
+ lines.push(` ${paint(state.hint ?? keys, state.hint ? GREEN3 : DIM4)}`);
25330
+ return lines;
25331
+ }
25332
+ function runSelect(opts) {
25333
+ const input = opts.input ?? process.stdin;
25334
+ const output = opts.output ?? process.stdout;
25335
+ const { choices, mode: mode2 } = opts;
25336
+ if (typeof input.setRawMode !== "function" || !input.isTTY) return Promise.resolve(null);
25337
+ const initialIdx = choices.map((c, i) => opts.initial.includes(c.id) ? i : -1).filter((i) => i >= 0);
25338
+ let state = {
25339
+ cursor: initialIdx[0] ?? 0,
25340
+ chosen: new Set(mode2 === "single" ? [initialIdx[0] ?? 0] : initialIdx)
25341
+ };
25342
+ return new Promise((resolve4) => {
25343
+ let painted = 0;
25344
+ let settled = false;
25345
+ const draw = () => {
25346
+ if (painted > 0) {
25347
+ readline2.moveCursor(output, 0, -painted);
25348
+ readline2.cursorTo(output, 0);
25349
+ readline2.clearScreenDown(output);
25350
+ }
25351
+ const lines = renderSelect(opts.question, choices, state, mode2);
25352
+ output.write(lines.join("\n") + "\n");
25353
+ painted = lines.length;
25354
+ };
25355
+ const onKey = (str, key) => {
25356
+ const action = keyToAction(str, key);
25357
+ if (!action) return;
25358
+ const outcome = applyKey(state, action, choices.length, mode2);
25359
+ if (outcome.status === "open") {
25360
+ state = outcome.state;
25361
+ draw();
25362
+ return;
25363
+ }
25364
+ if (outcome.status === "confirmed") {
25365
+ state = { ...state, hint: void 0 };
25366
+ draw();
25367
+ finish(outcome.indices.map((i) => choices[i].id));
25368
+ return;
25369
+ }
25370
+ if (outcome.status === "eof") {
25371
+ finish(null);
25372
+ return;
25373
+ }
25374
+ restore();
25375
+ output.write("\n");
25376
+ process.exit(130);
25377
+ };
25378
+ const restore = () => {
25379
+ input.removeListener("keypress", onKey);
25380
+ try {
25381
+ input.setRawMode(false);
25382
+ } catch {
25383
+ }
25384
+ input.pause();
25385
+ };
25386
+ const finish = (value) => {
25387
+ if (settled) return;
25388
+ settled = true;
25389
+ restore();
25390
+ resolve4(value);
25391
+ };
25392
+ readline2.emitKeypressEvents(input);
25393
+ input.setRawMode(true);
25394
+ input.resume();
25395
+ input.on("keypress", onKey);
25396
+ input.once("end", () => finish(null));
25397
+ draw();
25398
+ });
25399
+ }
25400
+
25401
+ // src/lib/prompt.ts
24272
25402
  function interactive() {
24273
25403
  return !!process.stdin.isTTY && !!process.stdout.isTTY;
24274
25404
  }
24275
25405
  async function askLine(question, io = {}) {
24276
- const rl = readline2.createInterface({
25406
+ const rl = readline3.createInterface({
24277
25407
  input: io.input ?? process.stdin,
24278
25408
  output: io.output ?? process.stdout
24279
25409
  });
@@ -24331,6 +25461,8 @@ function printOptions(question, choices) {
24331
25461
  }
24332
25462
  async function promptChoice(question, choices, fallback) {
24333
25463
  if (!interactive()) return fallback;
25464
+ const picked = await runSelect({ question, choices, initial: [fallback], mode: "single" });
25465
+ if (picked !== null) return picked[0] ?? fallback;
24334
25466
  printOptions(question, choices);
24335
25467
  const defaultIdx = choices.findIndex((c) => c.id === fallback);
24336
25468
  const answer = await ask(` Choose [${defaultIdx + 1}]: `);
@@ -24344,6 +25476,8 @@ async function promptChoice(question, choices, fallback) {
24344
25476
  }
24345
25477
  async function promptMultiSelect(question, choices, fallback) {
24346
25478
  if (!interactive()) return [...fallback];
25479
+ const picked = await runSelect({ question, choices, initial: fallback, mode: "multi" });
25480
+ if (picked !== null) return picked.length > 0 ? picked : [...fallback];
24347
25481
  printOptions(question, choices);
24348
25482
  const defaultLabel = choices.map((c, i) => fallback.includes(c.id) ? String(i + 1) : null).filter(Boolean).join(",");
24349
25483
  const answer = await ask(` Choose one or more, comma-separated [${defaultLabel}]: `);
@@ -24356,6 +25490,100 @@ async function promptMultiSelect(question, choices, fallback) {
24356
25490
  return parsed.ids;
24357
25491
  }
24358
25492
 
25493
+ // src/lib/remote-config.ts
25494
+ var import_node_fs50 = require("node:fs");
25495
+ var import_promises16 = require("node:fs/promises");
25496
+ var import_node_path32 = require("node:path");
25497
+ var import_yaml5 = __toESM(require_dist());
25498
+ var IGNORE_RIDER = "verityignore";
25499
+ async function fetchRemoteSetup(opts) {
25500
+ const standard = await apiRequest({
25501
+ method: "GET",
25502
+ path: "/standards/latest",
25503
+ serviceUrl: opts.serviceUrl,
25504
+ token: opts.token,
25505
+ verbose: opts.verbose
25506
+ });
25507
+ if (!standard.ok) {
25508
+ const missing = /STANDARD_NOT_FOUND|not found|404/i.test(standard.error);
25509
+ return missing ? { status: "none" } : { status: "unavailable", reason: standard.error };
25510
+ }
25511
+ const config = await apiRequest({
25512
+ method: "GET",
25513
+ path: "/analysis-configs",
25514
+ serviceUrl: opts.serviceUrl,
25515
+ token: opts.token,
25516
+ verbose: opts.verbose
25517
+ });
25518
+ return {
25519
+ status: "found",
25520
+ standard: {
25521
+ version: standard.data.version,
25522
+ content: standard.data.content ?? {},
25523
+ createdBy: standard.data.created_by,
25524
+ createdAt: standard.data.created_at
25525
+ },
25526
+ // Absent is normal and not an error: the two are stored independently, and a
25527
+ // project can have a Standard with no analysis config.
25528
+ analysisConfig: config.ok ? config.data.content ?? null : null
25529
+ };
25530
+ }
25531
+ async function adoptRemoteSetup(found, opts) {
25532
+ const written = [];
25533
+ const notes = [];
25534
+ const content = { ...found.standard.content };
25535
+ const rider = typeof content[IGNORE_RIDER] === "string" ? content[IGNORE_RIDER] : null;
25536
+ delete content[IGNORE_RIDER];
25537
+ await writeOut(STANDARD_FILE, (0, import_yaml5.stringify)(content));
25538
+ written.push(STANDARD_FILE);
25539
+ if (rider !== null) {
25540
+ const localIgnore = projectPath(VERITYIGNORE_FILE);
25541
+ if (!(0, import_node_fs50.existsSync)(localIgnore)) {
25542
+ await writeOut(VERITYIGNORE_FILE, rider);
25543
+ written.push(VERITYIGNORE_FILE);
25544
+ } else {
25545
+ const local = await (0, import_promises16.readFile)(localIgnore, "utf-8").catch(() => null);
25546
+ if (local !== null && local !== rider) {
25547
+ notes.push(`${VERITYIGNORE_FILE} already exists here and differs from the pushed copy \u2014 kept yours.`);
25548
+ }
25549
+ }
25550
+ }
25551
+ if (found.analysisConfig) {
25552
+ await writeOut(CODACY_CONFIG_FILE, JSON.stringify(found.analysisConfig, null, 2) + "\n");
25553
+ written.push(CODACY_CONFIG_FILE);
25554
+ } else {
25555
+ const derived = await deriveConfigForStandard(content);
25556
+ written.push(...derived.written);
25557
+ notes.push(...derived.notes);
25558
+ if (derived.written.length > 0) {
25559
+ notes.push("No analysis config was stored for this repository \u2014 derived one from the adopted Standard.");
25560
+ }
25561
+ }
25562
+ await writeOut(VERITY_MD_FILE, renderVerityMd({
25563
+ content,
25564
+ version: found.standard.version,
25565
+ serviceUrl: opts.serviceUrl,
25566
+ projectId: opts.projectId,
25567
+ origin: { kind: "adopted", createdBy: found.standard.createdBy }
25568
+ }));
25569
+ written.push(VERITY_MD_FILE);
25570
+ return { written, notes };
25571
+ }
25572
+ async function writeOut(relative2, body) {
25573
+ const target = projectPath(relative2);
25574
+ await (0, import_promises16.mkdir)((0, import_node_path32.dirname)(target), { recursive: true });
25575
+ await (0, import_promises16.writeFile)(target, body);
25576
+ }
25577
+ function describeRemote(found) {
25578
+ const when = found.standard.createdAt.slice(0, 10);
25579
+ const who = found.standard.createdBy ? ` by ${found.standard.createdBy}` : "";
25580
+ const extras = [];
25581
+ if (found.analysisConfig) extras.push("analysis config");
25582
+ if (typeof found.standard.content[IGNORE_RIDER] === "string") extras.push(".verityignore");
25583
+ const also = extras.length > 0 ? ` \xB7 with ${extras.join(" and ")}` : "";
25584
+ return `version ${found.standard.version}, pushed${who} on ${when}${also}`;
25585
+ }
25586
+
24359
25587
  // src/commands/init.ts
24360
25588
  async function confirmExistingLogin(serviceUrl, remote, opts) {
24361
25589
  const existing = await resolveToken(opts.token);
@@ -24414,7 +25642,7 @@ async function runOptionalAuth(resolution, opts = {}) {
24414
25642
  }
24415
25643
  let remote = "";
24416
25644
  try {
24417
- remote = (0, import_node_child_process14.execSync)("git remote get-url origin", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
25645
+ remote = (0, import_node_child_process16.execSync)("git remote get-url origin", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
24418
25646
  } catch {
24419
25647
  }
24420
25648
  if (!healed) {
@@ -24458,17 +25686,17 @@ async function runOptionalAuth(resolution, opts = {}) {
24458
25686
  localOnlyNote();
24459
25687
  }
24460
25688
  }
24461
- function resolveDataDir() {
25689
+ function resolveDataDir2() {
24462
25690
  const candidates = [
24463
- (0, import_node_path29.join)(__dirname, "..", "data"),
25691
+ (0, import_node_path33.join)(__dirname, "..", "data"),
24464
25692
  // installed: node_modules/@codacy/verity-cli/data
24465
- (0, import_node_path29.join)(__dirname, "..", "..", "data"),
25693
+ (0, import_node_path33.join)(__dirname, "..", "..", "data"),
24466
25694
  // edge case: nested resolution
24467
- (0, import_node_path29.join)(process.cwd(), "cli", "data")
25695
+ (0, import_node_path33.join)(process.cwd(), "cli", "data")
24468
25696
  // local dev: running from repo root
24469
25697
  ];
24470
25698
  for (const candidate of candidates) {
24471
- if ((0, import_node_fs46.existsSync)((0, import_node_path29.join)(candidate, "skills"))) {
25699
+ if ((0, import_node_fs51.existsSync)((0, import_node_path33.join)(candidate, "skills"))) {
24472
25700
  return candidate;
24473
25701
  }
24474
25702
  }
@@ -24477,28 +25705,28 @@ function resolveDataDir() {
24477
25705
  );
24478
25706
  }
24479
25707
  async function copyDir(src, dest) {
24480
- await (0, import_promises14.mkdir)(dest, { recursive: true });
24481
- await (0, import_promises14.cp)(src, dest, { recursive: true, force: true });
25708
+ await (0, import_promises17.mkdir)(dest, { recursive: true });
25709
+ await (0, import_promises17.cp)(src, dest, { recursive: true, force: true });
24482
25710
  }
24483
25711
  async function skillIsCurrent(src, dest) {
24484
25712
  const list2 = (dir) => {
24485
25713
  const out = [];
24486
- const walk = (d, prefix) => {
24487
- for (const e of (0, import_node_fs46.readdirSync)(d, { withFileTypes: true })) {
25714
+ const walk2 = (d, prefix) => {
25715
+ for (const e of (0, import_node_fs51.readdirSync)(d, { withFileTypes: true })) {
24488
25716
  const rel = prefix ? `${prefix}/${e.name}` : e.name;
24489
- if (e.isDirectory()) walk((0, import_node_path29.join)(d, e.name), rel);
25717
+ if (e.isDirectory()) walk2((0, import_node_path33.join)(d, e.name), rel);
24490
25718
  else if (e.isFile()) out.push(rel);
24491
25719
  }
24492
25720
  };
24493
- walk(dir, "");
25721
+ walk2(dir, "");
24494
25722
  return out.sort();
24495
25723
  };
24496
25724
  try {
24497
25725
  const shipped = list2(src);
24498
25726
  if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
24499
25727
  for (const rel of shipped) {
24500
- const a = await (0, import_promises14.readFile)((0, import_node_path29.join)(src, rel), "utf-8");
24501
- const b = await (0, import_promises14.readFile)((0, import_node_path29.join)(dest, rel), "utf-8");
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");
24502
25730
  if (a !== b) return false;
24503
25731
  }
24504
25732
  return true;
@@ -24527,9 +25755,17 @@ var MOMENT_CHOICES = [
24527
25755
  { id: "pre-push", label: "Before push / PR", hint: "reviews the to-be-pushed commits, blocks on FAIL" }
24528
25756
  ];
24529
25757
  var DEFAULT_MOMENTS = ["stop"];
25758
+ async function momentsFromInstalledHooks() {
25759
+ const status = await checkAllVerityHooks();
25760
+ const wired = [];
25761
+ if (status.stop) wired.push("stop");
25762
+ if (status.guardOn.includes("commit")) wired.push("pre-commit");
25763
+ if (status.guardOn.includes("push")) wired.push("pre-push");
25764
+ return wired.length > 0 ? wired : DEFAULT_MOMENTS;
25765
+ }
24530
25766
  async function askSetupQuestions(defaultsOnly, previous) {
24531
25767
  const intensityDefault = previous?.intensity ?? "balanced";
24532
- const momentsDefault = previous?.moments?.length ? previous.moments : DEFAULT_MOMENTS;
25768
+ const momentsDefault = previous?.moments?.length ? previous.moments : await momentsFromInstalledHooks();
24533
25769
  if (defaultsOnly) {
24534
25770
  return { intensity: intensityDefault, moments: momentsDefault, telemetry: "not-asked" };
24535
25771
  }
@@ -24566,6 +25802,127 @@ function insideClaudeCode() {
24566
25802
  function resumeDeferredPending(previous) {
24567
25803
  return previous?.telemetry === "deferred";
24568
25804
  }
25805
+ async function maybeAdoptRemoteSetup(opts) {
25806
+ if (!opts.adopt) {
25807
+ printInfo(" Skipped (--no-adopt) \u2014 the setup below runs from this codebase.");
25808
+ return false;
25809
+ }
25810
+ const token = await resolveToken(opts.globals.token);
25811
+ const url = await resolveServiceUrl(opts.globals.serviceUrl);
25812
+ if (!token.ok || !url.ok) {
25813
+ printInfo(" Not signed in, so there is nothing to fetch \u2014 the setup below runs from your codebase.");
25814
+ return false;
25815
+ }
25816
+ const found = await fetchRemoteSetup({
25817
+ token: token.data.token,
25818
+ serviceUrl: url.data,
25819
+ verbose: opts.globals.verbose
25820
+ });
25821
+ if (found.status === "unavailable") {
25822
+ printWarn(` Could not ask the service (${found.reason}) \u2014 continuing with the regular setup.`);
25823
+ return false;
25824
+ }
25825
+ if (found.status === "none") {
25826
+ printInfo(" No Standard stored for this repository yet \u2014 this setup will create the first one.");
25827
+ return false;
25828
+ }
25829
+ if (opts.previous?.declinedStandardVersion === found.standard.version) {
25830
+ printInfo(` Standard v${found.standard.version} is available; you declined this version before \u2014 not asking again.`);
25831
+ printInfo(" A newer version will be offered. To take it now: verity standard get, or /verity-setup.");
25832
+ return false;
25833
+ }
25834
+ console.log("");
25835
+ console.log(` This repository already has a Standard on Verity: ${describeRemote(found)}`);
25836
+ console.log(" Using it keeps you consistent with everyone else on the project.");
25837
+ console.log(" Synthesizing a new one from this codebase would push a competing version.");
25838
+ console.log("");
25839
+ const use = opts.defaultsOnly ? true : await promptYes(" Use the existing Standard? [Y/n] ", { nonInteractive: true });
25840
+ if (!use) {
25841
+ printInfo(" Keeping the existing version untouched; /verity-setup will synthesize a new one.");
25842
+ await writeSetupState({ declinedStandardVersion: found.standard.version }).catch(() => {
25843
+ });
25844
+ return false;
25845
+ }
25846
+ try {
25847
+ const outcome = await adoptRemoteSetup(found, {
25848
+ serviceUrl: url.data,
25849
+ projectId: await projectLabel(token.data.token, url.data, opts.globals.verbose)
25850
+ });
25851
+ for (const path of outcome.written) printInfo(` ${path} \u2713`);
25852
+ for (const note of outcome.notes) printWarn(` ${note}`);
25853
+ if (opts.previous?.declinedStandardVersion != null) {
25854
+ await writeSetupState({ declinedStandardVersion: void 0 }).catch(() => {
25855
+ });
25856
+ }
25857
+ return true;
25858
+ } catch (err) {
25859
+ printWarn(` Could not write the fetched configuration: ${err.message}`);
25860
+ printInfo(" Falling back to the regular setup.");
25861
+ return false;
25862
+ }
25863
+ }
25864
+ async function projectLabel(token, serviceUrl, verbose) {
25865
+ try {
25866
+ const who = await whoami(token, serviceUrl, verbose);
25867
+ return who.ok ? who.data.project_id : null;
25868
+ } catch {
25869
+ return null;
25870
+ }
25871
+ }
25872
+ async function synthesizeLocally(opts) {
25873
+ printInfo(" Building a Standard from your codebase\u2026");
25874
+ try {
25875
+ const url = await resolveServiceUrl(opts.globals.serviceUrl);
25876
+ const result = await runSynthesis({
25877
+ intensity: opts.intensity,
25878
+ serviceUrl: url.ok ? url.data : void 0
25879
+ });
25880
+ if ("refused" in result) {
25881
+ printWarn(` ${result.refused}`);
25882
+ return false;
25883
+ }
25884
+ printInfo(` ${describeDetected(result.detected)}`);
25885
+ for (const path of result.written) printInfo(` ${path} \u2713`);
25886
+ for (const note of result.notes) printWarn(` ${note}`);
25887
+ const pushed = await pushStandardAndConfig(opts.globals);
25888
+ for (const line of pushed.lines) printInfo(` ${line}`);
25889
+ if (pushed.standardVersion !== null) {
25890
+ await correctVerityMdVersion({
25891
+ standard: result.standard,
25892
+ version: pushed.standardVersion,
25893
+ tools: result.tools,
25894
+ serviceUrl: url.ok ? url.data : void 0
25895
+ });
25896
+ }
25897
+ return true;
25898
+ } catch (err) {
25899
+ printWarn(` Could not derive a Standard: ${err.message}`);
25900
+ printInfo(" Run /verity-setup in Claude Code to synthesize one instead.");
25901
+ return false;
25902
+ }
25903
+ }
25904
+ async function healStaleAnalysisConfig(globals) {
25905
+ const configPath = projectPath(CODACY_CONFIG_FILE);
25906
+ const standardPath = projectPath(STANDARD_FILE);
25907
+ if (!(0, import_node_fs51.existsSync)(configPath) || !(0, import_node_fs51.existsSync)(standardPath)) return;
25908
+ const validation = validatePatternIds();
25909
+ if (validation.status !== "invalid") return;
25910
+ printWarn(" Your analysis config names pattern ids that no longer resolve \u2014 those tools were");
25911
+ printWarn(" running silently with nothing enabled. Re-deriving it from your Standard\u2026");
25912
+ try {
25913
+ const content = (0, import_yaml6.parse)(await (0, import_promises17.readFile)(standardPath, "utf-8"));
25914
+ const derived = await deriveConfigForStandard(content);
25915
+ for (const path of derived.written) printInfo(` ${path} \u2713 (re-derived)`);
25916
+ for (const note of derived.notes) printWarn(` ${note}`);
25917
+ if (derived.written.length > 0) {
25918
+ const pushed = await pushStandardAndConfig(globals, { standard: false });
25919
+ for (const line of pushed.lines) printInfo(` ${line}`);
25920
+ }
25921
+ } catch (err) {
25922
+ printWarn(` Could not re-derive it: ${err.message}`);
25923
+ printInfo(" Fix it with: verity standard synthesize --config-only");
25924
+ }
25925
+ }
24569
25926
  var PHASE_TWO_ARTIFACTS = [
24570
25927
  {
24571
25928
  path: ".verity/standard.yaml",
@@ -24634,7 +25991,7 @@ async function handoffToSetup(enabled, claudeInstalled) {
24634
25991
  console.log(" Usually a minute or two. Quit any time \u2014 re-running /verity-setup resumes.");
24635
25992
  console.log("");
24636
25993
  const startedAt = Date.now();
24637
- const run2 = (0, import_node_child_process14.spawnSync)("claude", ["/verity-setup"], { stdio: "inherit" });
25994
+ const run2 = (0, import_node_child_process16.spawnSync)("claude", ["/verity-setup"], { stdio: "inherit" });
24638
25995
  if (run2.error) {
24639
25996
  printWarn(`Could not start Claude Code: ${run2.error.message}`);
24640
25997
  return instruct("start it yourself and run the skill there");
@@ -24643,18 +26000,18 @@ async function handoffToSetup(enabled, claudeInstalled) {
24643
26000
  }
24644
26001
  async function installSkills(force, step) {
24645
26002
  step("Installing skills");
24646
- const dataDir = resolveDataDir();
24647
- const skillsSource = (0, import_node_path29.join)(dataDir, "skills");
26003
+ const dataDir = resolveDataDir2();
26004
+ const skillsSource = (0, import_node_path33.join)(dataDir, "skills");
24648
26005
  const skillsDest = ".claude/skills";
24649
26006
  let skillsInstalled = 0;
24650
26007
  for (const skill of SKILLS) {
24651
- const src = (0, import_node_path29.join)(skillsSource, skill);
24652
- const dest = (0, import_node_path29.join)(skillsDest, skill);
24653
- if (!(0, import_node_fs46.existsSync)(src)) {
26008
+ const src = (0, import_node_path33.join)(skillsSource, skill);
26009
+ const dest = (0, import_node_path33.join)(skillsDest, skill);
26010
+ if (!(0, import_node_fs51.existsSync)(src)) {
24654
26011
  printWarn(` Skill data not found: ${skill}`);
24655
26012
  continue;
24656
26013
  }
24657
- if ((0, import_node_fs46.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) {
26014
+ if ((0, import_node_fs51.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) {
24658
26015
  skillsInstalled++;
24659
26016
  continue;
24660
26017
  }
@@ -24713,7 +26070,7 @@ async function checkPrerequisites(step) {
24713
26070
  }
24714
26071
  async function scaffoldProject(step, defaultsOnly) {
24715
26072
  step("Knowledge base, .gitignore and CLAUDE.md");
24716
- await (0, import_promises14.mkdir)(VERITY_DIR, { recursive: true });
26073
+ await (0, import_promises17.mkdir)(VERITY_DIR, { recursive: true });
24717
26074
  await ensureMemoryDir();
24718
26075
  const ignoreResult = ensureVerityGitignore();
24719
26076
  if (ignoreResult === "failed") {
@@ -24752,13 +26109,14 @@ function registerInitCommand(program2) {
24752
26109
  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(
24753
26110
  "--plugin-mode",
24754
26111
  "The Claude Code plugin owns the skills and hooks: install neither, and remove any this project already has"
24755
- ).action(async (opts) => {
26112
+ ).option("--no-adopt", "Don't offer this repository's existing Standard from the service; synthesize a new one").action(async (opts) => {
24756
26113
  const force = opts.force ?? false;
24757
26114
  const wantsHandoff = opts.setup !== false;
26115
+ const wantsAdopt = opts.adopt !== false;
24758
26116
  const defaultsOnly = (opts.yes ?? false) || !interactive();
24759
26117
  const pluginMode = opts.pluginMode ?? pluginActiveHere();
24760
26118
  const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
24761
- const isProject = projectMarkers.some((m) => (0, import_node_fs46.existsSync)(m));
26119
+ const isProject = projectMarkers.some((m) => (0, import_node_fs51.existsSync)(m));
24762
26120
  if (!isProject) {
24763
26121
  printError("No project detected in the current directory.");
24764
26122
  printInfo('Run "verity init" from your project root.');
@@ -24773,7 +26131,7 @@ function registerInitCommand(program2) {
24773
26131
  } else {
24774
26132
  printPhase(1, 2, "this machine", "prerequisites \xB7 skills \xB7 hooks \xB7 sign-in");
24775
26133
  }
24776
- const TOTAL_STEPS = 8;
26134
+ const TOTAL_STEPS = 9;
24777
26135
  let stepNo = 0;
24778
26136
  const step = (label2) => {
24779
26137
  stepNo++;
@@ -24804,8 +26162,8 @@ function registerInitCommand(program2) {
24804
26162
  printInfo(` intensity: ${intensity} \xB7 moments: ${moments.join(", ") || "none"} (no questions asked)`);
24805
26163
  }
24806
26164
  await scaffoldProject(step, defaultsOnly);
24807
- const globalVerityDir = (0, import_node_path29.join)(process.env.HOME ?? "", ".verity");
24808
- await (0, import_promises14.mkdir)(globalVerityDir, { recursive: true });
26165
+ const globalVerityDir = (0, import_node_path33.join)(process.env.HOME ?? "", ".verity");
26166
+ await (0, import_promises17.mkdir)(globalVerityDir, { recursive: true });
24809
26167
  console.log("");
24810
26168
  step("Wiring Claude Code hooks");
24811
26169
  const gitMoments = [
@@ -24857,6 +26215,27 @@ function registerInitCommand(program2) {
24857
26215
  printWarn('Telemetry needs a Verity token \u2014 run "verity login", then "verity telemetry install".');
24858
26216
  }
24859
26217
  }
26218
+ step("Your project's Standard");
26219
+ let haveStandard = false;
26220
+ if ((0, import_node_fs51.existsSync)(projectPath(STANDARD_FILE))) {
26221
+ printInfo(" This project already has .verity/standard.yaml \u2014 keeping it.");
26222
+ haveStandard = true;
26223
+ } else {
26224
+ haveStandard = await maybeAdoptRemoteSetup({
26225
+ globals: program2.opts(),
26226
+ defaultsOnly,
26227
+ previous,
26228
+ adopt: wantsAdopt
26229
+ });
26230
+ }
26231
+ if (!haveStandard) {
26232
+ haveStandard = await synthesizeLocally({
26233
+ globals: program2.opts(),
26234
+ intensity
26235
+ });
26236
+ } else {
26237
+ await healStaleAnalysisConfig(program2.opts());
26238
+ }
24860
26239
  step("Recording your answers");
24861
26240
  try {
24862
26241
  await writeSetupState({
@@ -24865,7 +26244,7 @@ function registerInitCommand(program2) {
24865
26244
  ...telemetryChoice ? { telemetry: telemetryChoice } : {},
24866
26245
  init: {
24867
26246
  completed_at: (/* @__PURE__ */ new Date()).toISOString(),
24868
- cli_version: true ? "0.31.4" : "dev"
26247
+ cli_version: true ? "0.32.0-experimental.68ae2ee" : "dev"
24869
26248
  }
24870
26249
  });
24871
26250
  } catch (err) {
@@ -24882,19 +26261,30 @@ function registerInitCommand(program2) {
24882
26261
  console.log(" .claude/settings.json hooks, reconciled to your chosen moments");
24883
26262
  }
24884
26263
  console.log(" .verity/memory/ knowledge base (commit to git)");
26264
+ console.log(" .verity/standard.yaml the Standard the gate enforces");
26265
+ console.log(" .codacy/codacy.config.json static-analysis patterns (validated)");
26266
+ console.log(" VERITY.md project quality overview");
24885
26267
  console.log(" .verity/setup.json your answers, read by /verity-setup");
24886
26268
  console.log(" .gitignore Verity block (whitelist form)");
24887
26269
  console.log(" CLAUDE.md memory pointer, waive policy, reflection");
24888
26270
  console.log("");
24889
26271
  console.log(` Intensity: ${intensity} Moments: ${moments.join(", ") || "none"}`);
24890
- await handoffToSetup(wantsHandoff, claudeInstalled);
26272
+ console.log("");
26273
+ if (haveStandard) {
26274
+ printInfo("Setup complete \u2014 the gate is live on your next Claude Code session.");
26275
+ printInfo(' Add project-specific rules any time: edit .verity/standard.yaml, then "verity standard push".');
26276
+ printInfo(" Or have a model propose them: /verity-setup --force in Claude Code.");
26277
+ } else {
26278
+ printWarn("No Standard for this project yet \u2014 the gate cannot review until there is one.");
26279
+ await handoffToSetup(wantsHandoff, claudeInstalled);
26280
+ }
24891
26281
  console.log("");
24892
26282
  });
24893
26283
  }
24894
26284
 
24895
26285
  // src/commands/uninstall.ts
24896
- var import_node_fs47 = require("node:fs");
24897
- var import_node_path30 = require("node:path");
26286
+ var import_node_fs52 = require("node:fs");
26287
+ var import_node_path34 = require("node:path");
24898
26288
  var SKILL_NAMES = [
24899
26289
  "verity-setup",
24900
26290
  "verity-analyze",
@@ -24913,11 +26303,11 @@ function registerUninstallCommand(program2) {
24913
26303
  const actions = [];
24914
26304
  const skillsRoot = projectPath(".claude/skills");
24915
26305
  for (const name of SKILL_NAMES) {
24916
- const dir = (0, import_node_path30.join)(skillsRoot, name);
24917
- if ((0, import_node_fs47.existsSync)(dir)) {
26306
+ const dir = (0, import_node_path34.join)(skillsRoot, name);
26307
+ if ((0, import_node_fs52.existsSync)(dir)) {
24918
26308
  actions.push({
24919
26309
  label: `Remove .claude/skills/${name}/`,
24920
- apply: () => (0, import_node_fs47.rmSync)(dir, { recursive: true, force: true })
26310
+ apply: () => (0, import_node_fs52.rmSync)(dir, { recursive: true, force: true })
24921
26311
  });
24922
26312
  }
24923
26313
  }
@@ -24931,24 +26321,24 @@ function registerUninstallCommand(program2) {
24931
26321
  });
24932
26322
  }
24933
26323
  const verityDir = projectPath(VERITY_DIR);
24934
- if ((0, import_node_fs47.existsSync)(verityDir)) {
26324
+ if ((0, import_node_fs52.existsSync)(verityDir)) {
24935
26325
  actions.push({
24936
26326
  label: `Remove ${VERITY_DIR}/`,
24937
- apply: () => (0, import_node_fs47.rmSync)(verityDir, { recursive: true, force: true })
26327
+ apply: () => (0, import_node_fs52.rmSync)(verityDir, { recursive: true, force: true })
24938
26328
  });
24939
26329
  }
24940
26330
  if (!keepVerityMd) {
24941
26331
  const verityMd = projectPath(VERITY_MD_FILE);
24942
- if ((0, import_node_fs47.existsSync)(verityMd)) {
26332
+ if ((0, import_node_fs52.existsSync)(verityMd)) {
24943
26333
  actions.push({
24944
26334
  label: `Remove ${VERITY_MD_FILE}`,
24945
- apply: () => (0, import_node_fs47.rmSync)(verityMd, { force: true })
26335
+ apply: () => (0, import_node_fs52.rmSync)(verityMd, { force: true })
24946
26336
  });
24947
26337
  }
24948
26338
  }
24949
26339
  const cleanupEmptyDir = (path) => {
24950
- if ((0, import_node_fs47.existsSync)(path) && (0, import_node_fs47.statSync)(path).isDirectory() && (0, import_node_fs47.readdirSync)(path).length === 0) {
24951
- (0, import_node_fs47.rmdirSync)(path);
26340
+ if ((0, import_node_fs52.existsSync)(path) && (0, import_node_fs52.statSync)(path).isDirectory() && (0, import_node_fs52.readdirSync)(path).length === 0) {
26341
+ (0, import_node_fs52.rmdirSync)(path);
24952
26342
  }
24953
26343
  };
24954
26344
  actions.push({
@@ -24959,11 +26349,11 @@ function registerUninstallCommand(program2) {
24959
26349
  }
24960
26350
  });
24961
26351
  const home = process.env.HOME ?? "";
24962
- const globalVerityDir = (0, import_node_path30.join)(home, ".verity");
24963
- if (purgeGlobal && (0, import_node_fs47.existsSync)(globalVerityDir)) {
26352
+ const globalVerityDir = (0, import_node_path34.join)(home, ".verity");
26353
+ if (purgeGlobal && (0, import_node_fs52.existsSync)(globalVerityDir)) {
24964
26354
  actions.push({
24965
26355
  label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
24966
- apply: () => (0, import_node_fs47.rmSync)(globalVerityDir, { recursive: true, force: true })
26356
+ apply: () => (0, import_node_fs52.rmSync)(globalVerityDir, { recursive: true, force: true })
24967
26357
  });
24968
26358
  }
24969
26359
  if (actions.length === 0) {
@@ -25157,8 +26547,8 @@ function registerTaskCommands(program2) {
25157
26547
  }
25158
26548
 
25159
26549
  // src/commands/reset.ts
25160
- var import_node_fs48 = require("node:fs");
25161
- var import_node_path31 = require("node:path");
26550
+ var import_node_fs53 = require("node:fs");
26551
+ var import_node_path35 = require("node:path");
25162
26552
  function registerResetCommand(program2) {
25163
26553
  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) => {
25164
26554
  const globals = program2.opts();
@@ -25195,11 +26585,11 @@ function registerResetCommand(program2) {
25195
26585
  }
25196
26586
  const cacheDir = projectPath(CACHE_DIR);
25197
26587
  let purged = 0;
25198
- if ((0, import_node_fs48.existsSync)(cacheDir)) {
25199
- for (const entry of (0, import_node_fs48.readdirSync)(cacheDir)) {
26588
+ if ((0, import_node_fs53.existsSync)(cacheDir)) {
26589
+ for (const entry of (0, import_node_fs53.readdirSync)(cacheDir)) {
25200
26590
  if (entry.startsWith("pending-")) {
25201
26591
  try {
25202
- (0, import_node_fs48.unlinkSync)((0, import_node_path31.join)(cacheDir, entry));
26592
+ (0, import_node_fs53.unlinkSync)((0, import_node_path35.join)(cacheDir, entry));
25203
26593
  purged++;
25204
26594
  } catch {
25205
26595
  }
@@ -25214,19 +26604,19 @@ function registerResetCommand(program2) {
25214
26604
  projectPath(`${VERITY_DIR}/.last-analysis`)
25215
26605
  ];
25216
26606
  for (const file of filesToClear) {
25217
- if ((0, import_node_fs48.existsSync)(file)) {
26607
+ if ((0, import_node_fs53.existsSync)(file)) {
25218
26608
  try {
25219
- (0, import_node_fs48.writeFileSync)(file, "");
26609
+ (0, import_node_fs53.writeFileSync)(file, "");
25220
26610
  } catch {
25221
26611
  }
25222
26612
  }
25223
26613
  }
25224
26614
  if (opts.all) {
25225
26615
  const logsDir = projectPath(`${VERITY_DIR}/.logs`);
25226
- if ((0, import_node_fs48.existsSync)(logsDir)) {
25227
- for (const entry of (0, import_node_fs48.readdirSync)(logsDir)) {
26616
+ if ((0, import_node_fs53.existsSync)(logsDir)) {
26617
+ for (const entry of (0, import_node_fs53.readdirSync)(logsDir)) {
25228
26618
  try {
25229
- (0, import_node_fs48.unlinkSync)((0, import_node_path31.join)(logsDir, entry));
26619
+ (0, import_node_fs53.unlinkSync)((0, import_node_path35.join)(logsDir, entry));
25230
26620
  } catch {
25231
26621
  }
25232
26622
  }
@@ -25534,8 +26924,8 @@ function registerTelemetryCommands(program2) {
25534
26924
  }
25535
26925
 
25536
26926
  // src/cli.ts
25537
- program.name("verity").description("CLI for Verity quality gate service").version("0.31.4").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) => {
25538
- installStderrLog(actionCommand.name(), process.argv.slice(2), "0.31.4");
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");
25539
26929
  setUserNamedServiceUrl(program.opts().serviceUrl);
25540
26930
  try {
25541
26931
  await foldLegacyLocalCredential();