@codacy/verity-cli 0.32.6-experimental.8f2b5f7 → 0.32.6-experimental.df0a578
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/verity.js +933 -546
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -13846,14 +13846,206 @@ async function appendEntry(taskId, entry) {
|
|
|
13846
13846
|
}
|
|
13847
13847
|
|
|
13848
13848
|
// src/lib/memory-retrieval.ts
|
|
13849
|
-
var
|
|
13849
|
+
var import_promises8 = require("node:fs/promises");
|
|
13850
|
+
var import_node_fs11 = require("node:fs");
|
|
13851
|
+
var import_node_path11 = require("node:path");
|
|
13852
|
+
|
|
13853
|
+
// src/lib/org-mirror.ts
|
|
13850
13854
|
var import_node_fs10 = require("node:fs");
|
|
13855
|
+
var import_promises7 = require("node:fs/promises");
|
|
13851
13856
|
var import_node_path10 = require("node:path");
|
|
13857
|
+
var ORG_KINDS = ["decision", "security", "gotcha", "pattern", "domain", "integration"];
|
|
13858
|
+
var STATE_FILE = ".org-pull-state.json";
|
|
13859
|
+
var BODY_MAX = 8192;
|
|
13860
|
+
function orgMirrorDir(remote = requestRemote()) {
|
|
13861
|
+
const parsed = parseRemote(remote);
|
|
13862
|
+
if (!parsed) return null;
|
|
13863
|
+
return (0, import_node_path10.join)(verityHome(), "orgs", parsed.host, parsed.owner.toLowerCase(), "memory");
|
|
13864
|
+
}
|
|
13865
|
+
function slugify(s) {
|
|
13866
|
+
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
13867
|
+
}
|
|
13868
|
+
function orgNodePath(node) {
|
|
13869
|
+
const kind = ORG_KINDS.includes(node.kind) ? node.kind : "domain";
|
|
13870
|
+
return `${kind}/${slugify(node.title) || "claim"}-${node.tag_id.replace(/-/g, "").slice(0, 8)}.md`;
|
|
13871
|
+
}
|
|
13872
|
+
function renderOrgNode(node, orgName) {
|
|
13873
|
+
const fm = [
|
|
13874
|
+
"---",
|
|
13875
|
+
`id: ${JSON.stringify(node.tag_id)}`,
|
|
13876
|
+
`node_id: ${JSON.stringify(node.node_id)}`,
|
|
13877
|
+
'scope: "org"',
|
|
13878
|
+
`org: ${JSON.stringify(orgName)}`,
|
|
13879
|
+
`kind: ${JSON.stringify(node.kind)}`,
|
|
13880
|
+
`title: ${JSON.stringify(node.title)}`,
|
|
13881
|
+
`origin: ${JSON.stringify(node.origin)}`,
|
|
13882
|
+
`signal: ${JSON.stringify(node.signal)}`,
|
|
13883
|
+
`tier: ${node.tier === null ? "null" : JSON.stringify(node.tier)}`,
|
|
13884
|
+
`applies_to: ${JSON.stringify(node.applies_to)}`,
|
|
13885
|
+
`source_repo_count: ${JSON.stringify(node.source_repo_count)}`,
|
|
13886
|
+
`promoted_at: ${JSON.stringify(node.promoted_at)}`,
|
|
13887
|
+
'status: "active"',
|
|
13888
|
+
"---"
|
|
13889
|
+
];
|
|
13890
|
+
return `${fm.join("\n")}
|
|
13891
|
+
|
|
13892
|
+
# ${node.title}
|
|
13893
|
+
|
|
13894
|
+
${node.body.trim()}
|
|
13895
|
+
`;
|
|
13896
|
+
}
|
|
13897
|
+
function parseOrgNode(content) {
|
|
13898
|
+
const m = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
13899
|
+
if (!m) return null;
|
|
13900
|
+
const fm = {};
|
|
13901
|
+
for (const line of m[1].split("\n")) {
|
|
13902
|
+
const kv = line.match(/^([a-z_]+):\s*(.*)$/);
|
|
13903
|
+
if (!kv) continue;
|
|
13904
|
+
try {
|
|
13905
|
+
fm[kv[1]] = JSON.parse(kv[2]);
|
|
13906
|
+
} catch {
|
|
13907
|
+
fm[kv[1]] = kv[2];
|
|
13908
|
+
}
|
|
13909
|
+
}
|
|
13910
|
+
if (fm.scope !== "org" || typeof fm.id !== "string" || typeof fm.title !== "string") return null;
|
|
13911
|
+
if (fm.status && fm.status !== "active") return null;
|
|
13912
|
+
const body = m[2].replace(/^\s*#[^\n]*\n/, "").trim();
|
|
13913
|
+
return {
|
|
13914
|
+
tag_id: fm.id,
|
|
13915
|
+
node_id: typeof fm.node_id === "string" ? fm.node_id : "",
|
|
13916
|
+
kind: typeof fm.kind === "string" ? fm.kind : "domain",
|
|
13917
|
+
title: fm.title,
|
|
13918
|
+
body,
|
|
13919
|
+
origin: typeof fm.origin === "string" ? fm.origin : "",
|
|
13920
|
+
signal: typeof fm.signal === "string" ? fm.signal : "",
|
|
13921
|
+
tier: typeof fm.tier === "number" ? fm.tier : null,
|
|
13922
|
+
applies_to: Array.isArray(fm.applies_to) ? fm.applies_to.filter((v) => typeof v === "string") : [],
|
|
13923
|
+
source_repo_count: typeof fm.source_repo_count === "number" ? fm.source_repo_count : 1,
|
|
13924
|
+
promoted_at: typeof fm.promoted_at === "string" ? fm.promoted_at : ""
|
|
13925
|
+
};
|
|
13926
|
+
}
|
|
13927
|
+
async function readState(dir) {
|
|
13928
|
+
try {
|
|
13929
|
+
const parsed = JSON.parse(await (0, import_promises7.readFile)((0, import_node_path10.join)(dir, STATE_FILE), "utf-8"));
|
|
13930
|
+
return {
|
|
13931
|
+
version: typeof parsed?.version === "string" ? parsed.version : null,
|
|
13932
|
+
organization: parsed?.organization && typeof parsed.organization.id === "string" ? parsed.organization : null,
|
|
13933
|
+
files: Array.isArray(parsed?.files) ? parsed.files.filter((f) => typeof f === "string") : []
|
|
13934
|
+
};
|
|
13935
|
+
} catch {
|
|
13936
|
+
return { version: null, organization: null, files: [] };
|
|
13937
|
+
}
|
|
13938
|
+
}
|
|
13939
|
+
async function writeState(dir, state) {
|
|
13940
|
+
await (0, import_promises7.mkdir)(dir, { recursive: true });
|
|
13941
|
+
await (0, import_promises7.writeFile)((0, import_node_path10.join)(dir, STATE_FILE), JSON.stringify({
|
|
13942
|
+
...state.version ? { version: state.version } : {},
|
|
13943
|
+
organization: state.organization,
|
|
13944
|
+
pulled_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13945
|
+
files: state.files
|
|
13946
|
+
}, null, 2) + "\n");
|
|
13947
|
+
}
|
|
13948
|
+
function renderIndex(orgName, nodes) {
|
|
13949
|
+
const lines = [
|
|
13950
|
+
`# Org Knowledge \u2014 ${orgName}`,
|
|
13951
|
+
"",
|
|
13952
|
+
"*Auto-generated by verity CLI from what this organization's repositories learned. Do not hand-edit; `verity memory pull` overwrites it.*",
|
|
13953
|
+
"",
|
|
13954
|
+
'> These claims hold across the organization\'s repositories, not only this one. Each names where it came from. A claim that is wrong for this repository is demoted with `verity memory demote <id> --reason "\u2026"`, for everyone.',
|
|
13955
|
+
""
|
|
13956
|
+
];
|
|
13957
|
+
const byKind = /* @__PURE__ */ new Map();
|
|
13958
|
+
for (const n of nodes) byKind.set(n.kind, [...byKind.get(n.kind) ?? [], n]);
|
|
13959
|
+
for (const kind of ORG_KINDS) {
|
|
13960
|
+
const list2 = byKind.get(kind);
|
|
13961
|
+
if (!list2?.length) continue;
|
|
13962
|
+
lines.push(`## ${kind}/ (${list2.length})`);
|
|
13963
|
+
for (const n of list2) lines.push(`- [[${orgNodePath(n).split("/")[1].replace(/\.md$/, "")}]] \u2014 ${n.title} \xB7 ${n.origin}`);
|
|
13964
|
+
lines.push("");
|
|
13965
|
+
}
|
|
13966
|
+
if (nodes.length === 0) lines.push("No org knowledge yet.", "");
|
|
13967
|
+
return lines.join("\n");
|
|
13968
|
+
}
|
|
13969
|
+
async function pullOrgKnowledge(opts) {
|
|
13970
|
+
const dir = orgMirrorDir(opts.remote ?? requestRemote());
|
|
13971
|
+
if (!dir) return { ok: true, status: "no_remote", received: 0, dir: null };
|
|
13972
|
+
const state = await readState(dir);
|
|
13973
|
+
const params = new URLSearchParams({ for: "agent" });
|
|
13974
|
+
if (!opts.force && state.version) params.set("if_version", state.version);
|
|
13975
|
+
const res = await apiRequest({
|
|
13976
|
+
method: "GET",
|
|
13977
|
+
path: `/memory/org?${params.toString()}`,
|
|
13978
|
+
serviceUrl: opts.serviceUrl,
|
|
13979
|
+
token: opts.token,
|
|
13980
|
+
verbose: opts.verbose,
|
|
13981
|
+
timeout: opts.timeoutMs ?? 3e4,
|
|
13982
|
+
cmd: "memory-org-pull"
|
|
13983
|
+
});
|
|
13984
|
+
if (!res.ok) return { ok: false, error: res.error, category: res.category };
|
|
13985
|
+
const page = res.data;
|
|
13986
|
+
if (page.unchanged) return { ok: true, status: "unchanged", received: 0, dir };
|
|
13987
|
+
const org = page.organization;
|
|
13988
|
+
const nodes = org ? (page.nodes ?? []).flatMap((n) => typeof n.tag_id === "string" && typeof n.title === "string" && typeof n.body === "string" ? [{
|
|
13989
|
+
tag_id: n.tag_id,
|
|
13990
|
+
node_id: typeof n.node_id === "string" ? n.node_id : "",
|
|
13991
|
+
kind: typeof n.kind === "string" ? n.kind : "domain",
|
|
13992
|
+
title: n.title,
|
|
13993
|
+
body: n.body.slice(0, BODY_MAX),
|
|
13994
|
+
origin: typeof n.origin === "string" ? n.origin : "",
|
|
13995
|
+
signal: typeof n.signal === "string" ? n.signal : "",
|
|
13996
|
+
tier: typeof n.tier === "number" ? n.tier : null,
|
|
13997
|
+
applies_to: Array.isArray(n.applies_to) ? n.applies_to.filter((v) => typeof v === "string") : [],
|
|
13998
|
+
source_repo_count: typeof n.source_repo_count === "number" ? n.source_repo_count : 1,
|
|
13999
|
+
promoted_at: typeof n.promoted_at === "string" ? n.promoted_at : ""
|
|
14000
|
+
}] : []) : [];
|
|
14001
|
+
const written = /* @__PURE__ */ new Set();
|
|
14002
|
+
await (0, import_promises7.mkdir)(dir, { recursive: true });
|
|
14003
|
+
for (const n of nodes) {
|
|
14004
|
+
const rel = orgNodePath(n);
|
|
14005
|
+
if (written.has(rel)) continue;
|
|
14006
|
+
await (0, import_promises7.mkdir)((0, import_node_path10.join)(dir, rel.split("/")[0]), { recursive: true });
|
|
14007
|
+
await (0, import_promises7.writeFile)((0, import_node_path10.join)(dir, rel), renderOrgNode(n, org?.name ?? ""));
|
|
14008
|
+
written.add(rel);
|
|
14009
|
+
}
|
|
14010
|
+
for (const rel of state.files) {
|
|
14011
|
+
if (!written.has(rel)) await (0, import_promises7.rm)((0, import_node_path10.join)(dir, rel), { force: true });
|
|
14012
|
+
}
|
|
14013
|
+
await (0, import_promises7.writeFile)((0, import_node_path10.join)(dir, "index.md"), renderIndex(org?.name ?? "no organization", nodes));
|
|
14014
|
+
await writeState(dir, { version: org ? page.version : null, organization: org, files: [...written].sort() });
|
|
14015
|
+
return { ok: true, status: org ? "pulled" : "none", received: nodes.length, dir };
|
|
14016
|
+
}
|
|
14017
|
+
async function readOrgMirror(remote = requestRemote()) {
|
|
14018
|
+
const dir = orgMirrorDir(remote);
|
|
14019
|
+
if (!dir || !(0, import_node_fs10.existsSync)(dir)) return [];
|
|
14020
|
+
const out = [];
|
|
14021
|
+
for (const kind of ORG_KINDS) {
|
|
14022
|
+
const kindDir = (0, import_node_path10.join)(dir, kind);
|
|
14023
|
+
if (!(0, import_node_fs10.existsSync)(kindDir)) continue;
|
|
14024
|
+
let files;
|
|
14025
|
+
try {
|
|
14026
|
+
files = await (0, import_promises7.readdir)(kindDir);
|
|
14027
|
+
} catch {
|
|
14028
|
+
continue;
|
|
14029
|
+
}
|
|
14030
|
+
for (const file of files) {
|
|
14031
|
+
if (!file.endsWith(".md")) continue;
|
|
14032
|
+
try {
|
|
14033
|
+
const node = parseOrgNode(await (0, import_promises7.readFile)((0, import_node_path10.join)(kindDir, file), "utf-8"));
|
|
14034
|
+
if (node) out.push(node);
|
|
14035
|
+
} catch {
|
|
14036
|
+
}
|
|
14037
|
+
}
|
|
14038
|
+
}
|
|
14039
|
+
return out;
|
|
14040
|
+
}
|
|
14041
|
+
|
|
14042
|
+
// src/lib/memory-retrieval.ts
|
|
13852
14043
|
var memoryDir = () => projectPath(`${VERITY_DIR}/memory`);
|
|
13853
14044
|
var DOMAINS = ["decisions", "quality", "security", "intent", "gotchas", "patterns", "domain", "integrations"];
|
|
13854
14045
|
var DEFAULT_BUDGET_TOKENS = 2e3;
|
|
13855
14046
|
var MAX_BUDGET_TOKENS = 4e3;
|
|
13856
14047
|
var MIN_SCORE = 0.5;
|
|
14048
|
+
var ORG_MIN_SHARED_TERMS = 2;
|
|
13857
14049
|
function tokenize(text) {
|
|
13858
14050
|
return new Set(
|
|
13859
14051
|
text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2)
|
|
@@ -13866,6 +14058,26 @@ function jaccardKeywords(a, b) {
|
|
|
13866
14058
|
const union = a.size + b.size - inter;
|
|
13867
14059
|
return union === 0 ? 0 : inter / union;
|
|
13868
14060
|
}
|
|
14061
|
+
function sharedTerms(a, b) {
|
|
14062
|
+
let n = 0;
|
|
14063
|
+
for (const w of a) if (b.has(w)) n++;
|
|
14064
|
+
return n;
|
|
14065
|
+
}
|
|
14066
|
+
function orgNodeToLocal(n) {
|
|
14067
|
+
return {
|
|
14068
|
+
path: `org:${n.tag_id}`,
|
|
14069
|
+
nodeId: n.tag_id,
|
|
14070
|
+
kind: n.kind,
|
|
14071
|
+
title: n.title,
|
|
14072
|
+
body: n.body.slice(0, 2e3),
|
|
14073
|
+
fileGlobs: [],
|
|
14074
|
+
confidence: 0.5,
|
|
14075
|
+
citedCount: 0,
|
|
14076
|
+
tokenEstimate: Math.ceil((n.title.length + n.body.length) / 4) + 20,
|
|
14077
|
+
scope: "org",
|
|
14078
|
+
origin: n.origin
|
|
14079
|
+
};
|
|
14080
|
+
}
|
|
13869
14081
|
function globMatch(glob, filePath) {
|
|
13870
14082
|
if (glob === filePath) return true;
|
|
13871
14083
|
const suffixMatch = glob.match(/^\*\*\/\*(.+)$/);
|
|
@@ -13941,19 +14153,19 @@ function parseFrontmatter(content) {
|
|
|
13941
14153
|
return { fm, body: match[2].trim() };
|
|
13942
14154
|
}
|
|
13943
14155
|
async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = DEFAULT_BUDGET_TOKENS) {
|
|
13944
|
-
|
|
14156
|
+
const hasRepoGraph = (0, import_node_fs11.existsSync)(memoryDir());
|
|
13945
14157
|
const budget = Math.min(budgetTokens, MAX_BUDGET_TOKENS);
|
|
13946
14158
|
const promptTokens = tokenize(promptText);
|
|
13947
14159
|
const nodes = [];
|
|
13948
|
-
for (const domain of DOMAINS) {
|
|
13949
|
-
const domainDir = (0,
|
|
13950
|
-
if (!(0,
|
|
14160
|
+
for (const domain of hasRepoGraph ? DOMAINS : []) {
|
|
14161
|
+
const domainDir = (0, import_node_path11.join)(memoryDir(), domain);
|
|
14162
|
+
if (!(0, import_node_fs11.existsSync)(domainDir)) continue;
|
|
13951
14163
|
try {
|
|
13952
|
-
const files = await (0,
|
|
14164
|
+
const files = await (0, import_promises8.readdir)(domainDir);
|
|
13953
14165
|
for (const file of files) {
|
|
13954
14166
|
if (!file.endsWith(".md")) continue;
|
|
13955
14167
|
try {
|
|
13956
|
-
const content = await (0,
|
|
14168
|
+
const content = await (0, import_promises8.readFile)((0, import_node_path11.join)(domainDir, file), "utf-8");
|
|
13957
14169
|
const { fm, body } = parseFrontmatter(content);
|
|
13958
14170
|
if (fm.status && fm.status !== "active") continue;
|
|
13959
14171
|
nodes.push({
|
|
@@ -13973,6 +14185,13 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
13973
14185
|
} catch {
|
|
13974
14186
|
}
|
|
13975
14187
|
}
|
|
14188
|
+
try {
|
|
14189
|
+
for (const claim of await readOrgMirror()) {
|
|
14190
|
+
const local = orgNodeToLocal(claim);
|
|
14191
|
+
if (sharedTerms(tokenize(`${local.title} ${local.body}`), promptTokens) >= ORG_MIN_SHARED_TERMS) nodes.push(local);
|
|
14192
|
+
}
|
|
14193
|
+
} catch {
|
|
14194
|
+
}
|
|
13976
14195
|
if (nodes.length === 0) return null;
|
|
13977
14196
|
const scored = nodes.map((n) => ({
|
|
13978
14197
|
...n,
|
|
@@ -13991,12 +14210,13 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
13991
14210
|
const lines = [
|
|
13992
14211
|
"## Project Knowledge (auto-injected)",
|
|
13993
14212
|
"",
|
|
13994
|
-
`*${selected.length} node(s) relevant to your current task. See \`.verity/memory/index.md\` for the full knowledge base.*`,
|
|
14213
|
+
`*${selected.length} node(s) relevant to your current task. See \`.verity/memory/index.md\` for the full knowledge base${selected.some((n) => n.scope === "org") ? ", and `~/.verity/orgs/` for what the organization's other repositories learned" : ""}.*`,
|
|
13995
14214
|
""
|
|
13996
14215
|
];
|
|
13997
14216
|
for (const node of selected) {
|
|
13998
14217
|
lines.push(`### ${node.title}`);
|
|
13999
|
-
lines.push(
|
|
14218
|
+
if (node.scope === "org") lines.push(`*org \xB7 ${node.origin}* \xB7 ${node.kind}`);
|
|
14219
|
+
else lines.push(`*${node.kind}* \xB7 confidence ${Math.round(node.confidence * 100)}%`);
|
|
14000
14220
|
lines.push("");
|
|
14001
14221
|
lines.push(node.body.slice(0, 800));
|
|
14002
14222
|
lines.push("");
|
|
@@ -14011,14 +14231,14 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
14011
14231
|
}
|
|
14012
14232
|
|
|
14013
14233
|
// src/lib/memory-sync.ts
|
|
14014
|
-
var
|
|
14015
|
-
var
|
|
14016
|
-
var
|
|
14234
|
+
var import_promises9 = require("node:fs/promises");
|
|
14235
|
+
var import_node_fs14 = require("node:fs");
|
|
14236
|
+
var import_node_path13 = require("node:path");
|
|
14017
14237
|
var import_node_crypto3 = require("node:crypto");
|
|
14018
14238
|
|
|
14019
14239
|
// src/lib/gitignore.ts
|
|
14020
14240
|
var import_node_child_process6 = require("node:child_process");
|
|
14021
|
-
var
|
|
14241
|
+
var import_node_fs12 = require("node:fs");
|
|
14022
14242
|
var VERITY_GITIGNORE_MARKER = "# Verity \u2014 machine-local state.";
|
|
14023
14243
|
var SETTINGS_LOCAL_IGNORE_ENTRY = ".claude/settings.local.json";
|
|
14024
14244
|
var VERITY_GITIGNORE_BLOCK = [
|
|
@@ -14102,7 +14322,7 @@ function fenceMemoryLines(lines) {
|
|
|
14102
14322
|
function ensureVerityGitignore() {
|
|
14103
14323
|
let content = "";
|
|
14104
14324
|
try {
|
|
14105
|
-
content = (0,
|
|
14325
|
+
content = (0, import_node_fs12.readFileSync)(".gitignore", "utf-8");
|
|
14106
14326
|
} catch {
|
|
14107
14327
|
}
|
|
14108
14328
|
const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
|
|
@@ -14129,7 +14349,7 @@ function ensureVerityGitignore() {
|
|
|
14129
14349
|
const sep4 = text === "" ? "" : text.endsWith("\n") ? "\n" : "\n\n";
|
|
14130
14350
|
text = text + sep4 + VERITY_GITIGNORE_BLOCK;
|
|
14131
14351
|
}
|
|
14132
|
-
if (text !== content) (0,
|
|
14352
|
+
if (text !== content) (0, import_node_fs12.writeFileSync)(".gitignore", text);
|
|
14133
14353
|
return verified(
|
|
14134
14354
|
memoryIsCommitted ? "memory-tracked" : hasSupersededMemory ? "memory-fenced" : needsRepair ? "repaired" : "added"
|
|
14135
14355
|
);
|
|
@@ -14149,7 +14369,7 @@ function untrackMemory() {
|
|
|
14149
14369
|
function writeFencedBlock() {
|
|
14150
14370
|
let content = "";
|
|
14151
14371
|
try {
|
|
14152
|
-
content = (0,
|
|
14372
|
+
content = (0, import_node_fs12.readFileSync)(".gitignore", "utf-8");
|
|
14153
14373
|
} catch {
|
|
14154
14374
|
}
|
|
14155
14375
|
const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
|
|
@@ -14161,7 +14381,7 @@ function writeFencedBlock() {
|
|
|
14161
14381
|
text = text + sep4 + VERITY_GITIGNORE_BLOCK;
|
|
14162
14382
|
}
|
|
14163
14383
|
try {
|
|
14164
|
-
(0,
|
|
14384
|
+
(0, import_node_fs12.writeFileSync)(".gitignore", text);
|
|
14165
14385
|
return true;
|
|
14166
14386
|
} catch {
|
|
14167
14387
|
return false;
|
|
@@ -14170,14 +14390,14 @@ function writeFencedBlock() {
|
|
|
14170
14390
|
function fenceMemory() {
|
|
14171
14391
|
let original = null;
|
|
14172
14392
|
try {
|
|
14173
|
-
original = (0,
|
|
14393
|
+
original = (0, import_node_fs12.readFileSync)(".gitignore", "utf-8");
|
|
14174
14394
|
} catch {
|
|
14175
14395
|
original = null;
|
|
14176
14396
|
}
|
|
14177
14397
|
const restore = () => {
|
|
14178
14398
|
try {
|
|
14179
|
-
if (original === null) (0,
|
|
14180
|
-
else (0,
|
|
14399
|
+
if (original === null) (0, import_node_fs12.rmSync)(".gitignore", { force: true });
|
|
14400
|
+
else (0, import_node_fs12.writeFileSync)(".gitignore", original);
|
|
14181
14401
|
} catch {
|
|
14182
14402
|
}
|
|
14183
14403
|
};
|
|
@@ -14195,7 +14415,7 @@ function fenceMemory() {
|
|
|
14195
14415
|
}
|
|
14196
14416
|
function memoryOptOut() {
|
|
14197
14417
|
try {
|
|
14198
|
-
return (0,
|
|
14418
|
+
return (0, import_node_fs12.readFileSync)(".gitignore", "utf-8").includes(MEMORY_OPT_OUT_MARKER);
|
|
14199
14419
|
} catch {
|
|
14200
14420
|
return false;
|
|
14201
14421
|
}
|
|
@@ -14203,13 +14423,13 @@ function memoryOptOut() {
|
|
|
14203
14423
|
function keepMemoryTracked() {
|
|
14204
14424
|
let content = "";
|
|
14205
14425
|
try {
|
|
14206
|
-
content = (0,
|
|
14426
|
+
content = (0, import_node_fs12.readFileSync)(".gitignore", "utf-8");
|
|
14207
14427
|
} catch {
|
|
14208
14428
|
}
|
|
14209
14429
|
if (content.includes(MEMORY_OPT_OUT_MARKER)) return "already";
|
|
14210
14430
|
try {
|
|
14211
14431
|
const sep4 = content === "" ? "" : content.endsWith("\n") ? "\n" : "\n\n";
|
|
14212
|
-
(0,
|
|
14432
|
+
(0, import_node_fs12.writeFileSync)(".gitignore", content + sep4 + MEMORY_OPT_OUT_STANZA);
|
|
14213
14433
|
} catch {
|
|
14214
14434
|
return "failed";
|
|
14215
14435
|
}
|
|
@@ -14244,26 +14464,26 @@ function untrackVerityState() {
|
|
|
14244
14464
|
}
|
|
14245
14465
|
|
|
14246
14466
|
// src/lib/safe-path.ts
|
|
14247
|
-
var
|
|
14248
|
-
var
|
|
14467
|
+
var import_node_fs13 = require("node:fs");
|
|
14468
|
+
var import_node_path12 = require("node:path");
|
|
14249
14469
|
function resolveInside(baseDir, candidate) {
|
|
14250
14470
|
if (typeof candidate !== "string" || candidate.length === 0) return null;
|
|
14251
|
-
if ((0,
|
|
14252
|
-
const baseAbs = (0,
|
|
14253
|
-
const full = (0,
|
|
14254
|
-
const baseSep = baseAbs.endsWith(
|
|
14471
|
+
if ((0, import_node_path12.isAbsolute)(candidate)) return null;
|
|
14472
|
+
const baseAbs = (0, import_node_path12.resolve)(baseDir);
|
|
14473
|
+
const full = (0, import_node_path12.resolve)(baseAbs, candidate);
|
|
14474
|
+
const baseSep = baseAbs.endsWith(import_node_path12.sep) ? baseAbs : baseAbs + import_node_path12.sep;
|
|
14255
14475
|
if (full !== baseAbs && !full.startsWith(baseSep)) return null;
|
|
14256
14476
|
try {
|
|
14257
|
-
if ((0,
|
|
14258
|
-
const realBase = (0,
|
|
14259
|
-
const realBaseSep = realBase.endsWith(
|
|
14477
|
+
if ((0, import_node_fs13.existsSync)(baseAbs)) {
|
|
14478
|
+
const realBase = (0, import_node_fs13.realpathSync)(baseAbs);
|
|
14479
|
+
const realBaseSep = realBase.endsWith(import_node_path12.sep) ? realBase : realBase + import_node_path12.sep;
|
|
14260
14480
|
let probe = full;
|
|
14261
|
-
while (!(0,
|
|
14262
|
-
const parent = (0,
|
|
14481
|
+
while (!(0, import_node_fs13.existsSync)(probe)) {
|
|
14482
|
+
const parent = (0, import_node_path12.dirname)(probe);
|
|
14263
14483
|
if (parent === probe) break;
|
|
14264
14484
|
probe = parent;
|
|
14265
14485
|
}
|
|
14266
|
-
const realProbe = (0,
|
|
14486
|
+
const realProbe = (0, import_node_fs13.realpathSync)(probe);
|
|
14267
14487
|
if (realProbe !== realBase && !realProbe.startsWith(realBaseSep)) return null;
|
|
14268
14488
|
}
|
|
14269
14489
|
} catch {
|
|
@@ -14346,36 +14566,36 @@ var memoryDir2 = () => projectPath(`${VERITY_DIR}/memory`);
|
|
|
14346
14566
|
var DOMAINS2 = ["decisions", "quality", "security", "intent", "gotchas", "patterns", "domain", "integrations", "_archive"];
|
|
14347
14567
|
var syncStateFile = () => projectPath(`${VERITY_DIR}/.memory-sync-state.json`);
|
|
14348
14568
|
async function ensureMemoryDir() {
|
|
14349
|
-
await (0,
|
|
14569
|
+
await (0, import_promises9.mkdir)(memoryDir2(), { recursive: true });
|
|
14350
14570
|
for (const domain of DOMAINS2) {
|
|
14351
|
-
await (0,
|
|
14571
|
+
await (0, import_promises9.mkdir)((0, import_node_path13.join)(memoryDir2(), domain), { recursive: true });
|
|
14352
14572
|
}
|
|
14353
|
-
if (!(0,
|
|
14354
|
-
await (0,
|
|
14573
|
+
if (!(0, import_node_fs14.existsSync)((0, import_node_path13.join)(memoryDir2(), "SCHEMA.md"))) {
|
|
14574
|
+
await (0, import_promises9.writeFile)((0, import_node_path13.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
|
|
14355
14575
|
}
|
|
14356
|
-
if (!(0,
|
|
14357
|
-
await (0,
|
|
14576
|
+
if (!(0, import_node_fs14.existsSync)((0, import_node_path13.join)(memoryDir2(), "index.md"))) {
|
|
14577
|
+
await (0, import_promises9.writeFile)((0, import_node_path13.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
|
|
14358
14578
|
}
|
|
14359
|
-
if (!(0,
|
|
14360
|
-
await (0,
|
|
14579
|
+
if (!(0, import_node_fs14.existsSync)((0, import_node_path13.join)(memoryDir2(), "log.md"))) {
|
|
14580
|
+
await (0, import_promises9.writeFile)((0, import_node_path13.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
|
|
14361
14581
|
}
|
|
14362
14582
|
}
|
|
14363
14583
|
async function buildManifest() {
|
|
14364
|
-
if (!(0,
|
|
14584
|
+
if (!(0, import_node_fs14.existsSync)(memoryDir2())) {
|
|
14365
14585
|
return { schema_version: 1, nodes: [], index_hash: null, log_length: 0 };
|
|
14366
14586
|
}
|
|
14367
14587
|
const nodes = [];
|
|
14368
14588
|
for (const domain of DOMAINS2) {
|
|
14369
|
-
const domainDir = (0,
|
|
14370
|
-
if (!(0,
|
|
14589
|
+
const domainDir = (0, import_node_path13.join)(memoryDir2(), domain);
|
|
14590
|
+
if (!(0, import_node_fs14.existsSync)(domainDir)) continue;
|
|
14371
14591
|
try {
|
|
14372
|
-
const files = await (0,
|
|
14592
|
+
const files = await (0, import_promises9.readdir)(domainDir);
|
|
14373
14593
|
for (const file of files) {
|
|
14374
14594
|
if (!file.endsWith(".md")) continue;
|
|
14375
14595
|
const filePath = `${domain}/${file}`;
|
|
14376
|
-
const fullPath = (0,
|
|
14596
|
+
const fullPath = (0, import_node_path13.join)(memoryDir2(), filePath);
|
|
14377
14597
|
try {
|
|
14378
|
-
const content = await (0,
|
|
14598
|
+
const content = await (0, import_promises9.readFile)(fullPath, "utf-8");
|
|
14379
14599
|
const hash = (0, import_node_crypto3.createHash)("sha256").update(content).digest("hex").slice(0, 16);
|
|
14380
14600
|
nodes.push({ path: filePath, content_hash: `sha256:${hash}` });
|
|
14381
14601
|
} catch {
|
|
@@ -14386,13 +14606,13 @@ async function buildManifest() {
|
|
|
14386
14606
|
}
|
|
14387
14607
|
let indexHash = null;
|
|
14388
14608
|
try {
|
|
14389
|
-
const indexContent = await (0,
|
|
14609
|
+
const indexContent = await (0, import_promises9.readFile)((0, import_node_path13.join)(memoryDir2(), "index.md"), "utf-8");
|
|
14390
14610
|
indexHash = `sha256:${(0, import_node_crypto3.createHash)("sha256").update(indexContent).digest("hex").slice(0, 16)}`;
|
|
14391
14611
|
} catch {
|
|
14392
14612
|
}
|
|
14393
14613
|
let logLength = 0;
|
|
14394
14614
|
try {
|
|
14395
|
-
const logContent = await (0,
|
|
14615
|
+
const logContent = await (0, import_promises9.readFile)((0, import_node_path13.join)(memoryDir2(), "log.md"), "utf-8");
|
|
14396
14616
|
logLength = logContent.split("\n").length;
|
|
14397
14617
|
} catch {
|
|
14398
14618
|
}
|
|
@@ -14403,15 +14623,15 @@ function hashContent(content) {
|
|
|
14403
14623
|
}
|
|
14404
14624
|
async function readOnDiskNodes() {
|
|
14405
14625
|
const out = /* @__PURE__ */ new Map();
|
|
14406
|
-
if (!(0,
|
|
14626
|
+
if (!(0, import_node_fs14.existsSync)(memoryDir2())) return out;
|
|
14407
14627
|
for (const domain of DOMAINS2) {
|
|
14408
|
-
const domainDir = (0,
|
|
14409
|
-
if (!(0,
|
|
14628
|
+
const domainDir = (0, import_node_path13.join)(memoryDir2(), domain);
|
|
14629
|
+
if (!(0, import_node_fs14.existsSync)(domainDir)) continue;
|
|
14410
14630
|
try {
|
|
14411
|
-
for (const file of await (0,
|
|
14631
|
+
for (const file of await (0, import_promises9.readdir)(domainDir)) {
|
|
14412
14632
|
if (!file.endsWith(".md")) continue;
|
|
14413
14633
|
try {
|
|
14414
|
-
out.set(`${domain}/${file}`, hashContent(await (0,
|
|
14634
|
+
out.set(`${domain}/${file}`, hashContent(await (0, import_promises9.readFile)((0, import_node_path13.join)(domainDir, file), "utf-8")));
|
|
14415
14635
|
} catch {
|
|
14416
14636
|
}
|
|
14417
14637
|
}
|
|
@@ -14423,7 +14643,7 @@ async function readOnDiskNodes() {
|
|
|
14423
14643
|
async function readSyncBaseline() {
|
|
14424
14644
|
const out = /* @__PURE__ */ new Map();
|
|
14425
14645
|
try {
|
|
14426
|
-
const parsed = JSON.parse(await (0,
|
|
14646
|
+
const parsed = JSON.parse(await (0, import_promises9.readFile)(syncStateFile(), "utf-8"));
|
|
14427
14647
|
if (Array.isArray(parsed?.nodes)) {
|
|
14428
14648
|
for (const n of parsed.nodes) if (n?.path) out.set(n.path, n.hash ?? null);
|
|
14429
14649
|
} else if (Array.isArray(parsed?.paths)) {
|
|
@@ -14439,7 +14659,7 @@ async function recordSyncedNodePaths() {
|
|
|
14439
14659
|
const next = JSON.stringify({ schema: 2, nodes }) + "\n";
|
|
14440
14660
|
let existing = "";
|
|
14441
14661
|
try {
|
|
14442
|
-
existing = await (0,
|
|
14662
|
+
existing = await (0, import_promises9.readFile)(syncStateFile(), "utf-8");
|
|
14443
14663
|
} catch {
|
|
14444
14664
|
}
|
|
14445
14665
|
if (existing === next) return;
|
|
@@ -14448,10 +14668,10 @@ async function recordSyncedNodePaths() {
|
|
|
14448
14668
|
}
|
|
14449
14669
|
}
|
|
14450
14670
|
async function writeFileAtomic(path, content) {
|
|
14451
|
-
await (0,
|
|
14671
|
+
await (0, import_promises9.mkdir)((0, import_node_path13.dirname)(path), { recursive: true });
|
|
14452
14672
|
const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
14453
|
-
await (0,
|
|
14454
|
-
await (0,
|
|
14673
|
+
await (0, import_promises9.writeFile)(tmp, content);
|
|
14674
|
+
await (0, import_promises9.rename)(tmp, path);
|
|
14455
14675
|
}
|
|
14456
14676
|
async function recordSyncBaseline() {
|
|
14457
14677
|
await recordSyncedNodePaths();
|
|
@@ -14462,11 +14682,11 @@ async function computeEditedNodeUploads() {
|
|
|
14462
14682
|
const uploads = [];
|
|
14463
14683
|
for (const [path, prevHash] of prev) {
|
|
14464
14684
|
if (prevHash == null) continue;
|
|
14465
|
-
const full = (0,
|
|
14466
|
-
if (!(0,
|
|
14685
|
+
const full = (0, import_node_path13.join)(memoryDir2(), path);
|
|
14686
|
+
if (!(0, import_node_fs14.existsSync)(full)) continue;
|
|
14467
14687
|
let content;
|
|
14468
14688
|
try {
|
|
14469
|
-
content = await (0,
|
|
14689
|
+
content = await (0, import_promises9.readFile)(full, "utf-8");
|
|
14470
14690
|
} catch {
|
|
14471
14691
|
continue;
|
|
14472
14692
|
}
|
|
@@ -14507,8 +14727,8 @@ async function applyMemoryWrites(writes, opts = {}) {
|
|
|
14507
14727
|
const logLines = [`- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)} \u2014 Applied ${count} write(s) from server`];
|
|
14508
14728
|
for (const n of notes) logLines.push(` - ${n}`);
|
|
14509
14729
|
try {
|
|
14510
|
-
const existing = (0,
|
|
14511
|
-
await (0,
|
|
14730
|
+
const existing = (0, import_node_fs14.existsSync)((0, import_node_path13.join)(memoryDir2(), "log.md")) ? await (0, import_promises9.readFile)((0, import_node_path13.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
|
|
14731
|
+
await (0, import_promises9.writeFile)((0, import_node_path13.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
|
|
14512
14732
|
} catch {
|
|
14513
14733
|
}
|
|
14514
14734
|
if (opts.baseline === "written") await mergeSyncBaseline(synced);
|
|
@@ -14518,9 +14738,9 @@ async function applyMemoryWrites(writes, opts = {}) {
|
|
|
14518
14738
|
async function mergeSyncBaseline(entries) {
|
|
14519
14739
|
if (entries.size === 0) return;
|
|
14520
14740
|
try {
|
|
14521
|
-
if ((0,
|
|
14741
|
+
if ((0, import_node_fs14.existsSync)(syncStateFile())) {
|
|
14522
14742
|
try {
|
|
14523
|
-
JSON.parse(await (0,
|
|
14743
|
+
JSON.parse(await (0, import_promises9.readFile)(syncStateFile(), "utf-8"));
|
|
14524
14744
|
} catch {
|
|
14525
14745
|
return;
|
|
14526
14746
|
}
|
|
@@ -14546,10 +14766,10 @@ async function applyOneWrite(write, treePaths, lastServed) {
|
|
|
14546
14766
|
notes.push(`${write.path}: dropped unmatched file_globs [${grounded.dropped.join(", ")}]`);
|
|
14547
14767
|
}
|
|
14548
14768
|
}
|
|
14549
|
-
if ((0,
|
|
14769
|
+
if ((0, import_node_fs14.existsSync)(fullPath)) {
|
|
14550
14770
|
let existing = "";
|
|
14551
14771
|
try {
|
|
14552
|
-
existing = await (0,
|
|
14772
|
+
existing = await (0, import_promises9.readFile)(fullPath, "utf-8");
|
|
14553
14773
|
} catch {
|
|
14554
14774
|
}
|
|
14555
14775
|
if (existing === content) return { written: false, syncedHash: hashContent(content), notes };
|
|
@@ -14562,8 +14782,8 @@ async function applyOneWrite(write, treePaths, lastServed) {
|
|
|
14562
14782
|
notes.push(`${write.path}: updated from server (untouched here since the server delivered it)`);
|
|
14563
14783
|
}
|
|
14564
14784
|
}
|
|
14565
|
-
await (0,
|
|
14566
|
-
await (0,
|
|
14785
|
+
await (0, import_promises9.mkdir)((0, import_node_path13.dirname)(fullPath), { recursive: true });
|
|
14786
|
+
await (0, import_promises9.writeFile)(fullPath, content);
|
|
14567
14787
|
return { written: true, syncedHash: hashContent(content), notes };
|
|
14568
14788
|
}
|
|
14569
14789
|
function groundFileGlobs(content, treePaths) {
|
|
@@ -14603,10 +14823,10 @@ async function regenerateIndex() {
|
|
|
14603
14823
|
];
|
|
14604
14824
|
let totalNodes = 0;
|
|
14605
14825
|
for (const domain of DOMAINS2.filter((d) => d !== "_archive")) {
|
|
14606
|
-
const domainDir = (0,
|
|
14607
|
-
if (!(0,
|
|
14826
|
+
const domainDir = (0, import_node_path13.join)(memoryDir2(), domain);
|
|
14827
|
+
if (!(0, import_node_fs14.existsSync)(domainDir)) continue;
|
|
14608
14828
|
try {
|
|
14609
|
-
const files = await (0,
|
|
14829
|
+
const files = await (0, import_promises9.readdir)(domainDir);
|
|
14610
14830
|
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
14611
14831
|
if (mdFiles.length === 0) continue;
|
|
14612
14832
|
lines.push(`## ${domain}/ (${mdFiles.length})`);
|
|
@@ -14614,7 +14834,7 @@ async function regenerateIndex() {
|
|
|
14614
14834
|
for (const file of mdFiles.sort()) {
|
|
14615
14835
|
const slug = file.replace(/\.md$/, "");
|
|
14616
14836
|
try {
|
|
14617
|
-
const content = await (0,
|
|
14837
|
+
const content = await (0, import_promises9.readFile)((0, import_node_path13.join)(domainDir, file), "utf-8");
|
|
14618
14838
|
const title = pickFrontmatter(content, "title") ?? slug;
|
|
14619
14839
|
const kind = pickFrontmatter(content, "kind") ?? "-";
|
|
14620
14840
|
const confidence = pickFrontmatter(content, "confidence");
|
|
@@ -14638,14 +14858,14 @@ async function regenerateIndex() {
|
|
|
14638
14858
|
lines.push("No nodes yet. Run an analysis to start building the knowledge graph.");
|
|
14639
14859
|
}
|
|
14640
14860
|
const next = lines.join("\n") + "\n";
|
|
14641
|
-
const indexPath = (0,
|
|
14861
|
+
const indexPath = (0, import_node_path13.join)(memoryDir2(), "index.md");
|
|
14642
14862
|
let existing = null;
|
|
14643
14863
|
try {
|
|
14644
|
-
existing = await (0,
|
|
14864
|
+
existing = await (0, import_promises9.readFile)(indexPath, "utf-8");
|
|
14645
14865
|
} catch {
|
|
14646
14866
|
}
|
|
14647
14867
|
if (existing === next) return;
|
|
14648
|
-
await (0,
|
|
14868
|
+
await (0, import_promises9.writeFile)(indexPath, next);
|
|
14649
14869
|
}
|
|
14650
14870
|
function pickFrontmatter(content, key) {
|
|
14651
14871
|
const re = new RegExp(`^${key}:\\s*"?([^"\\n]+?)"?\\s*$`, "m");
|
|
@@ -14672,6 +14892,90 @@ var LEGACY_MD_END = "<!-- gate-memory:end -->";
|
|
|
14672
14892
|
var LEGACY_PRESERVE_START = "<!-- gate-memory:preserve -->";
|
|
14673
14893
|
var LEGACY_PRESERVE_END = "<!-- /gate-memory:preserve -->";
|
|
14674
14894
|
var CLAUDE_MD_PROSE = [
|
|
14895
|
+
"## Project Memory",
|
|
14896
|
+
"",
|
|
14897
|
+
"This project has a knowledge graph maintained at `.verity/memory/`. Before starting",
|
|
14898
|
+
"non-trivial work, scan `.verity/memory/index.md` for decisions, gotchas, and patterns",
|
|
14899
|
+
"that may apply to the change you are about to make. Open specific node files via",
|
|
14900
|
+
"the Read tool when the title or scope suggests relevance.",
|
|
14901
|
+
"",
|
|
14902
|
+
"The graph is auto-maintained by Verity. Files at `.verity/memory/_archive/` are",
|
|
14903
|
+
"superseded \u2014 ignore them unless investigating history.",
|
|
14904
|
+
"",
|
|
14905
|
+
"Knowledge the organization's other repositories learned is mirrored outside the",
|
|
14906
|
+
"repo at `~/.verity/orgs/<host>/<owner>/memory/` (`verity memory org` lists it).",
|
|
14907
|
+
"Each claim says where it came from; one that is wrong here is demoted for",
|
|
14908
|
+
'everyone with `verity memory demote <id> --reason "\u2026"`.',
|
|
14909
|
+
"",
|
|
14910
|
+
"## Quality gate: accepted risks",
|
|
14911
|
+
"",
|
|
14912
|
+
"When the Verity pre-commit/pre-push gate FAILs, fix the findings \u2014 that is the",
|
|
14913
|
+
'default. Use `verity waive <pattern-id> --file <path> --reason "\u2026"` ONLY to relay',
|
|
14914
|
+
"a risk a human has explicitly accepted: a named code-review finding, an ADR, or",
|
|
14915
|
+
"the user saying so in this conversation. The --reason must cite that source.",
|
|
14916
|
+
"",
|
|
14917
|
+
"Never waive on your own judgment, to get past a block, or pre-emptively. A waive",
|
|
14918
|
+
"binds to the file's current bytes and voids automatically when the file changes,",
|
|
14919
|
+
"and every waive is recorded in the run ledger. For a pattern-level false positive",
|
|
14920
|
+
"use `verity feedback finding <run-id> <pattern-id> false_positive` instead.",
|
|
14921
|
+
"",
|
|
14922
|
+
"## Post-task reflection",
|
|
14923
|
+
"",
|
|
14924
|
+
`When a task is complete (you've created a PR, the user says "done" or "ship it",`,
|
|
14925
|
+
"or the work is clearly finished), **draft the reflection yourself** \u2014 1\u20133",
|
|
14926
|
+
"concrete things worth remembering (a decision, a gotcha, or a pattern), each",
|
|
14927
|
+
"cited with the files / PR / commands / error-signatures it came from. Skip",
|
|
14928
|
+
"entirely if nothing non-obvious happened \u2014 that judgement is the ONLY filter,",
|
|
14929
|
+
"because nothing reviews the reflection before it lands.",
|
|
14930
|
+
"",
|
|
14931
|
+
"Then record it straight away. There is no confirm step, in any environment:",
|
|
14932
|
+
"",
|
|
14933
|
+
"```bash",
|
|
14934
|
+
'verity reflect --user-input "<your draft>" --kind <kind>',
|
|
14935
|
+
"```",
|
|
14936
|
+
"",
|
|
14937
|
+
"Add `--confirmed` ONLY when the user authored or dictated the words. Without",
|
|
14938
|
+
"it the node is stored as `source: agent` \u2014 Verity thought this, nobody checked",
|
|
14939
|
+
"it. With it, `source: user` at full confidence \u2014 a person stands behind this.",
|
|
14940
|
+
"Never claim the second for your own draft, however good it is.",
|
|
14941
|
+
"",
|
|
14942
|
+
"**Name the files in the text.** Verity scopes the reflection to the paths it",
|
|
14943
|
+
"cites, and a reflection that names no file in this repo is never retrieved for",
|
|
14944
|
+
"a later review \u2014 it is recorded and then invisible. The command says so when it",
|
|
14945
|
+
'happens; `--file-globs "<path or glob>"` is the fix when the prose cannot carry',
|
|
14946
|
+
"the paths.",
|
|
14947
|
+
"",
|
|
14948
|
+
"Then tell the user, in one line, what you recorded and where: the command",
|
|
14949
|
+
"prints the node id, the path under `.verity/memory/`, and a dashboard link.",
|
|
14950
|
+
"They did not agree to it in advance, so say it happened \u2014 editing or deleting",
|
|
14951
|
+
"that file is how they correct it.",
|
|
14952
|
+
"",
|
|
14953
|
+
"> Durable, hand-curated guidance goes in the preserve region below (it survives",
|
|
14954
|
+
"> regeneration) or anywhere OUTSIDE these markers. Everything else between the",
|
|
14955
|
+
"> markers is tool-owned and overwritten on each run.",
|
|
14956
|
+
"",
|
|
14957
|
+
"## Housekeeping Turns",
|
|
14958
|
+
"",
|
|
14959
|
+
"When a turn will be pure housekeeping \u2014 pulling, installing dependencies,",
|
|
14960
|
+
"rebasing, a formatting sweep you are not authoring \u2014 declare it BEFORE doing it:",
|
|
14961
|
+
"",
|
|
14962
|
+
"```bash",
|
|
14963
|
+
'verity ignore --turn --agent --reason "pulling latest before starting"',
|
|
14964
|
+
"```",
|
|
14965
|
+
"",
|
|
14966
|
+
"This skips the review for that turn, which saves the turn Verity would",
|
|
14967
|
+
"otherwise spend saying it had nothing to say. Use `--for 30m` instead of",
|
|
14968
|
+
"`--turn` when a single piece of housekeeping spans several turns.",
|
|
14969
|
+
"",
|
|
14970
|
+
"**It is a claim about the turn, not a way to silence review.** The declaration",
|
|
14971
|
+
"is checked against what the turn actually did: if anything is authored \u2014 by you,",
|
|
14972
|
+
"by a subagent, or by a shell command that can write files \u2014 it voids, the review",
|
|
14973
|
+
"runs anyway, and the broken declaration is reported. So declare housekeeping you",
|
|
14974
|
+
"are about to do, never work you have already done, and never as a way to get past",
|
|
14975
|
+
"a finding. Declarations are budgeted per session and every one is recorded with",
|
|
14976
|
+
"its reason."
|
|
14977
|
+
].join("\n");
|
|
14978
|
+
var CLAUDE_MD_PROSE_PRE_ORG = [
|
|
14675
14979
|
"## Project Memory",
|
|
14676
14980
|
"",
|
|
14677
14981
|
"This project has a knowledge graph maintained at `.verity/memory/`. Before starting",
|
|
@@ -14951,10 +15255,10 @@ function hasLegacyMemoryBlock(text) {
|
|
|
14951
15255
|
return findMarker(text, LEGACY_MD_START) !== -1;
|
|
14952
15256
|
}
|
|
14953
15257
|
async function ensureClaudeMdPointer(cwd = repoRoot()) {
|
|
14954
|
-
const claudeMdPath = (0,
|
|
15258
|
+
const claudeMdPath = (0, import_node_path13.join)(cwd, "CLAUDE.md");
|
|
14955
15259
|
let existing = "";
|
|
14956
|
-
if ((0,
|
|
14957
|
-
existing = await (0,
|
|
15260
|
+
if ((0, import_node_fs14.existsSync)(claudeMdPath)) {
|
|
15261
|
+
existing = await (0, import_promises9.readFile)(claudeMdPath, "utf-8");
|
|
14958
15262
|
}
|
|
14959
15263
|
let startTag = CLAUDE_MD_START;
|
|
14960
15264
|
let endTag = CLAUDE_MD_END;
|
|
@@ -15010,7 +15314,7 @@ async function ensureClaudeMdPointer(cwd = repoRoot()) {
|
|
|
15010
15314
|
next = existing.replace(/\n*$/, "") + "\n\n" + block + "\n";
|
|
15011
15315
|
}
|
|
15012
15316
|
if (next === existing) return;
|
|
15013
|
-
await (0,
|
|
15317
|
+
await (0, import_promises9.writeFile)(claudeMdPath, next);
|
|
15014
15318
|
}
|
|
15015
15319
|
function extractPreserveContent(interior) {
|
|
15016
15320
|
for (const [start, end] of [
|
|
@@ -15029,6 +15333,7 @@ function stripKnownProse(interior) {
|
|
|
15029
15333
|
const trimmed = interior.replace(/^\n+/, "");
|
|
15030
15334
|
for (const prose of [
|
|
15031
15335
|
CLAUDE_MD_PROSE,
|
|
15336
|
+
CLAUDE_MD_PROSE_PRE_ORG,
|
|
15032
15337
|
CLAUDE_MD_PROSE_PRE_AUTORECORD,
|
|
15033
15338
|
CLAUDE_MD_PROSE_PRE_REFLECT,
|
|
15034
15339
|
CLAUDE_MD_PROSE_PRE_WAIVE,
|
|
@@ -15093,9 +15398,9 @@ Body content (\u22648KB). Use [[node-id]] wikilinks for cross-references.
|
|
|
15093
15398
|
`;
|
|
15094
15399
|
|
|
15095
15400
|
// src/lib/dossier-session.ts
|
|
15096
|
-
var
|
|
15401
|
+
var import_node_fs19 = require("node:fs");
|
|
15097
15402
|
var import_node_crypto7 = require("node:crypto");
|
|
15098
|
-
var
|
|
15403
|
+
var import_node_path16 = require("node:path");
|
|
15099
15404
|
|
|
15100
15405
|
// src/lib/pending-repeat.ts
|
|
15101
15406
|
var STOP = /* @__PURE__ */ new Set([
|
|
@@ -15200,8 +15505,8 @@ function statementAnchorKey(file, patternId) {
|
|
|
15200
15505
|
|
|
15201
15506
|
// src/lib/dossier/log.ts
|
|
15202
15507
|
var import_node_crypto4 = require("node:crypto");
|
|
15203
|
-
var
|
|
15204
|
-
var
|
|
15508
|
+
var import_node_fs15 = require("node:fs");
|
|
15509
|
+
var import_node_path14 = require("node:path");
|
|
15205
15510
|
var CRC_TABLE = (() => {
|
|
15206
15511
|
const t = new Int32Array(256);
|
|
15207
15512
|
for (let i = 0; i < 256; i++) {
|
|
@@ -15220,13 +15525,13 @@ function crc32(s) {
|
|
|
15220
15525
|
function openDossier(identity) {
|
|
15221
15526
|
try {
|
|
15222
15527
|
const dir = dossierDir(identity);
|
|
15223
|
-
(0,
|
|
15528
|
+
(0, import_node_fs15.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
15224
15529
|
return {
|
|
15225
15530
|
dir,
|
|
15226
15531
|
identity,
|
|
15227
|
-
eventsPath: (0,
|
|
15228
|
-
foldPath: (0,
|
|
15229
|
-
rotatedDir: (0,
|
|
15532
|
+
eventsPath: (0, import_node_path14.join)(dir, "events.jsonl"),
|
|
15533
|
+
foldPath: (0, import_node_path14.join)(dir, "fold.json"),
|
|
15534
|
+
rotatedDir: (0, import_node_path14.join)(dir, "rotated")
|
|
15230
15535
|
};
|
|
15231
15536
|
} catch {
|
|
15232
15537
|
return null;
|
|
@@ -15288,7 +15593,7 @@ function appendEvent(d, ev) {
|
|
|
15288
15593
|
at: ev.at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
15289
15594
|
...ev
|
|
15290
15595
|
});
|
|
15291
|
-
(0,
|
|
15596
|
+
(0, import_node_fs15.appendFileSync)(d.eventsPath, line, { mode: 384 });
|
|
15292
15597
|
return true;
|
|
15293
15598
|
} catch {
|
|
15294
15599
|
return false;
|
|
@@ -15296,14 +15601,14 @@ function appendEvent(d, ev) {
|
|
|
15296
15601
|
}
|
|
15297
15602
|
function rotateIfNeeded2(d) {
|
|
15298
15603
|
try {
|
|
15299
|
-
if (!(0,
|
|
15300
|
-
if ((0,
|
|
15301
|
-
(0,
|
|
15302
|
-
(0,
|
|
15303
|
-
const kept = (0,
|
|
15604
|
+
if (!(0, import_node_fs15.existsSync)(d.eventsPath)) return;
|
|
15605
|
+
if ((0, import_node_fs15.statSync)(d.eventsPath).size < ROTATE_BYTES) return;
|
|
15606
|
+
(0, import_node_fs15.mkdirSync)(d.rotatedDir, { recursive: true, mode: 448 });
|
|
15607
|
+
(0, import_node_fs15.renameSync)(d.eventsPath, (0, import_node_path14.join)(d.rotatedDir, `events.${Date.now()}.jsonl`));
|
|
15608
|
+
const kept = (0, import_node_fs15.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
15304
15609
|
for (const stale of kept.slice(0, Math.max(0, kept.length - ROTATE_KEEP))) {
|
|
15305
15610
|
try {
|
|
15306
|
-
(0,
|
|
15611
|
+
(0, import_node_fs15.renameSync)((0, import_node_path14.join)(d.rotatedDir, stale), (0, import_node_path14.join)(d.rotatedDir, `${stale}.pruned`));
|
|
15307
15612
|
} catch {
|
|
15308
15613
|
}
|
|
15309
15614
|
}
|
|
@@ -15313,8 +15618,8 @@ function rotateIfNeeded2(d) {
|
|
|
15313
15618
|
|
|
15314
15619
|
// src/lib/dossier/fold-dossier.ts
|
|
15315
15620
|
var import_node_crypto5 = require("node:crypto");
|
|
15316
|
-
var
|
|
15317
|
-
var
|
|
15621
|
+
var import_node_fs16 = require("node:fs");
|
|
15622
|
+
var import_node_path15 = require("node:path");
|
|
15318
15623
|
var EMPTY_CAPABILITIES = () => ({
|
|
15319
15624
|
human_reachable: { value: "unknown", tier: "unknown" },
|
|
15320
15625
|
authorship_observability: { value: "unknown", tier: "unknown" },
|
|
@@ -15365,12 +15670,12 @@ function foldDossier(d, opts = {}) {
|
|
|
15365
15670
|
}
|
|
15366
15671
|
};
|
|
15367
15672
|
try {
|
|
15368
|
-
if ((0,
|
|
15369
|
-
const files = (0,
|
|
15673
|
+
if ((0, import_node_fs16.existsSync)(d.rotatedDir)) {
|
|
15674
|
+
const files = (0, import_node_fs16.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
15370
15675
|
state.meta.rotations = files.length;
|
|
15371
15676
|
for (const f of files) {
|
|
15372
15677
|
try {
|
|
15373
|
-
ingest((0,
|
|
15678
|
+
ingest((0, import_node_fs16.readFileSync)((0, import_node_path15.join)(d.rotatedDir, f), "utf8"));
|
|
15374
15679
|
} catch {
|
|
15375
15680
|
state.meta.dropped_lines++;
|
|
15376
15681
|
}
|
|
@@ -15379,9 +15684,9 @@ function foldDossier(d, opts = {}) {
|
|
|
15379
15684
|
} catch {
|
|
15380
15685
|
}
|
|
15381
15686
|
try {
|
|
15382
|
-
if ((0,
|
|
15383
|
-
state.meta.upto_offset = (0,
|
|
15384
|
-
ingest((0,
|
|
15687
|
+
if ((0, import_node_fs16.existsSync)(d.eventsPath)) {
|
|
15688
|
+
state.meta.upto_offset = (0, import_node_fs16.statSync)(d.eventsPath).size;
|
|
15689
|
+
ingest((0, import_node_fs16.readFileSync)(d.eventsPath, "utf8"));
|
|
15385
15690
|
}
|
|
15386
15691
|
} catch {
|
|
15387
15692
|
}
|
|
@@ -15652,7 +15957,7 @@ function applyBounds(state, input) {
|
|
|
15652
15957
|
}
|
|
15653
15958
|
|
|
15654
15959
|
// src/lib/dossier/cache.ts
|
|
15655
|
-
var
|
|
15960
|
+
var import_node_fs17 = require("node:fs");
|
|
15656
15961
|
function compactState(s) {
|
|
15657
15962
|
const ms = (iso) => Date.parse(iso) || 0;
|
|
15658
15963
|
return {
|
|
@@ -15781,20 +16086,20 @@ function encodeState(s) {
|
|
|
15781
16086
|
function writeFoldCache(d, state) {
|
|
15782
16087
|
try {
|
|
15783
16088
|
const tmp = `${d.foldPath}.${process.pid}.tmp`;
|
|
15784
|
-
(0,
|
|
15785
|
-
(0,
|
|
16089
|
+
(0, import_node_fs17.writeFileSync)(tmp, encodeState(state), { mode: 384 });
|
|
16090
|
+
(0, import_node_fs17.renameSync)(tmp, d.foldPath);
|
|
15786
16091
|
} catch {
|
|
15787
16092
|
}
|
|
15788
16093
|
}
|
|
15789
16094
|
function readFoldCache(d) {
|
|
15790
16095
|
try {
|
|
15791
|
-
if (!(0,
|
|
15792
|
-
const raw = JSON.parse((0,
|
|
16096
|
+
if (!(0, import_node_fs17.existsSync)(d.foldPath)) return null;
|
|
16097
|
+
const raw = JSON.parse((0, import_node_fs17.readFileSync)(d.foldPath, "utf8"));
|
|
15793
16098
|
if (raw?.v !== 1) return null;
|
|
15794
16099
|
const cached2 = expandState(raw);
|
|
15795
16100
|
if (!cached2?.meta) return null;
|
|
15796
|
-
const size = (0,
|
|
15797
|
-
const rotations = (0,
|
|
16101
|
+
const size = (0, import_node_fs17.existsSync)(d.eventsPath) ? (0, import_node_fs17.statSync)(d.eventsPath).size : 0;
|
|
16102
|
+
const rotations = (0, import_node_fs17.existsSync)(d.rotatedDir) ? (0, import_node_fs17.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).length : 0;
|
|
15798
16103
|
if (cached2.meta.upto_offset !== size || cached2.meta.rotations !== rotations) return null;
|
|
15799
16104
|
return cached2;
|
|
15800
16105
|
} catch {
|
|
@@ -15845,13 +16150,13 @@ function assessContinuity(i) {
|
|
|
15845
16150
|
|
|
15846
16151
|
// src/lib/dossier/reanchor.ts
|
|
15847
16152
|
var import_node_crypto6 = require("node:crypto");
|
|
15848
|
-
var
|
|
16153
|
+
var import_node_fs18 = require("node:fs");
|
|
15849
16154
|
function lineSha(text) {
|
|
15850
16155
|
return (0, import_node_crypto6.createHash)("sha256").update(text.trim()).digest("hex").slice(0, HASH_WIDTH);
|
|
15851
16156
|
}
|
|
15852
16157
|
function fileHash(path) {
|
|
15853
16158
|
try {
|
|
15854
|
-
return (0, import_node_crypto6.createHash)("sha256").update((0,
|
|
16159
|
+
return (0, import_node_crypto6.createHash)("sha256").update((0, import_node_fs18.readFileSync)(path)).digest("hex").slice(0, HASH_WIDTH);
|
|
15855
16160
|
} catch {
|
|
15856
16161
|
return null;
|
|
15857
16162
|
}
|
|
@@ -16223,20 +16528,20 @@ function foreignAuthoredPaths(identity, opts = {}) {
|
|
|
16223
16528
|
let sessions = 0;
|
|
16224
16529
|
try {
|
|
16225
16530
|
const dir = treeDir(identity);
|
|
16226
|
-
if (!(0,
|
|
16227
|
-
for (const entry of (0,
|
|
16531
|
+
if (!(0, import_node_fs19.existsSync)(dir)) return { paths: [], sessions: 0 };
|
|
16532
|
+
for (const entry of (0, import_node_fs19.readdirSync)(dir, { withFileTypes: true })) {
|
|
16228
16533
|
if (!entry.isDirectory()) continue;
|
|
16229
16534
|
if (entry.name === identity.sessionKey) continue;
|
|
16230
|
-
const log = (0,
|
|
16535
|
+
const log = (0, import_node_path16.join)(dir, entry.name, "events.jsonl");
|
|
16231
16536
|
try {
|
|
16232
|
-
if (!(0,
|
|
16233
|
-
if (now - (0,
|
|
16537
|
+
if (!(0, import_node_fs19.existsSync)(log)) continue;
|
|
16538
|
+
if (now - (0, import_node_fs19.statSync)(log).mtimeMs > windowMs) continue;
|
|
16234
16539
|
const sib = {
|
|
16235
|
-
dir: (0,
|
|
16540
|
+
dir: (0, import_node_path16.join)(dir, entry.name),
|
|
16236
16541
|
identity,
|
|
16237
16542
|
eventsPath: log,
|
|
16238
|
-
foldPath: (0,
|
|
16239
|
-
rotatedDir: (0,
|
|
16543
|
+
foldPath: (0, import_node_path16.join)(dir, entry.name, "fold.json"),
|
|
16544
|
+
rotatedDir: (0, import_node_path16.join)(dir, entry.name, "rotated")
|
|
16240
16545
|
};
|
|
16241
16546
|
const state = readFoldCache(sib) ?? foldDossier(sib);
|
|
16242
16547
|
sessions++;
|
|
@@ -16264,25 +16569,25 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
16264
16569
|
let removed = 0;
|
|
16265
16570
|
try {
|
|
16266
16571
|
const mine = dossierDir(identity);
|
|
16267
|
-
const userDir = (0,
|
|
16268
|
-
if (!(0,
|
|
16572
|
+
const userDir = (0, import_node_path16.dirname)((0, import_node_path16.dirname)(mine));
|
|
16573
|
+
if (!(0, import_node_fs19.existsSync)(userDir)) return 0;
|
|
16269
16574
|
const cutoff = Date.now() - maxAgeMs;
|
|
16270
|
-
for (const tree of (0,
|
|
16575
|
+
for (const tree of (0, import_node_fs19.readdirSync)(userDir, { withFileTypes: true })) {
|
|
16271
16576
|
if (!tree.isDirectory()) continue;
|
|
16272
|
-
const treePath = (0,
|
|
16577
|
+
const treePath = (0, import_node_path16.join)(userDir, tree.name);
|
|
16273
16578
|
let live = 0;
|
|
16274
|
-
for (const entry of (0,
|
|
16579
|
+
for (const entry of (0, import_node_fs19.readdirSync)(treePath, { withFileTypes: true })) {
|
|
16275
16580
|
if (!entry.isDirectory()) continue;
|
|
16276
|
-
const dir = (0,
|
|
16581
|
+
const dir = (0, import_node_path16.join)(treePath, entry.name);
|
|
16277
16582
|
if (dir === mine) {
|
|
16278
16583
|
live++;
|
|
16279
16584
|
continue;
|
|
16280
16585
|
}
|
|
16281
16586
|
try {
|
|
16282
|
-
const log = (0,
|
|
16283
|
-
const at = (0,
|
|
16587
|
+
const log = (0, import_node_path16.join)(dir, "events.jsonl");
|
|
16588
|
+
const at = (0, import_node_fs19.existsSync)(log) ? (0, import_node_fs19.statSync)(log).mtimeMs : (0, import_node_fs19.statSync)(dir).mtimeMs;
|
|
16284
16589
|
if (at < cutoff) {
|
|
16285
|
-
(0,
|
|
16590
|
+
(0, import_node_fs19.rmSync)(dir, { recursive: true, force: true });
|
|
16286
16591
|
removed++;
|
|
16287
16592
|
} else {
|
|
16288
16593
|
live++;
|
|
@@ -16292,7 +16597,7 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
16292
16597
|
}
|
|
16293
16598
|
if (live === 0) {
|
|
16294
16599
|
try {
|
|
16295
|
-
(0,
|
|
16600
|
+
(0, import_node_fs19.rmSync)(treePath, { recursive: false, force: false });
|
|
16296
16601
|
} catch {
|
|
16297
16602
|
}
|
|
16298
16603
|
}
|
|
@@ -16309,8 +16614,8 @@ function sessionDossier(token, sessionId) {
|
|
|
16309
16614
|
}
|
|
16310
16615
|
function hasActiveGoal(d) {
|
|
16311
16616
|
try {
|
|
16312
|
-
if (!(0,
|
|
16313
|
-
return (0,
|
|
16617
|
+
if (!(0, import_node_fs19.existsSync)(d.eventsPath)) return false;
|
|
16618
|
+
return (0, import_node_fs19.readFileSync)(d.eventsPath, "utf8").includes('"k":"goal"');
|
|
16314
16619
|
} catch {
|
|
16315
16620
|
return false;
|
|
16316
16621
|
}
|
|
@@ -16334,7 +16639,7 @@ function recordTurn(d, t) {
|
|
|
16334
16639
|
for (const a of t.authored) {
|
|
16335
16640
|
const origin = a.owner === "subagent" ? "subagent" : "edit_tool";
|
|
16336
16641
|
const prior = t.known?.authored?.get(a.p);
|
|
16337
|
-
const hash = fileHash((0,
|
|
16642
|
+
const hash = fileHash((0, import_node_path16.join)(root, a.p));
|
|
16338
16643
|
const hunks = Math.max(0, a.h - (prior?.hunks ?? 0));
|
|
16339
16644
|
const adds = Math.max(0, a.a - (prior?.adds ?? 0));
|
|
16340
16645
|
const dels = Math.max(0, a.d - (prior?.dels ?? 0));
|
|
@@ -16367,7 +16672,7 @@ function recordTurn(d, t) {
|
|
|
16367
16672
|
}
|
|
16368
16673
|
const seenDivergence = t.known?.divergence ?? /* @__PURE__ */ new Set();
|
|
16369
16674
|
for (const u of t.unobserved) {
|
|
16370
|
-
const hash = fileHash((0,
|
|
16675
|
+
const hash = fileHash((0, import_node_path16.join)(root, u.p));
|
|
16371
16676
|
if (seenDivergence.has(divergenceKey(u.p, hash))) continue;
|
|
16372
16677
|
appendEvent(d, { k: "divergence", kind: "external_mutation", path: u.p, hash });
|
|
16373
16678
|
}
|
|
@@ -16402,8 +16707,8 @@ function recordVerdict(d, v) {
|
|
|
16402
16707
|
if (!sent.has(f.file)) continue;
|
|
16403
16708
|
if (!lines.has(f.file)) {
|
|
16404
16709
|
try {
|
|
16405
|
-
const abs = (0,
|
|
16406
|
-
lines.set(f.file, (0,
|
|
16710
|
+
const abs = (0, import_node_path16.join)(root, f.file);
|
|
16711
|
+
lines.set(f.file, (0, import_node_fs19.existsSync)(abs) ? (0, import_node_fs19.readFileSync)(abs, "utf8").split("\n") : null);
|
|
16407
16712
|
} catch {
|
|
16408
16713
|
lines.set(f.file, null);
|
|
16409
16714
|
}
|
|
@@ -16503,8 +16808,8 @@ function recallMemory(d, identity, opts) {
|
|
|
16503
16808
|
budgetBytes: opts.budgetBytes,
|
|
16504
16809
|
readFileLines: (file) => {
|
|
16505
16810
|
try {
|
|
16506
|
-
const abs = (0,
|
|
16507
|
-
return (0,
|
|
16811
|
+
const abs = (0, import_node_path16.join)(root, file);
|
|
16812
|
+
return (0, import_node_fs19.existsSync)(abs) ? (0, import_node_fs19.readFileSync)(abs, "utf8").split("\n") : null;
|
|
16508
16813
|
} catch {
|
|
16509
16814
|
return null;
|
|
16510
16815
|
}
|
|
@@ -16648,46 +16953,46 @@ async function fireClassify(prompt, sessionId, globals) {
|
|
|
16648
16953
|
}
|
|
16649
16954
|
|
|
16650
16955
|
// src/commands/lifecycle.ts
|
|
16651
|
-
var
|
|
16652
|
-
var
|
|
16956
|
+
var import_node_fs23 = require("node:fs");
|
|
16957
|
+
var import_node_path21 = require("node:path");
|
|
16653
16958
|
|
|
16654
16959
|
// src/lib/baseline.ts
|
|
16655
|
-
var
|
|
16656
|
-
var
|
|
16960
|
+
var import_node_fs22 = require("node:fs");
|
|
16961
|
+
var import_node_path20 = require("node:path");
|
|
16657
16962
|
var import_node_crypto9 = require("node:crypto");
|
|
16658
16963
|
|
|
16659
16964
|
// src/lib/snapshot.ts
|
|
16660
|
-
var
|
|
16661
|
-
var
|
|
16965
|
+
var import_node_fs21 = require("node:fs");
|
|
16966
|
+
var import_node_path19 = require("node:path");
|
|
16662
16967
|
var import_node_child_process7 = require("node:child_process");
|
|
16663
16968
|
|
|
16664
16969
|
// src/lib/files.ts
|
|
16665
|
-
var
|
|
16970
|
+
var import_node_path18 = require("node:path");
|
|
16666
16971
|
|
|
16667
16972
|
// src/lib/safe-read.ts
|
|
16668
|
-
var
|
|
16669
|
-
var
|
|
16670
|
-
var FLAGS =
|
|
16973
|
+
var import_node_fs20 = require("node:fs");
|
|
16974
|
+
var import_node_path17 = require("node:path");
|
|
16975
|
+
var FLAGS = import_node_fs20.constants;
|
|
16671
16976
|
var NOFOLLOW = FLAGS.O_NOFOLLOW;
|
|
16672
16977
|
var NONBLOCK = FLAGS.O_NONBLOCK;
|
|
16673
16978
|
function closeOpened(fd) {
|
|
16674
16979
|
try {
|
|
16675
|
-
(0,
|
|
16980
|
+
(0, import_node_fs20.closeSync)(fd);
|
|
16676
16981
|
} catch {
|
|
16677
16982
|
}
|
|
16678
16983
|
}
|
|
16679
16984
|
function isInsideRoot(realRoot, realPath) {
|
|
16680
|
-
return realPath === realRoot || realPath.startsWith(realRoot.endsWith(
|
|
16985
|
+
return realPath === realRoot || realPath.startsWith(realRoot.endsWith(import_node_path17.sep) ? realRoot : realRoot + import_node_path17.sep);
|
|
16681
16986
|
}
|
|
16682
16987
|
function sameOpenedFile(opened, current, nofollowAvailable) {
|
|
16683
16988
|
if (!nofollowAvailable && (opened.ino === 0n || current.ino === 0n)) return false;
|
|
16684
16989
|
return opened.ino === current.ino && opened.dev === current.dev;
|
|
16685
16990
|
}
|
|
16686
16991
|
function openRegularInRoot(root, path) {
|
|
16687
|
-
const full = (0,
|
|
16992
|
+
const full = (0, import_node_path17.isAbsolute)(path) ? path : (0, import_node_path17.join)(root, path);
|
|
16688
16993
|
let fd;
|
|
16689
16994
|
try {
|
|
16690
|
-
fd = (0,
|
|
16995
|
+
fd = (0, import_node_fs20.openSync)(full, import_node_fs20.constants.O_RDONLY | (NOFOLLOW ?? 0) | (NONBLOCK ?? 0));
|
|
16691
16996
|
} catch (err) {
|
|
16692
16997
|
const code = err.code;
|
|
16693
16998
|
if (code === "ELOOP" || code === "EMLINK" || code === "EFTYPE") return { ok: false, reason: "symlink" };
|
|
@@ -16695,18 +17000,18 @@ function openRegularInRoot(root, path) {
|
|
|
16695
17000
|
return { ok: false, reason: "unreadable" };
|
|
16696
17001
|
}
|
|
16697
17002
|
try {
|
|
16698
|
-
const opened = (0,
|
|
17003
|
+
const opened = (0, import_node_fs20.fstatSync)(fd, { bigint: true });
|
|
16699
17004
|
if (!opened.isFile()) {
|
|
16700
17005
|
closeOpened(fd);
|
|
16701
17006
|
return { ok: false, reason: "not-regular" };
|
|
16702
17007
|
}
|
|
16703
|
-
const realRoot =
|
|
16704
|
-
const realPath =
|
|
17008
|
+
const realRoot = import_node_fs20.realpathSync.native(root);
|
|
17009
|
+
const realPath = import_node_fs20.realpathSync.native(full);
|
|
16705
17010
|
if (!isInsideRoot(realRoot, realPath)) {
|
|
16706
17011
|
closeOpened(fd);
|
|
16707
17012
|
return { ok: false, reason: "outside-root" };
|
|
16708
17013
|
}
|
|
16709
|
-
const current = (0,
|
|
17014
|
+
const current = (0, import_node_fs20.statSync)(realPath, { bigint: true });
|
|
16710
17015
|
if (!sameOpenedFile(opened, current, NOFOLLOW !== void 0)) {
|
|
16711
17016
|
closeOpened(fd);
|
|
16712
17017
|
return { ok: false, reason: NOFOLLOW === void 0 ? "unreadable" : "outside-root" };
|
|
@@ -16728,7 +17033,7 @@ function readOpened(fd, size) {
|
|
|
16728
17033
|
const buffer = Buffer.alloc(size);
|
|
16729
17034
|
let offset = 0;
|
|
16730
17035
|
while (offset < size) {
|
|
16731
|
-
const n = (0,
|
|
17036
|
+
const n = (0, import_node_fs20.readSync)(fd, buffer, offset, size - offset, offset);
|
|
16732
17037
|
if (n === 0) break;
|
|
16733
17038
|
offset += n;
|
|
16734
17039
|
}
|
|
@@ -16822,7 +17127,7 @@ var LANG_MAP = {
|
|
|
16822
17127
|
mk: "make"
|
|
16823
17128
|
};
|
|
16824
17129
|
function detectLanguage(filepath) {
|
|
16825
|
-
const ext = (0,
|
|
17130
|
+
const ext = (0, import_node_path18.extname)(filepath).slice(1);
|
|
16826
17131
|
return LANG_MAP[ext] ?? ext;
|
|
16827
17132
|
}
|
|
16828
17133
|
function sortByMtime(files) {
|
|
@@ -16913,16 +17218,16 @@ function collectCodeDelta(files, opts) {
|
|
|
16913
17218
|
|
|
16914
17219
|
// src/lib/snapshot.ts
|
|
16915
17220
|
function generateSnapshotDiffs(files) {
|
|
16916
|
-
if (!(0,
|
|
17221
|
+
if (!(0, import_node_fs21.existsSync)(SNAPSHOT_DIR)) {
|
|
16917
17222
|
return { diffs: [], has_snapshots: false };
|
|
16918
17223
|
}
|
|
16919
17224
|
const diffs = [];
|
|
16920
17225
|
for (const file of files) {
|
|
16921
17226
|
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
16922
|
-
const snapshotPath = (0,
|
|
17227
|
+
const snapshotPath = (0, import_node_path19.join)(SNAPSHOT_DIR, file.path);
|
|
16923
17228
|
const language = file.language ?? detectLanguage(file.path);
|
|
16924
|
-
if ((0,
|
|
16925
|
-
const oldContent = (0,
|
|
17229
|
+
if ((0, import_node_fs21.existsSync)(snapshotPath)) {
|
|
17230
|
+
const oldContent = (0, import_node_fs21.readFileSync)(snapshotPath, "utf-8");
|
|
16926
17231
|
if (oldContent === file.content) continue;
|
|
16927
17232
|
const diff = computeDiff(oldContent, file.content, file.path);
|
|
16928
17233
|
if (diff) {
|
|
@@ -16947,20 +17252,20 @@ function saveSnapshots(files) {
|
|
|
16947
17252
|
const snapshotPaths = /* @__PURE__ */ new Set();
|
|
16948
17253
|
for (const file of files) {
|
|
16949
17254
|
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
16950
|
-
const snapshotPath = (0,
|
|
17255
|
+
const snapshotPath = (0, import_node_path19.join)(SNAPSHOT_DIR, file.path);
|
|
16951
17256
|
snapshotPaths.add(snapshotPath);
|
|
16952
|
-
(0,
|
|
16953
|
-
(0,
|
|
17257
|
+
(0, import_node_fs21.mkdirSync)((0, import_node_path19.dirname)(snapshotPath), { recursive: true });
|
|
17258
|
+
(0, import_node_fs21.writeFileSync)(snapshotPath, file.content);
|
|
16954
17259
|
}
|
|
16955
17260
|
cleanStaleSnapshots(SNAPSHOT_DIR, snapshotPaths);
|
|
16956
17261
|
}
|
|
16957
17262
|
function computeDiff(oldContent, newContent, filePath) {
|
|
16958
|
-
const tmpOld = (0,
|
|
16959
|
-
const tmpNew = (0,
|
|
17263
|
+
const tmpOld = (0, import_node_path19.join)(SNAPSHOT_DIR, ".diff-old.tmp");
|
|
17264
|
+
const tmpNew = (0, import_node_path19.join)(SNAPSHOT_DIR, ".diff-new.tmp");
|
|
16960
17265
|
try {
|
|
16961
|
-
(0,
|
|
16962
|
-
(0,
|
|
16963
|
-
(0,
|
|
17266
|
+
(0, import_node_fs21.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
|
|
17267
|
+
(0, import_node_fs21.writeFileSync)(tmpOld, oldContent);
|
|
17268
|
+
(0, import_node_fs21.writeFileSync)(tmpNew, newContent);
|
|
16964
17269
|
const result = (0, import_node_child_process7.execSync)(
|
|
16965
17270
|
`git diff --no-index --unified=10 -- "${tmpOld}" "${tmpNew}"`,
|
|
16966
17271
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -16974,32 +17279,32 @@ function computeDiff(oldContent, newContent, filePath) {
|
|
|
16974
17279
|
return null;
|
|
16975
17280
|
} finally {
|
|
16976
17281
|
try {
|
|
16977
|
-
(0,
|
|
17282
|
+
(0, import_node_fs21.unlinkSync)(tmpOld);
|
|
16978
17283
|
} catch {
|
|
16979
17284
|
}
|
|
16980
17285
|
try {
|
|
16981
|
-
(0,
|
|
17286
|
+
(0, import_node_fs21.unlinkSync)(tmpNew);
|
|
16982
17287
|
} catch {
|
|
16983
17288
|
}
|
|
16984
17289
|
}
|
|
16985
17290
|
}
|
|
16986
17291
|
function cleanStaleSnapshots(dir, keepSet) {
|
|
16987
|
-
if (!(0,
|
|
17292
|
+
if (!(0, import_node_fs21.existsSync)(dir)) return;
|
|
16988
17293
|
try {
|
|
16989
|
-
const entries = (0,
|
|
17294
|
+
const entries = (0, import_node_fs21.readdirSync)(dir, { withFileTypes: true });
|
|
16990
17295
|
for (const entry of entries) {
|
|
16991
17296
|
if (dir === SNAPSHOT_DIR && (entry.name === ".diff-old.tmp" || entry.name === ".diff-new.tmp")) continue;
|
|
16992
|
-
const fullPath = (0,
|
|
17297
|
+
const fullPath = (0, import_node_path19.join)(dir, entry.name);
|
|
16993
17298
|
if (entry.isDirectory()) {
|
|
16994
17299
|
cleanStaleSnapshots(fullPath, keepSet);
|
|
16995
17300
|
try {
|
|
16996
|
-
const remaining = (0,
|
|
16997
|
-
if (remaining.length === 0) (0,
|
|
17301
|
+
const remaining = (0, import_node_fs21.readdirSync)(fullPath);
|
|
17302
|
+
if (remaining.length === 0) (0, import_node_fs21.rmdirSync)(fullPath);
|
|
16998
17303
|
} catch {
|
|
16999
17304
|
}
|
|
17000
17305
|
} else if (!keepSet.has(fullPath)) {
|
|
17001
17306
|
try {
|
|
17002
|
-
(0,
|
|
17307
|
+
(0, import_node_fs21.unlinkSync)(fullPath);
|
|
17003
17308
|
} catch {
|
|
17004
17309
|
}
|
|
17005
17310
|
}
|
|
@@ -17018,20 +17323,20 @@ function sessionKey(sessionId) {
|
|
|
17018
17323
|
return (0, import_node_crypto9.createHash)("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
17019
17324
|
}
|
|
17020
17325
|
function sessionDir(key) {
|
|
17021
|
-
return (0,
|
|
17326
|
+
return (0, import_node_path20.join)(projectPath(BASELINE_DIR), key);
|
|
17022
17327
|
}
|
|
17023
17328
|
function manifestPath(dir) {
|
|
17024
|
-
return (0,
|
|
17329
|
+
return (0, import_node_path20.join)(dir, "manifest.json");
|
|
17025
17330
|
}
|
|
17026
17331
|
function mirrorPath(dir, repoRelPath) {
|
|
17027
|
-
return (0,
|
|
17332
|
+
return (0, import_node_path20.join)(dir, "files", repoRelPath);
|
|
17028
17333
|
}
|
|
17029
17334
|
var CARRY_FILE = `${BASELINE_DIR}/.carry`;
|
|
17030
17335
|
var CARRY_WINDOW_MS = 12e4;
|
|
17031
17336
|
function writeCarry(sessionId, headSha) {
|
|
17032
17337
|
try {
|
|
17033
|
-
(0,
|
|
17034
|
-
(0,
|
|
17338
|
+
(0, import_node_fs22.mkdirSync)(projectPath(BASELINE_DIR), { recursive: true });
|
|
17339
|
+
(0, import_node_fs22.writeFileSync)(
|
|
17035
17340
|
projectPath(CARRY_FILE),
|
|
17036
17341
|
JSON.stringify({ from_key: sessionKey(sessionId), head_sha: headSha, ts: Date.now() })
|
|
17037
17342
|
);
|
|
@@ -17041,10 +17346,10 @@ function writeCarry(sessionId, headSha) {
|
|
|
17041
17346
|
function claimCarry(newKey) {
|
|
17042
17347
|
const carryPath = projectPath(CARRY_FILE);
|
|
17043
17348
|
try {
|
|
17044
|
-
if (!(0,
|
|
17045
|
-
const carry = JSON.parse((0,
|
|
17349
|
+
if (!(0, import_node_fs22.existsSync)(carryPath)) return null;
|
|
17350
|
+
const carry = JSON.parse((0, import_node_fs22.readFileSync)(carryPath, "utf-8"));
|
|
17046
17351
|
try {
|
|
17047
|
-
(0,
|
|
17352
|
+
(0, import_node_fs22.rmSync)(carryPath, { force: true });
|
|
17048
17353
|
} catch {
|
|
17049
17354
|
}
|
|
17050
17355
|
if (!carry?.from_key || typeof carry.ts !== "number") return null;
|
|
@@ -17055,11 +17360,11 @@ function claimCarry(newKey) {
|
|
|
17055
17360
|
if (!prior) return null;
|
|
17056
17361
|
const toDir = sessionDir(newKey);
|
|
17057
17362
|
try {
|
|
17058
|
-
(0,
|
|
17363
|
+
(0, import_node_fs22.rmSync)(toDir, { recursive: true, force: true });
|
|
17059
17364
|
} catch {
|
|
17060
17365
|
}
|
|
17061
|
-
(0,
|
|
17062
|
-
(0,
|
|
17366
|
+
(0, import_node_fs22.renameSync)(fromDir, toDir);
|
|
17367
|
+
(0, import_node_fs22.writeFileSync)(manifestPath(toDir), JSON.stringify({ ...prior, session_id: newKey }) + "\n");
|
|
17063
17368
|
return readManifest(toDir);
|
|
17064
17369
|
} catch {
|
|
17065
17370
|
return null;
|
|
@@ -17083,21 +17388,21 @@ function captureBaseline(opts = {}) {
|
|
|
17083
17388
|
const head_sha = getCurrentCommit();
|
|
17084
17389
|
const dirty = getDirtyFiles();
|
|
17085
17390
|
try {
|
|
17086
|
-
(0,
|
|
17391
|
+
(0, import_node_fs22.rmSync)(dir, { recursive: true, force: true });
|
|
17087
17392
|
} catch {
|
|
17088
17393
|
}
|
|
17089
|
-
const filesDir = (0,
|
|
17394
|
+
const filesDir = (0, import_node_path20.join)(dir, "files");
|
|
17090
17395
|
const mirrored = [];
|
|
17091
17396
|
try {
|
|
17092
|
-
(0,
|
|
17397
|
+
(0, import_node_fs22.mkdirSync)(filesDir, { recursive: true });
|
|
17093
17398
|
for (const p of dirty) {
|
|
17094
17399
|
if (p.includes("..")) continue;
|
|
17095
17400
|
const content = safeReadForMirror(projectPath(p));
|
|
17096
17401
|
if (content === null) continue;
|
|
17097
17402
|
const dest = mirrorPath(dir, p);
|
|
17098
17403
|
try {
|
|
17099
|
-
(0,
|
|
17100
|
-
(0,
|
|
17404
|
+
(0, import_node_fs22.mkdirSync)((0, import_node_path20.dirname)(dest), { recursive: true });
|
|
17405
|
+
(0, import_node_fs22.writeFileSync)(dest, content);
|
|
17101
17406
|
mirrored.push(p);
|
|
17102
17407
|
} catch {
|
|
17103
17408
|
}
|
|
@@ -17112,8 +17417,8 @@ function captureBaseline(opts = {}) {
|
|
|
17112
17417
|
version: BASELINE_VERSION
|
|
17113
17418
|
};
|
|
17114
17419
|
try {
|
|
17115
|
-
(0,
|
|
17116
|
-
(0,
|
|
17420
|
+
(0, import_node_fs22.mkdirSync)(dir, { recursive: true });
|
|
17421
|
+
(0, import_node_fs22.writeFileSync)(manifestPath(dir), JSON.stringify(baseline));
|
|
17117
17422
|
} catch {
|
|
17118
17423
|
}
|
|
17119
17424
|
pruneOldBaselines();
|
|
@@ -17124,9 +17429,9 @@ function readBaseline(sessionId) {
|
|
|
17124
17429
|
}
|
|
17125
17430
|
function readManifest(dir) {
|
|
17126
17431
|
const mp = manifestPath(dir);
|
|
17127
|
-
if (!(0,
|
|
17432
|
+
if (!(0, import_node_fs22.existsSync)(mp)) return null;
|
|
17128
17433
|
try {
|
|
17129
|
-
const parsed = JSON.parse((0,
|
|
17434
|
+
const parsed = JSON.parse((0, import_node_fs22.readFileSync)(mp, "utf-8"));
|
|
17130
17435
|
if (typeof parsed.head_sha !== "string" || typeof parsed.captured_at !== "number" || !Array.isArray(parsed.dirty_paths) || parsed.version !== BASELINE_VERSION) {
|
|
17131
17436
|
return null;
|
|
17132
17437
|
}
|
|
@@ -17157,9 +17462,9 @@ function preImage(repoRelPath, baseline) {
|
|
|
17157
17462
|
function resolvePreImage(repoRelPath, baseline) {
|
|
17158
17463
|
if (baseline.dirty_paths.includes(repoRelPath)) {
|
|
17159
17464
|
const mp = mirrorPath(sessionDir(sessionKey(baseline.session_id)), repoRelPath);
|
|
17160
|
-
if ((0,
|
|
17465
|
+
if ((0, import_node_fs22.existsSync)(mp)) {
|
|
17161
17466
|
try {
|
|
17162
|
-
return { content: (0,
|
|
17467
|
+
return { content: (0, import_node_fs22.readFileSync)(mp, "utf-8"), existed: true };
|
|
17163
17468
|
} catch {
|
|
17164
17469
|
}
|
|
17165
17470
|
}
|
|
@@ -17204,8 +17509,8 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
17204
17509
|
const content = safeReadForMirror(projectPath(p));
|
|
17205
17510
|
if (content === null) continue;
|
|
17206
17511
|
const dest = mirrorPath(dir, p);
|
|
17207
|
-
(0,
|
|
17208
|
-
(0,
|
|
17512
|
+
(0, import_node_fs22.mkdirSync)((0, import_node_path20.dirname)(dest), { recursive: true });
|
|
17513
|
+
(0, import_node_fs22.writeFileSync)(dest, content);
|
|
17209
17514
|
dirty.add(p);
|
|
17210
17515
|
adopted++;
|
|
17211
17516
|
} catch {
|
|
@@ -17214,7 +17519,7 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
17214
17519
|
if (adopted === 0) return 0;
|
|
17215
17520
|
try {
|
|
17216
17521
|
const updated = { ...baseline, dirty_paths: [...dirty] };
|
|
17217
|
-
(0,
|
|
17522
|
+
(0, import_node_fs22.writeFileSync)(manifestPath(dir), JSON.stringify(updated));
|
|
17218
17523
|
preImageCache.delete(baseline);
|
|
17219
17524
|
} catch {
|
|
17220
17525
|
return 0;
|
|
@@ -17225,7 +17530,7 @@ function changedSinceBaseline(repoRelPath, baseline) {
|
|
|
17225
17530
|
const pre = preImage(repoRelPath, baseline);
|
|
17226
17531
|
let current;
|
|
17227
17532
|
try {
|
|
17228
|
-
current = (0,
|
|
17533
|
+
current = (0, import_node_fs22.readFileSync)(projectPath(repoRelPath), "utf-8");
|
|
17229
17534
|
} catch {
|
|
17230
17535
|
return pre.existed;
|
|
17231
17536
|
}
|
|
@@ -17234,8 +17539,8 @@ function changedSinceBaseline(repoRelPath, baseline) {
|
|
|
17234
17539
|
}
|
|
17235
17540
|
function safeReadForMirror(absPath) {
|
|
17236
17541
|
try {
|
|
17237
|
-
if ((0,
|
|
17238
|
-
const buf = (0,
|
|
17542
|
+
if ((0, import_node_fs22.statSync)(absPath).size > MIRROR_MAX_BYTES) return null;
|
|
17543
|
+
const buf = (0, import_node_fs22.readFileSync)(absPath);
|
|
17239
17544
|
if (buf.includes(0)) return null;
|
|
17240
17545
|
return buf.toString("utf-8");
|
|
17241
17546
|
} catch {
|
|
@@ -17246,18 +17551,18 @@ function pruneOldBaselines() {
|
|
|
17246
17551
|
const root = projectPath(BASELINE_DIR);
|
|
17247
17552
|
let entries;
|
|
17248
17553
|
try {
|
|
17249
|
-
entries = (0,
|
|
17554
|
+
entries = (0, import_node_fs22.readdirSync)(root);
|
|
17250
17555
|
} catch {
|
|
17251
17556
|
return;
|
|
17252
17557
|
}
|
|
17253
17558
|
const now = Date.now();
|
|
17254
17559
|
for (const name of entries) {
|
|
17255
|
-
const dir = (0,
|
|
17560
|
+
const dir = (0, import_node_path20.join)(root, name);
|
|
17256
17561
|
const manifest = readManifest(dir);
|
|
17257
17562
|
if (!manifest) {
|
|
17258
17563
|
try {
|
|
17259
|
-
if (now - (0,
|
|
17260
|
-
(0,
|
|
17564
|
+
if (now - (0, import_node_fs22.statSync)(dir).mtimeMs > BASELINE_TTL_MS) {
|
|
17565
|
+
(0, import_node_fs22.rmSync)(dir, { recursive: true, force: true });
|
|
17261
17566
|
}
|
|
17262
17567
|
} catch {
|
|
17263
17568
|
}
|
|
@@ -17265,7 +17570,7 @@ function pruneOldBaselines() {
|
|
|
17265
17570
|
}
|
|
17266
17571
|
if (now - manifest.captured_at <= BASELINE_TTL_MS) continue;
|
|
17267
17572
|
try {
|
|
17268
|
-
(0,
|
|
17573
|
+
(0, import_node_fs22.rmSync)(dir, { recursive: true, force: true });
|
|
17269
17574
|
} catch {
|
|
17270
17575
|
}
|
|
17271
17576
|
}
|
|
@@ -17440,8 +17745,8 @@ function buildCompactionContext(session) {
|
|
|
17440
17745
|
commitsSince: commitsSincePaths(watermark, (state.authored ?? []).map((a) => a.path)),
|
|
17441
17746
|
readFileLines: (file) => {
|
|
17442
17747
|
try {
|
|
17443
|
-
const abs = (0,
|
|
17444
|
-
return (0,
|
|
17748
|
+
const abs = (0, import_node_path21.join)(root, file);
|
|
17749
|
+
return (0, import_node_fs23.existsSync)(abs) ? (0, import_node_fs23.readFileSync)(abs, "utf8").split("\n") : null;
|
|
17445
17750
|
} catch {
|
|
17446
17751
|
return null;
|
|
17447
17752
|
}
|
|
@@ -17497,25 +17802,25 @@ async function readHookStdin() {
|
|
|
17497
17802
|
}
|
|
17498
17803
|
|
|
17499
17804
|
// src/commands/standard.ts
|
|
17500
|
-
var
|
|
17501
|
-
var
|
|
17805
|
+
var import_promises13 = require("node:fs/promises");
|
|
17806
|
+
var import_node_fs30 = require("node:fs");
|
|
17502
17807
|
var import_yaml3 = __toESM(require_dist());
|
|
17503
17808
|
|
|
17504
17809
|
// src/lib/synthesize.ts
|
|
17505
17810
|
var import_node_child_process9 = require("node:child_process");
|
|
17506
|
-
var
|
|
17507
|
-
var
|
|
17508
|
-
var
|
|
17811
|
+
var import_node_fs26 = require("node:fs");
|
|
17812
|
+
var import_promises10 = require("node:fs/promises");
|
|
17813
|
+
var import_node_path24 = require("node:path");
|
|
17509
17814
|
var import_yaml = __toESM(require_dist());
|
|
17510
17815
|
|
|
17511
17816
|
// src/lib/data-dir.ts
|
|
17512
|
-
var
|
|
17513
|
-
var
|
|
17817
|
+
var import_node_fs24 = require("node:fs");
|
|
17818
|
+
var import_node_path22 = require("node:path");
|
|
17514
17819
|
function resolveDataDir() {
|
|
17515
17820
|
const candidates2 = [
|
|
17516
|
-
(0,
|
|
17821
|
+
(0, import_node_path22.join)(__dirname, "..", "data"),
|
|
17517
17822
|
// installed: node_modules/@codacy/verity-cli/data
|
|
17518
|
-
(0,
|
|
17823
|
+
(0, import_node_path22.join)(__dirname, "..", "..", "data"),
|
|
17519
17824
|
// edge case: nested resolution
|
|
17520
17825
|
// THE COMMITTED SOURCE, for a source checkout that has not been built.
|
|
17521
17826
|
// cli/data/skills/ is a BUILD ARTIFACT (scripts/build.js copies client/skills
|
|
@@ -17524,14 +17829,14 @@ function resolveDataDir() {
|
|
|
17524
17829
|
// without this the synthesizer throws "Could not find Verity skill data"
|
|
17525
17830
|
// for every test and every `verity` run from source. Resolved from this
|
|
17526
17831
|
// module's own location, never the cwd: see the warning below.
|
|
17527
|
-
(0,
|
|
17832
|
+
(0, import_node_path22.join)(__dirname, "..", "..", "client"),
|
|
17528
17833
|
// bundled: cli/bin/ → ../../client
|
|
17529
|
-
(0,
|
|
17834
|
+
(0, import_node_path22.join)(__dirname, "..", "..", "..", "client"),
|
|
17530
17835
|
// tsx: cli/src/lib/ → ../../../client
|
|
17531
17836
|
...process.env.VERITY_DEV_DATA_DIR ? [process.env.VERITY_DEV_DATA_DIR] : []
|
|
17532
17837
|
];
|
|
17533
17838
|
for (const candidate of candidates2) {
|
|
17534
|
-
if ((0,
|
|
17839
|
+
if ((0, import_node_fs24.existsSync)((0, import_node_path22.join)(candidate, "skills"))) {
|
|
17535
17840
|
return candidate;
|
|
17536
17841
|
}
|
|
17537
17842
|
}
|
|
@@ -17540,13 +17845,13 @@ function resolveDataDir() {
|
|
|
17540
17845
|
);
|
|
17541
17846
|
}
|
|
17542
17847
|
function setupDataPath(file) {
|
|
17543
|
-
return (0,
|
|
17848
|
+
return (0, import_node_path22.join)(resolveDataDir(), "skills", "verity-setup", file);
|
|
17544
17849
|
}
|
|
17545
17850
|
|
|
17546
17851
|
// src/lib/detect.ts
|
|
17547
17852
|
var import_node_child_process8 = require("node:child_process");
|
|
17548
|
-
var
|
|
17549
|
-
var
|
|
17853
|
+
var import_node_fs25 = require("node:fs");
|
|
17854
|
+
var import_node_path23 = require("node:path");
|
|
17550
17855
|
var TOOLED_LANGUAGES = /* @__PURE__ */ new Set([
|
|
17551
17856
|
"typescript",
|
|
17552
17857
|
"javascript",
|
|
@@ -17603,25 +17908,25 @@ function walk(root) {
|
|
|
17603
17908
|
if (depth > WALK_MAX_DEPTH || found.length >= WALK_MAX_FILES) return;
|
|
17604
17909
|
let entries;
|
|
17605
17910
|
try {
|
|
17606
|
-
entries = (0,
|
|
17911
|
+
entries = (0, import_node_fs25.readdirSync)(dir, { withFileTypes: true });
|
|
17607
17912
|
} catch {
|
|
17608
17913
|
return;
|
|
17609
17914
|
}
|
|
17610
17915
|
for (const entry of entries) {
|
|
17611
17916
|
if (found.length >= WALK_MAX_FILES) return;
|
|
17612
17917
|
if (IGNORED_SEGMENTS.includes(entry.name)) continue;
|
|
17613
|
-
const full = (0,
|
|
17918
|
+
const full = (0, import_node_path23.join)(dir, entry.name);
|
|
17614
17919
|
if (entry.isDirectory()) visit(full, depth + 1);
|
|
17615
|
-
else if (entry.isFile()) found.push((0,
|
|
17920
|
+
else if (entry.isFile()) found.push((0, import_node_path23.relative)(root, full));
|
|
17616
17921
|
}
|
|
17617
17922
|
};
|
|
17618
17923
|
visit(root, 0);
|
|
17619
17924
|
return found;
|
|
17620
17925
|
}
|
|
17621
17926
|
function languageOf(path) {
|
|
17622
|
-
const name = (0,
|
|
17927
|
+
const name = (0, import_node_path23.basename)(path);
|
|
17623
17928
|
if (/^Dockerfile(\..+)?$/i.test(name)) return "dockerfile";
|
|
17624
|
-
if (!(0,
|
|
17929
|
+
if (!(0, import_node_path23.extname)(name)) return null;
|
|
17625
17930
|
const lang = detectLanguage(path);
|
|
17626
17931
|
return lang || null;
|
|
17627
17932
|
}
|
|
@@ -17678,7 +17983,7 @@ var TOOL_CONFIG_MARKERS = [
|
|
|
17678
17983
|
];
|
|
17679
17984
|
function readJson(path) {
|
|
17680
17985
|
try {
|
|
17681
|
-
return JSON.parse((0,
|
|
17986
|
+
return JSON.parse((0, import_node_fs25.readFileSync)(path, "utf-8"));
|
|
17682
17987
|
} catch {
|
|
17683
17988
|
return null;
|
|
17684
17989
|
}
|
|
@@ -17703,17 +18008,17 @@ function declaredDependencies(root, files) {
|
|
|
17703
18008
|
if (deps && typeof deps === "object") names2.push(...Object.keys(deps));
|
|
17704
18009
|
}
|
|
17705
18010
|
};
|
|
17706
|
-
readPackageJson((0,
|
|
17707
|
-
const nested = files.filter((f) => f.includes("/") && (0,
|
|
17708
|
-
for (const rel of nested) readPackageJson((0,
|
|
18011
|
+
readPackageJson((0, import_node_path23.join)(root, "package.json"));
|
|
18012
|
+
const nested = files.filter((f) => f.includes("/") && (0, import_node_path23.basename)(f) === "package.json").slice(0, NESTED_MANIFEST_LIMIT);
|
|
18013
|
+
for (const rel of nested) readPackageJson((0, import_node_path23.join)(root, rel));
|
|
17709
18014
|
const pythonManifests = [
|
|
17710
|
-
...["pyproject.toml", "requirements.txt", "Pipfile", "setup.py"].map((f) => (0,
|
|
17711
|
-
...files.filter((f) => f.includes("/") && /(^|\/)(pyproject\.toml|requirements\.txt)$/.test(f)).slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0,
|
|
18015
|
+
...["pyproject.toml", "requirements.txt", "Pipfile", "setup.py"].map((f) => (0, import_node_path23.join)(root, f)),
|
|
18016
|
+
...files.filter((f) => f.includes("/") && /(^|\/)(pyproject\.toml|requirements\.txt)$/.test(f)).slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path23.join)(root, f))
|
|
17712
18017
|
];
|
|
17713
18018
|
for (const path of pythonManifests) {
|
|
17714
|
-
if (!(0,
|
|
18019
|
+
if (!(0, import_node_fs25.existsSync)(path)) continue;
|
|
17715
18020
|
try {
|
|
17716
|
-
const text = (0,
|
|
18021
|
+
const text = (0, import_node_fs25.readFileSync)(path, "utf-8");
|
|
17717
18022
|
for (const m of text.matchAll(/^\s*["']?([A-Za-z][A-Za-z0-9._-]+)/gm)) names2.push(m[1]);
|
|
17718
18023
|
for (const line of text.split("\n")) {
|
|
17719
18024
|
if (!/dependencies\s*=/.test(line)) continue;
|
|
@@ -17723,13 +18028,13 @@ function declaredDependencies(root, files) {
|
|
|
17723
18028
|
}
|
|
17724
18029
|
}
|
|
17725
18030
|
const goMods = [
|
|
17726
|
-
(0,
|
|
17727
|
-
...files.filter((f) => f.includes("/") && (0,
|
|
18031
|
+
(0, import_node_path23.join)(root, "go.mod"),
|
|
18032
|
+
...files.filter((f) => f.includes("/") && (0, import_node_path23.basename)(f) === "go.mod").slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path23.join)(root, f))
|
|
17728
18033
|
];
|
|
17729
18034
|
for (const path of goMods) {
|
|
17730
|
-
if (!(0,
|
|
18035
|
+
if (!(0, import_node_fs25.existsSync)(path)) continue;
|
|
17731
18036
|
try {
|
|
17732
|
-
const text = (0,
|
|
18037
|
+
const text = (0, import_node_fs25.readFileSync)(path, "utf-8");
|
|
17733
18038
|
for (const m of text.matchAll(/^\s+([\w.-]+\/[\w./-]+)\s+v/gm)) {
|
|
17734
18039
|
names2.push(m[1].replace(/^github\.com\//, ""));
|
|
17735
18040
|
}
|
|
@@ -17737,10 +18042,10 @@ function declaredDependencies(root, files) {
|
|
|
17737
18042
|
}
|
|
17738
18043
|
}
|
|
17739
18044
|
for (const file of ["pom.xml", "build.gradle", "build.gradle.kts", "Gemfile", "Cargo.toml"]) {
|
|
17740
|
-
const path = (0,
|
|
17741
|
-
if (!(0,
|
|
18045
|
+
const path = (0, import_node_path23.join)(root, file);
|
|
18046
|
+
if (!(0, import_node_fs25.existsSync)(path)) continue;
|
|
17742
18047
|
try {
|
|
17743
|
-
const text = (0,
|
|
18048
|
+
const text = (0, import_node_fs25.readFileSync)(path, "utf-8");
|
|
17744
18049
|
for (const m of text.matchAll(/["'<]([A-Za-z][A-Za-z0-9._-]{2,})["'>]/g)) names2.push(m[1]);
|
|
17745
18050
|
} catch {
|
|
17746
18051
|
}
|
|
@@ -17748,7 +18053,7 @@ function declaredDependencies(root, files) {
|
|
|
17748
18053
|
return names2;
|
|
17749
18054
|
}
|
|
17750
18055
|
function detectBuildSystem(root, files) {
|
|
17751
|
-
const has = (f) => (0,
|
|
18056
|
+
const has = (f) => (0, import_node_fs25.existsSync)((0, import_node_path23.join)(root, f)) || files.some((p) => (0, import_node_path23.basename)(p) === f);
|
|
17752
18057
|
if (has("pnpm-lock.yaml")) return "pnpm";
|
|
17753
18058
|
if (has("yarn.lock")) return "yarn";
|
|
17754
18059
|
if (has("bun.lock") || has("bun.lockb")) return "bun";
|
|
@@ -17765,8 +18070,8 @@ function detectBuildSystem(root, files) {
|
|
|
17765
18070
|
}
|
|
17766
18071
|
function detectArchitecture(root, files) {
|
|
17767
18072
|
const workspaceMarkers = ["lerna.json", "pnpm-workspace.yaml", "nx.json", "turbo.json", "rush.json"];
|
|
17768
|
-
if (workspaceMarkers.some((m) => (0,
|
|
17769
|
-
const pkg = readJson((0,
|
|
18073
|
+
if (workspaceMarkers.some((m) => (0, import_node_fs25.existsSync)((0, import_node_path23.join)(root, m)))) return "monorepo";
|
|
18074
|
+
const pkg = readJson((0, import_node_path23.join)(root, "package.json"));
|
|
17770
18075
|
if (pkg && "workspaces" in pkg) return "monorepo";
|
|
17771
18076
|
const manifests = files.filter((f) => /(^|\/)(package\.json|go\.mod|pyproject\.toml|Cargo\.toml|pom\.xml)$/.test(f));
|
|
17772
18077
|
const nested = manifests.filter((f) => f.includes("/"));
|
|
@@ -17788,10 +18093,10 @@ function measureAvgFileLength(root, files, languages) {
|
|
|
17788
18093
|
let total = 0;
|
|
17789
18094
|
let counted = 0;
|
|
17790
18095
|
for (let i = 0; i < candidates2.length; i += stride) {
|
|
17791
|
-
const path = (0,
|
|
18096
|
+
const path = (0, import_node_path23.join)(root, candidates2[i]);
|
|
17792
18097
|
try {
|
|
17793
|
-
if ((0,
|
|
17794
|
-
total += (0,
|
|
18098
|
+
if ((0, import_node_fs25.statSync)(path).size > 2 * 1024 * 1024) continue;
|
|
18099
|
+
total += (0, import_node_fs25.readFileSync)(path, "utf-8").split("\n").length;
|
|
17795
18100
|
counted++;
|
|
17796
18101
|
} catch {
|
|
17797
18102
|
}
|
|
@@ -17821,14 +18126,14 @@ function detectProject(root = repoRoot()) {
|
|
|
17821
18126
|
const existingToolConfigs = [];
|
|
17822
18127
|
for (const [tool, markers] of TOOL_CONFIG_MARKERS) {
|
|
17823
18128
|
for (const marker of markers) {
|
|
17824
|
-
if ((0,
|
|
18129
|
+
if ((0, import_node_fs25.existsSync)((0, import_node_path23.join)(root, marker))) {
|
|
17825
18130
|
existingToolConfigs.push({ tool, path: `./${marker}` });
|
|
17826
18131
|
break;
|
|
17827
18132
|
}
|
|
17828
18133
|
}
|
|
17829
18134
|
}
|
|
17830
18135
|
return {
|
|
17831
|
-
projectName: (0,
|
|
18136
|
+
projectName: (0, import_node_path23.basename)(root),
|
|
17832
18137
|
languages,
|
|
17833
18138
|
languageCounts,
|
|
17834
18139
|
frameworks: matchAll(dependencies, FRAMEWORK_BY_DEPENDENCY),
|
|
@@ -17926,8 +18231,8 @@ ${closingNote(input.origin)}
|
|
|
17926
18231
|
|
|
17927
18232
|
// src/lib/synthesize.ts
|
|
17928
18233
|
function loadCatalog() {
|
|
17929
|
-
const catalog = (0, import_yaml.parse)((0,
|
|
17930
|
-
const template = (0, import_yaml.parse)((0,
|
|
18234
|
+
const catalog = (0, import_yaml.parse)((0, import_node_fs26.readFileSync)(setupDataPath("patterns-reference.yaml"), "utf-8"));
|
|
18235
|
+
const template = (0, import_yaml.parse)((0, import_node_fs26.readFileSync)(setupDataPath("standard-template.yaml"), "utf-8"));
|
|
17931
18236
|
return { catalog, template };
|
|
17932
18237
|
}
|
|
17933
18238
|
function selectTools(languages, intensity, catalog) {
|
|
@@ -18205,7 +18510,7 @@ function validatePatternIds() {
|
|
|
18205
18510
|
}
|
|
18206
18511
|
async function runSynthesis(opts) {
|
|
18207
18512
|
const standardPath = projectPath(STANDARD_FILE);
|
|
18208
|
-
if ((0,
|
|
18513
|
+
if ((0, import_node_fs26.existsSync)(standardPath) && !opts.force) {
|
|
18209
18514
|
return { refused: `${STANDARD_FILE} already exists \u2014 pass --force to replace it.` };
|
|
18210
18515
|
}
|
|
18211
18516
|
const detected = opts.detected ?? detectProject();
|
|
@@ -18274,8 +18579,8 @@ async function correctVerityMdVersion(opts) {
|
|
|
18274
18579
|
}
|
|
18275
18580
|
async function writeFileTo(relative2, body) {
|
|
18276
18581
|
const target = projectPath(relative2);
|
|
18277
|
-
await (0,
|
|
18278
|
-
await (0,
|
|
18582
|
+
await (0, import_promises10.mkdir)((0, import_node_path24.dirname)(target), { recursive: true });
|
|
18583
|
+
await (0, import_promises10.writeFile)(target, body);
|
|
18279
18584
|
}
|
|
18280
18585
|
async function deriveConfigForStandard(standard) {
|
|
18281
18586
|
const spec = standard.knowledge_spec ?? {};
|
|
@@ -18332,14 +18637,14 @@ ${validation.detail}`);
|
|
|
18332
18637
|
}
|
|
18333
18638
|
|
|
18334
18639
|
// src/lib/setup-state.ts
|
|
18335
|
-
var
|
|
18336
|
-
var
|
|
18640
|
+
var import_promises11 = require("node:fs/promises");
|
|
18641
|
+
var import_node_fs27 = require("node:fs");
|
|
18337
18642
|
var SETUP_STATE_FILE = `${VERITY_DIR}/setup.json`;
|
|
18338
18643
|
async function readSetupState() {
|
|
18339
18644
|
const path = projectPath(SETUP_STATE_FILE);
|
|
18340
|
-
if (!(0,
|
|
18645
|
+
if (!(0, import_node_fs27.existsSync)(path)) return null;
|
|
18341
18646
|
try {
|
|
18342
|
-
const parsed = JSON.parse(await (0,
|
|
18647
|
+
const parsed = JSON.parse(await (0, import_promises11.readFile)(path, "utf-8"));
|
|
18343
18648
|
return parsed && typeof parsed === "object" ? parsed : null;
|
|
18344
18649
|
} catch {
|
|
18345
18650
|
return null;
|
|
@@ -18353,12 +18658,12 @@ async function writeSetupState(patch) {
|
|
|
18353
18658
|
}
|
|
18354
18659
|
|
|
18355
18660
|
// src/lib/push-setup.ts
|
|
18356
|
-
var
|
|
18357
|
-
var
|
|
18661
|
+
var import_node_fs29 = require("node:fs");
|
|
18662
|
+
var import_promises12 = require("node:fs/promises");
|
|
18358
18663
|
var import_yaml2 = __toESM(require_dist());
|
|
18359
18664
|
|
|
18360
18665
|
// src/lib/verityignore.ts
|
|
18361
|
-
var
|
|
18666
|
+
var import_node_fs28 = require("node:fs");
|
|
18362
18667
|
var EMPTY = { rules: [], securityOverlap: [], problems: [] };
|
|
18363
18668
|
var SECURITY_PROBES = [
|
|
18364
18669
|
".env",
|
|
@@ -18451,9 +18756,9 @@ function isIgnored3(ig, path) {
|
|
|
18451
18756
|
}
|
|
18452
18757
|
function loadVerityIgnore() {
|
|
18453
18758
|
const file = projectPath(VERITYIGNORE_FILE);
|
|
18454
|
-
if (!(0,
|
|
18759
|
+
if (!(0, import_node_fs28.existsSync)(file)) return EMPTY;
|
|
18455
18760
|
try {
|
|
18456
|
-
return parseVerityIgnore((0,
|
|
18761
|
+
return parseVerityIgnore((0, import_node_fs28.readFileSync)(file, "utf-8"));
|
|
18457
18762
|
} catch {
|
|
18458
18763
|
return EMPTY;
|
|
18459
18764
|
}
|
|
@@ -18491,9 +18796,9 @@ function buildStandardUpload(standard, ignoreRaw) {
|
|
|
18491
18796
|
}
|
|
18492
18797
|
function readVerityIgnoreRaw() {
|
|
18493
18798
|
const file = projectPath(VERITYIGNORE_FILE);
|
|
18494
|
-
if (!(0,
|
|
18799
|
+
if (!(0, import_node_fs28.existsSync)(file)) return null;
|
|
18495
18800
|
try {
|
|
18496
|
-
return (0,
|
|
18801
|
+
return (0, import_node_fs28.readFileSync)(file, "utf-8");
|
|
18497
18802
|
} catch {
|
|
18498
18803
|
return null;
|
|
18499
18804
|
}
|
|
@@ -18521,9 +18826,9 @@ async function pushStandardAndConfig(globals, what = {}) {
|
|
|
18521
18826
|
}
|
|
18522
18827
|
let standardVersion = null;
|
|
18523
18828
|
const standardPath = projectPath(STANDARD_FILE);
|
|
18524
|
-
if (pushStandard && (0,
|
|
18829
|
+
if (pushStandard && (0, import_node_fs29.existsSync)(standardPath)) {
|
|
18525
18830
|
try {
|
|
18526
|
-
const content = (0, import_yaml2.parse)(await (0,
|
|
18831
|
+
const content = (0, import_yaml2.parse)(await (0, import_promises12.readFile)(standardPath, "utf-8"));
|
|
18527
18832
|
const upload = buildStandardUpload(content, readVerityIgnoreRaw());
|
|
18528
18833
|
if (upload.warning) lines.push(upload.warning);
|
|
18529
18834
|
const result = await apiRequest({
|
|
@@ -18546,9 +18851,9 @@ async function pushStandardAndConfig(globals, what = {}) {
|
|
|
18546
18851
|
}
|
|
18547
18852
|
let configPushed = false;
|
|
18548
18853
|
const configPath = projectPath(CODACY_CONFIG_FILE);
|
|
18549
|
-
if (pushConfig && (0,
|
|
18854
|
+
if (pushConfig && (0, import_node_fs29.existsSync)(configPath)) {
|
|
18550
18855
|
try {
|
|
18551
|
-
const content = JSON.parse(await (0,
|
|
18856
|
+
const content = JSON.parse(await (0, import_promises12.readFile)(configPath, "utf-8"));
|
|
18552
18857
|
const result = await apiRequest({
|
|
18553
18858
|
method: "POST",
|
|
18554
18859
|
path: "/analysis-configs",
|
|
@@ -18578,11 +18883,11 @@ function registerStandardCommands(program2) {
|
|
|
18578
18883
|
const state = await readSetupState();
|
|
18579
18884
|
if (opts.configOnly) {
|
|
18580
18885
|
const standardPath = projectPath(STANDARD_FILE);
|
|
18581
|
-
if (!(0,
|
|
18886
|
+
if (!(0, import_node_fs30.existsSync)(standardPath)) {
|
|
18582
18887
|
printError(`No ${STANDARD_FILE} here \u2014 run "verity standard synthesize" to create one.`);
|
|
18583
18888
|
process.exit(1);
|
|
18584
18889
|
}
|
|
18585
|
-
const content = (0, import_yaml3.parse)(await (0,
|
|
18890
|
+
const content = (0, import_yaml3.parse)(await (0, import_promises13.readFile)(standardPath, "utf-8"));
|
|
18586
18891
|
const derived = await deriveConfigForStandard(content);
|
|
18587
18892
|
for (const path of derived.written) printInfo(` ${path} \u2713`);
|
|
18588
18893
|
for (const note of derived.notes) printWarn(` ${note}`);
|
|
@@ -18638,7 +18943,7 @@ function registerStandardCommands(program2) {
|
|
|
18638
18943
|
}
|
|
18639
18944
|
let yamlContent;
|
|
18640
18945
|
try {
|
|
18641
|
-
yamlContent = await (0,
|
|
18946
|
+
yamlContent = await (0, import_promises13.readFile)(opts.file, "utf-8");
|
|
18642
18947
|
} catch {
|
|
18643
18948
|
printError(`Cannot read ${opts.file}`);
|
|
18644
18949
|
process.exit(1);
|
|
@@ -18735,7 +19040,7 @@ function parseIntensity(value) {
|
|
|
18735
19040
|
}
|
|
18736
19041
|
|
|
18737
19042
|
// src/commands/config.ts
|
|
18738
|
-
var
|
|
19043
|
+
var import_promises14 = require("node:fs/promises");
|
|
18739
19044
|
function registerConfigCommands(program2) {
|
|
18740
19045
|
const config = program2.command("config").description("Manage analysis configuration");
|
|
18741
19046
|
config.command("service-url").description("Print the resolved service URL (used by the shipped skills)").action(async () => {
|
|
@@ -18781,7 +19086,7 @@ function registerConfigCommands(program2) {
|
|
|
18781
19086
|
}
|
|
18782
19087
|
let content;
|
|
18783
19088
|
try {
|
|
18784
|
-
const raw = await (0,
|
|
19089
|
+
const raw = await (0, import_promises14.readFile)(opts.file, "utf-8");
|
|
18785
19090
|
content = JSON.parse(raw);
|
|
18786
19091
|
} catch {
|
|
18787
19092
|
printError(`Cannot read or parse ${opts.file}`);
|
|
@@ -18909,10 +19214,10 @@ function formatRunDetail(run2) {
|
|
|
18909
19214
|
}
|
|
18910
19215
|
|
|
18911
19216
|
// src/lib/ignore-declaration.ts
|
|
18912
|
-
var
|
|
19217
|
+
var import_node_fs32 = require("node:fs");
|
|
18913
19218
|
|
|
18914
19219
|
// src/lib/debounce.ts
|
|
18915
|
-
var
|
|
19220
|
+
var import_node_fs31 = require("node:fs");
|
|
18916
19221
|
var import_node_crypto10 = require("node:crypto");
|
|
18917
19222
|
function scopedFile(base, sessionId) {
|
|
18918
19223
|
if (!sessionId) return base;
|
|
@@ -18920,9 +19225,9 @@ function scopedFile(base, sessionId) {
|
|
|
18920
19225
|
}
|
|
18921
19226
|
function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
|
|
18922
19227
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
18923
|
-
if (!(0,
|
|
19228
|
+
if (!(0, import_node_fs31.existsSync)(file)) return null;
|
|
18924
19229
|
try {
|
|
18925
|
-
const lastTs = parseInt((0,
|
|
19230
|
+
const lastTs = parseInt((0, import_node_fs31.readFileSync)(file, "utf-8").trim(), 10);
|
|
18926
19231
|
const nowTs = Math.floor(Date.now() / 1e3);
|
|
18927
19232
|
const elapsed = nowTs - lastTs;
|
|
18928
19233
|
if (elapsed < debounceSeconds) {
|
|
@@ -18935,10 +19240,10 @@ function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
|
|
|
18935
19240
|
function checkMtime(files, bypassForRecentCommits, sessionId) {
|
|
18936
19241
|
if (bypassForRecentCommits) return null;
|
|
18937
19242
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
18938
|
-
if (!(0,
|
|
19243
|
+
if (!(0, import_node_fs31.existsSync)(file)) return null;
|
|
18939
19244
|
let debounceTime;
|
|
18940
19245
|
try {
|
|
18941
|
-
debounceTime = (0,
|
|
19246
|
+
debounceTime = (0, import_node_fs31.statSync)(file).mtimeMs;
|
|
18942
19247
|
} catch {
|
|
18943
19248
|
return null;
|
|
18944
19249
|
}
|
|
@@ -18946,7 +19251,7 @@ function checkMtime(files, bypassForRecentCommits, sessionId) {
|
|
|
18946
19251
|
const resolved = resolveFile(f);
|
|
18947
19252
|
if (!resolved) continue;
|
|
18948
19253
|
try {
|
|
18949
|
-
const stat3 = (0,
|
|
19254
|
+
const stat3 = (0, import_node_fs31.statSync)(resolved);
|
|
18950
19255
|
if (stat3.mtimeMs > debounceTime) {
|
|
18951
19256
|
return null;
|
|
18952
19257
|
}
|
|
@@ -18962,8 +19267,8 @@ function computeContentHash(files) {
|
|
|
18962
19267
|
for (const f of sorted) {
|
|
18963
19268
|
const resolved = resolveFile(f) ?? f;
|
|
18964
19269
|
try {
|
|
18965
|
-
if ((0,
|
|
18966
|
-
hash.update((0,
|
|
19270
|
+
if ((0, import_node_fs31.existsSync)(resolved)) {
|
|
19271
|
+
hash.update((0, import_node_fs31.readFileSync)(resolved));
|
|
18967
19272
|
}
|
|
18968
19273
|
} catch {
|
|
18969
19274
|
}
|
|
@@ -18973,9 +19278,9 @@ function computeContentHash(files) {
|
|
|
18973
19278
|
function checkContentHash(files, sessionId) {
|
|
18974
19279
|
const hash = computeContentHash(files);
|
|
18975
19280
|
const file = scopedFile(HASH_FILE, sessionId);
|
|
18976
|
-
if ((0,
|
|
19281
|
+
if ((0, import_node_fs31.existsSync)(file)) {
|
|
18977
19282
|
try {
|
|
18978
|
-
const storedHash = (0,
|
|
19283
|
+
const storedHash = (0, import_node_fs31.readFileSync)(file, "utf-8").trim();
|
|
18979
19284
|
if (hash === storedHash) {
|
|
18980
19285
|
return { skip: "No source changes since last analysis", hash };
|
|
18981
19286
|
}
|
|
@@ -18985,24 +19290,24 @@ function checkContentHash(files, sessionId) {
|
|
|
18985
19290
|
return { skip: null, hash };
|
|
18986
19291
|
}
|
|
18987
19292
|
function recordAnalysisStart(sessionId) {
|
|
18988
|
-
(0,
|
|
18989
|
-
(0,
|
|
19293
|
+
(0, import_node_fs31.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
19294
|
+
(0, import_node_fs31.writeFileSync)(scopedFile(DEBOUNCE_FILE, sessionId), String(Math.floor(Date.now() / 1e3)));
|
|
18990
19295
|
}
|
|
18991
19296
|
function recordPassHash(hash, sessionId) {
|
|
18992
|
-
(0,
|
|
19297
|
+
(0, import_node_fs31.writeFileSync)(scopedFile(HASH_FILE, sessionId), hash);
|
|
18993
19298
|
}
|
|
18994
19299
|
function narrowToRecent(files, sessionId) {
|
|
18995
19300
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
18996
|
-
if (!(0,
|
|
19301
|
+
if (!(0, import_node_fs31.existsSync)(file)) return files;
|
|
18997
19302
|
let debounceTime;
|
|
18998
19303
|
try {
|
|
18999
|
-
debounceTime = (0,
|
|
19304
|
+
debounceTime = (0, import_node_fs31.statSync)(file).mtimeMs;
|
|
19000
19305
|
} catch {
|
|
19001
19306
|
return files;
|
|
19002
19307
|
}
|
|
19003
19308
|
const recent = files.filter((f) => {
|
|
19004
19309
|
try {
|
|
19005
|
-
return (0,
|
|
19310
|
+
return (0, import_node_fs31.existsSync)(f) && (0, import_node_fs31.statSync)(f).mtimeMs > debounceTime;
|
|
19006
19311
|
} catch {
|
|
19007
19312
|
return false;
|
|
19008
19313
|
}
|
|
@@ -19015,9 +19320,9 @@ function readIteration(currentCommit, _contentHash) {
|
|
|
19015
19320
|
var NO_BLOCKS = { attempts: 0, blocks: 0, fingerprint: null };
|
|
19016
19321
|
function readBlockState(currentCommit, opts) {
|
|
19017
19322
|
if (opts?.newUserPrompt) return NO_BLOCKS;
|
|
19018
|
-
if (!(0,
|
|
19323
|
+
if (!(0, import_node_fs31.existsSync)(ITERATION_FILE)) return NO_BLOCKS;
|
|
19019
19324
|
try {
|
|
19020
|
-
const stored = (0,
|
|
19325
|
+
const stored = (0, import_node_fs31.readFileSync)(ITERATION_FILE, "utf-8").trim();
|
|
19021
19326
|
const parsed = stored.startsWith("{") ? parseJsonState(stored) : parseLegacyState(stored);
|
|
19022
19327
|
if (!parsed) return NO_BLOCKS;
|
|
19023
19328
|
if (parsed.commit !== currentCommit) return NO_BLOCKS;
|
|
@@ -19063,8 +19368,8 @@ function isSameProblem(previous, current) {
|
|
|
19063
19368
|
return current.split(",").some((k) => prev.has(k));
|
|
19064
19369
|
}
|
|
19065
19370
|
function writeBlockState(commit, state) {
|
|
19066
|
-
(0,
|
|
19067
|
-
(0,
|
|
19371
|
+
(0, import_node_fs31.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
19372
|
+
(0, import_node_fs31.writeFileSync)(
|
|
19068
19373
|
ITERATION_FILE,
|
|
19069
19374
|
JSON.stringify({
|
|
19070
19375
|
v: 2,
|
|
@@ -19169,9 +19474,9 @@ function resolveIgnoreState(keys) {
|
|
|
19169
19474
|
}
|
|
19170
19475
|
function readIgnoreState(sessionId) {
|
|
19171
19476
|
const file = stateFile(sessionId);
|
|
19172
|
-
if (!(0,
|
|
19477
|
+
if (!(0, import_node_fs32.existsSync)(file)) return null;
|
|
19173
19478
|
try {
|
|
19174
|
-
const o = JSON.parse((0,
|
|
19479
|
+
const o = JSON.parse((0, import_node_fs32.readFileSync)(file, "utf-8")) ?? {};
|
|
19175
19480
|
const spent = typeof o.spent === "number" ? o.spent : 0;
|
|
19176
19481
|
const raw = o.active;
|
|
19177
19482
|
let active = null;
|
|
@@ -19195,8 +19500,8 @@ function readIgnoreState(sessionId) {
|
|
|
19195
19500
|
}
|
|
19196
19501
|
function writeIgnoreState(state, sessionId) {
|
|
19197
19502
|
try {
|
|
19198
|
-
(0,
|
|
19199
|
-
(0,
|
|
19503
|
+
(0, import_node_fs32.mkdirSync)(projectPath(VERITY_DIR), { recursive: true });
|
|
19504
|
+
(0, import_node_fs32.writeFileSync)(stateFile(sessionId), JSON.stringify({ v: 1, active: state.active, spent: state.spent }));
|
|
19200
19505
|
} catch {
|
|
19201
19506
|
}
|
|
19202
19507
|
}
|
|
@@ -19579,7 +19884,7 @@ function createRun(opts, globals) {
|
|
|
19579
19884
|
}
|
|
19580
19885
|
|
|
19581
19886
|
// src/commands/analyze/index.ts
|
|
19582
|
-
var
|
|
19887
|
+
var import_node_fs45 = require("node:fs");
|
|
19583
19888
|
|
|
19584
19889
|
// src/lib/repo-context.ts
|
|
19585
19890
|
var import_node_child_process10 = require("node:child_process");
|
|
@@ -20407,10 +20712,10 @@ function installRunEvidence(run2) {
|
|
|
20407
20712
|
}
|
|
20408
20713
|
|
|
20409
20714
|
// src/lib/git-frame.ts
|
|
20410
|
-
var
|
|
20715
|
+
var import_node_fs33 = require("node:fs");
|
|
20411
20716
|
var import_node_os5 = require("node:os");
|
|
20412
|
-
var import_node_path24 = require("node:path");
|
|
20413
20717
|
var import_node_path25 = require("node:path");
|
|
20718
|
+
var import_node_path26 = require("node:path");
|
|
20414
20719
|
|
|
20415
20720
|
// src/lib/hardened-git.ts
|
|
20416
20721
|
var import_node_child_process11 = require("node:child_process");
|
|
@@ -20572,8 +20877,8 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
20572
20877
|
if (SHELL_DYNAMIC.test(raw) || raw === "-") {
|
|
20573
20878
|
return { dir: null, named: true, unresolvable: `cd target not statically resolvable: ${raw}` };
|
|
20574
20879
|
}
|
|
20575
|
-
const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0,
|
|
20576
|
-
dir = (0,
|
|
20880
|
+
const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0, import_node_path26.join)((0, import_node_os5.homedir)(), raw.slice(2)) : raw;
|
|
20881
|
+
dir = (0, import_node_path25.isAbsolute)(expanded) ? expanded : (0, import_node_path25.resolve)(dir, expanded);
|
|
20577
20882
|
}
|
|
20578
20883
|
const seg = segments[segmentIndex];
|
|
20579
20884
|
const overrideMatch = /--(?:git-dir|work-tree)(?:=|\s)|\bGIT_(?:DIR|WORK_TREE|INDEX_FILE)=/.exec(seg);
|
|
@@ -20591,8 +20896,8 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
20591
20896
|
if (SHELL_DYNAMIC.test(raw)) {
|
|
20592
20897
|
return { dir: null, named: true, unresolvable: `-C target not statically resolvable: ${raw}` };
|
|
20593
20898
|
}
|
|
20594
|
-
const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0,
|
|
20595
|
-
dir = (0,
|
|
20899
|
+
const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0, import_node_path26.join)((0, import_node_os5.homedir)(), raw.slice(2)) : raw;
|
|
20900
|
+
dir = (0, import_node_path25.isAbsolute)(expanded) ? expanded : (0, import_node_path25.resolve)(dir, expanded);
|
|
20596
20901
|
}
|
|
20597
20902
|
}
|
|
20598
20903
|
return { dir, named, unresolvable: null };
|
|
@@ -20652,14 +20957,14 @@ function gitAt(dir, args) {
|
|
|
20652
20957
|
}
|
|
20653
20958
|
function realpathOr2(p) {
|
|
20654
20959
|
try {
|
|
20655
|
-
return
|
|
20960
|
+
return import_node_fs33.realpathSync.native(p);
|
|
20656
20961
|
} catch {
|
|
20657
|
-
return (0,
|
|
20962
|
+
return (0, import_node_path25.resolve)(p);
|
|
20658
20963
|
}
|
|
20659
20964
|
}
|
|
20660
20965
|
function resolveFrame(input) {
|
|
20661
20966
|
const found = findMomentSegment(input.command, input.on);
|
|
20662
|
-
const hookDirUsable = !!input.hookCwd && (0,
|
|
20967
|
+
const hookDirUsable = !!input.hookCwd && (0, import_node_fs33.existsSync)(input.hookCwd);
|
|
20663
20968
|
const baseDir = hookDirUsable ? input.hookCwd : process.cwd();
|
|
20664
20969
|
let anchor = hookDirUsable ? "hook-cwd" : "process-cwd";
|
|
20665
20970
|
const refuse = (refusal) => ({
|
|
@@ -20682,7 +20987,7 @@ function resolveFrame(input) {
|
|
|
20682
20987
|
if (dirs.size > 1) return refuse(`target:multiple ${found.moment} targets in one command`);
|
|
20683
20988
|
const targetDir = dirs.size === 1 ? [...dirs][0] : baseDir;
|
|
20684
20989
|
if (targetDir !== baseDir) {
|
|
20685
|
-
if (!(0,
|
|
20990
|
+
if (!(0, import_node_fs33.existsSync)(targetDir)) return refuse(`target:directory does not exist: ${targetDir}`);
|
|
20686
20991
|
dir = targetDir;
|
|
20687
20992
|
}
|
|
20688
20993
|
}
|
|
@@ -20693,7 +20998,7 @@ function resolveFrame(input) {
|
|
|
20693
20998
|
const gitDirRaw = gitAt(dir, ["rev-parse", "--absolute-git-dir"]);
|
|
20694
20999
|
const commonRaw = gitAt(dir, ["rev-parse", "--git-common-dir"]);
|
|
20695
21000
|
const gitDir = gitDirRaw ? realpathOr2(gitDirRaw) : null;
|
|
20696
|
-
const commonDir = commonRaw ? realpathOr2((0,
|
|
21001
|
+
const commonDir = commonRaw ? realpathOr2((0, import_node_path25.isAbsolute)(commonRaw) ? commonRaw : (0, import_node_path25.resolve)(dir, commonRaw)) : null;
|
|
20697
21002
|
const branchRaw = gitAt(dir, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
20698
21003
|
return {
|
|
20699
21004
|
moment: found?.moment ?? null,
|
|
@@ -20868,8 +21173,8 @@ function stagedRange(frame, command) {
|
|
|
20868
21173
|
if (plan.kind === "unpredictable") {
|
|
20869
21174
|
return { kind: "staged", base: "HEAD", head: "INDEX", via: "staged-in-command", refusal: plan.reason };
|
|
20870
21175
|
}
|
|
20871
|
-
const mergeHead = frame.gitDir ? (0,
|
|
20872
|
-
if (mergeHead && (0,
|
|
21176
|
+
const mergeHead = frame.gitDir ? (0, import_node_path26.join)(frame.gitDir, "MERGE_HEAD") : null;
|
|
21177
|
+
if (mergeHead && (0, import_node_fs33.existsSync)(mergeHead)) {
|
|
20873
21178
|
const vsHead = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "HEAD"]).split("\n").filter(Boolean));
|
|
20874
21179
|
const vsMerge = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "MERGE_HEAD"]).split("\n").filter(Boolean));
|
|
20875
21180
|
const resolutions = new Set([...vsHead].filter((f) => vsMerge.has(f) && !isVerityOwnedPath(f)));
|
|
@@ -21003,7 +21308,7 @@ function truthy(v) {
|
|
|
21003
21308
|
}
|
|
21004
21309
|
|
|
21005
21310
|
// src/lib/transcript.ts
|
|
21006
|
-
var
|
|
21311
|
+
var import_node_fs34 = require("node:fs");
|
|
21007
21312
|
var MAX_READ_BYTES = 256 * 1024;
|
|
21008
21313
|
var SMALL_FILE_BYTES = 64 * 1024;
|
|
21009
21314
|
var MAX_FILES_LIST = 20;
|
|
@@ -21030,7 +21335,7 @@ async function extractActionSummary(transcriptPath) {
|
|
|
21030
21335
|
function readTurnLines(transcriptPath) {
|
|
21031
21336
|
let size;
|
|
21032
21337
|
try {
|
|
21033
|
-
size = (0,
|
|
21338
|
+
size = (0, import_node_fs34.statSync)(transcriptPath).size;
|
|
21034
21339
|
} catch {
|
|
21035
21340
|
return null;
|
|
21036
21341
|
}
|
|
@@ -21038,7 +21343,7 @@ function readTurnLines(transcriptPath) {
|
|
|
21038
21343
|
let raw;
|
|
21039
21344
|
let windowed = false;
|
|
21040
21345
|
if (size <= SMALL_FILE_BYTES) {
|
|
21041
|
-
raw = (0,
|
|
21346
|
+
raw = (0, import_node_fs34.readFileSync)(transcriptPath, "utf-8");
|
|
21042
21347
|
} else {
|
|
21043
21348
|
windowed = true;
|
|
21044
21349
|
const buf = Buffer.alloc(Math.min(MAX_READ_BYTES, size));
|
|
@@ -21546,7 +21851,7 @@ function channelSilence(input) {
|
|
|
21546
21851
|
// src/lib/cli-version.ts
|
|
21547
21852
|
function cliVersion() {
|
|
21548
21853
|
try {
|
|
21549
|
-
return true ? "0.32.6-experimental.
|
|
21854
|
+
return true ? "0.32.6-experimental.df0a578" : "dev";
|
|
21550
21855
|
} catch {
|
|
21551
21856
|
return "dev";
|
|
21552
21857
|
}
|
|
@@ -21587,7 +21892,7 @@ async function sendSkipBeacon(ctx, reason) {
|
|
|
21587
21892
|
|
|
21588
21893
|
// src/lib/static-analysis.ts
|
|
21589
21894
|
var import_node_child_process12 = require("node:child_process");
|
|
21590
|
-
var
|
|
21895
|
+
var import_node_fs35 = require("node:fs");
|
|
21591
21896
|
var SEVERITY_ORDER = {
|
|
21592
21897
|
Error: 0,
|
|
21593
21898
|
Critical: 0,
|
|
@@ -21635,7 +21940,7 @@ function runCodacyAnalysis(files) {
|
|
|
21635
21940
|
if (files.length === 0) return empty;
|
|
21636
21941
|
const existingFiles = files.filter((f) => {
|
|
21637
21942
|
try {
|
|
21638
|
-
return (0,
|
|
21943
|
+
return (0, import_node_fs35.existsSync)(f);
|
|
21639
21944
|
} catch {
|
|
21640
21945
|
return false;
|
|
21641
21946
|
}
|
|
@@ -21904,8 +22209,8 @@ async function scope(run2) {
|
|
|
21904
22209
|
}
|
|
21905
22210
|
|
|
21906
22211
|
// src/lib/specs.ts
|
|
21907
|
-
var
|
|
21908
|
-
var
|
|
22212
|
+
var import_node_fs36 = require("node:fs");
|
|
22213
|
+
var import_node_path27 = require("node:path");
|
|
21909
22214
|
var SPEC_CANDIDATES = [
|
|
21910
22215
|
"CLAUDE.md",
|
|
21911
22216
|
"AGENTS.md",
|
|
@@ -21936,7 +22241,7 @@ function discoverSpecs(consulted = []) {
|
|
|
21936
22241
|
const totalCap = relevant ? MAX_TOTAL_SPEC_BYTES : UNCONSULTED_TOTAL_BYTES;
|
|
21937
22242
|
if (totalBytes >= totalCap) return false;
|
|
21938
22243
|
if (seen.has(specPath)) return true;
|
|
21939
|
-
if (!(0,
|
|
22244
|
+
if (!(0, import_node_fs36.existsSync)(specPath)) return true;
|
|
21940
22245
|
seen.add(specPath);
|
|
21941
22246
|
const remaining = totalCap - totalBytes;
|
|
21942
22247
|
const fileCap = relevant ? MAX_SPEC_FILE_BYTES : UNCONSULTED_FILE_BYTES;
|
|
@@ -21959,7 +22264,7 @@ function discoverSpecs(consulted = []) {
|
|
|
21959
22264
|
if (!addSpec(candidate)) break;
|
|
21960
22265
|
}
|
|
21961
22266
|
for (const dir of ["spec", "docs"]) {
|
|
21962
|
-
if (!(0,
|
|
22267
|
+
if (!(0, import_node_fs36.existsSync)(dir)) continue;
|
|
21963
22268
|
try {
|
|
21964
22269
|
const mdFiles = findMdFiles(dir, 2).sort();
|
|
21965
22270
|
for (const mdFile of mdFiles) {
|
|
@@ -21974,9 +22279,9 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
21974
22279
|
if (depth >= maxDepth) return [];
|
|
21975
22280
|
const result = [];
|
|
21976
22281
|
try {
|
|
21977
|
-
const entries = (0,
|
|
22282
|
+
const entries = (0, import_node_fs36.readdirSync)(dir, { withFileTypes: true });
|
|
21978
22283
|
for (const entry of entries) {
|
|
21979
|
-
const fullPath = (0,
|
|
22284
|
+
const fullPath = (0, import_node_path27.join)(dir, entry.name);
|
|
21980
22285
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
21981
22286
|
result.push(fullPath);
|
|
21982
22287
|
} else if (entry.isDirectory() && depth < maxDepth - 1) {
|
|
@@ -21989,25 +22294,25 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
21989
22294
|
}
|
|
21990
22295
|
function discoverPlans() {
|
|
21991
22296
|
const home = process.env.HOME ?? "";
|
|
21992
|
-
const homePlansDir = (0,
|
|
22297
|
+
const homePlansDir = (0, import_node_path27.join)(home, ".claude", "plans");
|
|
21993
22298
|
const sources = [];
|
|
21994
22299
|
if (isRealDirectoryChain(process.cwd(), [".claude", "plans"])) {
|
|
21995
|
-
sources.push({ root: process.cwd(), prefix: (0,
|
|
22300
|
+
sources.push({ root: process.cwd(), prefix: (0, import_node_path27.join)(".claude", "plans") });
|
|
21996
22301
|
}
|
|
21997
|
-
if (home && (0,
|
|
22302
|
+
if (home && (0, import_node_fs36.existsSync)(homePlansDir)) sources.push({ root: homePlansDir, prefix: "" });
|
|
21998
22303
|
const candidates2 = [];
|
|
21999
22304
|
const seen = /* @__PURE__ */ new Set();
|
|
22000
22305
|
for (const source of sources) {
|
|
22001
22306
|
let names2;
|
|
22002
22307
|
try {
|
|
22003
|
-
names2 = (0,
|
|
22308
|
+
names2 = (0, import_node_fs36.readdirSync)(source.prefix ? (0, import_node_path27.join)(source.root, source.prefix) : source.root);
|
|
22004
22309
|
} catch {
|
|
22005
22310
|
continue;
|
|
22006
22311
|
}
|
|
22007
22312
|
for (const f of names2) {
|
|
22008
22313
|
if (!f.endsWith(".md") || seen.has(f)) continue;
|
|
22009
22314
|
seen.add(f);
|
|
22010
|
-
const relPath = source.prefix ? (0,
|
|
22315
|
+
const relPath = source.prefix ? (0, import_node_path27.join)(source.prefix, f) : f;
|
|
22011
22316
|
const stat3 = statRegularInRoot(source.root, relPath);
|
|
22012
22317
|
if (!stat3.ok) continue;
|
|
22013
22318
|
candidates2.push({ name: f, root: source.root, relPath, mtime: stat3.mtimeMs, size: stat3.size });
|
|
@@ -22025,9 +22330,9 @@ function discoverPlans() {
|
|
|
22025
22330
|
function isRealDirectoryChain(root, parts) {
|
|
22026
22331
|
let current = root;
|
|
22027
22332
|
for (const part of parts) {
|
|
22028
|
-
current = (0,
|
|
22333
|
+
current = (0, import_node_path27.join)(current, part);
|
|
22029
22334
|
try {
|
|
22030
|
-
if (!(0,
|
|
22335
|
+
if (!(0, import_node_fs36.lstatSync)(current).isDirectory()) return false;
|
|
22031
22336
|
} catch {
|
|
22032
22337
|
return false;
|
|
22033
22338
|
}
|
|
@@ -22042,7 +22347,7 @@ function discoverGuardDocs(rangeFiles2) {
|
|
|
22042
22347
|
if (result.length >= MAX_SPEC_FILES) break;
|
|
22043
22348
|
if (!GUARD_DOC_EXT.test(path)) continue;
|
|
22044
22349
|
if (path.startsWith("/") || path.includes("..")) continue;
|
|
22045
|
-
if (!(0,
|
|
22350
|
+
if (!(0, import_node_fs36.existsSync)(path)) continue;
|
|
22046
22351
|
const opened = openRegularInRoot(process.cwd(), path);
|
|
22047
22352
|
if (!opened.ok) continue;
|
|
22048
22353
|
if (opened.size > MAX_PLAN_FILE_BYTES || totalBytes + opened.size > MAX_TOTAL_SPEC_BYTES) {
|
|
@@ -22228,8 +22533,8 @@ async function mode(run2) {
|
|
|
22228
22533
|
}
|
|
22229
22534
|
|
|
22230
22535
|
// src/lib/fold.ts
|
|
22231
|
-
var
|
|
22232
|
-
var
|
|
22536
|
+
var import_node_fs37 = require("node:fs");
|
|
22537
|
+
var import_node_path28 = require("node:path");
|
|
22233
22538
|
var KNOWN_RECORD_TYPES = /* @__PURE__ */ new Set([
|
|
22234
22539
|
"user",
|
|
22235
22540
|
"assistant",
|
|
@@ -22366,7 +22671,7 @@ function candidateRoots(repoRoot2) {
|
|
|
22366
22671
|
const norm = repoRoot2.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
22367
22672
|
const out = [norm];
|
|
22368
22673
|
try {
|
|
22369
|
-
const real =
|
|
22674
|
+
const real = import_node_fs37.realpathSync.native(norm).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
22370
22675
|
if (real !== norm) out.push(real);
|
|
22371
22676
|
} catch {
|
|
22372
22677
|
}
|
|
@@ -22454,31 +22759,31 @@ function fold(transcriptPath, opts = {}) {
|
|
|
22454
22759
|
}
|
|
22455
22760
|
};
|
|
22456
22761
|
try {
|
|
22457
|
-
if (!(0,
|
|
22458
|
-
ingest((0,
|
|
22762
|
+
if (!(0, import_node_fs37.existsSync)(transcriptPath)) return result;
|
|
22763
|
+
ingest((0, import_node_fs37.readFileSync)(transcriptPath, "utf8"), "agent");
|
|
22459
22764
|
result.coverage.complete = true;
|
|
22460
22765
|
} catch {
|
|
22461
22766
|
return result;
|
|
22462
22767
|
}
|
|
22463
22768
|
try {
|
|
22464
|
-
const sidecarDir = (0,
|
|
22465
|
-
(0,
|
|
22466
|
-
(0,
|
|
22769
|
+
const sidecarDir = (0, import_node_path28.join)(
|
|
22770
|
+
(0, import_node_path28.dirname)(transcriptPath),
|
|
22771
|
+
(0, import_node_path28.basename)(transcriptPath).replace(/\.jsonl$/, ""),
|
|
22467
22772
|
"subagents"
|
|
22468
22773
|
);
|
|
22469
|
-
if ((0,
|
|
22774
|
+
if ((0, import_node_fs37.existsSync)(sidecarDir)) {
|
|
22470
22775
|
const maxFiles = opts.maxSidecars ?? 200;
|
|
22471
22776
|
const maxBytes = opts.maxSidecarBytes ?? 16 * 1024 * 1024;
|
|
22472
22777
|
const found = [];
|
|
22473
22778
|
const walk2 = (d, depth) => {
|
|
22474
22779
|
if (depth > 4) return;
|
|
22475
|
-
for (const e of (0,
|
|
22476
|
-
const p = (0,
|
|
22780
|
+
for (const e of (0, import_node_fs37.readdirSync)(d, { withFileTypes: true })) {
|
|
22781
|
+
const p = (0, import_node_path28.join)(d, e.name);
|
|
22477
22782
|
if (e.isDirectory()) {
|
|
22478
22783
|
walk2(p, depth + 1);
|
|
22479
22784
|
} else if (e.name.startsWith("agent-") && e.name.endsWith(".jsonl")) {
|
|
22480
22785
|
try {
|
|
22481
|
-
const st = (0,
|
|
22786
|
+
const st = (0, import_node_fs37.statSync)(p);
|
|
22482
22787
|
found.push({ path: p, size: st.size, mtimeMs: st.mtimeMs });
|
|
22483
22788
|
} catch {
|
|
22484
22789
|
result.coverage.malformed++;
|
|
@@ -22495,7 +22800,7 @@ function fold(transcriptPath, opts = {}) {
|
|
|
22495
22800
|
continue;
|
|
22496
22801
|
}
|
|
22497
22802
|
try {
|
|
22498
|
-
ingest((0,
|
|
22803
|
+
ingest((0, import_node_fs37.readFileSync)(f.path, "utf8"), "subagent");
|
|
22499
22804
|
bytes += f.size;
|
|
22500
22805
|
result.coverage.subagentFiles++;
|
|
22501
22806
|
} catch {
|
|
@@ -22530,7 +22835,7 @@ function fold(transcriptPath, opts = {}) {
|
|
|
22530
22835
|
}
|
|
22531
22836
|
function classifyUnobserved(path) {
|
|
22532
22837
|
try {
|
|
22533
|
-
const st = (0,
|
|
22838
|
+
const st = (0, import_node_fs37.statSync)(path);
|
|
22534
22839
|
if (!st.isFile()) return "unreadable";
|
|
22535
22840
|
} catch {
|
|
22536
22841
|
return "unreadable";
|
|
@@ -22847,20 +23152,20 @@ async function evidence(run2) {
|
|
|
22847
23152
|
}
|
|
22848
23153
|
|
|
22849
23154
|
// src/lib/cache-cleanup.ts
|
|
22850
|
-
var
|
|
22851
|
-
var
|
|
23155
|
+
var import_node_fs38 = require("node:fs");
|
|
23156
|
+
var import_node_path29 = require("node:path");
|
|
22852
23157
|
var CACHE_TTL_DAYS = 7;
|
|
22853
23158
|
function pruneStaleCache() {
|
|
22854
23159
|
try {
|
|
22855
23160
|
const dir = projectPath(CACHE_DIR);
|
|
22856
23161
|
const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
|
|
22857
|
-
for (const entry of (0,
|
|
23162
|
+
for (const entry of (0, import_node_fs38.readdirSync)(dir)) {
|
|
22858
23163
|
if (!entry.startsWith("pending-")) continue;
|
|
22859
|
-
const path = (0,
|
|
23164
|
+
const path = (0, import_node_path29.join)(dir, entry);
|
|
22860
23165
|
try {
|
|
22861
|
-
const stat3 = (0,
|
|
23166
|
+
const stat3 = (0, import_node_fs38.statSync)(path);
|
|
22862
23167
|
if (stat3.mtimeMs < cutoff) {
|
|
22863
|
-
(0,
|
|
23168
|
+
(0, import_node_fs38.unlinkSync)(path);
|
|
22864
23169
|
logEvent("cache_entry_pruned", {
|
|
22865
23170
|
path: entry,
|
|
22866
23171
|
age_days: Math.round((Date.now() - stat3.mtimeMs) / 864e5)
|
|
@@ -22874,7 +23179,7 @@ function pruneStaleCache() {
|
|
|
22874
23179
|
}
|
|
22875
23180
|
|
|
22876
23181
|
// src/lib/context-files.ts
|
|
22877
|
-
var
|
|
23182
|
+
var import_node_fs39 = require("node:fs");
|
|
22878
23183
|
var import_node_os6 = require("node:os");
|
|
22879
23184
|
var MAX_CONTEXT_FILES = 10;
|
|
22880
23185
|
var MAX_CONTEXT_FILE_BYTES = 10240;
|
|
@@ -22932,7 +23237,7 @@ function gatherContextFiles(contextPaths, deltaFiles, opts) {
|
|
|
22932
23237
|
continue;
|
|
22933
23238
|
}
|
|
22934
23239
|
try {
|
|
22935
|
-
const content = (0,
|
|
23240
|
+
const content = (0, import_node_fs39.readFileSync)(safePath, "utf8");
|
|
22936
23241
|
const bytes = Buffer.byteLength(content);
|
|
22937
23242
|
if (bytes > MAX_CONTEXT_FILE_BYTES) {
|
|
22938
23243
|
logEvent("context_file_skipped", { path: filePath, reason: "too_large", bytes });
|
|
@@ -23022,9 +23327,9 @@ async function repoContext(run2) {
|
|
|
23022
23327
|
}
|
|
23023
23328
|
|
|
23024
23329
|
// src/lib/seed-runner.ts
|
|
23025
|
-
var
|
|
23026
|
-
var
|
|
23027
|
-
var
|
|
23330
|
+
var import_promises15 = require("node:fs/promises");
|
|
23331
|
+
var import_node_fs40 = require("node:fs");
|
|
23332
|
+
var import_node_path30 = require("node:path");
|
|
23028
23333
|
var import_yaml4 = __toESM(require_dist());
|
|
23029
23334
|
|
|
23030
23335
|
// src/lib/seed.ts
|
|
@@ -23100,7 +23405,7 @@ function classifyClaudeSection(heading) {
|
|
|
23100
23405
|
if (hasAny(["integration", "webhook", "third-party", "third party", "provider"])) return "integration";
|
|
23101
23406
|
return "domain";
|
|
23102
23407
|
}
|
|
23103
|
-
function
|
|
23408
|
+
function slugify2(s) {
|
|
23104
23409
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
23105
23410
|
}
|
|
23106
23411
|
var FRAMEWORK_GLOBS = [
|
|
@@ -23197,7 +23502,7 @@ _Extracted from README on setup. Update when project direction changes._`,
|
|
|
23197
23502
|
for (const fwRaw of frameworks) {
|
|
23198
23503
|
const fw = fwRaw.trim();
|
|
23199
23504
|
if (!fw) continue;
|
|
23200
|
-
const slug =
|
|
23505
|
+
const slug = slugify2(fw);
|
|
23201
23506
|
if (!slug || seenFrameworkSlugs.has(slug)) continue;
|
|
23202
23507
|
seenFrameworkSlugs.add(slug);
|
|
23203
23508
|
out.push({
|
|
@@ -23263,29 +23568,29 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
|
|
|
23263
23568
|
return fm;
|
|
23264
23569
|
}
|
|
23265
23570
|
async function runSeed(opts) {
|
|
23266
|
-
if (!(0,
|
|
23571
|
+
if (!(0, import_node_fs40.existsSync)(STANDARD_FILE)) {
|
|
23267
23572
|
return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
23268
23573
|
}
|
|
23269
23574
|
let standardDoc;
|
|
23270
23575
|
try {
|
|
23271
|
-
const raw = await (0,
|
|
23576
|
+
const raw = await (0, import_promises15.readFile)(STANDARD_FILE, "utf-8");
|
|
23272
23577
|
standardDoc = (0, import_yaml4.parse)(raw);
|
|
23273
23578
|
} catch {
|
|
23274
23579
|
return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
23275
23580
|
}
|
|
23276
23581
|
const knowledgeSpec = standardDoc.knowledge_spec ?? {};
|
|
23277
23582
|
let readmeContent;
|
|
23278
|
-
if ((0,
|
|
23583
|
+
if ((0, import_node_fs40.existsSync)("README.md")) {
|
|
23279
23584
|
try {
|
|
23280
|
-
readmeContent = await (0,
|
|
23585
|
+
readmeContent = await (0, import_promises15.readFile)("README.md", "utf-8");
|
|
23281
23586
|
} catch {
|
|
23282
23587
|
}
|
|
23283
23588
|
}
|
|
23284
23589
|
let claudeMdContent;
|
|
23285
23590
|
for (const p of ["CLAUDE.md", ".claude/CLAUDE.md"]) {
|
|
23286
|
-
if ((0,
|
|
23591
|
+
if ((0, import_node_fs40.existsSync)(p)) {
|
|
23287
23592
|
try {
|
|
23288
|
-
claudeMdContent = await (0,
|
|
23593
|
+
claudeMdContent = await (0, import_promises15.readFile)(p, "utf-8");
|
|
23289
23594
|
break;
|
|
23290
23595
|
} catch {
|
|
23291
23596
|
}
|
|
@@ -23306,8 +23611,8 @@ async function runSeed(opts) {
|
|
|
23306
23611
|
if (candidates2.length === 0) {
|
|
23307
23612
|
return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
|
|
23308
23613
|
}
|
|
23309
|
-
const overviewPath = (0,
|
|
23310
|
-
if ((0,
|
|
23614
|
+
const overviewPath = (0, import_node_path30.join)(MEMORY_DIR, "domain", "project-overview.md");
|
|
23615
|
+
if ((0, import_node_fs40.existsSync)(overviewPath) && !opts.force) {
|
|
23311
23616
|
return { created: 0, failed: 0, skipped: "already_seeded", candidates: candidates2 };
|
|
23312
23617
|
}
|
|
23313
23618
|
if (opts.dryRun) {
|
|
@@ -23349,8 +23654,8 @@ async function runSeed(opts) {
|
|
|
23349
23654
|
continue;
|
|
23350
23655
|
}
|
|
23351
23656
|
try {
|
|
23352
|
-
await (0,
|
|
23353
|
-
await (0,
|
|
23657
|
+
await (0, import_promises15.mkdir)((0, import_node_path30.dirname)(targetPath), { recursive: true });
|
|
23658
|
+
await (0, import_promises15.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
|
|
23354
23659
|
created++;
|
|
23355
23660
|
opts.onCreated?.(nodeId, filePathRel, c);
|
|
23356
23661
|
} catch (err) {
|
|
@@ -23362,8 +23667,8 @@ async function runSeed(opts) {
|
|
|
23362
23667
|
}
|
|
23363
23668
|
|
|
23364
23669
|
// src/commands/analyze/phases/08-memory-manifest.ts
|
|
23365
|
-
var
|
|
23366
|
-
var
|
|
23670
|
+
var import_node_fs41 = require("node:fs");
|
|
23671
|
+
var import_node_path31 = require("node:path");
|
|
23367
23672
|
async function memoryManifest(run2) {
|
|
23368
23673
|
const { globals } = run2;
|
|
23369
23674
|
const { serviceUrl, token } = run2;
|
|
@@ -23373,9 +23678,9 @@ async function memoryManifest(run2) {
|
|
|
23373
23678
|
let autoSeedNotice = null;
|
|
23374
23679
|
try {
|
|
23375
23680
|
await ensureMemoryDir();
|
|
23376
|
-
const seedMarker = (0,
|
|
23377
|
-
const hasStandard = (0,
|
|
23378
|
-
const alreadyTried = (0,
|
|
23681
|
+
const seedMarker = (0, import_node_path31.join)(VERITY_DIR, ".seeded");
|
|
23682
|
+
const hasStandard = (0, import_node_fs41.existsSync)(STANDARD_FILE);
|
|
23683
|
+
const alreadyTried = (0, import_node_fs41.existsSync)(seedMarker);
|
|
23379
23684
|
if (hasStandard && !alreadyTried) {
|
|
23380
23685
|
const preManifest = await buildManifest();
|
|
23381
23686
|
if (preManifest.nodes.length === 0) {
|
|
@@ -23388,7 +23693,7 @@ async function memoryManifest(run2) {
|
|
|
23388
23693
|
dryRun: false
|
|
23389
23694
|
});
|
|
23390
23695
|
if (seedResult.created > 0) {
|
|
23391
|
-
(0,
|
|
23696
|
+
(0, import_node_fs41.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
|
|
23392
23697
|
`);
|
|
23393
23698
|
autoSeedNotice = `Seeded ${seedResult.created} knowledge node(s) from your existing Standard (one-time).`;
|
|
23394
23699
|
logEvent("auto_seed_ran", {
|
|
@@ -23396,7 +23701,7 @@ async function memoryManifest(run2) {
|
|
|
23396
23701
|
failed: seedResult.failed
|
|
23397
23702
|
});
|
|
23398
23703
|
} else if (seedResult.skipped === "already_seeded") {
|
|
23399
|
-
(0,
|
|
23704
|
+
(0, import_node_fs41.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
|
|
23400
23705
|
`);
|
|
23401
23706
|
} else {
|
|
23402
23707
|
logEvent("auto_seed_noop", {
|
|
@@ -23491,7 +23796,7 @@ function computeIncrement(reviewedPaths, hashOf, priorAuthored) {
|
|
|
23491
23796
|
}
|
|
23492
23797
|
|
|
23493
23798
|
// src/commands/analyze/phases/10-working-memory.ts
|
|
23494
|
-
var
|
|
23799
|
+
var import_node_path32 = require("node:path");
|
|
23495
23800
|
async function workingMemory(run2) {
|
|
23496
23801
|
const { opts } = run2;
|
|
23497
23802
|
const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run2;
|
|
@@ -23503,7 +23808,7 @@ async function workingMemory(run2) {
|
|
|
23503
23808
|
const priorState = foldForMarks(memorySession.d);
|
|
23504
23809
|
incrementReport = computeIncrement(
|
|
23505
23810
|
allForReview,
|
|
23506
|
-
(p) => fileHash((0,
|
|
23811
|
+
(p) => fileHash((0, import_node_path32.join)(repoRoot(), p)),
|
|
23507
23812
|
priorState.authored_all.map((a) => ({
|
|
23508
23813
|
path: a.path,
|
|
23509
23814
|
hash_at_last_verdict: a.hash_at_last_verdict
|
|
@@ -23585,7 +23890,7 @@ async function workingMemory(run2) {
|
|
|
23585
23890
|
}
|
|
23586
23891
|
|
|
23587
23892
|
// src/lib/note-budget.ts
|
|
23588
|
-
var
|
|
23893
|
+
var import_node_fs42 = require("node:fs");
|
|
23589
23894
|
var ADVISORY_BUDGET = { PASS: 1, WARN: 2 };
|
|
23590
23895
|
var EPISODE_STALE_SECONDS = 30 * 60;
|
|
23591
23896
|
var FRESH = { delivered: 0, tasksCompleted: 0, ts: 0 };
|
|
@@ -23607,9 +23912,9 @@ function advisoryBudgetSpent(episode, rawDecision) {
|
|
|
23607
23912
|
}
|
|
23608
23913
|
function readAdvisoryEpisode(sessionId) {
|
|
23609
23914
|
const file = scopedFile(ADVISORY_EPISODE_FILE, sessionId);
|
|
23610
|
-
if (!(0,
|
|
23915
|
+
if (!(0, import_node_fs42.existsSync)(file)) return null;
|
|
23611
23916
|
try {
|
|
23612
|
-
const o = JSON.parse((0,
|
|
23917
|
+
const o = JSON.parse((0, import_node_fs42.readFileSync)(file, "utf-8")) ?? {};
|
|
23613
23918
|
const delivered = typeof o.delivered === "number" ? o.delivered : NaN;
|
|
23614
23919
|
if (isNaN(delivered)) return null;
|
|
23615
23920
|
return {
|
|
@@ -23623,8 +23928,8 @@ function readAdvisoryEpisode(sessionId) {
|
|
|
23623
23928
|
}
|
|
23624
23929
|
function writeAdvisoryEpisode(episode, sessionId) {
|
|
23625
23930
|
try {
|
|
23626
|
-
(0,
|
|
23627
|
-
(0,
|
|
23931
|
+
(0, import_node_fs42.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
23932
|
+
(0, import_node_fs42.writeFileSync)(
|
|
23628
23933
|
scopedFile(ADVISORY_EPISODE_FILE, sessionId),
|
|
23629
23934
|
JSON.stringify({ v: 1, ...episode })
|
|
23630
23935
|
);
|
|
@@ -23932,14 +24237,14 @@ async function buildRequest(run2) {
|
|
|
23932
24237
|
}
|
|
23933
24238
|
|
|
23934
24239
|
// src/lib/offline.ts
|
|
23935
|
-
var
|
|
24240
|
+
var import_node_fs43 = require("node:fs");
|
|
23936
24241
|
var import_node_crypto11 = require("node:crypto");
|
|
23937
24242
|
function cacheRequest(body) {
|
|
23938
24243
|
try {
|
|
23939
|
-
(0,
|
|
24244
|
+
(0, import_node_fs43.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
23940
24245
|
const suffix = (0, import_node_crypto11.randomBytes)(4).toString("hex");
|
|
23941
24246
|
const filename = `pending-${Math.floor(Date.now() / 1e3)}-${suffix}.json`;
|
|
23942
|
-
(0,
|
|
24247
|
+
(0, import_node_fs43.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(redactRequest(body)));
|
|
23943
24248
|
} catch {
|
|
23944
24249
|
}
|
|
23945
24250
|
}
|
|
@@ -24058,8 +24363,8 @@ async function transmit(run2) {
|
|
|
24058
24363
|
}
|
|
24059
24364
|
|
|
24060
24365
|
// src/commands/analyze/phases/13-reconcile.ts
|
|
24061
|
-
var
|
|
24062
|
-
var
|
|
24366
|
+
var import_node_fs44 = require("node:fs");
|
|
24367
|
+
var import_node_path33 = require("node:path");
|
|
24063
24368
|
async function reconcile(run2) {
|
|
24064
24369
|
const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run2;
|
|
24065
24370
|
const sentPaths = codeDelta.files.map((f) => f.path);
|
|
@@ -24088,7 +24393,7 @@ async function reconcile(run2) {
|
|
|
24088
24393
|
const st = foldDossier(memorySession.d);
|
|
24089
24394
|
openElsewhere = openBlockingElsewhere(st.statements, sentPaths, (file, line) => {
|
|
24090
24395
|
try {
|
|
24091
|
-
const src = (0,
|
|
24396
|
+
const src = (0, import_node_fs44.readFileSync)((0, import_node_path33.join)(repoRoot(), file), "utf8").split("\n");
|
|
24092
24397
|
const at = src[line - 1];
|
|
24093
24398
|
return at === void 0 ? null : lineSha(at);
|
|
24094
24399
|
} catch {
|
|
@@ -24353,7 +24658,7 @@ function describeRelease(release, input) {
|
|
|
24353
24658
|
|
|
24354
24659
|
// src/lib/memory-pull.ts
|
|
24355
24660
|
var import_node_child_process14 = require("node:child_process");
|
|
24356
|
-
var
|
|
24661
|
+
var import_promises16 = require("node:fs/promises");
|
|
24357
24662
|
var pullStateFile = () => projectPath(`${VERITY_DIR}/.memory-pull-state.json`);
|
|
24358
24663
|
var PAGE_SIZE = 200;
|
|
24359
24664
|
var MAX_PAGES = 500;
|
|
@@ -24437,7 +24742,7 @@ async function recordServedFiles(served) {
|
|
|
24437
24742
|
}
|
|
24438
24743
|
async function readPullState() {
|
|
24439
24744
|
try {
|
|
24440
|
-
const parsed = JSON.parse(await (0,
|
|
24745
|
+
const parsed = JSON.parse(await (0, import_promises16.readFile)(pullStateFile(), "utf-8"));
|
|
24441
24746
|
const served = /* @__PURE__ */ new Map();
|
|
24442
24747
|
if (parsed?.served && typeof parsed.served === "object") {
|
|
24443
24748
|
for (const [path, hash] of Object.entries(parsed.served)) {
|
|
@@ -24451,8 +24756,8 @@ async function readPullState() {
|
|
|
24451
24756
|
}
|
|
24452
24757
|
async function writePullState(state) {
|
|
24453
24758
|
try {
|
|
24454
|
-
await (0,
|
|
24455
|
-
await (0,
|
|
24759
|
+
await (0, import_promises16.mkdir)(projectPath(VERITY_DIR), { recursive: true });
|
|
24760
|
+
await (0, import_promises16.writeFile)(pullStateFile(), JSON.stringify({
|
|
24456
24761
|
...state.version ? { version: state.version } : {},
|
|
24457
24762
|
pulled_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24458
24763
|
served: Object.fromEntries(state.served)
|
|
@@ -24895,7 +25200,7 @@ function registerAnalyzeCommand(program2) {
|
|
|
24895
25200
|
var tracing = () => process.env.VERITY_TRACE_PHASES === "1";
|
|
24896
25201
|
async function runAnalyze(opts, globals) {
|
|
24897
25202
|
if (!verityConfigured()) {
|
|
24898
|
-
(0,
|
|
25203
|
+
(0, import_node_fs45.writeSync)(2, '[verity] not set up in this project \u2014 run "verity init" first.\n');
|
|
24899
25204
|
process.exit(0);
|
|
24900
25205
|
}
|
|
24901
25206
|
const run2 = createRun(opts, globals);
|
|
@@ -24916,11 +25221,11 @@ async function runAnalyze(opts, globals) {
|
|
|
24916
25221
|
}
|
|
24917
25222
|
|
|
24918
25223
|
// src/commands/baseline.ts
|
|
24919
|
-
var
|
|
25224
|
+
var import_node_fs47 = require("node:fs");
|
|
24920
25225
|
|
|
24921
25226
|
// src/lib/project-skills.ts
|
|
24922
|
-
var
|
|
24923
|
-
var
|
|
25227
|
+
var import_node_fs46 = require("node:fs");
|
|
25228
|
+
var import_node_path34 = require("node:path");
|
|
24924
25229
|
var PROJECT_SKILL_NAMES = [
|
|
24925
25230
|
"verity-setup",
|
|
24926
25231
|
"verity-analyze",
|
|
@@ -24945,14 +25250,14 @@ var LEGACY_SKILL_NAMES = [
|
|
|
24945
25250
|
var ALL = [...PROJECT_SKILL_NAMES, ...LEGACY_SKILL_NAMES];
|
|
24946
25251
|
function staleProjectSkills() {
|
|
24947
25252
|
const root = projectPath(".claude/skills");
|
|
24948
|
-
if (!(0,
|
|
24949
|
-
return ALL.filter((name) => (0,
|
|
25253
|
+
if (!(0, import_node_fs46.existsSync)(root)) return [];
|
|
25254
|
+
return ALL.filter((name) => (0, import_node_fs46.existsSync)((0, import_node_path34.join)(root, name)));
|
|
24950
25255
|
}
|
|
24951
25256
|
function removeProjectSkills() {
|
|
24952
25257
|
const root = projectPath(".claude/skills");
|
|
24953
25258
|
const removed = [];
|
|
24954
25259
|
for (const name of staleProjectSkills()) {
|
|
24955
|
-
(0,
|
|
25260
|
+
(0, import_node_fs46.rmSync)((0, import_node_path34.join)(root, name), { recursive: true, force: true });
|
|
24956
25261
|
removed.push(name);
|
|
24957
25262
|
}
|
|
24958
25263
|
return removed;
|
|
@@ -25017,13 +25322,13 @@ function registerBaselineCommands(program2) {
|
|
|
25017
25322
|
let memoryMsg = null;
|
|
25018
25323
|
let memoryAgentLine = null;
|
|
25019
25324
|
const memoryNotice = projectPath(`${VERITY_DIR}/.memory-fence-notice`);
|
|
25020
|
-
if (realStart && !(0,
|
|
25325
|
+
if (realStart && !(0, import_node_fs47.existsSync)(memoryNotice)) {
|
|
25021
25326
|
const trackedGraph = memoryOptOut() ? 0 : committedMemoryFiles().length;
|
|
25022
25327
|
if (trackedGraph > 0) {
|
|
25023
25328
|
memoryMsg = `Verity: this project commits its knowledge base (${trackedGraph} files under .verity/memory/), so Verity's generated notes show up in every diff and pull request. Run \`verity memory untrack\` to keep them on disk but out of git, or \`verity memory track\` to keep committing them on purpose.`;
|
|
25024
25329
|
memoryAgentLine = `This project has ${trackedGraph} knowledge-graph files tracked in git under .verity/memory/. As of Verity 0.32.6 the graph is machine-local by default \u2014 it is rebuilt from the service, and committing it puts generated notes in every pull request. If the user wants that stopped, run \`verity memory untrack\` for them: it keeps every file on disk and stages their removal from the index, so they only need to commit \u2014 and their teammates' working copies will vanish on the next pull and re-sync from the service, which is expected. If they would rather keep committing it, \`verity memory track\` records that and nothing will offer again.`;
|
|
25025
25330
|
try {
|
|
25026
|
-
(0,
|
|
25331
|
+
(0, import_node_fs47.writeFileSync)(memoryNotice, (/* @__PURE__ */ new Date()).toISOString() + "\n");
|
|
25027
25332
|
} catch {
|
|
25028
25333
|
}
|
|
25029
25334
|
}
|
|
@@ -25124,7 +25429,7 @@ function hookSource(value) {
|
|
|
25124
25429
|
}
|
|
25125
25430
|
|
|
25126
25431
|
// src/commands/review.ts
|
|
25127
|
-
var
|
|
25432
|
+
var import_node_fs48 = require("node:fs");
|
|
25128
25433
|
function registerReviewCommand(program2) {
|
|
25129
25434
|
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) => {
|
|
25130
25435
|
const globals = program2.opts();
|
|
@@ -25143,7 +25448,7 @@ async function runReview(opts, globals) {
|
|
|
25143
25448
|
const securityFiles = filterSecurity(allFiles);
|
|
25144
25449
|
let staticResults;
|
|
25145
25450
|
if (isCodacyAvailable()) {
|
|
25146
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0,
|
|
25451
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs48.existsSync)(f) || resolveFile(f) !== null);
|
|
25147
25452
|
staticResults = runCodacyAnalysis(scannable);
|
|
25148
25453
|
} else {
|
|
25149
25454
|
staticResults = {
|
|
@@ -25169,7 +25474,7 @@ async function runReview(opts, globals) {
|
|
|
25169
25474
|
const specPaths = opts.specs.split(",").map((f) => f.trim()).filter(Boolean);
|
|
25170
25475
|
specs = [];
|
|
25171
25476
|
for (const p of specPaths) {
|
|
25172
|
-
if (!(0,
|
|
25477
|
+
if (!(0, import_node_fs48.existsSync)(p)) continue;
|
|
25173
25478
|
try {
|
|
25174
25479
|
const { readFileSync: readFileSync26 } = await import("node:fs");
|
|
25175
25480
|
const content = readFileSync26(p, "utf-8");
|
|
@@ -25229,8 +25534,8 @@ async function runReview(opts, globals) {
|
|
|
25229
25534
|
}
|
|
25230
25535
|
|
|
25231
25536
|
// src/commands/guard.ts
|
|
25232
|
-
var
|
|
25233
|
-
var
|
|
25537
|
+
var import_node_fs49 = require("node:fs");
|
|
25538
|
+
var import_node_path35 = require("node:path");
|
|
25234
25539
|
|
|
25235
25540
|
// src/lib/terminal-text.ts
|
|
25236
25541
|
var CONTROL = /[\x00-\x08\x0b-\x1f\x7f-\x9f\u061c\u200e\u200f\u2028-\u202e\u2066-\u2069]/g;
|
|
@@ -25605,7 +25910,7 @@ async function buildAgentDiffs(ctx, paths, limits = { perFileChars: 24e3, totalC
|
|
|
25605
25910
|
// src/commands/guard.ts
|
|
25606
25911
|
var EXCERPT_SOURCE_MAX_BYTES = 2 * 1024 * 1024;
|
|
25607
25912
|
var GUARD_BLOCK_CAP = 2;
|
|
25608
|
-
var GUARD_ITER_FILE = (0,
|
|
25913
|
+
var GUARD_ITER_FILE = (0, import_node_path35.join)(VERITY_DIR, ".guard-iteration");
|
|
25609
25914
|
function readPreToolUseStdin() {
|
|
25610
25915
|
const empty = { command: "", cwd: null, sessionId: null };
|
|
25611
25916
|
return new Promise((resolve6) => {
|
|
@@ -25650,7 +25955,7 @@ function readPreToolUseStdin() {
|
|
|
25650
25955
|
}
|
|
25651
25956
|
function readIterMap() {
|
|
25652
25957
|
try {
|
|
25653
|
-
const raw = JSON.parse((0,
|
|
25958
|
+
const raw = JSON.parse((0, import_node_fs49.readFileSync)(GUARD_ITER_FILE, "utf-8"));
|
|
25654
25959
|
if (raw && typeof raw === "object") {
|
|
25655
25960
|
if (typeof raw.moment === "string" && typeof raw.count === "number") {
|
|
25656
25961
|
return { [raw.moment]: raw.count };
|
|
@@ -25670,10 +25975,10 @@ function readIter(moment) {
|
|
|
25670
25975
|
}
|
|
25671
25976
|
function writeIter(moment, count) {
|
|
25672
25977
|
try {
|
|
25673
|
-
(0,
|
|
25978
|
+
(0, import_node_fs49.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
25674
25979
|
const map = readIterMap();
|
|
25675
25980
|
map[moment] = count;
|
|
25676
|
-
(0,
|
|
25981
|
+
(0, import_node_fs49.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
25677
25982
|
} catch {
|
|
25678
25983
|
}
|
|
25679
25984
|
}
|
|
@@ -25683,10 +25988,10 @@ function resetIter(moment) {
|
|
|
25683
25988
|
if (!(moment in map)) return;
|
|
25684
25989
|
delete map[moment];
|
|
25685
25990
|
if (Object.keys(map).length === 0) {
|
|
25686
|
-
if ((0,
|
|
25991
|
+
if ((0, import_node_fs49.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs49.unlinkSync)(GUARD_ITER_FILE);
|
|
25687
25992
|
} else {
|
|
25688
|
-
(0,
|
|
25689
|
-
(0,
|
|
25993
|
+
(0, import_node_fs49.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
25994
|
+
(0, import_node_fs49.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
25690
25995
|
}
|
|
25691
25996
|
} catch {
|
|
25692
25997
|
}
|
|
@@ -25758,7 +26063,7 @@ function buildGuardRequest(moment, files, codeDelta, iter, sessionId, statedInte
|
|
|
25758
26063
|
const securityFiles = filterSecurity(files);
|
|
25759
26064
|
let staticResults;
|
|
25760
26065
|
if (isCodacyAvailable()) {
|
|
25761
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0,
|
|
26066
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs49.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
|
|
25762
26067
|
staticResults = runCodacyAnalysis(scannable);
|
|
25763
26068
|
} else {
|
|
25764
26069
|
staticResults = { tool: "@codacy/analysis-cli", findings: [], summary: { total_findings: 0, by_severity: {}, tools_run: [] } };
|
|
@@ -26261,7 +26566,7 @@ function registerIgnoreCommand(program2) {
|
|
|
26261
26566
|
|
|
26262
26567
|
// src/commands/waive.ts
|
|
26263
26568
|
var import_node_crypto12 = require("node:crypto");
|
|
26264
|
-
var
|
|
26569
|
+
var import_node_fs50 = require("node:fs");
|
|
26265
26570
|
function registerWaiveCommand(program2) {
|
|
26266
26571
|
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) => {
|
|
26267
26572
|
const globals = program2.opts();
|
|
@@ -26290,7 +26595,7 @@ function registerWaiveCommand(program2) {
|
|
|
26290
26595
|
if (opts.file) {
|
|
26291
26596
|
body.file = opts.file;
|
|
26292
26597
|
try {
|
|
26293
|
-
body.file_sha256 = (0, import_node_crypto12.createHash)("sha256").update((0,
|
|
26598
|
+
body.file_sha256 = (0, import_node_crypto12.createHash)("sha256").update((0, import_node_fs50.readFileSync)(opts.file)).digest("hex");
|
|
26294
26599
|
} catch {
|
|
26295
26600
|
printError(`Cannot read ${opts.file} \u2014 run from the repo root, or omit --file to waive by pattern.`);
|
|
26296
26601
|
process.exit(1);
|
|
@@ -26315,10 +26620,10 @@ function registerWaiveCommand(program2) {
|
|
|
26315
26620
|
}
|
|
26316
26621
|
|
|
26317
26622
|
// src/commands/init.ts
|
|
26318
|
-
var
|
|
26319
|
-
var
|
|
26623
|
+
var import_node_fs54 = require("node:fs");
|
|
26624
|
+
var import_promises19 = require("node:fs/promises");
|
|
26320
26625
|
var import_yaml6 = __toESM(require_dist());
|
|
26321
|
-
var
|
|
26626
|
+
var import_node_path38 = require("node:path");
|
|
26322
26627
|
var import_node_child_process17 = require("node:child_process");
|
|
26323
26628
|
|
|
26324
26629
|
// src/lib/banner.ts
|
|
@@ -26397,7 +26702,7 @@ function printPhase(n, of, title, subtitle) {
|
|
|
26397
26702
|
}
|
|
26398
26703
|
|
|
26399
26704
|
// src/commands/doctor.ts
|
|
26400
|
-
var
|
|
26705
|
+
var import_node_fs51 = require("node:fs");
|
|
26401
26706
|
|
|
26402
26707
|
// src/lib/prereqs.ts
|
|
26403
26708
|
var import_node_child_process15 = require("node:child_process");
|
|
@@ -26513,7 +26818,7 @@ async function checkPrereqs(opts = {}) {
|
|
|
26513
26818
|
}
|
|
26514
26819
|
|
|
26515
26820
|
// src/lib/telemetry.ts
|
|
26516
|
-
var
|
|
26821
|
+
var import_promises17 = require("node:fs/promises");
|
|
26517
26822
|
var SETTINGS_LOCAL_FILE2 = ".claude/settings.local.json";
|
|
26518
26823
|
var GITIGNORE_FILE = ".gitignore";
|
|
26519
26824
|
var GITIGNORE_ENTRY = SETTINGS_LOCAL_IGNORE_ENTRY;
|
|
@@ -26543,7 +26848,7 @@ function buildTelemetryEnv(serviceUrl) {
|
|
|
26543
26848
|
var VERITY_TELEMETRY_KEYS = Object.keys(buildTelemetryEnv(""));
|
|
26544
26849
|
async function readSettingsLocal() {
|
|
26545
26850
|
try {
|
|
26546
|
-
return JSON.parse(await (0,
|
|
26851
|
+
return JSON.parse(await (0, import_promises17.readFile)(projectPath(SETTINGS_LOCAL_FILE2), "utf-8"));
|
|
26547
26852
|
} catch {
|
|
26548
26853
|
return {};
|
|
26549
26854
|
}
|
|
@@ -26555,7 +26860,7 @@ async function ensureGitignore() {
|
|
|
26555
26860
|
const file = projectPath(GITIGNORE_FILE);
|
|
26556
26861
|
let content = "";
|
|
26557
26862
|
try {
|
|
26558
|
-
content = await (0,
|
|
26863
|
+
content = await (0, import_promises17.readFile)(file, "utf-8");
|
|
26559
26864
|
} catch {
|
|
26560
26865
|
}
|
|
26561
26866
|
const lines = content.split("\n").map((l) => l.trim());
|
|
@@ -26564,7 +26869,7 @@ async function ensureGitignore() {
|
|
|
26564
26869
|
}
|
|
26565
26870
|
const block = "# Verity telemetry \u2014 machine-local Claude Code settings\n" + GITIGNORE_ENTRY + "\n";
|
|
26566
26871
|
const next = content ? content + (content.endsWith("\n") ? "" : "\n") + "\n" + block : block;
|
|
26567
|
-
await (0,
|
|
26872
|
+
await (0, import_promises17.writeFile)(file, next);
|
|
26568
26873
|
}
|
|
26569
26874
|
async function installTelemetry(serviceUrl) {
|
|
26570
26875
|
const env = buildTelemetryEnv(serviceUrl);
|
|
@@ -26609,11 +26914,11 @@ async function buildReport() {
|
|
|
26609
26914
|
const wiring = await resolveHookWiring();
|
|
26610
26915
|
const hooks = wiring.status;
|
|
26611
26916
|
const telemetry = await checkTelemetry();
|
|
26612
|
-
const hasConfig = (0,
|
|
26917
|
+
const hasConfig = (0, import_node_fs51.existsSync)(projectPath(CODACY_CONFIG_FILE));
|
|
26613
26918
|
const artifacts = {
|
|
26614
|
-
standard: (0,
|
|
26919
|
+
standard: (0, import_node_fs51.existsSync)(projectPath(STANDARD_FILE)),
|
|
26615
26920
|
analysisConfig: hasConfig,
|
|
26616
|
-
verityMd: (0,
|
|
26921
|
+
verityMd: (0, import_node_fs51.existsSync)(projectPath(VERITY_MD_FILE)),
|
|
26617
26922
|
analysisConfigIds: hasConfig ? validatePatternIds().status : "absent"
|
|
26618
26923
|
};
|
|
26619
26924
|
const next = [];
|
|
@@ -26744,8 +27049,8 @@ function registerDoctorCommand(program2) {
|
|
|
26744
27049
|
}
|
|
26745
27050
|
|
|
26746
27051
|
// src/commands/migrate.ts
|
|
26747
|
-
var
|
|
26748
|
-
var
|
|
27052
|
+
var import_node_fs52 = require("node:fs");
|
|
27053
|
+
var import_node_path36 = require("node:path");
|
|
26749
27054
|
var import_node_child_process16 = require("node:child_process");
|
|
26750
27055
|
var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
|
|
26751
27056
|
function defaultNpmRemover(pkg) {
|
|
@@ -26782,12 +27087,12 @@ async function runMigration(opts = {}) {
|
|
|
26782
27087
|
return { actions, migrated: actions.length > 0 };
|
|
26783
27088
|
}
|
|
26784
27089
|
function migrateProjectDir(root, actions) {
|
|
26785
|
-
const gateDir = (0,
|
|
26786
|
-
const verityDir = (0,
|
|
26787
|
-
if ((0,
|
|
27090
|
+
const gateDir = (0, import_node_path36.join)(root, ".gate");
|
|
27091
|
+
const verityDir = (0, import_node_path36.join)(root, ".verity");
|
|
27092
|
+
if ((0, import_node_fs52.existsSync)(gateDir) && !(0, import_node_fs52.existsSync)(verityDir)) {
|
|
26788
27093
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
26789
27094
|
}
|
|
26790
|
-
if ((0,
|
|
27095
|
+
if ((0, import_node_fs52.existsSync)(gateDir) && (0, import_node_fs52.existsSync)(verityDir)) {
|
|
26791
27096
|
return migrateProjectDirCarry(gateDir, verityDir, actions);
|
|
26792
27097
|
}
|
|
26793
27098
|
return false;
|
|
@@ -26808,13 +27113,13 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
|
|
|
26808
27113
|
}
|
|
26809
27114
|
}
|
|
26810
27115
|
if (moved) {
|
|
26811
|
-
if ((0,
|
|
27116
|
+
if ((0, import_node_fs52.existsSync)(gateDir)) {
|
|
26812
27117
|
const carried = carryLegacyContents(gateDir, verityDir);
|
|
26813
27118
|
if (carried > 0) {
|
|
26814
27119
|
actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
|
|
26815
27120
|
}
|
|
26816
27121
|
try {
|
|
26817
|
-
(0,
|
|
27122
|
+
(0, import_node_fs52.rmSync)(gateDir, { recursive: true, force: true });
|
|
26818
27123
|
} catch {
|
|
26819
27124
|
}
|
|
26820
27125
|
}
|
|
@@ -26830,18 +27135,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
26830
27135
|
actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
|
|
26831
27136
|
}
|
|
26832
27137
|
try {
|
|
26833
|
-
(0,
|
|
27138
|
+
(0, import_node_fs52.rmSync)(gateDir, { recursive: true, force: true });
|
|
26834
27139
|
} catch {
|
|
26835
27140
|
}
|
|
26836
27141
|
return carried > 0;
|
|
26837
27142
|
}
|
|
26838
27143
|
function migrateGlobalCredentials(home, actions) {
|
|
26839
27144
|
if (!home) return;
|
|
26840
|
-
const gateCreds = (0,
|
|
26841
|
-
const verityCreds = (0,
|
|
26842
|
-
if (!(0,
|
|
26843
|
-
if (!(0,
|
|
26844
|
-
(0,
|
|
27145
|
+
const gateCreds = (0, import_node_path36.join)(home, ".gate", "credentials");
|
|
27146
|
+
const verityCreds = (0, import_node_path36.join)(home, ".verity", "credentials");
|
|
27147
|
+
if (!(0, import_node_fs52.existsSync)(gateCreds)) return;
|
|
27148
|
+
if (!(0, import_node_fs52.existsSync)(verityCreds)) {
|
|
27149
|
+
(0, import_node_fs52.mkdirSync)((0, import_node_path36.join)(home, ".verity"), { recursive: true });
|
|
26845
27150
|
moveFile(gateCreds, verityCreds);
|
|
26846
27151
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
26847
27152
|
return;
|
|
@@ -26863,8 +27168,8 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
26863
27168
|
}
|
|
26864
27169
|
}
|
|
26865
27170
|
async function migrateClaudeMd(root, actions) {
|
|
26866
|
-
const claudeMd = (0,
|
|
26867
|
-
const hadLegacyBlock = (0,
|
|
27171
|
+
const claudeMd = (0, import_node_path36.join)(root, "CLAUDE.md");
|
|
27172
|
+
const hadLegacyBlock = (0, import_node_fs52.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
|
|
26868
27173
|
if (!hadLegacyBlock) return;
|
|
26869
27174
|
try {
|
|
26870
27175
|
await ensureClaudeMdPointer(root);
|
|
@@ -26874,9 +27179,9 @@ async function migrateClaudeMd(root, actions) {
|
|
|
26874
27179
|
}
|
|
26875
27180
|
}
|
|
26876
27181
|
function migrateStandardFile(root, actions) {
|
|
26877
|
-
const gateMd = (0,
|
|
26878
|
-
const verityMd = (0,
|
|
26879
|
-
if (!(0,
|
|
27182
|
+
const gateMd = (0, import_node_path36.join)(root, "GATE.md");
|
|
27183
|
+
const verityMd = (0, import_node_path36.join)(root, "VERITY.md");
|
|
27184
|
+
if (!(0, import_node_fs52.existsSync)(gateMd) || (0, import_node_fs52.existsSync)(verityMd)) return;
|
|
26880
27185
|
let moved = false;
|
|
26881
27186
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
26882
27187
|
try {
|
|
@@ -26888,12 +27193,12 @@ function migrateStandardFile(root, actions) {
|
|
|
26888
27193
|
if (!moved) moveFile(gateMd, verityMd);
|
|
26889
27194
|
const content = readFileSyncSafe(verityMd);
|
|
26890
27195
|
const refreshed = content.split("GATE.md").join("VERITY.md");
|
|
26891
|
-
if (refreshed !== content) (0,
|
|
27196
|
+
if (refreshed !== content) (0, import_node_fs52.writeFileSync)(verityMd, refreshed);
|
|
26892
27197
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
26893
27198
|
}
|
|
26894
27199
|
async function migrateTelemetryHeaders(root, actions) {
|
|
26895
|
-
const file = (0,
|
|
26896
|
-
if (!(0,
|
|
27200
|
+
const file = (0, import_node_path36.join)(root, ".claude", "settings.local.json");
|
|
27201
|
+
if (!(0, import_node_fs52.existsSync)(file)) return;
|
|
26897
27202
|
let settings;
|
|
26898
27203
|
try {
|
|
26899
27204
|
settings = JSON.parse(readFileSyncSafe(file) || "{}");
|
|
@@ -26941,14 +27246,14 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
26941
27246
|
}
|
|
26942
27247
|
if (toAppend.length > 0) {
|
|
26943
27248
|
const sep4 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
26944
|
-
(0,
|
|
27249
|
+
(0, import_node_fs52.writeFileSync)(verityCreds, verityContent + sep4 + toAppend.join("\n") + "\n");
|
|
26945
27250
|
}
|
|
26946
|
-
(0,
|
|
27251
|
+
(0, import_node_fs52.rmSync)(gateCreds, { force: true });
|
|
26947
27252
|
return toAppend.length;
|
|
26948
27253
|
}
|
|
26949
27254
|
function readFileSyncSafe(path) {
|
|
26950
27255
|
try {
|
|
26951
|
-
return (0,
|
|
27256
|
+
return (0, import_node_fs52.readFileSync)(path, "utf-8");
|
|
26952
27257
|
} catch {
|
|
26953
27258
|
return "";
|
|
26954
27259
|
}
|
|
@@ -26963,35 +27268,35 @@ function hasStagedChanges(root) {
|
|
|
26963
27268
|
}
|
|
26964
27269
|
function moveDir(from, to) {
|
|
26965
27270
|
try {
|
|
26966
|
-
(0,
|
|
27271
|
+
(0, import_node_fs52.renameSync)(from, to);
|
|
26967
27272
|
} catch (err) {
|
|
26968
27273
|
if (err.code !== "EXDEV") throw err;
|
|
26969
|
-
(0,
|
|
26970
|
-
(0,
|
|
27274
|
+
(0, import_node_fs52.cpSync)(from, to, { recursive: true });
|
|
27275
|
+
(0, import_node_fs52.rmSync)(from, { recursive: true, force: true });
|
|
26971
27276
|
}
|
|
26972
27277
|
}
|
|
26973
27278
|
function moveFile(from, to) {
|
|
26974
27279
|
try {
|
|
26975
|
-
(0,
|
|
27280
|
+
(0, import_node_fs52.renameSync)(from, to);
|
|
26976
27281
|
} catch (err) {
|
|
26977
27282
|
if (err.code !== "EXDEV") throw err;
|
|
26978
|
-
(0,
|
|
26979
|
-
(0,
|
|
27283
|
+
(0, import_node_fs52.cpSync)(from, to);
|
|
27284
|
+
(0, import_node_fs52.rmSync)(from, { force: true });
|
|
26980
27285
|
}
|
|
26981
27286
|
}
|
|
26982
27287
|
function carryLegacyContents(gateDir, verityDir) {
|
|
26983
27288
|
let copied = 0;
|
|
26984
27289
|
const walk2 = (relDir) => {
|
|
26985
|
-
const srcDir = (0,
|
|
26986
|
-
for (const entry of (0,
|
|
26987
|
-
const rel = relDir ? (0,
|
|
26988
|
-
const src = (0,
|
|
26989
|
-
const dest = (0,
|
|
26990
|
-
if ((0,
|
|
27290
|
+
const srcDir = (0, import_node_path36.join)(gateDir, relDir);
|
|
27291
|
+
for (const entry of (0, import_node_fs52.readdirSync)(srcDir)) {
|
|
27292
|
+
const rel = relDir ? (0, import_node_path36.join)(relDir, entry) : entry;
|
|
27293
|
+
const src = (0, import_node_path36.join)(gateDir, rel);
|
|
27294
|
+
const dest = (0, import_node_path36.join)(verityDir, rel);
|
|
27295
|
+
if ((0, import_node_fs52.statSync)(src).isDirectory()) {
|
|
26991
27296
|
walk2(rel);
|
|
26992
|
-
} else if (!(0,
|
|
26993
|
-
(0,
|
|
26994
|
-
(0,
|
|
27297
|
+
} else if (!(0, import_node_fs52.existsSync)(dest)) {
|
|
27298
|
+
(0, import_node_fs52.mkdirSync)((0, import_node_path36.dirname)(dest), { recursive: true });
|
|
27299
|
+
(0, import_node_fs52.cpSync)(src, dest);
|
|
26995
27300
|
copied++;
|
|
26996
27301
|
}
|
|
26997
27302
|
}
|
|
@@ -27000,22 +27305,22 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
27000
27305
|
return copied;
|
|
27001
27306
|
}
|
|
27002
27307
|
async function needsMigration(root = repoRoot()) {
|
|
27003
|
-
const gateDir = (0,
|
|
27004
|
-
const verityDir = (0,
|
|
27005
|
-
if ((0,
|
|
27006
|
-
if ((0,
|
|
27007
|
-
if ((0,
|
|
27308
|
+
const gateDir = (0, import_node_path36.join)(root, ".gate");
|
|
27309
|
+
const verityDir = (0, import_node_path36.join)(root, ".verity");
|
|
27310
|
+
if ((0, import_node_fs52.existsSync)(gateDir) && !(0, import_node_fs52.existsSync)(verityDir)) return true;
|
|
27311
|
+
if ((0, import_node_fs52.existsSync)(gateDir) && (0, import_node_fs52.existsSync)(verityDir)) {
|
|
27312
|
+
if ((0, import_node_fs52.existsSync)((0, import_node_path36.join)(gateDir, "credentials")) && !(0, import_node_fs52.existsSync)((0, import_node_path36.join)(verityDir, "credentials"))) {
|
|
27008
27313
|
return true;
|
|
27009
27314
|
}
|
|
27010
|
-
if ((0,
|
|
27315
|
+
if ((0, import_node_fs52.existsSync)((0, import_node_path36.join)(gateDir, "memory")) && !(0, import_node_fs52.existsSync)((0, import_node_path36.join)(verityDir, "memory"))) {
|
|
27011
27316
|
return true;
|
|
27012
27317
|
}
|
|
27013
27318
|
}
|
|
27014
|
-
const claudeMd = (0,
|
|
27015
|
-
if ((0,
|
|
27319
|
+
const claudeMd = (0, import_node_path36.join)(root, "CLAUDE.md");
|
|
27320
|
+
if ((0, import_node_fs52.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
27016
27321
|
return true;
|
|
27017
27322
|
}
|
|
27018
|
-
if ((0,
|
|
27323
|
+
if ((0, import_node_fs52.existsSync)((0, import_node_path36.join)(root, "GATE.md")) && !(0, import_node_fs52.existsSync)((0, import_node_path36.join)(root, "VERITY.md"))) {
|
|
27019
27324
|
return true;
|
|
27020
27325
|
}
|
|
27021
27326
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -27296,9 +27601,9 @@ async function promptMultiSelect(question, choices, fallback) {
|
|
|
27296
27601
|
}
|
|
27297
27602
|
|
|
27298
27603
|
// src/lib/remote-config.ts
|
|
27299
|
-
var
|
|
27300
|
-
var
|
|
27301
|
-
var
|
|
27604
|
+
var import_node_fs53 = require("node:fs");
|
|
27605
|
+
var import_promises18 = require("node:fs/promises");
|
|
27606
|
+
var import_node_path37 = require("node:path");
|
|
27302
27607
|
var import_yaml5 = __toESM(require_dist());
|
|
27303
27608
|
var IGNORE_RIDER = "verityignore";
|
|
27304
27609
|
async function fetchRemoteSetup(opts) {
|
|
@@ -27343,11 +27648,11 @@ async function adoptRemoteSetup(found, opts) {
|
|
|
27343
27648
|
written.push(STANDARD_FILE);
|
|
27344
27649
|
if (rider !== null) {
|
|
27345
27650
|
const localIgnore = projectPath(VERITYIGNORE_FILE);
|
|
27346
|
-
if (!(0,
|
|
27651
|
+
if (!(0, import_node_fs53.existsSync)(localIgnore)) {
|
|
27347
27652
|
await writeOut(VERITYIGNORE_FILE, rider);
|
|
27348
27653
|
written.push(VERITYIGNORE_FILE);
|
|
27349
27654
|
} else {
|
|
27350
|
-
const local = await (0,
|
|
27655
|
+
const local = await (0, import_promises18.readFile)(localIgnore, "utf-8").catch(() => null);
|
|
27351
27656
|
if (local !== null && local !== rider) {
|
|
27352
27657
|
notes.push(`${VERITYIGNORE_FILE} already exists here and differs from the pushed copy \u2014 kept yours.`);
|
|
27353
27658
|
}
|
|
@@ -27376,8 +27681,8 @@ async function adoptRemoteSetup(found, opts) {
|
|
|
27376
27681
|
}
|
|
27377
27682
|
async function writeOut(relative2, body) {
|
|
27378
27683
|
const target = projectPath(relative2);
|
|
27379
|
-
await (0,
|
|
27380
|
-
await (0,
|
|
27684
|
+
await (0, import_promises18.mkdir)((0, import_node_path37.dirname)(target), { recursive: true });
|
|
27685
|
+
await (0, import_promises18.writeFile)(target, body);
|
|
27381
27686
|
}
|
|
27382
27687
|
function describeRemote(found) {
|
|
27383
27688
|
const when = found.standard.createdAt.slice(0, 10);
|
|
@@ -27493,15 +27798,15 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
27493
27798
|
}
|
|
27494
27799
|
function resolveDataDir2() {
|
|
27495
27800
|
const candidates2 = [
|
|
27496
|
-
(0,
|
|
27801
|
+
(0, import_node_path38.join)(__dirname, "..", "data"),
|
|
27497
27802
|
// installed: node_modules/@codacy/verity-cli/data
|
|
27498
|
-
(0,
|
|
27803
|
+
(0, import_node_path38.join)(__dirname, "..", "..", "data"),
|
|
27499
27804
|
// edge case: nested resolution
|
|
27500
|
-
(0,
|
|
27805
|
+
(0, import_node_path38.join)(process.cwd(), "cli", "data")
|
|
27501
27806
|
// local dev: running from repo root
|
|
27502
27807
|
];
|
|
27503
27808
|
for (const candidate of candidates2) {
|
|
27504
|
-
if ((0,
|
|
27809
|
+
if ((0, import_node_fs54.existsSync)((0, import_node_path38.join)(candidate, "skills"))) {
|
|
27505
27810
|
return candidate;
|
|
27506
27811
|
}
|
|
27507
27812
|
}
|
|
@@ -27510,16 +27815,16 @@ function resolveDataDir2() {
|
|
|
27510
27815
|
);
|
|
27511
27816
|
}
|
|
27512
27817
|
async function copyDir(src, dest) {
|
|
27513
|
-
await (0,
|
|
27514
|
-
await (0,
|
|
27818
|
+
await (0, import_promises19.mkdir)(dest, { recursive: true });
|
|
27819
|
+
await (0, import_promises19.cp)(src, dest, { recursive: true, force: true });
|
|
27515
27820
|
}
|
|
27516
27821
|
async function skillIsCurrent(src, dest) {
|
|
27517
27822
|
const list2 = (dir) => {
|
|
27518
27823
|
const out = [];
|
|
27519
27824
|
const walk2 = (d, prefix) => {
|
|
27520
|
-
for (const e of (0,
|
|
27825
|
+
for (const e of (0, import_node_fs54.readdirSync)(d, { withFileTypes: true })) {
|
|
27521
27826
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
27522
|
-
if (e.isDirectory()) walk2((0,
|
|
27827
|
+
if (e.isDirectory()) walk2((0, import_node_path38.join)(d, e.name), rel);
|
|
27523
27828
|
else if (e.isFile()) out.push(rel);
|
|
27524
27829
|
}
|
|
27525
27830
|
};
|
|
@@ -27530,8 +27835,8 @@ async function skillIsCurrent(src, dest) {
|
|
|
27530
27835
|
const shipped = list2(src);
|
|
27531
27836
|
if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
|
|
27532
27837
|
for (const rel of shipped) {
|
|
27533
|
-
const a = await (0,
|
|
27534
|
-
const b = await (0,
|
|
27838
|
+
const a = await (0, import_promises19.readFile)((0, import_node_path38.join)(src, rel), "utf-8");
|
|
27839
|
+
const b = await (0, import_promises19.readFile)((0, import_node_path38.join)(dest, rel), "utf-8");
|
|
27535
27840
|
if (a !== b) return false;
|
|
27536
27841
|
}
|
|
27537
27842
|
return true;
|
|
@@ -27712,13 +28017,13 @@ async function synthesizeLocally(opts) {
|
|
|
27712
28017
|
async function healStaleAnalysisConfig(globals) {
|
|
27713
28018
|
const configPath = projectPath(CODACY_CONFIG_FILE);
|
|
27714
28019
|
const standardPath = projectPath(STANDARD_FILE);
|
|
27715
|
-
if (!(0,
|
|
28020
|
+
if (!(0, import_node_fs54.existsSync)(configPath) || !(0, import_node_fs54.existsSync)(standardPath)) return;
|
|
27716
28021
|
const validation = validatePatternIds();
|
|
27717
28022
|
if (validation.status !== "invalid") return;
|
|
27718
28023
|
printWarn(" Your analysis config names pattern ids that no longer resolve \u2014 those tools were");
|
|
27719
28024
|
printWarn(" running silently with nothing enabled. Re-deriving it from your Standard\u2026");
|
|
27720
28025
|
try {
|
|
27721
|
-
const content = (0, import_yaml6.parse)(await (0,
|
|
28026
|
+
const content = (0, import_yaml6.parse)(await (0, import_promises19.readFile)(standardPath, "utf-8"));
|
|
27722
28027
|
const derived = await deriveConfigForStandard(content);
|
|
27723
28028
|
for (const path of derived.written) printInfo(` ${path} \u2713 (re-derived)`);
|
|
27724
28029
|
for (const note of derived.notes) printWarn(` ${note}`);
|
|
@@ -27809,17 +28114,17 @@ async function handoffToSetup(enabled, claudeInstalled) {
|
|
|
27809
28114
|
async function installSkills(force, step) {
|
|
27810
28115
|
step("Installing skills");
|
|
27811
28116
|
const dataDir = resolveDataDir2();
|
|
27812
|
-
const skillsSource = (0,
|
|
28117
|
+
const skillsSource = (0, import_node_path38.join)(dataDir, "skills");
|
|
27813
28118
|
const skillsDest = ".claude/skills";
|
|
27814
28119
|
let skillsInstalled = 0;
|
|
27815
28120
|
for (const skill of SKILLS) {
|
|
27816
|
-
const src = (0,
|
|
27817
|
-
const dest = (0,
|
|
27818
|
-
if (!(0,
|
|
28121
|
+
const src = (0, import_node_path38.join)(skillsSource, skill);
|
|
28122
|
+
const dest = (0, import_node_path38.join)(skillsDest, skill);
|
|
28123
|
+
if (!(0, import_node_fs54.existsSync)(src)) {
|
|
27819
28124
|
printWarn(` Skill data not found: ${skill}`);
|
|
27820
28125
|
continue;
|
|
27821
28126
|
}
|
|
27822
|
-
if ((0,
|
|
28127
|
+
if ((0, import_node_fs54.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) {
|
|
27823
28128
|
skillsInstalled++;
|
|
27824
28129
|
continue;
|
|
27825
28130
|
}
|
|
@@ -27883,7 +28188,7 @@ async function checkPrerequisites(step) {
|
|
|
27883
28188
|
}
|
|
27884
28189
|
async function scaffoldProject(step, defaultsOnly) {
|
|
27885
28190
|
step("Knowledge base, .gitignore and CLAUDE.md");
|
|
27886
|
-
await (0,
|
|
28191
|
+
await (0, import_promises19.mkdir)(VERITY_DIR, { recursive: true });
|
|
27887
28192
|
await ensureMemoryDir();
|
|
27888
28193
|
const ignoreResult = ensureVerityGitignore();
|
|
27889
28194
|
if (ignoreResult === "failed") {
|
|
@@ -27958,7 +28263,7 @@ function registerInitCommand(program2) {
|
|
|
27958
28263
|
const staleMarker = clearStalePluginMarker();
|
|
27959
28264
|
const pluginMode = opts.plugin === false ? false : opts.pluginMode ?? pluginActiveHere();
|
|
27960
28265
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
27961
|
-
const isProject = projectMarkers.some((m) => (0,
|
|
28266
|
+
const isProject = projectMarkers.some((m) => (0, import_node_fs54.existsSync)(m));
|
|
27962
28267
|
if (!isProject) {
|
|
27963
28268
|
printError("No project detected in the current directory.");
|
|
27964
28269
|
printInfo('Run "verity init" from your project root.');
|
|
@@ -28048,8 +28353,8 @@ function registerInitCommand(program2) {
|
|
|
28048
28353
|
printInfo(` intensity: ${intensity} \xB7 moments: ${moments.join(", ") || "none"} (no questions asked)`);
|
|
28049
28354
|
}
|
|
28050
28355
|
await scaffoldProject(step, defaultsOnly);
|
|
28051
|
-
const globalVerityDir = (0,
|
|
28052
|
-
await (0,
|
|
28356
|
+
const globalVerityDir = (0, import_node_path38.join)(process.env.HOME ?? "", ".verity");
|
|
28357
|
+
await (0, import_promises19.mkdir)(globalVerityDir, { recursive: true });
|
|
28053
28358
|
console.log("");
|
|
28054
28359
|
step("Wiring Claude Code hooks");
|
|
28055
28360
|
const gitMoments = [
|
|
@@ -28117,7 +28422,7 @@ function registerInitCommand(program2) {
|
|
|
28117
28422
|
}
|
|
28118
28423
|
step("Your project's Standard");
|
|
28119
28424
|
let haveStandard = false;
|
|
28120
|
-
if ((0,
|
|
28425
|
+
if ((0, import_node_fs54.existsSync)(projectPath(STANDARD_FILE))) {
|
|
28121
28426
|
printInfo(" This project already has .verity/standard.yaml \u2014 keeping it.");
|
|
28122
28427
|
haveStandard = true;
|
|
28123
28428
|
} else {
|
|
@@ -28147,7 +28452,7 @@ function registerInitCommand(program2) {
|
|
|
28147
28452
|
...telemetryChoice ? { telemetry: telemetryChoice } : {},
|
|
28148
28453
|
init: {
|
|
28149
28454
|
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28150
|
-
cli_version: true ? "0.32.6-experimental.
|
|
28455
|
+
cli_version: true ? "0.32.6-experimental.df0a578" : "dev"
|
|
28151
28456
|
}
|
|
28152
28457
|
});
|
|
28153
28458
|
} catch (err) {
|
|
@@ -28197,8 +28502,8 @@ function registerInitCommand(program2) {
|
|
|
28197
28502
|
}
|
|
28198
28503
|
|
|
28199
28504
|
// src/commands/uninstall.ts
|
|
28200
|
-
var
|
|
28201
|
-
var
|
|
28505
|
+
var import_node_fs55 = require("node:fs");
|
|
28506
|
+
var import_node_path39 = require("node:path");
|
|
28202
28507
|
function registerUninstallCommand(program2) {
|
|
28203
28508
|
program2.command("uninstall").description("Remove Verity from this project (skills, hooks, .verity/, VERITY.md)").option("--dry-run", "Show what would be removed without doing it").option("--purge-global", "Also remove ~/.verity/ (deletes saved tokens \u2014 reconnect requires re-registration)").option("--keep-verity-md", "Keep the project root VERITY.md file").action(async (opts) => {
|
|
28204
28509
|
const dryRun = opts.dryRun ?? false;
|
|
@@ -28207,11 +28512,11 @@ function registerUninstallCommand(program2) {
|
|
|
28207
28512
|
const actions = [];
|
|
28208
28513
|
const skillsRoot = projectPath(".claude/skills");
|
|
28209
28514
|
for (const name of PROJECT_SKILL_NAMES) {
|
|
28210
|
-
const dir = (0,
|
|
28211
|
-
if ((0,
|
|
28515
|
+
const dir = (0, import_node_path39.join)(skillsRoot, name);
|
|
28516
|
+
if ((0, import_node_fs55.existsSync)(dir)) {
|
|
28212
28517
|
actions.push({
|
|
28213
28518
|
label: `Remove .claude/skills/${name}/`,
|
|
28214
|
-
apply: () => (0,
|
|
28519
|
+
apply: () => (0, import_node_fs55.rmSync)(dir, { recursive: true, force: true })
|
|
28215
28520
|
});
|
|
28216
28521
|
}
|
|
28217
28522
|
}
|
|
@@ -28225,24 +28530,24 @@ function registerUninstallCommand(program2) {
|
|
|
28225
28530
|
});
|
|
28226
28531
|
}
|
|
28227
28532
|
const verityDir = projectPath(VERITY_DIR);
|
|
28228
|
-
if ((0,
|
|
28533
|
+
if ((0, import_node_fs55.existsSync)(verityDir)) {
|
|
28229
28534
|
actions.push({
|
|
28230
28535
|
label: `Remove ${VERITY_DIR}/`,
|
|
28231
|
-
apply: () => (0,
|
|
28536
|
+
apply: () => (0, import_node_fs55.rmSync)(verityDir, { recursive: true, force: true })
|
|
28232
28537
|
});
|
|
28233
28538
|
}
|
|
28234
28539
|
if (!keepVerityMd) {
|
|
28235
28540
|
const verityMd = projectPath(VERITY_MD_FILE);
|
|
28236
|
-
if ((0,
|
|
28541
|
+
if ((0, import_node_fs55.existsSync)(verityMd)) {
|
|
28237
28542
|
actions.push({
|
|
28238
28543
|
label: `Remove ${VERITY_MD_FILE}`,
|
|
28239
|
-
apply: () => (0,
|
|
28544
|
+
apply: () => (0, import_node_fs55.rmSync)(verityMd, { force: true })
|
|
28240
28545
|
});
|
|
28241
28546
|
}
|
|
28242
28547
|
}
|
|
28243
28548
|
const cleanupEmptyDir = (path) => {
|
|
28244
|
-
if ((0,
|
|
28245
|
-
(0,
|
|
28549
|
+
if ((0, import_node_fs55.existsSync)(path) && (0, import_node_fs55.statSync)(path).isDirectory() && (0, import_node_fs55.readdirSync)(path).length === 0) {
|
|
28550
|
+
(0, import_node_fs55.rmdirSync)(path);
|
|
28246
28551
|
}
|
|
28247
28552
|
};
|
|
28248
28553
|
actions.push({
|
|
@@ -28253,11 +28558,11 @@ function registerUninstallCommand(program2) {
|
|
|
28253
28558
|
}
|
|
28254
28559
|
});
|
|
28255
28560
|
const home = process.env.HOME ?? "";
|
|
28256
|
-
const globalVerityDir = (0,
|
|
28257
|
-
if (purgeGlobal && (0,
|
|
28561
|
+
const globalVerityDir = (0, import_node_path39.join)(home, ".verity");
|
|
28562
|
+
if (purgeGlobal && (0, import_node_fs55.existsSync)(globalVerityDir)) {
|
|
28258
28563
|
actions.push({
|
|
28259
28564
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
28260
|
-
apply: () => (0,
|
|
28565
|
+
apply: () => (0, import_node_fs55.rmSync)(globalVerityDir, { recursive: true, force: true })
|
|
28261
28566
|
});
|
|
28262
28567
|
}
|
|
28263
28568
|
if (actions.length === 0) {
|
|
@@ -28451,8 +28756,8 @@ function registerTaskCommands(program2) {
|
|
|
28451
28756
|
}
|
|
28452
28757
|
|
|
28453
28758
|
// src/commands/reset.ts
|
|
28454
|
-
var
|
|
28455
|
-
var
|
|
28759
|
+
var import_node_fs56 = require("node:fs");
|
|
28760
|
+
var import_node_path40 = require("node:path");
|
|
28456
28761
|
function registerResetCommand(program2) {
|
|
28457
28762
|
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) => {
|
|
28458
28763
|
const globals = program2.opts();
|
|
@@ -28489,11 +28794,11 @@ function registerResetCommand(program2) {
|
|
|
28489
28794
|
}
|
|
28490
28795
|
const cacheDir = projectPath(CACHE_DIR);
|
|
28491
28796
|
let purged = 0;
|
|
28492
|
-
if ((0,
|
|
28493
|
-
for (const entry of (0,
|
|
28797
|
+
if ((0, import_node_fs56.existsSync)(cacheDir)) {
|
|
28798
|
+
for (const entry of (0, import_node_fs56.readdirSync)(cacheDir)) {
|
|
28494
28799
|
if (entry.startsWith("pending-")) {
|
|
28495
28800
|
try {
|
|
28496
|
-
(0,
|
|
28801
|
+
(0, import_node_fs56.unlinkSync)((0, import_node_path40.join)(cacheDir, entry));
|
|
28497
28802
|
purged++;
|
|
28498
28803
|
} catch {
|
|
28499
28804
|
}
|
|
@@ -28508,19 +28813,19 @@ function registerResetCommand(program2) {
|
|
|
28508
28813
|
projectPath(`${VERITY_DIR}/.last-analysis`)
|
|
28509
28814
|
];
|
|
28510
28815
|
for (const file of filesToClear) {
|
|
28511
|
-
if ((0,
|
|
28816
|
+
if ((0, import_node_fs56.existsSync)(file)) {
|
|
28512
28817
|
try {
|
|
28513
|
-
(0,
|
|
28818
|
+
(0, import_node_fs56.writeFileSync)(file, "");
|
|
28514
28819
|
} catch {
|
|
28515
28820
|
}
|
|
28516
28821
|
}
|
|
28517
28822
|
}
|
|
28518
28823
|
if (opts.all) {
|
|
28519
28824
|
const logsDir = projectPath(`${VERITY_DIR}/.logs`);
|
|
28520
|
-
if ((0,
|
|
28521
|
-
for (const entry of (0,
|
|
28825
|
+
if ((0, import_node_fs56.existsSync)(logsDir)) {
|
|
28826
|
+
for (const entry of (0, import_node_fs56.readdirSync)(logsDir)) {
|
|
28522
28827
|
try {
|
|
28523
|
-
(0,
|
|
28828
|
+
(0, import_node_fs56.unlinkSync)((0, import_node_path40.join)(logsDir, entry));
|
|
28524
28829
|
} catch {
|
|
28525
28830
|
}
|
|
28526
28831
|
}
|
|
@@ -28532,7 +28837,7 @@ function registerResetCommand(program2) {
|
|
|
28532
28837
|
}
|
|
28533
28838
|
|
|
28534
28839
|
// src/commands/reflect.ts
|
|
28535
|
-
var
|
|
28840
|
+
var import_node_fs57 = require("node:fs");
|
|
28536
28841
|
|
|
28537
28842
|
// src/lib/reflection-globs.ts
|
|
28538
28843
|
var MAX_GLOBS = 6;
|
|
@@ -28570,7 +28875,7 @@ async function writeNodeToDisk(args) {
|
|
|
28570
28875
|
{ treePaths: listTrackedFiles(), recordBaseline: false }
|
|
28571
28876
|
);
|
|
28572
28877
|
if (written === 0) return false;
|
|
28573
|
-
return (0,
|
|
28878
|
+
return (0, import_node_fs57.existsSync)(projectPath(`${VERITY_DIR}/memory/${args.filePath}`));
|
|
28574
28879
|
} catch {
|
|
28575
28880
|
return false;
|
|
28576
28881
|
}
|
|
@@ -28815,6 +29120,88 @@ function registerMemoryCommand(program2) {
|
|
|
28815
29120
|
if (!quiet) {
|
|
28816
29121
|
printInfo(result.status === "unchanged" ? "Knowledge graph is up to date." : result.status === "tracked" ? "Skipped: .verity/memory/ is tracked by git here, and the pull never rewrites tracked files. Run `verity memory untrack` to make the graph machine-local." : `Pulled ${result.received} node(s); ${result.written} new or updated file(s) written to .verity/memory/.`);
|
|
28817
29122
|
}
|
|
29123
|
+
let org;
|
|
29124
|
+
try {
|
|
29125
|
+
org = await pullOrgKnowledge({
|
|
29126
|
+
serviceUrl: urlResult.data,
|
|
29127
|
+
token: tokenResult.data.token,
|
|
29128
|
+
verbose: globals.verbose,
|
|
29129
|
+
force: !!opts.force
|
|
29130
|
+
});
|
|
29131
|
+
} catch (err) {
|
|
29132
|
+
org = { ok: false, error: err.message };
|
|
29133
|
+
}
|
|
29134
|
+
logEvent("memory_org_pull", org.ok ? { status: org.status, received: org.received } : { status: "failed", category: org.category ?? null });
|
|
29135
|
+
if (!quiet) {
|
|
29136
|
+
if (!org.ok) printWarn(`Could not refresh the org knowledge mirror: ${org.error}`);
|
|
29137
|
+
else if (org.status === "pulled") printInfo(`Org knowledge: ${org.received} claim(s) mirrored at ${org.dir}.`);
|
|
29138
|
+
else if (org.status === "unchanged") printInfo("Org knowledge mirror is up to date.");
|
|
29139
|
+
}
|
|
29140
|
+
process.exit(0);
|
|
29141
|
+
});
|
|
29142
|
+
memory.command("org").description("List the org knowledge mirrored for this repository's organization").action(async () => {
|
|
29143
|
+
try {
|
|
29144
|
+
process.chdir(repoRoot());
|
|
29145
|
+
} catch {
|
|
29146
|
+
}
|
|
29147
|
+
const dir = orgMirrorDir();
|
|
29148
|
+
if (!dir) {
|
|
29149
|
+
printError("Not a repository with an origin remote, so there is no organization to list.");
|
|
29150
|
+
process.exit(1);
|
|
29151
|
+
}
|
|
29152
|
+
const claims = await readOrgMirror();
|
|
29153
|
+
if (claims.length === 0) {
|
|
29154
|
+
printInfo(`No org knowledge mirrored yet (${dir}). Run \`verity memory pull\`.`);
|
|
29155
|
+
process.exit(0);
|
|
29156
|
+
}
|
|
29157
|
+
for (const c of claims) console.log(`${c.tag_id} ${c.kind.padEnd(11)} ${c.title} \xB7 ${c.origin}`);
|
|
29158
|
+
printInfo(`${claims.length} claim(s) at ${dir}. Demote one with \`verity memory demote <id> --reason "\u2026"\`.`);
|
|
29159
|
+
process.exit(0);
|
|
29160
|
+
});
|
|
29161
|
+
memory.command("demote <claim-id>").description("Demote an org knowledge claim for the whole organization, with a reason").requiredOption("--reason <text>", "Why this claim should no longer be shared (1\u2013500 characters)").action(async (claimId, opts) => {
|
|
29162
|
+
const globals = program2.opts();
|
|
29163
|
+
try {
|
|
29164
|
+
process.chdir(repoRoot());
|
|
29165
|
+
} catch {
|
|
29166
|
+
}
|
|
29167
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(claimId)) {
|
|
29168
|
+
printError("The claim id is the `id` in the mirrored file, a uuid. `verity memory org` lists them.");
|
|
29169
|
+
process.exit(1);
|
|
29170
|
+
}
|
|
29171
|
+
const reason = opts.reason.trim();
|
|
29172
|
+
if (reason.length === 0 || reason.length > 500) {
|
|
29173
|
+
printError("--reason is 1 to 500 characters.");
|
|
29174
|
+
process.exit(1);
|
|
29175
|
+
}
|
|
29176
|
+
const tokenResult = await resolveToken(globals.token);
|
|
29177
|
+
if (!tokenResult.ok) {
|
|
29178
|
+
printError(tokenResult.error);
|
|
29179
|
+
process.exit(1);
|
|
29180
|
+
}
|
|
29181
|
+
const urlResult = await resolveServiceUrl(globals.serviceUrl);
|
|
29182
|
+
if (!urlResult.ok) {
|
|
29183
|
+
printError(urlResult.error);
|
|
29184
|
+
process.exit(1);
|
|
29185
|
+
}
|
|
29186
|
+
const res = await apiRequest({
|
|
29187
|
+
method: "POST",
|
|
29188
|
+
path: `/memory/org/claims/${claimId}/demote`,
|
|
29189
|
+
serviceUrl: urlResult.data,
|
|
29190
|
+
token: tokenResult.data.token,
|
|
29191
|
+
body: { reason },
|
|
29192
|
+
verbose: globals.verbose,
|
|
29193
|
+
cmd: "memory-demote",
|
|
29194
|
+
extraHeaders: { "X-Verity-Via": "cli" }
|
|
29195
|
+
});
|
|
29196
|
+
if (!res.ok) {
|
|
29197
|
+
printError(`Could not demote the claim: ${res.error}`);
|
|
29198
|
+
process.exit(1);
|
|
29199
|
+
}
|
|
29200
|
+
printInfo(`Demoted ${claimId} for the whole organization. Restore it from the dashboard if that was wrong.`);
|
|
29201
|
+
try {
|
|
29202
|
+
await pullOrgKnowledge({ serviceUrl: urlResult.data, token: tokenResult.data.token, verbose: globals.verbose, force: true });
|
|
29203
|
+
} catch {
|
|
29204
|
+
}
|
|
28818
29205
|
process.exit(0);
|
|
28819
29206
|
});
|
|
28820
29207
|
memory.command("untrack").description("Stop committing .verity/memory/ \u2014 the graph stays on disk and leaves your diffs").action(() => {
|
|
@@ -28980,8 +29367,8 @@ function registerTelemetryCommands(program2) {
|
|
|
28980
29367
|
}
|
|
28981
29368
|
|
|
28982
29369
|
// src/cli.ts
|
|
28983
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.32.6-experimental.
|
|
28984
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.32.6-experimental.
|
|
29370
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.32.6-experimental.df0a578").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr").hook("preAction", async (_thisCommand, actionCommand) => {
|
|
29371
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.32.6-experimental.df0a578");
|
|
28985
29372
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
28986
29373
|
try {
|
|
28987
29374
|
await foldLegacyLocalCredential();
|