@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/CHANGELOG.md +136 -0
- package/README.md +50 -5
- package/bin/verity.js +1746 -356
- package/data/skills/verity-setup/SKILL.md +24 -1
- package/data/skills/verity-setup/patterns-reference.yaml +79 -54
- package/package.json +1 -1
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(
|
|
679
|
-
this.conflictsWith = this.conflictsWith.concat(
|
|
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(
|
|
1253
|
-
|
|
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
|
|
10959
|
-
if (REVIEWABLE_FILENAMES.has(
|
|
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
|
|
16769
|
+
var import_node_path20 = require("node:path");
|
|
16763
16770
|
var import_yaml = __toESM(require_dist());
|
|
16764
16771
|
|
|
16765
|
-
// src/lib/
|
|
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
|
|
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,
|
|
17709
|
+
if (!(0, import_node_fs26.existsSync)(file)) return EMPTY;
|
|
16860
17710
|
try {
|
|
16861
|
-
return parseVerityIgnore((0,
|
|
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 &&
|
|
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,
|
|
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,
|
|
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
|
-
|
|
16930
|
-
|
|
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
|
|
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,
|
|
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
|
|
18163
|
+
var import_node_fs30 = require("node:fs");
|
|
17192
18164
|
|
|
17193
18165
|
// src/lib/debounce.ts
|
|
17194
|
-
var
|
|
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,
|
|
18174
|
+
if (!(0, import_node_fs29.existsSync)(file)) return null;
|
|
17203
18175
|
try {
|
|
17204
|
-
const lastTs = parseInt((0,
|
|
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,
|
|
18189
|
+
if (!(0, import_node_fs29.existsSync)(file)) return null;
|
|
17218
18190
|
let debounceTime;
|
|
17219
18191
|
try {
|
|
17220
|
-
debounceTime = (0,
|
|
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,
|
|
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,
|
|
17245
|
-
hash.update((0,
|
|
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,
|
|
18227
|
+
if ((0, import_node_fs29.existsSync)(file)) {
|
|
17256
18228
|
try {
|
|
17257
|
-
const storedHash = (0,
|
|
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,
|
|
17268
|
-
(0,
|
|
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,
|
|
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,
|
|
18247
|
+
if (!(0, import_node_fs29.existsSync)(file)) return files;
|
|
17276
18248
|
let debounceTime;
|
|
17277
18249
|
try {
|
|
17278
|
-
debounceTime = (0,
|
|
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,
|
|
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,
|
|
18269
|
+
if (!(0, import_node_fs29.existsSync)(ITERATION_FILE)) return NO_BLOCKS;
|
|
17298
18270
|
try {
|
|
17299
|
-
const stored = (0,
|
|
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,
|
|
17346
|
-
(0,
|
|
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,
|
|
18423
|
+
if (!(0, import_node_fs30.existsSync)(file)) return null;
|
|
17452
18424
|
try {
|
|
17453
|
-
const o = JSON.parse((0,
|
|
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,
|
|
17478
|
-
(0,
|
|
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
|
|
18825
|
+
var import_node_fs43 = require("node:fs");
|
|
17854
18826
|
|
|
17855
18827
|
// src/lib/repo-context.ts
|
|
17856
|
-
var
|
|
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,
|
|
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
|
|
18674
|
-
var
|
|
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
|
|
18677
|
-
var
|
|
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,
|
|
18731
|
-
dir = (0,
|
|
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,
|
|
18750
|
-
dir = (0,
|
|
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,
|
|
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
|
|
19785
|
+
return import_node_fs31.realpathSync.native(p);
|
|
18814
19786
|
} catch {
|
|
18815
|
-
return (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
18882
|
-
if (mergeHead && (0,
|
|
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
|
|
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,
|
|
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,
|
|
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.
|
|
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
|
|
19581
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
19899
|
-
var
|
|
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,
|
|
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,
|
|
19938
|
-
const bytesRead = (0,
|
|
19939
|
-
(0,
|
|
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,
|
|
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,
|
|
20942
|
+
const entries = (0, import_node_fs34.readdirSync)(dir, { withFileTypes: true });
|
|
19971
20943
|
for (const entry of entries) {
|
|
19972
|
-
const fullPath = (0,
|
|
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,
|
|
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,
|
|
20961
|
+
if (!(0, import_node_fs34.existsSync)(plansDir)) continue;
|
|
19990
20962
|
try {
|
|
19991
|
-
for (const f of (0,
|
|
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,
|
|
20966
|
+
const fullPath = (0, import_node_path23.join)(plansDir, f);
|
|
19995
20967
|
try {
|
|
19996
|
-
const stat3 = (0,
|
|
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,
|
|
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,
|
|
20996
|
+
if (!(0, import_node_fs34.existsSync)(path)) continue;
|
|
20025
20997
|
try {
|
|
20026
|
-
const stat3 = (0,
|
|
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,
|
|
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
|
|
20206
|
-
var
|
|
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 =
|
|
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,
|
|
20432
|
-
ingest((0,
|
|
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,
|
|
20439
|
-
(0,
|
|
20440
|
-
(0,
|
|
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,
|
|
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
|
|
21419
|
+
const walk2 = (d, depth) => {
|
|
20448
21420
|
if (depth > 4) return;
|
|
20449
|
-
for (const e of (0,
|
|
20450
|
-
const p = (0,
|
|
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
|
-
|
|
21424
|
+
walk2(p, depth + 1);
|
|
20453
21425
|
} else if (e.name.startsWith("agent-") && e.name.endsWith(".jsonl")) {
|
|
20454
21426
|
try {
|
|
20455
|
-
const st = (0,
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
|
20825
|
-
var
|
|
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,
|
|
21803
|
+
for (const entry of (0, import_node_fs36.readdirSync)(dir)) {
|
|
20832
21804
|
if (!entry.startsWith("pending-")) continue;
|
|
20833
|
-
const path = (0,
|
|
21805
|
+
const path = (0, import_node_path25.join)(dir, entry);
|
|
20834
21806
|
try {
|
|
20835
|
-
const stat3 = (0,
|
|
21807
|
+
const stat3 = (0, import_node_fs36.statSync)(path);
|
|
20836
21808
|
if (stat3.mtimeMs < cutoff) {
|
|
20837
|
-
(0,
|
|
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
|
|
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,
|
|
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) => !
|
|
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 &&
|
|
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
|
|
21000
|
-
var
|
|
21001
|
-
var
|
|
21002
|
-
var
|
|
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,
|
|
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,
|
|
21246
|
-
standardDoc = (0,
|
|
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,
|
|
22224
|
+
if ((0, import_node_fs38.existsSync)("README.md")) {
|
|
21253
22225
|
try {
|
|
21254
|
-
readmeContent = await (0,
|
|
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,
|
|
22232
|
+
if ((0, import_node_fs38.existsSync)(p)) {
|
|
21261
22233
|
try {
|
|
21262
|
-
claudeMdContent = await (0,
|
|
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,
|
|
21284
|
-
if ((0,
|
|
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,
|
|
21327
|
-
await (0,
|
|
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
|
|
21340
|
-
var
|
|
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,
|
|
21351
|
-
const hasStandard = (0,
|
|
21352
|
-
const alreadyTried = (0,
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
22556
|
+
if (!(0, import_node_fs40.existsSync)(file)) return null;
|
|
21585
22557
|
try {
|
|
21586
|
-
const o = JSON.parse((0,
|
|
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,
|
|
21601
|
-
(0,
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
22045
|
-
var
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
23837
|
+
if (!(0, import_node_fs44.existsSync)(p)) continue;
|
|
22866
23838
|
try {
|
|
22867
|
-
const { readFileSync:
|
|
22868
|
-
const content =
|
|
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
|
|
22926
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
23965
|
+
(0, import_node_fs45.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
22994
23966
|
const map = readIterMap();
|
|
22995
23967
|
map[moment] = count;
|
|
22996
|
-
(0,
|
|
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,
|
|
23978
|
+
if ((0, import_node_fs45.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs45.unlinkSync)(GUARD_ITER_FILE);
|
|
23007
23979
|
} else {
|
|
23008
|
-
(0,
|
|
23009
|
-
(0,
|
|
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,
|
|
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) ||
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
23496
|
-
var
|
|
23497
|
-
var
|
|
23498
|
-
var
|
|
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
|
|
24549
|
+
var import_node_fs48 = require("node:fs");
|
|
23577
24550
|
|
|
23578
24551
|
// src/lib/prereqs.ts
|
|
23579
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
24665
|
+
var import_promises15 = require("node:fs/promises");
|
|
23693
24666
|
|
|
23694
24667
|
// src/lib/gitignore.ts
|
|
23695
|
-
var
|
|
23696
|
-
var
|
|
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
|
|
24683
|
+
function isIgnored3(path) {
|
|
23711
24684
|
try {
|
|
23712
|
-
(0,
|
|
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 =
|
|
23720
|
-
const standard =
|
|
23721
|
-
const node =
|
|
23722
|
-
const futureState =
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
23900
|
-
analysisConfig:
|
|
23901
|
-
verityMd: (0,
|
|
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
|
-
|
|
23909
|
-
|
|
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
|
-
|
|
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
|
|
23975
|
-
var
|
|
23976
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
24013
|
-
const verityDir = (0,
|
|
24014
|
-
if ((0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
24068
|
-
const verityCreds = (0,
|
|
24069
|
-
if (!(0,
|
|
24070
|
-
if (!(0,
|
|
24071
|
-
(0,
|
|
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,
|
|
24094
|
-
const hadLegacyBlock = (0,
|
|
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,
|
|
24105
|
-
const verityMd = (0,
|
|
24106
|
-
if (!(0,
|
|
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,
|
|
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,
|
|
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,
|
|
24123
|
-
if (!(0,
|
|
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,
|
|
25145
|
+
(0, import_node_fs49.writeFileSync)(verityCreds, verityContent + sep2 + toAppend.join("\n") + "\n");
|
|
24172
25146
|
}
|
|
24173
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
25167
|
+
(0, import_node_fs49.renameSync)(from, to);
|
|
24194
25168
|
} catch (err) {
|
|
24195
25169
|
if (err.code !== "EXDEV") throw err;
|
|
24196
|
-
(0,
|
|
24197
|
-
(0,
|
|
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,
|
|
25176
|
+
(0, import_node_fs49.renameSync)(from, to);
|
|
24203
25177
|
} catch (err) {
|
|
24204
25178
|
if (err.code !== "EXDEV") throw err;
|
|
24205
|
-
(0,
|
|
24206
|
-
(0,
|
|
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
|
|
24212
|
-
const srcDir = (0,
|
|
24213
|
-
for (const entry of (0,
|
|
24214
|
-
const rel = relDir ? (0,
|
|
24215
|
-
const src = (0,
|
|
24216
|
-
const dest = (0,
|
|
24217
|
-
if ((0,
|
|
24218
|
-
|
|
24219
|
-
} else if (!(0,
|
|
24220
|
-
(0,
|
|
24221
|
-
(0,
|
|
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
|
-
|
|
25200
|
+
walk2("");
|
|
24227
25201
|
return copied;
|
|
24228
25202
|
}
|
|
24229
25203
|
async function needsMigration(root = repoRoot()) {
|
|
24230
|
-
const gateDir = (0,
|
|
24231
|
-
const verityDir = (0,
|
|
24232
|
-
if ((0,
|
|
24233
|
-
if ((0,
|
|
24234
|
-
if ((0,
|
|
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,
|
|
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,
|
|
24242
|
-
if ((0,
|
|
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,
|
|
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
|
|
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 =
|
|
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,
|
|
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
|
|
25689
|
+
function resolveDataDir2() {
|
|
24462
25690
|
const candidates = [
|
|
24463
|
-
(0,
|
|
25691
|
+
(0, import_node_path33.join)(__dirname, "..", "data"),
|
|
24464
25692
|
// installed: node_modules/@codacy/verity-cli/data
|
|
24465
|
-
(0,
|
|
25693
|
+
(0, import_node_path33.join)(__dirname, "..", "..", "data"),
|
|
24466
25694
|
// edge case: nested resolution
|
|
24467
|
-
(0,
|
|
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,
|
|
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,
|
|
24481
|
-
await (0,
|
|
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
|
|
24487
|
-
for (const e of (0,
|
|
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())
|
|
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
|
-
|
|
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,
|
|
24501
|
-
const b = await (0,
|
|
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 :
|
|
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,
|
|
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 =
|
|
24647
|
-
const skillsSource = (0,
|
|
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,
|
|
24652
|
-
const dest = (0,
|
|
24653
|
-
if (!(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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 =
|
|
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,
|
|
24808
|
-
await (0,
|
|
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.
|
|
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
|
-
|
|
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
|
|
24897
|
-
var
|
|
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,
|
|
24917
|
-
if ((0,
|
|
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,
|
|
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,
|
|
26324
|
+
if ((0, import_node_fs52.existsSync)(verityDir)) {
|
|
24935
26325
|
actions.push({
|
|
24936
26326
|
label: `Remove ${VERITY_DIR}/`,
|
|
24937
|
-
apply: () => (0,
|
|
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,
|
|
26332
|
+
if ((0, import_node_fs52.existsSync)(verityMd)) {
|
|
24943
26333
|
actions.push({
|
|
24944
26334
|
label: `Remove ${VERITY_MD_FILE}`,
|
|
24945
|
-
apply: () => (0,
|
|
26335
|
+
apply: () => (0, import_node_fs52.rmSync)(verityMd, { force: true })
|
|
24946
26336
|
});
|
|
24947
26337
|
}
|
|
24948
26338
|
}
|
|
24949
26339
|
const cleanupEmptyDir = (path) => {
|
|
24950
|
-
if ((0,
|
|
24951
|
-
(0,
|
|
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,
|
|
24963
|
-
if (purgeGlobal && (0,
|
|
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,
|
|
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
|
|
25161
|
-
var
|
|
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,
|
|
25199
|
-
for (const entry of (0,
|
|
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,
|
|
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,
|
|
26607
|
+
if ((0, import_node_fs53.existsSync)(file)) {
|
|
25218
26608
|
try {
|
|
25219
|
-
(0,
|
|
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,
|
|
25227
|
-
for (const entry of (0,
|
|
26616
|
+
if ((0, import_node_fs53.existsSync)(logsDir)) {
|
|
26617
|
+
for (const entry of (0, import_node_fs53.readdirSync)(logsDir)) {
|
|
25228
26618
|
try {
|
|
25229
|
-
(0,
|
|
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.
|
|
25538
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.
|
|
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();
|