@codacy/verity-cli 0.31.1-experimental.be74f71 → 0.31.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/bin/verity.js +1479 -426
- package/data/skills/verity-analyze/SKILL.md +7 -0
- package/data/skills/verity-feedback/SKILL.md +6 -0
- package/data/skills/verity-insights/SKILL.md +7 -0
- package/data/skills/verity-learn/SKILL.md +6 -0
- package/data/skills/verity-memory/SKILL.md +7 -0
- package/data/skills/verity-reflect/SKILL.md +6 -0
- package/data/skills/verity-setup/SKILL.md +12 -5
- package/data/skills/verity-status/SKILL.md +6 -0
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -10395,6 +10395,7 @@ var MAX_DELTA_BYTES = 194560;
|
|
|
10395
10395
|
var MAX_FILES = 40;
|
|
10396
10396
|
var MAX_FILE_BYTES = 51200;
|
|
10397
10397
|
var DEBOUNCE_SECONDS = 30;
|
|
10398
|
+
var MAX_ITERATIONS = 2;
|
|
10398
10399
|
var MAX_SPEC_FILES = 6;
|
|
10399
10400
|
var MAX_SPEC_FILE_BYTES = 512e3;
|
|
10400
10401
|
var MAX_TOTAL_SPEC_BYTES = 512e3;
|
|
@@ -10404,6 +10405,8 @@ var MAX_INTENT_CHARS = 2e3;
|
|
|
10404
10405
|
var SNAPSHOT_DIR = `${VERITY_DIR}/.snapshot`;
|
|
10405
10406
|
var BASELINE_DIR = `${VERITY_DIR}/.baseline`;
|
|
10406
10407
|
var CONVERSATION_BUFFER_FILE = `${VERITY_DIR}/.conversation-buffer`;
|
|
10408
|
+
var PLUGIN_MARKER_FILE = `${VERITY_DIR}/.plugin-active`;
|
|
10409
|
+
var PROJECT_CONFIG_FILE = `${VERITY_DIR}/config.json`;
|
|
10407
10410
|
var CONVERSATION_MAX_ENTRIES = 10;
|
|
10408
10411
|
var CONVERSATION_WINDOW_MINUTES = 15;
|
|
10409
10412
|
var MAX_FINDINGS = 25;
|
|
@@ -10506,7 +10509,7 @@ var SECURITY_PATTERNS = [
|
|
|
10506
10509
|
/Dockerfile/
|
|
10507
10510
|
];
|
|
10508
10511
|
var PROD_SERVICE_URL = "https://ofcamwrjwrkazqvdchko.supabase.co/functions/v1";
|
|
10509
|
-
var DEFAULT_SERVICE_URL = "
|
|
10512
|
+
var DEFAULT_SERVICE_URL = "".length > 0 ? "" : PROD_SERVICE_URL;
|
|
10510
10513
|
var GITHUB_CLIENT_ID = "Iv23li88HxAi3ZrbYzWh";
|
|
10511
10514
|
var GITHUB_DEVICE_CODE_URL = "https://github.com/login/device/code";
|
|
10512
10515
|
var GITHUB_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
|
|
@@ -12700,9 +12703,155 @@ async function applyMomentSelection(moments) {
|
|
|
12700
12703
|
return settings;
|
|
12701
12704
|
}
|
|
12702
12705
|
|
|
12706
|
+
// src/lib/project-config.ts
|
|
12707
|
+
var import_node_fs4 = require("node:fs");
|
|
12708
|
+
var DEFAULTS = { git_moments: [] };
|
|
12709
|
+
function isMoment(value) {
|
|
12710
|
+
return value === "commit" || value === "push";
|
|
12711
|
+
}
|
|
12712
|
+
function parseMoments(raw) {
|
|
12713
|
+
return [...new Set(raw.split(",").map((s) => s.trim()).filter(isMoment))];
|
|
12714
|
+
}
|
|
12715
|
+
function readProjectConfig() {
|
|
12716
|
+
try {
|
|
12717
|
+
if (!(0, import_node_fs4.existsSync)(PROJECT_CONFIG_FILE)) return DEFAULTS;
|
|
12718
|
+
const raw = JSON.parse((0, import_node_fs4.readFileSync)(PROJECT_CONFIG_FILE, "utf-8"));
|
|
12719
|
+
const moments = Array.isArray(raw.git_moments) ? raw.git_moments.filter(isMoment) : [];
|
|
12720
|
+
return { git_moments: [...new Set(moments)] };
|
|
12721
|
+
} catch {
|
|
12722
|
+
return DEFAULTS;
|
|
12723
|
+
}
|
|
12724
|
+
}
|
|
12725
|
+
function writeProjectConfig(patch) {
|
|
12726
|
+
const next = { ...readProjectConfig(), ...patch };
|
|
12727
|
+
(0, import_node_fs4.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
12728
|
+
(0, import_node_fs4.writeFileSync)(PROJECT_CONFIG_FILE, JSON.stringify(next, null, 2) + "\n");
|
|
12729
|
+
return next;
|
|
12730
|
+
}
|
|
12731
|
+
function resolveGuardMoments(explicit) {
|
|
12732
|
+
if (explicit !== void 0) return parseMoments(explicit);
|
|
12733
|
+
return readProjectConfig().git_moments;
|
|
12734
|
+
}
|
|
12735
|
+
|
|
12736
|
+
// src/lib/plugin-ownership.ts
|
|
12737
|
+
var import_node_fs6 = require("node:fs");
|
|
12738
|
+
|
|
12739
|
+
// src/lib/stderr-log.ts
|
|
12740
|
+
var import_node_fs5 = require("node:fs");
|
|
12741
|
+
var TOKEN_RE2 = /verity_[0-9a-f]{16,}/g;
|
|
12742
|
+
var ANSI_RE = /\u001b\[[0-?]*[ -/]*[@-~]/g;
|
|
12743
|
+
function scrub(s) {
|
|
12744
|
+
return s.replace(TOKEN_RE2, "verity_***REDACTED***").replace(ANSI_RE, "");
|
|
12745
|
+
}
|
|
12746
|
+
var installed = false;
|
|
12747
|
+
var wroteBanner = false;
|
|
12748
|
+
var banner = "";
|
|
12749
|
+
function append(text) {
|
|
12750
|
+
try {
|
|
12751
|
+
const dir = projectPath(DEBUG_LOG_DIR);
|
|
12752
|
+
const file = projectPath(STDERR_LOG_FILE);
|
|
12753
|
+
(0, import_node_fs5.mkdirSync)(dir, { recursive: true });
|
|
12754
|
+
rotateIfNeeded(file);
|
|
12755
|
+
(0, import_node_fs5.appendFileSync)(file, text);
|
|
12756
|
+
} catch {
|
|
12757
|
+
}
|
|
12758
|
+
}
|
|
12759
|
+
function ensureBanner() {
|
|
12760
|
+
if (wroteBanner) return;
|
|
12761
|
+
wroteBanner = true;
|
|
12762
|
+
append(banner);
|
|
12763
|
+
}
|
|
12764
|
+
function installStderrLog(cmd, argv, version) {
|
|
12765
|
+
if (installed || !isDebugEnabled()) return;
|
|
12766
|
+
installed = true;
|
|
12767
|
+
banner = `
|
|
12768
|
+
\u2501\u2501 verity ${cmd} \xB7 ${(/* @__PURE__ */ new Date()).toISOString()} \xB7 pid ${process.pid}
|
|
12769
|
+
v${version} \xB7 ${process.cwd()}
|
|
12770
|
+
argv: ${scrub(argv.join(" "))}
|
|
12771
|
+
`;
|
|
12772
|
+
const original = process.stderr.write.bind(process.stderr);
|
|
12773
|
+
const tee = (...args) => {
|
|
12774
|
+
const result = original(...args);
|
|
12775
|
+
try {
|
|
12776
|
+
const chunk = args[0];
|
|
12777
|
+
const text = typeof chunk === "string" ? chunk : Buffer.isBuffer(chunk) ? chunk.toString("utf-8") : String(chunk);
|
|
12778
|
+
ensureBanner();
|
|
12779
|
+
append(scrub(text));
|
|
12780
|
+
} catch {
|
|
12781
|
+
}
|
|
12782
|
+
return result;
|
|
12783
|
+
};
|
|
12784
|
+
process.stderr.write = tee;
|
|
12785
|
+
}
|
|
12786
|
+
function logToFileOnly(text) {
|
|
12787
|
+
if (!installed) return;
|
|
12788
|
+
ensureBanner();
|
|
12789
|
+
append(text.endsWith("\n") ? text : `${text}
|
|
12790
|
+
`);
|
|
12791
|
+
}
|
|
12792
|
+
|
|
12793
|
+
// src/lib/plugin-ownership.ts
|
|
12794
|
+
var MARKER_TTL_SECONDS = 24 * 60 * 60;
|
|
12795
|
+
function isPluginInvocation() {
|
|
12796
|
+
return !!process.env.VERITY_PLUGIN_ROOT;
|
|
12797
|
+
}
|
|
12798
|
+
function readMarker() {
|
|
12799
|
+
try {
|
|
12800
|
+
if (!(0, import_node_fs6.existsSync)(PLUGIN_MARKER_FILE)) return null;
|
|
12801
|
+
const raw = JSON.parse((0, import_node_fs6.readFileSync)(PLUGIN_MARKER_FILE, "utf-8"));
|
|
12802
|
+
const pluginRoot = typeof raw.plugin_root === "string" ? raw.plugin_root : "";
|
|
12803
|
+
if (!pluginRoot) return null;
|
|
12804
|
+
return {
|
|
12805
|
+
session_id: typeof raw.session_id === "string" ? raw.session_id : null,
|
|
12806
|
+
plugin_root: pluginRoot,
|
|
12807
|
+
version: typeof raw.version === "string" ? raw.version : null,
|
|
12808
|
+
ts: typeof raw.ts === "number" ? raw.ts : 0
|
|
12809
|
+
};
|
|
12810
|
+
} catch {
|
|
12811
|
+
return null;
|
|
12812
|
+
}
|
|
12813
|
+
}
|
|
12814
|
+
function recordPluginOwnership(sessionId) {
|
|
12815
|
+
const pluginRoot = process.env.VERITY_PLUGIN_ROOT;
|
|
12816
|
+
if (!pluginRoot) return;
|
|
12817
|
+
try {
|
|
12818
|
+
(0, import_node_fs6.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
12819
|
+
const marker = {
|
|
12820
|
+
session_id: sessionId,
|
|
12821
|
+
plugin_root: pluginRoot,
|
|
12822
|
+
version: process.env.VERITY_PLUGIN_VERSION || null,
|
|
12823
|
+
ts: Math.floor(Date.now() / 1e3)
|
|
12824
|
+
};
|
|
12825
|
+
(0, import_node_fs6.writeFileSync)(PLUGIN_MARKER_FILE, JSON.stringify(marker));
|
|
12826
|
+
} catch {
|
|
12827
|
+
}
|
|
12828
|
+
}
|
|
12829
|
+
function shouldDeferToPlugin(sessionId) {
|
|
12830
|
+
if (isPluginInvocation()) {
|
|
12831
|
+
recordPluginOwnership(sessionId);
|
|
12832
|
+
return false;
|
|
12833
|
+
}
|
|
12834
|
+
const marker = readMarker();
|
|
12835
|
+
if (!marker) return false;
|
|
12836
|
+
if (!(0, import_node_fs6.existsSync)(marker.plugin_root)) return false;
|
|
12837
|
+
if (sessionId && marker.session_id) return sessionId === marker.session_id;
|
|
12838
|
+
return Math.floor(Date.now() / 1e3) - marker.ts < MARKER_TTL_SECONDS;
|
|
12839
|
+
}
|
|
12840
|
+
function pluginActiveHere() {
|
|
12841
|
+
const marker = readMarker();
|
|
12842
|
+
return !!marker && (0, import_node_fs6.existsSync)(marker.plugin_root);
|
|
12843
|
+
}
|
|
12844
|
+
function deferredToPlugin(command, sessionId) {
|
|
12845
|
+
if (!shouldDeferToPlugin(sessionId)) return false;
|
|
12846
|
+
logToFileOnly(
|
|
12847
|
+
`${command}: the Verity Claude Code plugin owns this session's hooks \u2014 standing down so the turn is not gated twice. Remove the duplicate settings.json hooks with \`verity init --plugin-mode\`.`
|
|
12848
|
+
);
|
|
12849
|
+
return true;
|
|
12850
|
+
}
|
|
12851
|
+
|
|
12703
12852
|
// src/commands/hooks.ts
|
|
12704
12853
|
var ALL_MOMENTS = ["stop", "pre-commit", "pre-push"];
|
|
12705
|
-
function
|
|
12854
|
+
function parseMoments2(raw) {
|
|
12706
12855
|
const seen = /* @__PURE__ */ new Set();
|
|
12707
12856
|
for (const part of raw.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
12708
12857
|
if (ALL_MOMENTS.includes(part)) seen.add(part);
|
|
@@ -12714,7 +12863,22 @@ function registerHooksCommands(program2) {
|
|
|
12714
12863
|
hooks.command("install").description("Install Verity hooks into Claude Code settings").option("--force", "Overwrite existing Verity hooks").option("--moments <list>", "Reconcile to exactly these moments: stop,pre-commit,pre-push").action(async (opts) => {
|
|
12715
12864
|
const force = opts.force ?? false;
|
|
12716
12865
|
if (opts.moments != null) {
|
|
12717
|
-
const moments =
|
|
12866
|
+
const moments = parseMoments2(opts.moments);
|
|
12867
|
+
const gitMoments = [
|
|
12868
|
+
...moments.includes("pre-commit") ? ["commit"] : [],
|
|
12869
|
+
...moments.includes("pre-push") ? ["push"] : []
|
|
12870
|
+
];
|
|
12871
|
+
writeProjectConfig({ git_moments: gitMoments });
|
|
12872
|
+
if (pluginActiveHere()) {
|
|
12873
|
+
printInfo("The Verity plugin wires the hooks; recorded your selection in .verity/config.json:");
|
|
12874
|
+
printInfo(` Stop (analysis on every turn): ${moments.includes("stop") ? "on" : "off \u2014 the plugin still wires it; see below"}`);
|
|
12875
|
+
printInfo(` Pre-commit gate: ${gitMoments.includes("commit") ? "on" : "off"}`);
|
|
12876
|
+
printInfo(` Pre-push/PR gate: ${gitMoments.includes("push") ? "on" : "off"}`);
|
|
12877
|
+
if (!moments.includes("stop")) {
|
|
12878
|
+
printWarn(" Turning the Stop review off is not yet supported under the plugin \u2014 it stays on.");
|
|
12879
|
+
}
|
|
12880
|
+
return;
|
|
12881
|
+
}
|
|
12718
12882
|
await applyMomentSelection(moments);
|
|
12719
12883
|
const status = await checkAllVerityHooks();
|
|
12720
12884
|
printInfo("Verity hooks reconciled in .claude/settings.json:");
|
|
@@ -12761,6 +12925,24 @@ function registerHooksCommands(program2) {
|
|
|
12761
12925
|
});
|
|
12762
12926
|
hooks.command("check").description("Check if Verity hooks are installed").action(async () => {
|
|
12763
12927
|
const status = await checkAllVerityHooks();
|
|
12928
|
+
if (pluginActiveHere()) {
|
|
12929
|
+
const moments = readProjectConfig().git_moments;
|
|
12930
|
+
printInfo("Wired by the Verity Claude Code plugin (not .claude/settings.json):");
|
|
12931
|
+
printInfo(" Stop hook (verity analyze): installed");
|
|
12932
|
+
printInfo(" Intent hook (verity intent capture): installed");
|
|
12933
|
+
printInfo(" Baseline hook (verity baseline capture): installed");
|
|
12934
|
+
printInfo(
|
|
12935
|
+
` Git-moment gate (verity guard): ${moments.length ? `installed [${moments.join(", ")}]` : "wired but gating nothing"}`
|
|
12936
|
+
);
|
|
12937
|
+
if (!moments.length) {
|
|
12938
|
+
printInfo(' Enable it with "verity config git-moments commit,push".');
|
|
12939
|
+
}
|
|
12940
|
+
if (status.stop || status.intent || status.baseline || status.guard) {
|
|
12941
|
+
printWarn(" Duplicate hooks also exist in .claude/settings.json. They stand down at run time,");
|
|
12942
|
+
printWarn(' but remove them with "verity init --plugin-mode" so the wiring says what it does.');
|
|
12943
|
+
}
|
|
12944
|
+
return;
|
|
12945
|
+
}
|
|
12764
12946
|
printInfo(`Stop hook (verity analyze): ${status.stop ? "installed" : "not installed"}`);
|
|
12765
12947
|
printInfo(`Intent hook (verity intent capture): ${status.intent ? "installed" : "not installed"}`);
|
|
12766
12948
|
printInfo(`Baseline hook (verity baseline capture): ${status.baseline ? "installed" : "not installed"}`);
|
|
@@ -12786,7 +12968,7 @@ var import_node_crypto8 = require("node:crypto");
|
|
|
12786
12968
|
|
|
12787
12969
|
// src/lib/conversation-buffer.ts
|
|
12788
12970
|
var import_promises5 = require("node:fs/promises");
|
|
12789
|
-
var
|
|
12971
|
+
var import_node_fs7 = require("node:fs");
|
|
12790
12972
|
var import_node_child_process5 = require("node:child_process");
|
|
12791
12973
|
var import_node_crypto = require("node:crypto");
|
|
12792
12974
|
function stripImageReferences(text) {
|
|
@@ -12822,7 +13004,7 @@ async function appendToConversationBuffer(prompt, sessionId) {
|
|
|
12822
13004
|
}
|
|
12823
13005
|
async function readAndClearConversationBuffer(currentSessionId) {
|
|
12824
13006
|
try {
|
|
12825
|
-
if ((0,
|
|
13007
|
+
if ((0, import_node_fs7.existsSync)(CONVERSATION_BUFFER_FILE)) {
|
|
12826
13008
|
const entries = await readBufferEntries();
|
|
12827
13009
|
let mine = entries;
|
|
12828
13010
|
let others = [];
|
|
@@ -12846,7 +13028,7 @@ async function readAndClearConversationBuffer(currentSessionId) {
|
|
|
12846
13028
|
};
|
|
12847
13029
|
}
|
|
12848
13030
|
}
|
|
12849
|
-
if ((0,
|
|
13031
|
+
if ((0, import_node_fs7.existsSync)(INTENT_FILE)) {
|
|
12850
13032
|
try {
|
|
12851
13033
|
const content = await (0, import_promises5.readFile)(INTENT_FILE, "utf-8");
|
|
12852
13034
|
await (0, import_promises5.unlink)(INTENT_FILE).catch(() => {
|
|
@@ -12903,7 +13085,7 @@ function getRecentCommitMessages() {
|
|
|
12903
13085
|
|
|
12904
13086
|
// src/lib/context-identity.ts
|
|
12905
13087
|
var import_node_crypto2 = require("node:crypto");
|
|
12906
|
-
var
|
|
13088
|
+
var import_node_fs8 = require("node:fs");
|
|
12907
13089
|
var import_node_os2 = require("node:os");
|
|
12908
13090
|
var import_node_path6 = require("node:path");
|
|
12909
13091
|
var SHARED_SENTINELS = /* @__PURE__ */ new Set([
|
|
@@ -12943,7 +13125,7 @@ function contextIdentity(input) {
|
|
|
12943
13125
|
if (rawTree && !isSharedSentinel(rawTree)) {
|
|
12944
13126
|
let resolved = rawTree;
|
|
12945
13127
|
try {
|
|
12946
|
-
resolved =
|
|
13128
|
+
resolved = import_node_fs8.realpathSync.native(rawTree);
|
|
12947
13129
|
} catch {
|
|
12948
13130
|
}
|
|
12949
13131
|
treeKey = (0, import_node_crypto2.createHash)("sha256").update(resolved).digest("hex").slice(0, 12);
|
|
@@ -12980,7 +13162,7 @@ function sessionScopeKey(token, sessionId) {
|
|
|
12980
13162
|
|
|
12981
13163
|
// src/lib/task-context-buffer.ts
|
|
12982
13164
|
var import_promises6 = require("node:fs/promises");
|
|
12983
|
-
var
|
|
13165
|
+
var import_node_fs9 = require("node:fs");
|
|
12984
13166
|
var import_node_path7 = require("node:path");
|
|
12985
13167
|
var TASK_CONTEXT_DIR = `${VERITY_DIR}/.task-context`;
|
|
12986
13168
|
var MAX_BUFFER_BYTES = 500 * 1024;
|
|
@@ -13020,7 +13202,7 @@ async function appendResponseToTaskBuffer(taskId, assistantResponse, actionSumma
|
|
|
13020
13202
|
}
|
|
13021
13203
|
async function readTaskContextBuffer(taskId) {
|
|
13022
13204
|
const filePath = bufferPath(taskId);
|
|
13023
|
-
if (!(0,
|
|
13205
|
+
if (!(0, import_node_fs9.existsSync)(filePath)) return null;
|
|
13024
13206
|
try {
|
|
13025
13207
|
const content = await (0, import_promises6.readFile)(filePath, "utf-8");
|
|
13026
13208
|
if (!content.trim()) return null;
|
|
@@ -13054,7 +13236,7 @@ async function readTaskContextBuffer(taskId) {
|
|
|
13054
13236
|
}
|
|
13055
13237
|
async function cleanupTaskContextBuffers() {
|
|
13056
13238
|
try {
|
|
13057
|
-
if (!(0,
|
|
13239
|
+
if (!(0, import_node_fs9.existsSync)(TASK_CONTEXT_DIR)) return;
|
|
13058
13240
|
const files = await (0, import_promises6.readdir)(TASK_CONTEXT_DIR);
|
|
13059
13241
|
const cutoffMs = Date.now() - RETENTION_DAYS * 24 * 60 * 60 * 1e3;
|
|
13060
13242
|
for (const file of files) {
|
|
@@ -13079,7 +13261,7 @@ async function appendEntry(taskId, entry) {
|
|
|
13079
13261
|
try {
|
|
13080
13262
|
await (0, import_promises6.mkdir)(TASK_CONTEXT_DIR, { recursive: true });
|
|
13081
13263
|
const filePath = bufferPath(taskId);
|
|
13082
|
-
if ((0,
|
|
13264
|
+
if ((0, import_node_fs9.existsSync)(filePath)) {
|
|
13083
13265
|
const stats = await (0, import_promises6.stat)(filePath);
|
|
13084
13266
|
if (stats.size >= MAX_BUFFER_BYTES) {
|
|
13085
13267
|
const content = await (0, import_promises6.readFile)(filePath, "utf-8");
|
|
@@ -13090,7 +13272,7 @@ async function appendEntry(taskId, entry) {
|
|
|
13090
13272
|
}
|
|
13091
13273
|
}
|
|
13092
13274
|
const line = JSON.stringify(entry) + "\n";
|
|
13093
|
-
const existing = (0,
|
|
13275
|
+
const existing = (0, import_node_fs9.existsSync)(filePath) ? await (0, import_promises6.readFile)(filePath, "utf-8") : "";
|
|
13094
13276
|
await (0, import_promises6.writeFile)(filePath, existing + line);
|
|
13095
13277
|
} catch {
|
|
13096
13278
|
}
|
|
@@ -13098,7 +13280,7 @@ async function appendEntry(taskId, entry) {
|
|
|
13098
13280
|
|
|
13099
13281
|
// src/lib/memory-retrieval.ts
|
|
13100
13282
|
var import_promises7 = require("node:fs/promises");
|
|
13101
|
-
var
|
|
13283
|
+
var import_node_fs10 = require("node:fs");
|
|
13102
13284
|
var import_node_path8 = require("node:path");
|
|
13103
13285
|
var memoryDir = () => projectPath(`${VERITY_DIR}/memory`);
|
|
13104
13286
|
var DOMAINS = ["decisions", "quality", "security", "intent", "gotchas", "patterns", "domain", "integrations"];
|
|
@@ -13192,13 +13374,13 @@ function parseFrontmatter(content) {
|
|
|
13192
13374
|
return { fm, body: match[2].trim() };
|
|
13193
13375
|
}
|
|
13194
13376
|
async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = DEFAULT_BUDGET_TOKENS) {
|
|
13195
|
-
if (!(0,
|
|
13377
|
+
if (!(0, import_node_fs10.existsSync)(memoryDir())) return null;
|
|
13196
13378
|
const budget = Math.min(budgetTokens, MAX_BUDGET_TOKENS);
|
|
13197
13379
|
const promptTokens = tokenize(promptText);
|
|
13198
13380
|
const nodes = [];
|
|
13199
13381
|
for (const domain of DOMAINS) {
|
|
13200
13382
|
const domainDir = (0, import_node_path8.join)(memoryDir(), domain);
|
|
13201
|
-
if (!(0,
|
|
13383
|
+
if (!(0, import_node_fs10.existsSync)(domainDir)) continue;
|
|
13202
13384
|
try {
|
|
13203
13385
|
const files = await (0, import_promises7.readdir)(domainDir);
|
|
13204
13386
|
for (const file of files) {
|
|
@@ -13263,12 +13445,12 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
13263
13445
|
|
|
13264
13446
|
// src/lib/memory-sync.ts
|
|
13265
13447
|
var import_promises8 = require("node:fs/promises");
|
|
13266
|
-
var
|
|
13448
|
+
var import_node_fs12 = require("node:fs");
|
|
13267
13449
|
var import_node_path10 = require("node:path");
|
|
13268
13450
|
var import_node_crypto3 = require("node:crypto");
|
|
13269
13451
|
|
|
13270
13452
|
// src/lib/safe-path.ts
|
|
13271
|
-
var
|
|
13453
|
+
var import_node_fs11 = require("node:fs");
|
|
13272
13454
|
var import_node_path9 = require("node:path");
|
|
13273
13455
|
function resolveInside(baseDir, candidate) {
|
|
13274
13456
|
if (typeof candidate !== "string" || candidate.length === 0) return null;
|
|
@@ -13278,16 +13460,16 @@ function resolveInside(baseDir, candidate) {
|
|
|
13278
13460
|
const baseSep = baseAbs.endsWith(import_node_path9.sep) ? baseAbs : baseAbs + import_node_path9.sep;
|
|
13279
13461
|
if (full !== baseAbs && !full.startsWith(baseSep)) return null;
|
|
13280
13462
|
try {
|
|
13281
|
-
if ((0,
|
|
13282
|
-
const realBase = (0,
|
|
13463
|
+
if ((0, import_node_fs11.existsSync)(baseAbs)) {
|
|
13464
|
+
const realBase = (0, import_node_fs11.realpathSync)(baseAbs);
|
|
13283
13465
|
const realBaseSep = realBase.endsWith(import_node_path9.sep) ? realBase : realBase + import_node_path9.sep;
|
|
13284
13466
|
let probe = full;
|
|
13285
|
-
while (!(0,
|
|
13467
|
+
while (!(0, import_node_fs11.existsSync)(probe)) {
|
|
13286
13468
|
const parent = (0, import_node_path9.dirname)(probe);
|
|
13287
13469
|
if (parent === probe) break;
|
|
13288
13470
|
probe = parent;
|
|
13289
13471
|
}
|
|
13290
|
-
const realProbe = (0,
|
|
13472
|
+
const realProbe = (0, import_node_fs11.realpathSync)(probe);
|
|
13291
13473
|
if (realProbe !== realBase && !realProbe.startsWith(realBaseSep)) return null;
|
|
13292
13474
|
}
|
|
13293
13475
|
} catch {
|
|
@@ -13366,24 +13548,24 @@ async function ensureMemoryDir() {
|
|
|
13366
13548
|
for (const domain of DOMAINS2) {
|
|
13367
13549
|
await (0, import_promises8.mkdir)((0, import_node_path10.join)(memoryDir2(), domain), { recursive: true });
|
|
13368
13550
|
}
|
|
13369
|
-
if (!(0,
|
|
13551
|
+
if (!(0, import_node_fs12.existsSync)((0, import_node_path10.join)(memoryDir2(), "SCHEMA.md"))) {
|
|
13370
13552
|
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
|
|
13371
13553
|
}
|
|
13372
|
-
if (!(0,
|
|
13554
|
+
if (!(0, import_node_fs12.existsSync)((0, import_node_path10.join)(memoryDir2(), "index.md"))) {
|
|
13373
13555
|
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
|
|
13374
13556
|
}
|
|
13375
|
-
if (!(0,
|
|
13557
|
+
if (!(0, import_node_fs12.existsSync)((0, import_node_path10.join)(memoryDir2(), "log.md"))) {
|
|
13376
13558
|
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
|
|
13377
13559
|
}
|
|
13378
13560
|
}
|
|
13379
13561
|
async function buildManifest() {
|
|
13380
|
-
if (!(0,
|
|
13562
|
+
if (!(0, import_node_fs12.existsSync)(memoryDir2())) {
|
|
13381
13563
|
return { schema_version: 1, nodes: [], index_hash: null, log_length: 0 };
|
|
13382
13564
|
}
|
|
13383
13565
|
const nodes = [];
|
|
13384
13566
|
for (const domain of DOMAINS2) {
|
|
13385
13567
|
const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
|
|
13386
|
-
if (!(0,
|
|
13568
|
+
if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
|
|
13387
13569
|
try {
|
|
13388
13570
|
const files = await (0, import_promises8.readdir)(domainDir);
|
|
13389
13571
|
for (const file of files) {
|
|
@@ -13419,10 +13601,10 @@ function hashContent(content) {
|
|
|
13419
13601
|
}
|
|
13420
13602
|
async function readOnDiskNodes() {
|
|
13421
13603
|
const out = /* @__PURE__ */ new Map();
|
|
13422
|
-
if (!(0,
|
|
13604
|
+
if (!(0, import_node_fs12.existsSync)(memoryDir2())) return out;
|
|
13423
13605
|
for (const domain of DOMAINS2) {
|
|
13424
13606
|
const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
|
|
13425
|
-
if (!(0,
|
|
13607
|
+
if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
|
|
13426
13608
|
try {
|
|
13427
13609
|
for (const file of await (0, import_promises8.readdir)(domainDir)) {
|
|
13428
13610
|
if (!file.endsWith(".md")) continue;
|
|
@@ -13474,7 +13656,7 @@ async function computeEditedNodeUploads() {
|
|
|
13474
13656
|
for (const [path, prevHash] of prev) {
|
|
13475
13657
|
if (prevHash == null) continue;
|
|
13476
13658
|
const full = (0, import_node_path10.join)(memoryDir2(), path);
|
|
13477
|
-
if (!(0,
|
|
13659
|
+
if (!(0, import_node_fs12.existsSync)(full)) continue;
|
|
13478
13660
|
let content;
|
|
13479
13661
|
try {
|
|
13480
13662
|
content = await (0, import_promises8.readFile)(full, "utf-8");
|
|
@@ -13510,7 +13692,7 @@ async function applyMemoryWrites(writes, opts = {}) {
|
|
|
13510
13692
|
const logLines = [`- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)} \u2014 Applied ${count} write(s) from server`];
|
|
13511
13693
|
for (const n of notes) logLines.push(` - ${n}`);
|
|
13512
13694
|
try {
|
|
13513
|
-
const existing = (0,
|
|
13695
|
+
const existing = (0, import_node_fs12.existsSync)((0, import_node_path10.join)(memoryDir2(), "log.md")) ? await (0, import_promises8.readFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
|
|
13514
13696
|
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
|
|
13515
13697
|
} catch {
|
|
13516
13698
|
}
|
|
@@ -13531,7 +13713,7 @@ async function applyOneWrite(write, treePaths) {
|
|
|
13531
13713
|
notes.push(`${write.path}: dropped unmatched file_globs [${grounded.dropped.join(", ")}]`);
|
|
13532
13714
|
}
|
|
13533
13715
|
}
|
|
13534
|
-
if ((0,
|
|
13716
|
+
if ((0, import_node_fs12.existsSync)(fullPath)) {
|
|
13535
13717
|
let existing = "";
|
|
13536
13718
|
try {
|
|
13537
13719
|
existing = await (0, import_promises8.readFile)(fullPath, "utf-8");
|
|
@@ -13585,7 +13767,7 @@ async function regenerateIndex() {
|
|
|
13585
13767
|
let totalNodes = 0;
|
|
13586
13768
|
for (const domain of DOMAINS2.filter((d) => d !== "_archive")) {
|
|
13587
13769
|
const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
|
|
13588
|
-
if (!(0,
|
|
13770
|
+
if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
|
|
13589
13771
|
try {
|
|
13590
13772
|
const files = await (0, import_promises8.readdir)(domainDir);
|
|
13591
13773
|
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
@@ -13855,7 +14037,7 @@ function hasLegacyMemoryBlock(text) {
|
|
|
13855
14037
|
async function ensureClaudeMdPointer(cwd = repoRoot()) {
|
|
13856
14038
|
const claudeMdPath = (0, import_node_path10.join)(cwd, "CLAUDE.md");
|
|
13857
14039
|
let existing = "";
|
|
13858
|
-
if ((0,
|
|
14040
|
+
if ((0, import_node_fs12.existsSync)(claudeMdPath)) {
|
|
13859
14041
|
existing = await (0, import_promises8.readFile)(claudeMdPath, "utf-8");
|
|
13860
14042
|
}
|
|
13861
14043
|
let startTag = CLAUDE_MD_START;
|
|
@@ -13991,7 +14173,7 @@ Body content (\u22648KB). Use [[node-id]] wikilinks for cross-references.
|
|
|
13991
14173
|
`;
|
|
13992
14174
|
|
|
13993
14175
|
// src/lib/dossier-session.ts
|
|
13994
|
-
var
|
|
14176
|
+
var import_node_fs17 = require("node:fs");
|
|
13995
14177
|
var import_node_crypto7 = require("node:crypto");
|
|
13996
14178
|
var import_node_path13 = require("node:path");
|
|
13997
14179
|
|
|
@@ -14325,7 +14507,7 @@ function statementAnchorKey(file, patternId) {
|
|
|
14325
14507
|
|
|
14326
14508
|
// src/lib/dossier/log.ts
|
|
14327
14509
|
var import_node_crypto4 = require("node:crypto");
|
|
14328
|
-
var
|
|
14510
|
+
var import_node_fs13 = require("node:fs");
|
|
14329
14511
|
var import_node_path11 = require("node:path");
|
|
14330
14512
|
var CRC_TABLE = (() => {
|
|
14331
14513
|
const t = new Int32Array(256);
|
|
@@ -14345,7 +14527,7 @@ function crc32(s) {
|
|
|
14345
14527
|
function openDossier(identity) {
|
|
14346
14528
|
try {
|
|
14347
14529
|
const dir = dossierDir(identity);
|
|
14348
|
-
(0,
|
|
14530
|
+
(0, import_node_fs13.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
14349
14531
|
return {
|
|
14350
14532
|
dir,
|
|
14351
14533
|
identity,
|
|
@@ -14413,7 +14595,7 @@ function appendEvent(d, ev) {
|
|
|
14413
14595
|
at: ev.at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
14414
14596
|
...ev
|
|
14415
14597
|
});
|
|
14416
|
-
(0,
|
|
14598
|
+
(0, import_node_fs13.appendFileSync)(d.eventsPath, line, { mode: 384 });
|
|
14417
14599
|
return true;
|
|
14418
14600
|
} catch {
|
|
14419
14601
|
return false;
|
|
@@ -14421,14 +14603,14 @@ function appendEvent(d, ev) {
|
|
|
14421
14603
|
}
|
|
14422
14604
|
function rotateIfNeeded2(d) {
|
|
14423
14605
|
try {
|
|
14424
|
-
if (!(0,
|
|
14425
|
-
if ((0,
|
|
14426
|
-
(0,
|
|
14427
|
-
(0,
|
|
14428
|
-
const kept = (0,
|
|
14606
|
+
if (!(0, import_node_fs13.existsSync)(d.eventsPath)) return;
|
|
14607
|
+
if ((0, import_node_fs13.statSync)(d.eventsPath).size < ROTATE_BYTES) return;
|
|
14608
|
+
(0, import_node_fs13.mkdirSync)(d.rotatedDir, { recursive: true, mode: 448 });
|
|
14609
|
+
(0, import_node_fs13.renameSync)(d.eventsPath, (0, import_node_path11.join)(d.rotatedDir, `events.${Date.now()}.jsonl`));
|
|
14610
|
+
const kept = (0, import_node_fs13.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
14429
14611
|
for (const stale of kept.slice(0, Math.max(0, kept.length - ROTATE_KEEP))) {
|
|
14430
14612
|
try {
|
|
14431
|
-
(0,
|
|
14613
|
+
(0, import_node_fs13.renameSync)((0, import_node_path11.join)(d.rotatedDir, stale), (0, import_node_path11.join)(d.rotatedDir, `${stale}.pruned`));
|
|
14432
14614
|
} catch {
|
|
14433
14615
|
}
|
|
14434
14616
|
}
|
|
@@ -14438,7 +14620,7 @@ function rotateIfNeeded2(d) {
|
|
|
14438
14620
|
|
|
14439
14621
|
// src/lib/dossier/fold-dossier.ts
|
|
14440
14622
|
var import_node_crypto5 = require("node:crypto");
|
|
14441
|
-
var
|
|
14623
|
+
var import_node_fs14 = require("node:fs");
|
|
14442
14624
|
var import_node_path12 = require("node:path");
|
|
14443
14625
|
var EMPTY_CAPABILITIES = () => ({
|
|
14444
14626
|
human_reachable: { value: "unknown", tier: "unknown" },
|
|
@@ -14490,12 +14672,12 @@ function foldDossier(d, opts = {}) {
|
|
|
14490
14672
|
}
|
|
14491
14673
|
};
|
|
14492
14674
|
try {
|
|
14493
|
-
if ((0,
|
|
14494
|
-
const files = (0,
|
|
14675
|
+
if ((0, import_node_fs14.existsSync)(d.rotatedDir)) {
|
|
14676
|
+
const files = (0, import_node_fs14.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
14495
14677
|
state.meta.rotations = files.length;
|
|
14496
14678
|
for (const f of files) {
|
|
14497
14679
|
try {
|
|
14498
|
-
ingest((0,
|
|
14680
|
+
ingest((0, import_node_fs14.readFileSync)((0, import_node_path12.join)(d.rotatedDir, f), "utf8"));
|
|
14499
14681
|
} catch {
|
|
14500
14682
|
state.meta.dropped_lines++;
|
|
14501
14683
|
}
|
|
@@ -14504,9 +14686,9 @@ function foldDossier(d, opts = {}) {
|
|
|
14504
14686
|
} catch {
|
|
14505
14687
|
}
|
|
14506
14688
|
try {
|
|
14507
|
-
if ((0,
|
|
14508
|
-
state.meta.upto_offset = (0,
|
|
14509
|
-
ingest((0,
|
|
14689
|
+
if ((0, import_node_fs14.existsSync)(d.eventsPath)) {
|
|
14690
|
+
state.meta.upto_offset = (0, import_node_fs14.statSync)(d.eventsPath).size;
|
|
14691
|
+
ingest((0, import_node_fs14.readFileSync)(d.eventsPath, "utf8"));
|
|
14510
14692
|
}
|
|
14511
14693
|
} catch {
|
|
14512
14694
|
}
|
|
@@ -14777,7 +14959,7 @@ function applyBounds(state, input) {
|
|
|
14777
14959
|
}
|
|
14778
14960
|
|
|
14779
14961
|
// src/lib/dossier/cache.ts
|
|
14780
|
-
var
|
|
14962
|
+
var import_node_fs15 = require("node:fs");
|
|
14781
14963
|
function compactState(s) {
|
|
14782
14964
|
const ms = (iso) => Date.parse(iso) || 0;
|
|
14783
14965
|
return {
|
|
@@ -14906,20 +15088,20 @@ function encodeState(s) {
|
|
|
14906
15088
|
function writeFoldCache(d, state) {
|
|
14907
15089
|
try {
|
|
14908
15090
|
const tmp = `${d.foldPath}.${process.pid}.tmp`;
|
|
14909
|
-
(0,
|
|
14910
|
-
(0,
|
|
15091
|
+
(0, import_node_fs15.writeFileSync)(tmp, encodeState(state), { mode: 384 });
|
|
15092
|
+
(0, import_node_fs15.renameSync)(tmp, d.foldPath);
|
|
14911
15093
|
} catch {
|
|
14912
15094
|
}
|
|
14913
15095
|
}
|
|
14914
15096
|
function readFoldCache(d) {
|
|
14915
15097
|
try {
|
|
14916
|
-
if (!(0,
|
|
14917
|
-
const raw = JSON.parse((0,
|
|
15098
|
+
if (!(0, import_node_fs15.existsSync)(d.foldPath)) return null;
|
|
15099
|
+
const raw = JSON.parse((0, import_node_fs15.readFileSync)(d.foldPath, "utf8"));
|
|
14918
15100
|
if (raw?.v !== 1) return null;
|
|
14919
15101
|
const cached2 = expandState(raw);
|
|
14920
15102
|
if (!cached2?.meta) return null;
|
|
14921
|
-
const size = (0,
|
|
14922
|
-
const rotations = (0,
|
|
15103
|
+
const size = (0, import_node_fs15.existsSync)(d.eventsPath) ? (0, import_node_fs15.statSync)(d.eventsPath).size : 0;
|
|
15104
|
+
const rotations = (0, import_node_fs15.existsSync)(d.rotatedDir) ? (0, import_node_fs15.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).length : 0;
|
|
14923
15105
|
if (cached2.meta.upto_offset !== size || cached2.meta.rotations !== rotations) return null;
|
|
14924
15106
|
return cached2;
|
|
14925
15107
|
} catch {
|
|
@@ -14970,13 +15152,13 @@ function assessContinuity(i) {
|
|
|
14970
15152
|
|
|
14971
15153
|
// src/lib/dossier/reanchor.ts
|
|
14972
15154
|
var import_node_crypto6 = require("node:crypto");
|
|
14973
|
-
var
|
|
15155
|
+
var import_node_fs16 = require("node:fs");
|
|
14974
15156
|
function lineSha(text) {
|
|
14975
15157
|
return (0, import_node_crypto6.createHash)("sha256").update(text.trim()).digest("hex").slice(0, HASH_WIDTH);
|
|
14976
15158
|
}
|
|
14977
15159
|
function fileHash(path) {
|
|
14978
15160
|
try {
|
|
14979
|
-
return (0, import_node_crypto6.createHash)("sha256").update((0,
|
|
15161
|
+
return (0, import_node_crypto6.createHash)("sha256").update((0, import_node_fs16.readFileSync)(path)).digest("hex").slice(0, HASH_WIDTH);
|
|
14980
15162
|
} catch {
|
|
14981
15163
|
return null;
|
|
14982
15164
|
}
|
|
@@ -15348,14 +15530,14 @@ function foreignAuthoredPaths(identity, opts = {}) {
|
|
|
15348
15530
|
let sessions = 0;
|
|
15349
15531
|
try {
|
|
15350
15532
|
const dir = treeDir(identity);
|
|
15351
|
-
if (!(0,
|
|
15352
|
-
for (const entry of (0,
|
|
15533
|
+
if (!(0, import_node_fs17.existsSync)(dir)) return { paths: [], sessions: 0 };
|
|
15534
|
+
for (const entry of (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true })) {
|
|
15353
15535
|
if (!entry.isDirectory()) continue;
|
|
15354
15536
|
if (entry.name === identity.sessionKey) continue;
|
|
15355
15537
|
const log = (0, import_node_path13.join)(dir, entry.name, "events.jsonl");
|
|
15356
15538
|
try {
|
|
15357
|
-
if (!(0,
|
|
15358
|
-
if (now - (0,
|
|
15539
|
+
if (!(0, import_node_fs17.existsSync)(log)) continue;
|
|
15540
|
+
if (now - (0, import_node_fs17.statSync)(log).mtimeMs > windowMs) continue;
|
|
15359
15541
|
const sib = {
|
|
15360
15542
|
dir: (0, import_node_path13.join)(dir, entry.name),
|
|
15361
15543
|
identity,
|
|
@@ -15390,13 +15572,13 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
15390
15572
|
try {
|
|
15391
15573
|
const mine = dossierDir(identity);
|
|
15392
15574
|
const userDir = (0, import_node_path13.dirname)((0, import_node_path13.dirname)(mine));
|
|
15393
|
-
if (!(0,
|
|
15575
|
+
if (!(0, import_node_fs17.existsSync)(userDir)) return 0;
|
|
15394
15576
|
const cutoff = Date.now() - maxAgeMs;
|
|
15395
|
-
for (const tree of (0,
|
|
15577
|
+
for (const tree of (0, import_node_fs17.readdirSync)(userDir, { withFileTypes: true })) {
|
|
15396
15578
|
if (!tree.isDirectory()) continue;
|
|
15397
15579
|
const treePath = (0, import_node_path13.join)(userDir, tree.name);
|
|
15398
15580
|
let live = 0;
|
|
15399
|
-
for (const entry of (0,
|
|
15581
|
+
for (const entry of (0, import_node_fs17.readdirSync)(treePath, { withFileTypes: true })) {
|
|
15400
15582
|
if (!entry.isDirectory()) continue;
|
|
15401
15583
|
const dir = (0, import_node_path13.join)(treePath, entry.name);
|
|
15402
15584
|
if (dir === mine) {
|
|
@@ -15405,9 +15587,9 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
15405
15587
|
}
|
|
15406
15588
|
try {
|
|
15407
15589
|
const log = (0, import_node_path13.join)(dir, "events.jsonl");
|
|
15408
|
-
const at = (0,
|
|
15590
|
+
const at = (0, import_node_fs17.existsSync)(log) ? (0, import_node_fs17.statSync)(log).mtimeMs : (0, import_node_fs17.statSync)(dir).mtimeMs;
|
|
15409
15591
|
if (at < cutoff) {
|
|
15410
|
-
(0,
|
|
15592
|
+
(0, import_node_fs17.rmSync)(dir, { recursive: true, force: true });
|
|
15411
15593
|
removed++;
|
|
15412
15594
|
} else {
|
|
15413
15595
|
live++;
|
|
@@ -15417,7 +15599,7 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
15417
15599
|
}
|
|
15418
15600
|
if (live === 0) {
|
|
15419
15601
|
try {
|
|
15420
|
-
(0,
|
|
15602
|
+
(0, import_node_fs17.rmSync)(treePath, { recursive: false, force: false });
|
|
15421
15603
|
} catch {
|
|
15422
15604
|
}
|
|
15423
15605
|
}
|
|
@@ -15434,8 +15616,8 @@ function sessionDossier(token, sessionId) {
|
|
|
15434
15616
|
}
|
|
15435
15617
|
function hasActiveGoal(d) {
|
|
15436
15618
|
try {
|
|
15437
|
-
if (!(0,
|
|
15438
|
-
return (0,
|
|
15619
|
+
if (!(0, import_node_fs17.existsSync)(d.eventsPath)) return false;
|
|
15620
|
+
return (0, import_node_fs17.readFileSync)(d.eventsPath, "utf8").includes('"k":"goal"');
|
|
15439
15621
|
} catch {
|
|
15440
15622
|
return false;
|
|
15441
15623
|
}
|
|
@@ -15528,7 +15710,7 @@ function recordVerdict(d, v) {
|
|
|
15528
15710
|
if (!lines.has(f.file)) {
|
|
15529
15711
|
try {
|
|
15530
15712
|
const abs = (0, import_node_path13.join)(root, f.file);
|
|
15531
|
-
lines.set(f.file, (0,
|
|
15713
|
+
lines.set(f.file, (0, import_node_fs17.existsSync)(abs) ? (0, import_node_fs17.readFileSync)(abs, "utf8").split("\n") : null);
|
|
15532
15714
|
} catch {
|
|
15533
15715
|
lines.set(f.file, null);
|
|
15534
15716
|
}
|
|
@@ -15629,7 +15811,7 @@ function recallMemory(d, identity, opts) {
|
|
|
15629
15811
|
readFileLines: (file) => {
|
|
15630
15812
|
try {
|
|
15631
15813
|
const abs = (0, import_node_path13.join)(root, file);
|
|
15632
|
-
return (0,
|
|
15814
|
+
return (0, import_node_fs17.existsSync)(abs) ? (0, import_node_fs17.readFileSync)(abs, "utf8").split("\n") : null;
|
|
15633
15815
|
} catch {
|
|
15634
15816
|
return null;
|
|
15635
15817
|
}
|
|
@@ -15678,6 +15860,9 @@ function registerIntentCommands(program2) {
|
|
|
15678
15860
|
if (!prompt) {
|
|
15679
15861
|
process.exit(0);
|
|
15680
15862
|
}
|
|
15863
|
+
if (deferredToPlugin("intent capture", event.session_id ?? process.env.CLAUDE_SESSION_ID ?? null)) {
|
|
15864
|
+
process.exit(0);
|
|
15865
|
+
}
|
|
15681
15866
|
const authForScope = await resolveToken(program2.opts().token);
|
|
15682
15867
|
const scopeToken = authForScope.ok ? authForScope.data.token : void 0;
|
|
15683
15868
|
const scopeSession = event.session_id || process.env.CLAUDE_SESSION_ID || "";
|
|
@@ -15767,21 +15952,21 @@ async function fireClassify(prompt, sessionId, globals) {
|
|
|
15767
15952
|
}
|
|
15768
15953
|
|
|
15769
15954
|
// src/commands/lifecycle.ts
|
|
15770
|
-
var
|
|
15955
|
+
var import_node_fs21 = require("node:fs");
|
|
15771
15956
|
var import_node_path17 = require("node:path");
|
|
15772
15957
|
|
|
15773
15958
|
// src/lib/baseline.ts
|
|
15774
|
-
var
|
|
15959
|
+
var import_node_fs20 = require("node:fs");
|
|
15775
15960
|
var import_node_path16 = require("node:path");
|
|
15776
15961
|
var import_node_crypto9 = require("node:crypto");
|
|
15777
15962
|
|
|
15778
15963
|
// src/lib/snapshot.ts
|
|
15779
|
-
var
|
|
15964
|
+
var import_node_fs19 = require("node:fs");
|
|
15780
15965
|
var import_node_path15 = require("node:path");
|
|
15781
15966
|
var import_node_child_process6 = require("node:child_process");
|
|
15782
15967
|
|
|
15783
15968
|
// src/lib/files.ts
|
|
15784
|
-
var
|
|
15969
|
+
var import_node_fs18 = require("node:fs");
|
|
15785
15970
|
var import_node_path14 = require("node:path");
|
|
15786
15971
|
var LANG_MAP = {
|
|
15787
15972
|
// Analyzable (static analysis + Gemini)
|
|
@@ -15858,7 +16043,7 @@ function sortByMtime(files) {
|
|
|
15858
16043
|
const resolved = resolveFile(f);
|
|
15859
16044
|
if (!resolved) return null;
|
|
15860
16045
|
try {
|
|
15861
|
-
const stat3 = (0,
|
|
16046
|
+
const stat3 = (0, import_node_fs18.statSync)(resolved);
|
|
15862
16047
|
return { path: f, resolved, mtime: stat3.mtimeMs };
|
|
15863
16048
|
} catch {
|
|
15864
16049
|
return null;
|
|
@@ -15891,7 +16076,7 @@ function collectCodeDelta(files, opts) {
|
|
|
15891
16076
|
}
|
|
15892
16077
|
let size;
|
|
15893
16078
|
try {
|
|
15894
|
-
size = (0,
|
|
16079
|
+
size = (0, import_node_fs18.statSync)(resolved).size;
|
|
15895
16080
|
} catch {
|
|
15896
16081
|
exclude(filepath, "not-stattable");
|
|
15897
16082
|
continue;
|
|
@@ -15908,7 +16093,7 @@ function collectCodeDelta(files, opts) {
|
|
|
15908
16093
|
}
|
|
15909
16094
|
let content;
|
|
15910
16095
|
try {
|
|
15911
|
-
content = (0,
|
|
16096
|
+
content = (0, import_node_fs18.readFileSync)(resolved, "utf-8");
|
|
15912
16097
|
} catch {
|
|
15913
16098
|
exclude(filepath, "not-readable");
|
|
15914
16099
|
continue;
|
|
@@ -15947,7 +16132,7 @@ function collectCodeDelta(files, opts) {
|
|
|
15947
16132
|
|
|
15948
16133
|
// src/lib/snapshot.ts
|
|
15949
16134
|
function generateSnapshotDiffs(files) {
|
|
15950
|
-
if (!(0,
|
|
16135
|
+
if (!(0, import_node_fs19.existsSync)(SNAPSHOT_DIR)) {
|
|
15951
16136
|
return { diffs: [], has_snapshots: false };
|
|
15952
16137
|
}
|
|
15953
16138
|
const diffs = [];
|
|
@@ -15955,8 +16140,8 @@ function generateSnapshotDiffs(files) {
|
|
|
15955
16140
|
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
15956
16141
|
const snapshotPath = (0, import_node_path15.join)(SNAPSHOT_DIR, file.path);
|
|
15957
16142
|
const language = file.language ?? detectLanguage(file.path);
|
|
15958
|
-
if ((0,
|
|
15959
|
-
const oldContent = (0,
|
|
16143
|
+
if ((0, import_node_fs19.existsSync)(snapshotPath)) {
|
|
16144
|
+
const oldContent = (0, import_node_fs19.readFileSync)(snapshotPath, "utf-8");
|
|
15960
16145
|
if (oldContent === file.content) continue;
|
|
15961
16146
|
const diff = computeDiff(oldContent, file.content, file.path);
|
|
15962
16147
|
if (diff) {
|
|
@@ -15983,8 +16168,8 @@ function saveSnapshots(files) {
|
|
|
15983
16168
|
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
15984
16169
|
const snapshotPath = (0, import_node_path15.join)(SNAPSHOT_DIR, file.path);
|
|
15985
16170
|
snapshotPaths.add(snapshotPath);
|
|
15986
|
-
(0,
|
|
15987
|
-
(0,
|
|
16171
|
+
(0, import_node_fs19.mkdirSync)((0, import_node_path15.dirname)(snapshotPath), { recursive: true });
|
|
16172
|
+
(0, import_node_fs19.writeFileSync)(snapshotPath, file.content);
|
|
15988
16173
|
}
|
|
15989
16174
|
cleanStaleSnapshots(SNAPSHOT_DIR, snapshotPaths);
|
|
15990
16175
|
}
|
|
@@ -15992,9 +16177,9 @@ function computeDiff(oldContent, newContent, filePath) {
|
|
|
15992
16177
|
const tmpOld = (0, import_node_path15.join)(SNAPSHOT_DIR, ".diff-old.tmp");
|
|
15993
16178
|
const tmpNew = (0, import_node_path15.join)(SNAPSHOT_DIR, ".diff-new.tmp");
|
|
15994
16179
|
try {
|
|
15995
|
-
(0,
|
|
15996
|
-
(0,
|
|
15997
|
-
(0,
|
|
16180
|
+
(0, import_node_fs19.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
|
|
16181
|
+
(0, import_node_fs19.writeFileSync)(tmpOld, oldContent);
|
|
16182
|
+
(0, import_node_fs19.writeFileSync)(tmpNew, newContent);
|
|
15998
16183
|
const result = (0, import_node_child_process6.execSync)(
|
|
15999
16184
|
`git diff --no-index --unified=10 -- "${tmpOld}" "${tmpNew}"`,
|
|
16000
16185
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -16008,32 +16193,32 @@ function computeDiff(oldContent, newContent, filePath) {
|
|
|
16008
16193
|
return null;
|
|
16009
16194
|
} finally {
|
|
16010
16195
|
try {
|
|
16011
|
-
(0,
|
|
16196
|
+
(0, import_node_fs19.unlinkSync)(tmpOld);
|
|
16012
16197
|
} catch {
|
|
16013
16198
|
}
|
|
16014
16199
|
try {
|
|
16015
|
-
(0,
|
|
16200
|
+
(0, import_node_fs19.unlinkSync)(tmpNew);
|
|
16016
16201
|
} catch {
|
|
16017
16202
|
}
|
|
16018
16203
|
}
|
|
16019
16204
|
}
|
|
16020
16205
|
function cleanStaleSnapshots(dir, keepSet) {
|
|
16021
|
-
if (!(0,
|
|
16206
|
+
if (!(0, import_node_fs19.existsSync)(dir)) return;
|
|
16022
16207
|
try {
|
|
16023
|
-
const entries = (0,
|
|
16208
|
+
const entries = (0, import_node_fs19.readdirSync)(dir, { withFileTypes: true });
|
|
16024
16209
|
for (const entry of entries) {
|
|
16025
16210
|
if (dir === SNAPSHOT_DIR && (entry.name === ".diff-old.tmp" || entry.name === ".diff-new.tmp")) continue;
|
|
16026
16211
|
const fullPath = (0, import_node_path15.join)(dir, entry.name);
|
|
16027
16212
|
if (entry.isDirectory()) {
|
|
16028
16213
|
cleanStaleSnapshots(fullPath, keepSet);
|
|
16029
16214
|
try {
|
|
16030
|
-
const remaining = (0,
|
|
16031
|
-
if (remaining.length === 0) (0,
|
|
16215
|
+
const remaining = (0, import_node_fs19.readdirSync)(fullPath);
|
|
16216
|
+
if (remaining.length === 0) (0, import_node_fs19.rmdirSync)(fullPath);
|
|
16032
16217
|
} catch {
|
|
16033
16218
|
}
|
|
16034
16219
|
} else if (!keepSet.has(fullPath)) {
|
|
16035
16220
|
try {
|
|
16036
|
-
(0,
|
|
16221
|
+
(0, import_node_fs19.unlinkSync)(fullPath);
|
|
16037
16222
|
} catch {
|
|
16038
16223
|
}
|
|
16039
16224
|
}
|
|
@@ -16064,8 +16249,8 @@ var CARRY_FILE = `${BASELINE_DIR}/.carry`;
|
|
|
16064
16249
|
var CARRY_WINDOW_MS = 12e4;
|
|
16065
16250
|
function writeCarry(sessionId, headSha) {
|
|
16066
16251
|
try {
|
|
16067
|
-
(0,
|
|
16068
|
-
(0,
|
|
16252
|
+
(0, import_node_fs20.mkdirSync)(projectPath(BASELINE_DIR), { recursive: true });
|
|
16253
|
+
(0, import_node_fs20.writeFileSync)(
|
|
16069
16254
|
projectPath(CARRY_FILE),
|
|
16070
16255
|
JSON.stringify({ from_key: sessionKey(sessionId), head_sha: headSha, ts: Date.now() })
|
|
16071
16256
|
);
|
|
@@ -16075,10 +16260,10 @@ function writeCarry(sessionId, headSha) {
|
|
|
16075
16260
|
function claimCarry(newKey) {
|
|
16076
16261
|
const carryPath = projectPath(CARRY_FILE);
|
|
16077
16262
|
try {
|
|
16078
|
-
if (!(0,
|
|
16079
|
-
const carry = JSON.parse((0,
|
|
16263
|
+
if (!(0, import_node_fs20.existsSync)(carryPath)) return null;
|
|
16264
|
+
const carry = JSON.parse((0, import_node_fs20.readFileSync)(carryPath, "utf-8"));
|
|
16080
16265
|
try {
|
|
16081
|
-
(0,
|
|
16266
|
+
(0, import_node_fs20.rmSync)(carryPath, { force: true });
|
|
16082
16267
|
} catch {
|
|
16083
16268
|
}
|
|
16084
16269
|
if (!carry?.from_key || typeof carry.ts !== "number") return null;
|
|
@@ -16089,11 +16274,11 @@ function claimCarry(newKey) {
|
|
|
16089
16274
|
if (!prior) return null;
|
|
16090
16275
|
const toDir = sessionDir(newKey);
|
|
16091
16276
|
try {
|
|
16092
|
-
(0,
|
|
16277
|
+
(0, import_node_fs20.rmSync)(toDir, { recursive: true, force: true });
|
|
16093
16278
|
} catch {
|
|
16094
16279
|
}
|
|
16095
|
-
(0,
|
|
16096
|
-
(0,
|
|
16280
|
+
(0, import_node_fs20.renameSync)(fromDir, toDir);
|
|
16281
|
+
(0, import_node_fs20.writeFileSync)(manifestPath(toDir), JSON.stringify({ ...prior, session_id: newKey }) + "\n");
|
|
16097
16282
|
return readManifest(toDir);
|
|
16098
16283
|
} catch {
|
|
16099
16284
|
return null;
|
|
@@ -16117,21 +16302,21 @@ function captureBaseline(opts = {}) {
|
|
|
16117
16302
|
const head_sha = getCurrentCommit();
|
|
16118
16303
|
const dirty = getDirtyFiles();
|
|
16119
16304
|
try {
|
|
16120
|
-
(0,
|
|
16305
|
+
(0, import_node_fs20.rmSync)(dir, { recursive: true, force: true });
|
|
16121
16306
|
} catch {
|
|
16122
16307
|
}
|
|
16123
16308
|
const filesDir = (0, import_node_path16.join)(dir, "files");
|
|
16124
16309
|
const mirrored = [];
|
|
16125
16310
|
try {
|
|
16126
|
-
(0,
|
|
16311
|
+
(0, import_node_fs20.mkdirSync)(filesDir, { recursive: true });
|
|
16127
16312
|
for (const p of dirty) {
|
|
16128
16313
|
if (p.includes("..")) continue;
|
|
16129
16314
|
const content = safeReadForMirror(projectPath(p));
|
|
16130
16315
|
if (content === null) continue;
|
|
16131
16316
|
const dest = mirrorPath(dir, p);
|
|
16132
16317
|
try {
|
|
16133
|
-
(0,
|
|
16134
|
-
(0,
|
|
16318
|
+
(0, import_node_fs20.mkdirSync)((0, import_node_path16.dirname)(dest), { recursive: true });
|
|
16319
|
+
(0, import_node_fs20.writeFileSync)(dest, content);
|
|
16135
16320
|
mirrored.push(p);
|
|
16136
16321
|
} catch {
|
|
16137
16322
|
}
|
|
@@ -16146,8 +16331,8 @@ function captureBaseline(opts = {}) {
|
|
|
16146
16331
|
version: BASELINE_VERSION
|
|
16147
16332
|
};
|
|
16148
16333
|
try {
|
|
16149
|
-
(0,
|
|
16150
|
-
(0,
|
|
16334
|
+
(0, import_node_fs20.mkdirSync)(dir, { recursive: true });
|
|
16335
|
+
(0, import_node_fs20.writeFileSync)(manifestPath(dir), JSON.stringify(baseline));
|
|
16151
16336
|
} catch {
|
|
16152
16337
|
}
|
|
16153
16338
|
pruneOldBaselines();
|
|
@@ -16158,9 +16343,9 @@ function readBaseline(sessionId) {
|
|
|
16158
16343
|
}
|
|
16159
16344
|
function readManifest(dir) {
|
|
16160
16345
|
const mp = manifestPath(dir);
|
|
16161
|
-
if (!(0,
|
|
16346
|
+
if (!(0, import_node_fs20.existsSync)(mp)) return null;
|
|
16162
16347
|
try {
|
|
16163
|
-
const parsed = JSON.parse((0,
|
|
16348
|
+
const parsed = JSON.parse((0, import_node_fs20.readFileSync)(mp, "utf-8"));
|
|
16164
16349
|
if (typeof parsed.head_sha !== "string" || typeof parsed.captured_at !== "number" || !Array.isArray(parsed.dirty_paths) || parsed.version !== BASELINE_VERSION) {
|
|
16165
16350
|
return null;
|
|
16166
16351
|
}
|
|
@@ -16191,9 +16376,9 @@ function preImage(repoRelPath, baseline) {
|
|
|
16191
16376
|
function resolvePreImage(repoRelPath, baseline) {
|
|
16192
16377
|
if (baseline.dirty_paths.includes(repoRelPath)) {
|
|
16193
16378
|
const mp = mirrorPath(sessionDir(sessionKey(baseline.session_id)), repoRelPath);
|
|
16194
|
-
if ((0,
|
|
16379
|
+
if ((0, import_node_fs20.existsSync)(mp)) {
|
|
16195
16380
|
try {
|
|
16196
|
-
return { content: (0,
|
|
16381
|
+
return { content: (0, import_node_fs20.readFileSync)(mp, "utf-8"), existed: true };
|
|
16197
16382
|
} catch {
|
|
16198
16383
|
}
|
|
16199
16384
|
}
|
|
@@ -16238,8 +16423,8 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
16238
16423
|
const content = safeReadForMirror(projectPath(p));
|
|
16239
16424
|
if (content === null) continue;
|
|
16240
16425
|
const dest = mirrorPath(dir, p);
|
|
16241
|
-
(0,
|
|
16242
|
-
(0,
|
|
16426
|
+
(0, import_node_fs20.mkdirSync)((0, import_node_path16.dirname)(dest), { recursive: true });
|
|
16427
|
+
(0, import_node_fs20.writeFileSync)(dest, content);
|
|
16243
16428
|
dirty.add(p);
|
|
16244
16429
|
adopted++;
|
|
16245
16430
|
} catch {
|
|
@@ -16248,7 +16433,7 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
16248
16433
|
if (adopted === 0) return 0;
|
|
16249
16434
|
try {
|
|
16250
16435
|
const updated = { ...baseline, dirty_paths: [...dirty] };
|
|
16251
|
-
(0,
|
|
16436
|
+
(0, import_node_fs20.writeFileSync)(manifestPath(dir), JSON.stringify(updated));
|
|
16252
16437
|
preImageCache.delete(baseline);
|
|
16253
16438
|
} catch {
|
|
16254
16439
|
return 0;
|
|
@@ -16259,7 +16444,7 @@ function changedSinceBaseline(repoRelPath, baseline) {
|
|
|
16259
16444
|
const pre = preImage(repoRelPath, baseline);
|
|
16260
16445
|
let current;
|
|
16261
16446
|
try {
|
|
16262
|
-
current = (0,
|
|
16447
|
+
current = (0, import_node_fs20.readFileSync)(projectPath(repoRelPath), "utf-8");
|
|
16263
16448
|
} catch {
|
|
16264
16449
|
return pre.existed;
|
|
16265
16450
|
}
|
|
@@ -16268,8 +16453,8 @@ function changedSinceBaseline(repoRelPath, baseline) {
|
|
|
16268
16453
|
}
|
|
16269
16454
|
function safeReadForMirror(absPath) {
|
|
16270
16455
|
try {
|
|
16271
|
-
if ((0,
|
|
16272
|
-
const buf = (0,
|
|
16456
|
+
if ((0, import_node_fs20.statSync)(absPath).size > MIRROR_MAX_BYTES) return null;
|
|
16457
|
+
const buf = (0, import_node_fs20.readFileSync)(absPath);
|
|
16273
16458
|
if (buf.includes(0)) return null;
|
|
16274
16459
|
return buf.toString("utf-8");
|
|
16275
16460
|
} catch {
|
|
@@ -16280,7 +16465,7 @@ function pruneOldBaselines() {
|
|
|
16280
16465
|
const root = projectPath(BASELINE_DIR);
|
|
16281
16466
|
let entries;
|
|
16282
16467
|
try {
|
|
16283
|
-
entries = (0,
|
|
16468
|
+
entries = (0, import_node_fs20.readdirSync)(root);
|
|
16284
16469
|
} catch {
|
|
16285
16470
|
return;
|
|
16286
16471
|
}
|
|
@@ -16290,8 +16475,8 @@ function pruneOldBaselines() {
|
|
|
16290
16475
|
const manifest = readManifest(dir);
|
|
16291
16476
|
if (!manifest) {
|
|
16292
16477
|
try {
|
|
16293
|
-
if (now - (0,
|
|
16294
|
-
(0,
|
|
16478
|
+
if (now - (0, import_node_fs20.statSync)(dir).mtimeMs > BASELINE_TTL_MS) {
|
|
16479
|
+
(0, import_node_fs20.rmSync)(dir, { recursive: true, force: true });
|
|
16295
16480
|
}
|
|
16296
16481
|
} catch {
|
|
16297
16482
|
}
|
|
@@ -16299,7 +16484,7 @@ function pruneOldBaselines() {
|
|
|
16299
16484
|
}
|
|
16300
16485
|
if (now - manifest.captured_at <= BASELINE_TTL_MS) continue;
|
|
16301
16486
|
try {
|
|
16302
|
-
(0,
|
|
16487
|
+
(0, import_node_fs20.rmSync)(dir, { recursive: true, force: true });
|
|
16303
16488
|
} catch {
|
|
16304
16489
|
}
|
|
16305
16490
|
}
|
|
@@ -16393,6 +16578,7 @@ function registerLifecycleCommands(program2) {
|
|
|
16393
16578
|
if (!verityConfigured()) process.exit(0);
|
|
16394
16579
|
const event = await readHookStdin();
|
|
16395
16580
|
const sessionId = opts.sessionId ?? event.session_id ?? process.env.CLAUDE_SESSION_ID ?? null;
|
|
16581
|
+
if (deferredToPlugin("compact", sessionId)) process.exit(0);
|
|
16396
16582
|
const globals = program2.opts();
|
|
16397
16583
|
const tok = await resolveToken(globals.token);
|
|
16398
16584
|
const session2 = sessionDossier(tok.ok ? tok.data.token : null, sessionId);
|
|
@@ -16421,6 +16607,7 @@ function registerLifecycleCommands(program2) {
|
|
|
16421
16607
|
if (!verityConfigured()) process.exit(0);
|
|
16422
16608
|
const event = await readHookStdin();
|
|
16423
16609
|
const sessionId = opts.sessionId ?? event.session_id ?? process.env.CLAUDE_SESSION_ID ?? null;
|
|
16610
|
+
if (deferredToPlugin("session end", sessionId)) process.exit(0);
|
|
16424
16611
|
const reason = opts.reason ?? event.session_end_reason ?? event.reason ?? "other";
|
|
16425
16612
|
if (reason === "clear") {
|
|
16426
16613
|
writeCarry(sessionId ?? void 0, getCurrentCommit());
|
|
@@ -16473,7 +16660,7 @@ function buildCompactionContext(session) {
|
|
|
16473
16660
|
readFileLines: (file) => {
|
|
16474
16661
|
try {
|
|
16475
16662
|
const abs = (0, import_node_path17.join)(root, file);
|
|
16476
|
-
return (0,
|
|
16663
|
+
return (0, import_node_fs21.existsSync)(abs) ? (0, import_node_fs21.readFileSync)(abs, "utf8").split("\n") : null;
|
|
16477
16664
|
} catch {
|
|
16478
16665
|
return null;
|
|
16479
16666
|
}
|
|
@@ -16530,11 +16717,11 @@ async function readHookStdin() {
|
|
|
16530
16717
|
|
|
16531
16718
|
// src/commands/standard.ts
|
|
16532
16719
|
var import_promises9 = require("node:fs/promises");
|
|
16533
|
-
var
|
|
16720
|
+
var import_node_fs23 = require("node:fs");
|
|
16534
16721
|
var import_yaml = __toESM(require_dist());
|
|
16535
16722
|
|
|
16536
16723
|
// src/lib/verityignore.ts
|
|
16537
|
-
var
|
|
16724
|
+
var import_node_fs22 = require("node:fs");
|
|
16538
16725
|
var EMPTY = { rules: [], securityOverlap: [], problems: [] };
|
|
16539
16726
|
var SECURITY_PROBES = [
|
|
16540
16727
|
".env",
|
|
@@ -16627,9 +16814,9 @@ function isIgnored(ig, path) {
|
|
|
16627
16814
|
}
|
|
16628
16815
|
function loadVerityIgnore() {
|
|
16629
16816
|
const file = projectPath(VERITYIGNORE_FILE);
|
|
16630
|
-
if (!(0,
|
|
16817
|
+
if (!(0, import_node_fs22.existsSync)(file)) return EMPTY;
|
|
16631
16818
|
try {
|
|
16632
|
-
return parseVerityIgnore((0,
|
|
16819
|
+
return parseVerityIgnore((0, import_node_fs22.readFileSync)(file, "utf-8"));
|
|
16633
16820
|
} catch {
|
|
16634
16821
|
return EMPTY;
|
|
16635
16822
|
}
|
|
@@ -16699,9 +16886,9 @@ function registerStandardCommands(program2) {
|
|
|
16699
16886
|
}
|
|
16700
16887
|
let ignoreRaw = null;
|
|
16701
16888
|
const ignorePath = projectPath(VERITYIGNORE_FILE);
|
|
16702
|
-
if ((0,
|
|
16889
|
+
if ((0, import_node_fs23.existsSync)(ignorePath)) {
|
|
16703
16890
|
try {
|
|
16704
|
-
ignoreRaw = (0,
|
|
16891
|
+
ignoreRaw = (0, import_node_fs23.readFileSync)(ignorePath, "utf-8");
|
|
16705
16892
|
const overlap = describeSecurityOverlap(parseVerityIgnore(ignoreRaw));
|
|
16706
16893
|
if (overlap) printWarn(overlap);
|
|
16707
16894
|
} catch {
|
|
@@ -16801,6 +16988,22 @@ function registerConfigCommands(program2) {
|
|
|
16801
16988
|
}
|
|
16802
16989
|
process.stdout.write(urlResult.data + "\n");
|
|
16803
16990
|
});
|
|
16991
|
+
config.command("git-moments [moments]").description('Get or set the git moments the guard reviews: commit,push \u2014 or "none"').action((moments) => {
|
|
16992
|
+
if (moments === void 0) {
|
|
16993
|
+
const current = readProjectConfig().git_moments;
|
|
16994
|
+
process.stdout.write((current.length ? current.join(",") : "none") + "\n");
|
|
16995
|
+
return;
|
|
16996
|
+
}
|
|
16997
|
+
const next = moments === "none" ? [] : parseMoments(moments);
|
|
16998
|
+
if (moments !== "none" && next.length === 0) {
|
|
16999
|
+
printError(`Unrecognised moments: ${moments}. Use "commit", "push", "commit,push", or "none".`);
|
|
17000
|
+
process.exit(1);
|
|
17001
|
+
}
|
|
17002
|
+
writeProjectConfig({ git_moments: next });
|
|
17003
|
+
printInfo(
|
|
17004
|
+
next.length ? `Git-moment review enabled for: ${next.join(", ")}` : "Git-moment review disabled \u2014 commits and pushes are no longer gated."
|
|
17005
|
+
);
|
|
17006
|
+
});
|
|
16804
17007
|
config.command("push").description("Upload the analysis config to the service").option("--file <path>", "Path to config file", CODACY_CONFIG_FILE).action(async (opts) => {
|
|
16805
17008
|
const globals = program2.opts();
|
|
16806
17009
|
const tokenResult = await resolveToken(globals.token);
|
|
@@ -16943,10 +17146,10 @@ function formatRunDetail(run2) {
|
|
|
16943
17146
|
}
|
|
16944
17147
|
|
|
16945
17148
|
// src/lib/ignore-declaration.ts
|
|
16946
|
-
var
|
|
17149
|
+
var import_node_fs25 = require("node:fs");
|
|
16947
17150
|
|
|
16948
17151
|
// src/lib/debounce.ts
|
|
16949
|
-
var
|
|
17152
|
+
var import_node_fs24 = require("node:fs");
|
|
16950
17153
|
var import_node_crypto10 = require("node:crypto");
|
|
16951
17154
|
function scopedFile(base, sessionId) {
|
|
16952
17155
|
if (!sessionId) return base;
|
|
@@ -16954,9 +17157,9 @@ function scopedFile(base, sessionId) {
|
|
|
16954
17157
|
}
|
|
16955
17158
|
function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
|
|
16956
17159
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
16957
|
-
if (!(0,
|
|
17160
|
+
if (!(0, import_node_fs24.existsSync)(file)) return null;
|
|
16958
17161
|
try {
|
|
16959
|
-
const lastTs = parseInt((0,
|
|
17162
|
+
const lastTs = parseInt((0, import_node_fs24.readFileSync)(file, "utf-8").trim(), 10);
|
|
16960
17163
|
const nowTs = Math.floor(Date.now() / 1e3);
|
|
16961
17164
|
const elapsed = nowTs - lastTs;
|
|
16962
17165
|
if (elapsed < debounceSeconds) {
|
|
@@ -16969,10 +17172,10 @@ function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
|
|
|
16969
17172
|
function checkMtime(files, bypassForRecentCommits, sessionId) {
|
|
16970
17173
|
if (bypassForRecentCommits) return null;
|
|
16971
17174
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
16972
|
-
if (!(0,
|
|
17175
|
+
if (!(0, import_node_fs24.existsSync)(file)) return null;
|
|
16973
17176
|
let debounceTime;
|
|
16974
17177
|
try {
|
|
16975
|
-
debounceTime = (0,
|
|
17178
|
+
debounceTime = (0, import_node_fs24.statSync)(file).mtimeMs;
|
|
16976
17179
|
} catch {
|
|
16977
17180
|
return null;
|
|
16978
17181
|
}
|
|
@@ -16980,7 +17183,7 @@ function checkMtime(files, bypassForRecentCommits, sessionId) {
|
|
|
16980
17183
|
const resolved = resolveFile(f);
|
|
16981
17184
|
if (!resolved) continue;
|
|
16982
17185
|
try {
|
|
16983
|
-
const stat3 = (0,
|
|
17186
|
+
const stat3 = (0, import_node_fs24.statSync)(resolved);
|
|
16984
17187
|
if (stat3.mtimeMs > debounceTime) {
|
|
16985
17188
|
return null;
|
|
16986
17189
|
}
|
|
@@ -16996,8 +17199,8 @@ function computeContentHash(files) {
|
|
|
16996
17199
|
for (const f of sorted) {
|
|
16997
17200
|
const resolved = resolveFile(f) ?? f;
|
|
16998
17201
|
try {
|
|
16999
|
-
if ((0,
|
|
17000
|
-
hash.update((0,
|
|
17202
|
+
if ((0, import_node_fs24.existsSync)(resolved)) {
|
|
17203
|
+
hash.update((0, import_node_fs24.readFileSync)(resolved));
|
|
17001
17204
|
}
|
|
17002
17205
|
} catch {
|
|
17003
17206
|
}
|
|
@@ -17007,9 +17210,9 @@ function computeContentHash(files) {
|
|
|
17007
17210
|
function checkContentHash(files, sessionId) {
|
|
17008
17211
|
const hash = computeContentHash(files);
|
|
17009
17212
|
const file = scopedFile(HASH_FILE, sessionId);
|
|
17010
|
-
if ((0,
|
|
17213
|
+
if ((0, import_node_fs24.existsSync)(file)) {
|
|
17011
17214
|
try {
|
|
17012
|
-
const storedHash = (0,
|
|
17215
|
+
const storedHash = (0, import_node_fs24.readFileSync)(file, "utf-8").trim();
|
|
17013
17216
|
if (hash === storedHash) {
|
|
17014
17217
|
return { skip: "No source changes since last analysis", hash };
|
|
17015
17218
|
}
|
|
@@ -17019,24 +17222,24 @@ function checkContentHash(files, sessionId) {
|
|
|
17019
17222
|
return { skip: null, hash };
|
|
17020
17223
|
}
|
|
17021
17224
|
function recordAnalysisStart(sessionId) {
|
|
17022
|
-
(0,
|
|
17023
|
-
(0,
|
|
17225
|
+
(0, import_node_fs24.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
17226
|
+
(0, import_node_fs24.writeFileSync)(scopedFile(DEBOUNCE_FILE, sessionId), String(Math.floor(Date.now() / 1e3)));
|
|
17024
17227
|
}
|
|
17025
17228
|
function recordPassHash(hash, sessionId) {
|
|
17026
|
-
(0,
|
|
17229
|
+
(0, import_node_fs24.writeFileSync)(scopedFile(HASH_FILE, sessionId), hash);
|
|
17027
17230
|
}
|
|
17028
17231
|
function narrowToRecent(files, sessionId) {
|
|
17029
17232
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
17030
|
-
if (!(0,
|
|
17233
|
+
if (!(0, import_node_fs24.existsSync)(file)) return files;
|
|
17031
17234
|
let debounceTime;
|
|
17032
17235
|
try {
|
|
17033
|
-
debounceTime = (0,
|
|
17236
|
+
debounceTime = (0, import_node_fs24.statSync)(file).mtimeMs;
|
|
17034
17237
|
} catch {
|
|
17035
17238
|
return files;
|
|
17036
17239
|
}
|
|
17037
17240
|
const recent = files.filter((f) => {
|
|
17038
17241
|
try {
|
|
17039
|
-
return (0,
|
|
17242
|
+
return (0, import_node_fs24.existsSync)(f) && (0, import_node_fs24.statSync)(f).mtimeMs > debounceTime;
|
|
17040
17243
|
} catch {
|
|
17041
17244
|
return false;
|
|
17042
17245
|
}
|
|
@@ -17049,9 +17252,9 @@ function readIteration(currentCommit, _contentHash) {
|
|
|
17049
17252
|
var NO_BLOCKS = { attempts: 0, blocks: 0, fingerprint: null };
|
|
17050
17253
|
function readBlockState(currentCommit, opts) {
|
|
17051
17254
|
if (opts?.newUserPrompt) return NO_BLOCKS;
|
|
17052
|
-
if (!(0,
|
|
17255
|
+
if (!(0, import_node_fs24.existsSync)(ITERATION_FILE)) return NO_BLOCKS;
|
|
17053
17256
|
try {
|
|
17054
|
-
const stored = (0,
|
|
17257
|
+
const stored = (0, import_node_fs24.readFileSync)(ITERATION_FILE, "utf-8").trim();
|
|
17055
17258
|
const parsed = stored.startsWith("{") ? parseJsonState(stored) : parseLegacyState(stored);
|
|
17056
17259
|
if (!parsed) return NO_BLOCKS;
|
|
17057
17260
|
if (parsed.commit !== currentCommit) return NO_BLOCKS;
|
|
@@ -17097,8 +17300,8 @@ function isSameProblem(previous, current) {
|
|
|
17097
17300
|
return current.split(",").some((k) => prev.has(k));
|
|
17098
17301
|
}
|
|
17099
17302
|
function writeBlockState(commit, state) {
|
|
17100
|
-
(0,
|
|
17101
|
-
(0,
|
|
17303
|
+
(0, import_node_fs24.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
17304
|
+
(0, import_node_fs24.writeFileSync)(
|
|
17102
17305
|
ITERATION_FILE,
|
|
17103
17306
|
JSON.stringify({
|
|
17104
17307
|
v: 2,
|
|
@@ -17203,9 +17406,9 @@ function resolveIgnoreState(keys) {
|
|
|
17203
17406
|
}
|
|
17204
17407
|
function readIgnoreState(sessionId) {
|
|
17205
17408
|
const file = stateFile(sessionId);
|
|
17206
|
-
if (!(0,
|
|
17409
|
+
if (!(0, import_node_fs25.existsSync)(file)) return null;
|
|
17207
17410
|
try {
|
|
17208
|
-
const o = JSON.parse((0,
|
|
17411
|
+
const o = JSON.parse((0, import_node_fs25.readFileSync)(file, "utf-8")) ?? {};
|
|
17209
17412
|
const spent = typeof o.spent === "number" ? o.spent : 0;
|
|
17210
17413
|
const raw = o.active;
|
|
17211
17414
|
let active = null;
|
|
@@ -17229,8 +17432,8 @@ function readIgnoreState(sessionId) {
|
|
|
17229
17432
|
}
|
|
17230
17433
|
function writeIgnoreState(state, sessionId) {
|
|
17231
17434
|
try {
|
|
17232
|
-
(0,
|
|
17233
|
-
(0,
|
|
17435
|
+
(0, import_node_fs25.mkdirSync)(projectPath(VERITY_DIR), { recursive: true });
|
|
17436
|
+
(0, import_node_fs25.writeFileSync)(stateFile(sessionId), JSON.stringify({ v: 1, active: state.active, spent: state.spent }));
|
|
17234
17437
|
} catch {
|
|
17235
17438
|
}
|
|
17236
17439
|
}
|
|
@@ -17567,7 +17770,6 @@ function createRun(opts, globals) {
|
|
|
17567
17770
|
token: "",
|
|
17568
17771
|
modeDecision: null,
|
|
17569
17772
|
sessionIdForMemory: "",
|
|
17570
|
-
contextFilePaths: [],
|
|
17571
17773
|
analysisMode: "standard",
|
|
17572
17774
|
sessionAuthoredCode: false,
|
|
17573
17775
|
staticResults: {
|
|
@@ -17577,6 +17779,7 @@ function createRun(opts, globals) {
|
|
|
17577
17779
|
},
|
|
17578
17780
|
codeDelta: { files: [], total_lines: 0, total_files: 0, excluded: [] },
|
|
17579
17781
|
snapshotResult: { has_snapshots: false, diffs: [] },
|
|
17782
|
+
repoContext: null,
|
|
17580
17783
|
contentHash: null,
|
|
17581
17784
|
iteration: 1,
|
|
17582
17785
|
currentCommit: "",
|
|
@@ -17604,58 +17807,702 @@ function createRun(opts, globals) {
|
|
|
17604
17807
|
};
|
|
17605
17808
|
}
|
|
17606
17809
|
|
|
17607
|
-
// src/lib/
|
|
17608
|
-
var
|
|
17609
|
-
var
|
|
17610
|
-
|
|
17611
|
-
|
|
17612
|
-
|
|
17810
|
+
// src/lib/repo-context.ts
|
|
17811
|
+
var import_node_child_process7 = require("node:child_process");
|
|
17812
|
+
var import_node_os3 = require("node:os");
|
|
17813
|
+
function rgInvocations(env = process.env) {
|
|
17814
|
+
const out = [{ cmd: "rg" }];
|
|
17815
|
+
if (env.CLAUDE_CODE_EXECPATH) out.push({ cmd: env.CLAUDE_CODE_EXECPATH, argv0: "rg" });
|
|
17816
|
+
out.push({ cmd: `${(0, import_node_os3.homedir)()}/.local/bin/claude`, argv0: "rg" });
|
|
17817
|
+
return out;
|
|
17613
17818
|
}
|
|
17614
|
-
var
|
|
17615
|
-
var
|
|
17616
|
-
var
|
|
17617
|
-
|
|
17618
|
-
|
|
17619
|
-
|
|
17620
|
-
|
|
17621
|
-
|
|
17622
|
-
|
|
17623
|
-
|
|
17624
|
-
|
|
17819
|
+
var MAX_SYMBOLS = 12;
|
|
17820
|
+
var MAX_SITES = 24;
|
|
17821
|
+
var MAX_SITES_PER_FILE = 3;
|
|
17822
|
+
var MAX_HITS_PER_SYMBOL = 50;
|
|
17823
|
+
var MAX_TEST_SLOTS = 8;
|
|
17824
|
+
var SITE_TEXT_MAX = 160;
|
|
17825
|
+
var ENCLOSING_SCAN_LINES = 200;
|
|
17826
|
+
var RG_TIMEOUT_MS = 1500;
|
|
17827
|
+
var IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
17828
|
+
var STOPLIST = /* @__PURE__ */ new Set([
|
|
17829
|
+
// keyword-shaped captures
|
|
17830
|
+
"if",
|
|
17831
|
+
"for",
|
|
17832
|
+
"while",
|
|
17833
|
+
"switch",
|
|
17834
|
+
"catch",
|
|
17835
|
+
"return",
|
|
17836
|
+
"function",
|
|
17837
|
+
"class",
|
|
17838
|
+
"const",
|
|
17839
|
+
"let",
|
|
17840
|
+
"var",
|
|
17841
|
+
"new",
|
|
17842
|
+
"else",
|
|
17843
|
+
"try",
|
|
17844
|
+
"finally",
|
|
17845
|
+
"throw",
|
|
17846
|
+
"await",
|
|
17847
|
+
"async",
|
|
17848
|
+
"yield",
|
|
17849
|
+
"delete",
|
|
17850
|
+
"typeof",
|
|
17851
|
+
"instanceof",
|
|
17852
|
+
"void",
|
|
17853
|
+
"this",
|
|
17854
|
+
"super",
|
|
17855
|
+
"import",
|
|
17856
|
+
"export",
|
|
17857
|
+
"default",
|
|
17858
|
+
"extends",
|
|
17859
|
+
"implements",
|
|
17860
|
+
"interface",
|
|
17861
|
+
"enum",
|
|
17862
|
+
"type",
|
|
17863
|
+
"public",
|
|
17864
|
+
"private",
|
|
17865
|
+
"protected",
|
|
17866
|
+
"static",
|
|
17867
|
+
"get",
|
|
17868
|
+
"set",
|
|
17869
|
+
"constructor",
|
|
17870
|
+
"def",
|
|
17871
|
+
"elif",
|
|
17872
|
+
"lambda",
|
|
17873
|
+
"with",
|
|
17874
|
+
"pass",
|
|
17875
|
+
"self",
|
|
17876
|
+
"cls",
|
|
17877
|
+
"not",
|
|
17878
|
+
"and",
|
|
17879
|
+
"or",
|
|
17880
|
+
"raise",
|
|
17881
|
+
"except",
|
|
17882
|
+
"func",
|
|
17883
|
+
"defer",
|
|
17884
|
+
"chan",
|
|
17885
|
+
"select",
|
|
17886
|
+
"range",
|
|
17887
|
+
"module",
|
|
17888
|
+
"struct",
|
|
17889
|
+
"trait",
|
|
17890
|
+
"impl",
|
|
17891
|
+
"using",
|
|
17892
|
+
"namespace",
|
|
17893
|
+
// universal noise
|
|
17894
|
+
"main",
|
|
17895
|
+
"init",
|
|
17896
|
+
"index",
|
|
17897
|
+
"data",
|
|
17898
|
+
"value",
|
|
17899
|
+
"result",
|
|
17900
|
+
"item",
|
|
17901
|
+
"name",
|
|
17902
|
+
"key",
|
|
17903
|
+
"run",
|
|
17904
|
+
"test",
|
|
17905
|
+
"setup",
|
|
17906
|
+
"update",
|
|
17907
|
+
"create",
|
|
17908
|
+
"handle",
|
|
17909
|
+
"check",
|
|
17910
|
+
"load",
|
|
17911
|
+
"save",
|
|
17912
|
+
"list",
|
|
17913
|
+
"map",
|
|
17914
|
+
"args",
|
|
17915
|
+
"params",
|
|
17916
|
+
"props",
|
|
17917
|
+
"state",
|
|
17918
|
+
"error",
|
|
17919
|
+
"err",
|
|
17920
|
+
"res",
|
|
17921
|
+
"req",
|
|
17922
|
+
"ctx",
|
|
17923
|
+
"config",
|
|
17924
|
+
"options",
|
|
17925
|
+
"util",
|
|
17926
|
+
"utils",
|
|
17927
|
+
"helper",
|
|
17928
|
+
"render",
|
|
17929
|
+
"build",
|
|
17930
|
+
"parse",
|
|
17931
|
+
"format",
|
|
17932
|
+
"apply",
|
|
17933
|
+
"process",
|
|
17934
|
+
"start",
|
|
17935
|
+
"stop"
|
|
17936
|
+
]);
|
|
17937
|
+
var TS_RULES = [
|
|
17938
|
+
/\b(?:function|class|interface|enum)\s+([A-Za-z_][A-Za-z0-9_]*)/,
|
|
17939
|
+
/\btype\s+([A-Za-z_][A-Za-z0-9_]*)\s*=/,
|
|
17940
|
+
// const foo = (…) => · const foo = x => · const foo = function.
|
|
17941
|
+
// ⚠ REQUIRES the arrow or `function` ON THE LINE. The first version accepted
|
|
17942
|
+
// any `= (` — and `const started = (rows?.[0] as Row)?.at` is a PARENTHESIZED
|
|
17943
|
+
// CAST, not a function. Replayed over 12 real commits, that one shape put
|
|
17944
|
+
// three local variables into the symbol set per commit. A multi-line arrow
|
|
17945
|
+
// is the accepted false negative; a cast is not an accepted false positive.
|
|
17946
|
+
/\b(?:const|let|var)\s+([A-Za-z_][A-Za-z0-9_]*)\s*(?::[^=\n]+)?=\s*(?:async\s+)?(?:function\b|\([^)]*\)(?:\s*:[^=\n]+)?\s*=>|[A-Za-z_$][\w$]*\s*=>)/,
|
|
17947
|
+
// method shape: name(…) { — keyword captures die at the stoplist
|
|
17948
|
+
/^\s*(?:(?:public|private|protected|static|readonly|async|override)\s+)*(?:\*\s*)?([A-Za-z_][A-Za-z0-9_]*)\s*\([^)]*\)\s*(?::[^{;\n]+)?\s*\{/
|
|
17949
|
+
];
|
|
17950
|
+
var PY_RULES = [
|
|
17951
|
+
/^\s*(?:async\s+)?def\s+([A-Za-z_]\w*)/,
|
|
17952
|
+
/^\s*class\s+([A-Za-z_]\w*)/
|
|
17953
|
+
];
|
|
17954
|
+
var GO_RULES = [
|
|
17955
|
+
/^func\s+(?:\([^)]*\)\s*)?([A-Za-z_]\w*)/,
|
|
17956
|
+
/^type\s+([A-Za-z_]\w*)/
|
|
17957
|
+
];
|
|
17958
|
+
var CLIKE_RULES = [
|
|
17959
|
+
/\b(?:class|interface|enum|record|struct)\s+([A-Za-z_]\w*)/,
|
|
17960
|
+
// access-modifier method shape: `public async Task<Foo> BarBaz(…`
|
|
17961
|
+
/(?:public|private|protected|internal|static|final|virtual|override|sealed|abstract)[\w<>[\],?\s]*?\s([A-Za-z_]\w*)\s*\(/
|
|
17962
|
+
];
|
|
17963
|
+
var RB_RULES = [
|
|
17964
|
+
/^\s*def\s+(?:self\.)?([A-Za-z_]\w*)/,
|
|
17965
|
+
/^\s*(?:class|module)\s+([A-Z]\w*)/
|
|
17966
|
+
];
|
|
17967
|
+
var RS_RULES = [
|
|
17968
|
+
/\bfn\s+([A-Za-z_]\w*)/,
|
|
17969
|
+
/\b(?:struct|enum|trait)\s+([A-Za-z_]\w*)/
|
|
17970
|
+
];
|
|
17971
|
+
var PHP_RULES = [
|
|
17972
|
+
/\bfunction\s+([A-Za-z_]\w*)/,
|
|
17973
|
+
/\bclass\s+([A-Za-z_]\w*)/
|
|
17974
|
+
];
|
|
17975
|
+
var C_RULES = [
|
|
17976
|
+
/^(?:static\s+|inline\s+|extern\s+|constexpr\s+)*(?:struct\s+|enum\s+|union\s+|unsigned\s+|const\s+)*[A-Za-z_]\w*(?:\s*[*&]+\s*|\s+)([A-Za-z_]\w*)\s*\([^;]*$/,
|
|
17977
|
+
/\b(?:struct|enum|union|class)\s+([A-Za-z_]\w*)/,
|
|
17978
|
+
/::\s*~?([A-Za-z_]\w*)\s*\([^;]*$/
|
|
17979
|
+
// out-of-line C++ method definition
|
|
17980
|
+
];
|
|
17981
|
+
var SH_RULES = [
|
|
17982
|
+
/^\s*(?:function\s+)?([A-Za-z_]\w*)\s*\(\)\s*\{/,
|
|
17983
|
+
/^function\s+([A-Za-z_]\w*)/
|
|
17984
|
+
];
|
|
17985
|
+
var SQL_RULES = [
|
|
17986
|
+
/\bcreate\s+(?:or\s+replace\s+)?(?:table|view|materialized\s+view|function|procedure|index|trigger|type|policy)\s+(?:if\s+not\s+exists\s+)?(?:[\w".]*\.)?"?([A-Za-z_]\w*)"?/i
|
|
17987
|
+
];
|
|
17988
|
+
var TF_RULES = [
|
|
17989
|
+
/^\s*(?:resource|data)\s+"[^"]+"\s+"([A-Za-z_]\w*)"/,
|
|
17990
|
+
/^\s*(?:module|variable|output)\s+"([A-Za-z_]\w*)"/
|
|
17991
|
+
];
|
|
17992
|
+
var SWIFT_RULES = [
|
|
17993
|
+
/\bfunc\s+([A-Za-z_]\w*)/,
|
|
17994
|
+
/\b(?:class|struct|enum|protocol|extension|actor)\s+([A-Za-z_]\w*)/
|
|
17995
|
+
];
|
|
17996
|
+
var DART_RULES = [
|
|
17997
|
+
/\b(?:class|enum|mixin|extension)\s+([A-Za-z_]\w*)/,
|
|
17998
|
+
/^\s*(?:static\s+)?(?:Future<[^>]*>|Stream<[^>]*>|void|int|double|bool|String|num|dynamic|[A-Z]\w*(?:<[^>]*>)?)\s+([a-z_]\w*)\s*\(/
|
|
17999
|
+
];
|
|
18000
|
+
var LUA_RULES = [
|
|
18001
|
+
/^\s*(?:local\s+)?function\s+(?:[\w.]+[.:])?([A-Za-z_]\w*)/
|
|
18002
|
+
];
|
|
18003
|
+
var EX_RULES = [
|
|
18004
|
+
/^\s*def(?:p|macro)?\s+([a-z_]\w*)/,
|
|
18005
|
+
/^\s*defmodule\s+(?:[\w.]*\.)?([A-Z]\w*)/
|
|
18006
|
+
];
|
|
18007
|
+
var PROTO_RULES = [
|
|
18008
|
+
/^\s*(?:message|service|enum)\s+([A-Za-z_]\w*)/,
|
|
18009
|
+
/^\s*rpc\s+([A-Za-z_]\w*)/
|
|
18010
|
+
];
|
|
18011
|
+
var GRAPHQL_RULES = [
|
|
18012
|
+
/^\s*(?:type|interface|enum|input|union|scalar)\s+([A-Za-z_]\w*)/
|
|
18013
|
+
];
|
|
18014
|
+
var RULES_BY_EXT = {
|
|
18015
|
+
ts: TS_RULES,
|
|
18016
|
+
tsx: TS_RULES,
|
|
18017
|
+
js: TS_RULES,
|
|
18018
|
+
jsx: TS_RULES,
|
|
18019
|
+
mjs: TS_RULES,
|
|
18020
|
+
cjs: TS_RULES,
|
|
18021
|
+
svelte: TS_RULES,
|
|
18022
|
+
vue: TS_RULES,
|
|
18023
|
+
// script blocks
|
|
18024
|
+
py: PY_RULES,
|
|
18025
|
+
go: GO_RULES,
|
|
18026
|
+
java: CLIKE_RULES,
|
|
18027
|
+
cs: CLIKE_RULES,
|
|
18028
|
+
kt: CLIKE_RULES,
|
|
18029
|
+
scala: CLIKE_RULES,
|
|
18030
|
+
rb: RB_RULES,
|
|
18031
|
+
rs: RS_RULES,
|
|
18032
|
+
php: PHP_RULES,
|
|
18033
|
+
c: C_RULES,
|
|
18034
|
+
cpp: C_RULES,
|
|
18035
|
+
cc: C_RULES,
|
|
18036
|
+
h: C_RULES,
|
|
18037
|
+
hpp: C_RULES,
|
|
18038
|
+
sh: SH_RULES,
|
|
18039
|
+
bash: SH_RULES,
|
|
18040
|
+
zsh: SH_RULES,
|
|
18041
|
+
sql: SQL_RULES,
|
|
18042
|
+
tf: TF_RULES,
|
|
18043
|
+
hcl: TF_RULES,
|
|
18044
|
+
swift: SWIFT_RULES,
|
|
18045
|
+
dart: DART_RULES,
|
|
18046
|
+
lua: LUA_RULES,
|
|
18047
|
+
ex: EX_RULES,
|
|
18048
|
+
exs: EX_RULES,
|
|
18049
|
+
proto: PROTO_RULES,
|
|
18050
|
+
graphql: GRAPHQL_RULES,
|
|
18051
|
+
gql: GRAPHQL_RULES
|
|
18052
|
+
};
|
|
18053
|
+
var HUNK_HEADER = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
18054
|
+
function parseDiffSignals(diff) {
|
|
18055
|
+
const addedRanges = [];
|
|
18056
|
+
const touchPoints = [];
|
|
18057
|
+
const deletedLines = [];
|
|
18058
|
+
let newLine = 0;
|
|
18059
|
+
let oldRemaining = 0;
|
|
18060
|
+
let newRemaining = 0;
|
|
18061
|
+
let runStart = -1;
|
|
18062
|
+
let deletionRun = false;
|
|
18063
|
+
const closeAddedRun = () => {
|
|
18064
|
+
if (runStart >= 0) addedRanges.push([runStart, newLine - 1]);
|
|
18065
|
+
runStart = -1;
|
|
18066
|
+
};
|
|
18067
|
+
const closeDeletionRun = () => {
|
|
18068
|
+
if (deletionRun) touchPoints.push(Math.max(1, newLine));
|
|
18069
|
+
deletionRun = false;
|
|
18070
|
+
};
|
|
18071
|
+
for (const line of diff.split("\n")) {
|
|
18072
|
+
const inHunk = oldRemaining > 0 || newRemaining > 0;
|
|
18073
|
+
if (!inHunk) {
|
|
18074
|
+
closeAddedRun();
|
|
18075
|
+
closeDeletionRun();
|
|
18076
|
+
const header = HUNK_HEADER.exec(line);
|
|
18077
|
+
if (header) {
|
|
18078
|
+
newLine = parseInt(header[3], 10);
|
|
18079
|
+
oldRemaining = header[2] === void 0 ? 1 : parseInt(header[2], 10);
|
|
18080
|
+
newRemaining = header[4] === void 0 ? 1 : parseInt(header[4], 10);
|
|
18081
|
+
if (newRemaining === 0) newLine = Math.max(1, newLine);
|
|
18082
|
+
}
|
|
18083
|
+
continue;
|
|
18084
|
+
}
|
|
18085
|
+
if (line.startsWith("\\")) continue;
|
|
18086
|
+
if (line.startsWith("+") && newRemaining > 0) {
|
|
18087
|
+
deletionRun = false;
|
|
18088
|
+
if (runStart < 0) runStart = newLine;
|
|
18089
|
+
newLine++;
|
|
18090
|
+
newRemaining--;
|
|
18091
|
+
continue;
|
|
18092
|
+
}
|
|
18093
|
+
if (line.startsWith("-") && oldRemaining > 0) {
|
|
18094
|
+
closeAddedRun();
|
|
18095
|
+
deletionRun = true;
|
|
18096
|
+
deletedLines.push(line.slice(1));
|
|
18097
|
+
oldRemaining--;
|
|
18098
|
+
continue;
|
|
18099
|
+
}
|
|
18100
|
+
closeAddedRun();
|
|
18101
|
+
closeDeletionRun();
|
|
18102
|
+
newLine++;
|
|
18103
|
+
if (oldRemaining > 0) oldRemaining--;
|
|
18104
|
+
if (newRemaining > 0) newRemaining--;
|
|
17625
18105
|
}
|
|
18106
|
+
closeAddedRun();
|
|
18107
|
+
closeDeletionRun();
|
|
18108
|
+
return { addedRanges, touchPoints, deletedLines };
|
|
17626
18109
|
}
|
|
17627
|
-
function
|
|
17628
|
-
|
|
17629
|
-
|
|
17630
|
-
|
|
18110
|
+
function declNameOn(line, rules) {
|
|
18111
|
+
for (const r of rules) {
|
|
18112
|
+
const m = r.exec(line);
|
|
18113
|
+
if (m?.[1]) return m[1];
|
|
18114
|
+
}
|
|
18115
|
+
return null;
|
|
17631
18116
|
}
|
|
17632
|
-
function
|
|
17633
|
-
if (
|
|
17634
|
-
|
|
17635
|
-
|
|
17636
|
-
|
|
17637
|
-
|
|
17638
|
-
|
|
17639
|
-
|
|
17640
|
-
|
|
17641
|
-
|
|
17642
|
-
|
|
17643
|
-
|
|
17644
|
-
|
|
17645
|
-
|
|
17646
|
-
|
|
17647
|
-
|
|
17648
|
-
|
|
18117
|
+
function acceptable(name) {
|
|
18118
|
+
if (!name || !IDENTIFIER.test(name) || STOPLIST.has(name.toLowerCase())) return false;
|
|
18119
|
+
if (name.length < 3) return false;
|
|
18120
|
+
if (name.length === 3 && name === name.toLowerCase() && !name.includes("_")) return false;
|
|
18121
|
+
return true;
|
|
18122
|
+
}
|
|
18123
|
+
function isMultiSegment(name) {
|
|
18124
|
+
return /[a-z][A-Z]/.test(name) || name.includes("_");
|
|
18125
|
+
}
|
|
18126
|
+
function extractFileSymbols(path, content, signals) {
|
|
18127
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
18128
|
+
const rules = RULES_BY_EXT[ext];
|
|
18129
|
+
if (!rules) return [];
|
|
18130
|
+
if (signals.addedRanges.length === 0 && signals.touchPoints.length === 0 && signals.deletedLines.length === 0) return [];
|
|
18131
|
+
const lines = content.split("\n");
|
|
18132
|
+
const found = [];
|
|
18133
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18134
|
+
const add = (name) => {
|
|
18135
|
+
if (acceptable(name) && !seen.has(name)) {
|
|
18136
|
+
seen.add(name);
|
|
18137
|
+
found.push(name);
|
|
17649
18138
|
}
|
|
17650
|
-
return result;
|
|
17651
18139
|
};
|
|
17652
|
-
|
|
18140
|
+
for (const deleted of signals.deletedLines) {
|
|
18141
|
+
add(declNameOn(deleted, rules));
|
|
18142
|
+
}
|
|
18143
|
+
for (const [start, end] of signals.addedRanges) {
|
|
18144
|
+
for (let n = start; n <= Math.min(end, lines.length); n++) {
|
|
18145
|
+
add(declNameOn(lines[n - 1] ?? "", rules));
|
|
18146
|
+
}
|
|
18147
|
+
}
|
|
18148
|
+
const scanStarts = [
|
|
18149
|
+
...signals.addedRanges.map(([start]) => start),
|
|
18150
|
+
...signals.touchPoints
|
|
18151
|
+
];
|
|
18152
|
+
for (const start of scanStarts) {
|
|
18153
|
+
const floor = Math.max(1, start - ENCLOSING_SCAN_LINES);
|
|
18154
|
+
for (let n = Math.min(start, lines.length); n >= floor; n--) {
|
|
18155
|
+
const name = declNameOn(lines[n - 1] ?? "", rules);
|
|
18156
|
+
if (acceptable(name)) {
|
|
18157
|
+
add(name);
|
|
18158
|
+
break;
|
|
18159
|
+
}
|
|
18160
|
+
}
|
|
18161
|
+
}
|
|
18162
|
+
return found;
|
|
17653
18163
|
}
|
|
17654
|
-
function
|
|
17655
|
-
|
|
17656
|
-
|
|
17657
|
-
|
|
17658
|
-
|
|
18164
|
+
function rankSymbols(symbols) {
|
|
18165
|
+
return symbols.map((s, i) => ({ s, i })).sort((a, b) => {
|
|
18166
|
+
const seg = Number(isMultiSegment(b.s)) - Number(isMultiSegment(a.s));
|
|
18167
|
+
if (seg !== 0) return seg;
|
|
18168
|
+
if (b.s.length !== a.s.length) return b.s.length - a.s.length;
|
|
18169
|
+
return a.i - b.i;
|
|
18170
|
+
}).slice(0, MAX_SYMBOLS).map((x) => x.s);
|
|
18171
|
+
}
|
|
18172
|
+
var TEST_PATH = /(^|\/)(tests?|specs?|__tests__|e2e)(\/|$)/i;
|
|
18173
|
+
var TEST_FILE = /(\.(test|spec|e2e)\.[^./]+|_test\.[^./]+|_spec\.rb)$/i;
|
|
18174
|
+
var TEST_PY_PREFIX = /(^|\/)test_[^/]+\.py$/i;
|
|
18175
|
+
var IMPORT_LINE = /^\s*(import\s|from\s+\S+\s+import\s|const\s+.*=\s*require\s*\(|require\s*\(|using\s+[\w.]+;|#include|export\s+\{[^}]*\}\s+from|export\s+\*\s+from)/;
|
|
18176
|
+
var BARE_MEMBER_LINE = /^(type\s+)?[A-Za-z_$][\w$]*\s*,?$/;
|
|
18177
|
+
var GO_IMPORT_PATH_LINE = /^"[^"]+",?$/;
|
|
18178
|
+
var SITE_CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
18179
|
+
"ts",
|
|
18180
|
+
"tsx",
|
|
18181
|
+
"js",
|
|
18182
|
+
"jsx",
|
|
18183
|
+
"mjs",
|
|
18184
|
+
"cjs",
|
|
18185
|
+
"py",
|
|
18186
|
+
"go",
|
|
18187
|
+
"java",
|
|
18188
|
+
"kt",
|
|
18189
|
+
"rb",
|
|
18190
|
+
"rs",
|
|
18191
|
+
"scala",
|
|
18192
|
+
"c",
|
|
18193
|
+
"cpp",
|
|
18194
|
+
"cc",
|
|
18195
|
+
"h",
|
|
18196
|
+
"hpp",
|
|
18197
|
+
"cs",
|
|
18198
|
+
"php",
|
|
18199
|
+
"swift",
|
|
18200
|
+
"dart",
|
|
18201
|
+
"lua",
|
|
18202
|
+
"sh",
|
|
18203
|
+
"bash",
|
|
18204
|
+
"zsh",
|
|
18205
|
+
"svelte",
|
|
18206
|
+
"vue",
|
|
18207
|
+
"ex",
|
|
18208
|
+
"exs",
|
|
18209
|
+
// sql/tf carry REAL call sites (SELECT my_function(...), module.name) —
|
|
18210
|
+
// excluded in an earlier round because of migration-comment noise, which the
|
|
18211
|
+
// COMMENT_LINE filter now handles on its own.
|
|
18212
|
+
"sql",
|
|
18213
|
+
"tf",
|
|
18214
|
+
"hcl"
|
|
18215
|
+
]);
|
|
18216
|
+
var COMMENT_LINE = /^(\/\/|#(?!\[)|\*|\/\*|--\s|<!--)/;
|
|
18217
|
+
function isCodeSiteFile(path) {
|
|
18218
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
18219
|
+
return SITE_CODE_EXTENSIONS.has(ext);
|
|
18220
|
+
}
|
|
18221
|
+
function isTestPath(path) {
|
|
18222
|
+
return TEST_PATH.test(path) || TEST_FILE.test(path) || TEST_PY_PREFIX.test(path);
|
|
18223
|
+
}
|
|
18224
|
+
function parseRgLine(line) {
|
|
18225
|
+
const first = line.indexOf(":");
|
|
18226
|
+
if (first <= 0) return null;
|
|
18227
|
+
const second = line.indexOf(":", first + 1);
|
|
18228
|
+
if (second < 0) return null;
|
|
18229
|
+
const n = parseInt(line.slice(first + 1, second), 10);
|
|
18230
|
+
if (!Number.isFinite(n) || n < 1) return null;
|
|
18231
|
+
return { file: line.slice(0, first), line: n, text: line.slice(second + 1) };
|
|
18232
|
+
}
|
|
18233
|
+
var isWordChar = (c) => c !== void 0 && /[A-Za-z0-9_]/.test(c);
|
|
18234
|
+
function wordHit(text, symbol) {
|
|
18235
|
+
let from = 0;
|
|
18236
|
+
for (; ; ) {
|
|
18237
|
+
const at = text.indexOf(symbol, from);
|
|
18238
|
+
if (at < 0) return false;
|
|
18239
|
+
const before = at === 0 ? void 0 : text[at - 1];
|
|
18240
|
+
const after = text[at + symbol.length];
|
|
18241
|
+
if (!isWordChar(before) && !isWordChar(after)) return true;
|
|
18242
|
+
from = at + 1;
|
|
18243
|
+
}
|
|
18244
|
+
}
|
|
18245
|
+
function isContractLine(text, symbol) {
|
|
18246
|
+
for (const kw of ["implements", "extends"]) {
|
|
18247
|
+
let from = 0;
|
|
18248
|
+
for (; ; ) {
|
|
18249
|
+
const at = text.indexOf(kw, from);
|
|
18250
|
+
if (at < 0) break;
|
|
18251
|
+
from = at + 1;
|
|
18252
|
+
const before = at === 0 ? void 0 : text[at - 1];
|
|
18253
|
+
const after = text[at + kw.length];
|
|
18254
|
+
if (isWordChar(before) || isWordChar(after)) continue;
|
|
18255
|
+
let clause = text.slice(at + kw.length);
|
|
18256
|
+
const stop = Math.min(
|
|
18257
|
+
...[clause.indexOf(";"), clause.indexOf("{")].filter((i) => i >= 0)
|
|
18258
|
+
);
|
|
18259
|
+
if (Number.isFinite(stop)) clause = clause.slice(0, stop);
|
|
18260
|
+
if (wordHit(clause, symbol)) return true;
|
|
18261
|
+
}
|
|
18262
|
+
}
|
|
18263
|
+
return false;
|
|
18264
|
+
}
|
|
18265
|
+
function partitionSites(rgLines, symbols, opts) {
|
|
18266
|
+
const hits = [];
|
|
18267
|
+
const hitCount = /* @__PURE__ */ new Map();
|
|
18268
|
+
for (const line of rgLines) {
|
|
18269
|
+
const hit = parseRgLine(line);
|
|
18270
|
+
if (!hit) continue;
|
|
18271
|
+
const matched = symbols.filter((s) => wordHit(hit.text, s));
|
|
18272
|
+
for (const s of matched) hitCount.set(s, (hitCount.get(s) ?? 0) + 1);
|
|
18273
|
+
if (matched.length === 0) continue;
|
|
18274
|
+
hits.push({ ...hit, symbol: matched[0] });
|
|
18275
|
+
}
|
|
18276
|
+
hits.sort((a, b) => a.file < b.file ? -1 : a.file > b.file ? 1 : a.line - b.line);
|
|
18277
|
+
const dropped = symbols.filter((s) => (hitCount.get(s) ?? 0) > MAX_HITS_PER_SYMBOL);
|
|
18278
|
+
const droppedSet = new Set(dropped);
|
|
18279
|
+
const perFile = /* @__PURE__ */ new Map();
|
|
18280
|
+
const callers = [];
|
|
18281
|
+
const tests = [];
|
|
18282
|
+
for (const h of hits) {
|
|
18283
|
+
if (droppedSet.has(h.symbol)) continue;
|
|
18284
|
+
if (opts.sentPaths.has(h.file)) continue;
|
|
18285
|
+
if (opts.isExcluded(h.file)) continue;
|
|
18286
|
+
if (!isCodeSiteFile(h.file)) continue;
|
|
18287
|
+
const text = h.text.trim();
|
|
18288
|
+
if (text.length === 0 || IMPORT_LINE.test(h.text)) continue;
|
|
18289
|
+
if (COMMENT_LINE.test(text)) continue;
|
|
18290
|
+
if (BARE_MEMBER_LINE.test(text) || GO_IMPORT_PATH_LINE.test(text)) continue;
|
|
18291
|
+
const n = perFile.get(h.file) ?? 0;
|
|
18292
|
+
if (n >= MAX_SITES_PER_FILE) continue;
|
|
18293
|
+
const site = {
|
|
18294
|
+
file: h.file,
|
|
18295
|
+
line: h.line,
|
|
18296
|
+
text: text.slice(0, SITE_TEXT_MAX),
|
|
18297
|
+
symbol: h.symbol,
|
|
18298
|
+
// R2 falls out of R1 for free: a word search for `Sym` already matches
|
|
18299
|
+
// `implements Sym` / `extends Sym` lines — classification is all R2 is.
|
|
18300
|
+
...isContractLine(text, h.symbol) ? { kind: "contract" } : {}
|
|
18301
|
+
};
|
|
18302
|
+
if (isTestPath(h.file)) {
|
|
18303
|
+
if (tests.length < MAX_TEST_SLOTS) {
|
|
18304
|
+
tests.push(site);
|
|
18305
|
+
perFile.set(h.file, n + 1);
|
|
18306
|
+
}
|
|
18307
|
+
} else if (callers.length + tests.length < MAX_SITES) {
|
|
18308
|
+
callers.push(site);
|
|
18309
|
+
perFile.set(h.file, n + 1);
|
|
18310
|
+
}
|
|
18311
|
+
}
|
|
18312
|
+
while (callers.length + tests.length > MAX_SITES) callers.pop();
|
|
18313
|
+
return { callers, tests, dropped };
|
|
18314
|
+
}
|
|
18315
|
+
function buildRepoContext(input) {
|
|
18316
|
+
const started = Date.now();
|
|
18317
|
+
let signalsByPath;
|
|
18318
|
+
if (input.signalsByPath) {
|
|
18319
|
+
if (input.signalsByPath.size === 0) return { state: "absent", reason: "no-diffs" };
|
|
18320
|
+
signalsByPath = input.signalsByPath;
|
|
18321
|
+
} else {
|
|
18322
|
+
if (input.diffs.length === 0) return { state: "absent", reason: "no-diffs" };
|
|
18323
|
+
signalsByPath = /* @__PURE__ */ new Map();
|
|
18324
|
+
for (const d of input.diffs) signalsByPath.set(d.path, parseDiffSignals(d.diff));
|
|
18325
|
+
}
|
|
18326
|
+
const collected = [];
|
|
18327
|
+
const unsupported = /* @__PURE__ */ new Set();
|
|
18328
|
+
const noteUnsupported = (path) => {
|
|
18329
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
18330
|
+
if (ext && !RULES_BY_EXT[ext]) unsupported.add(ext);
|
|
18331
|
+
};
|
|
18332
|
+
const deltaPathSet = new Set(input.deltaFiles.map((f) => f.path));
|
|
18333
|
+
for (const f of input.deltaFiles) {
|
|
18334
|
+
const signals = signalsByPath.get(f.path);
|
|
18335
|
+
if (!signals) continue;
|
|
18336
|
+
noteUnsupported(f.path);
|
|
18337
|
+
collected.push(...extractFileSymbols(f.path, f.content, signals));
|
|
18338
|
+
}
|
|
18339
|
+
for (const [path, signals] of signalsByPath) {
|
|
18340
|
+
if (deltaPathSet.has(path)) continue;
|
|
18341
|
+
if (signals.deletedLines.length > 0) {
|
|
18342
|
+
noteUnsupported(path);
|
|
18343
|
+
collected.push(...extractFileSymbols(path, "", signals));
|
|
18344
|
+
}
|
|
18345
|
+
}
|
|
18346
|
+
const unsupportedExts = [...unsupported].sort().slice(0, 8);
|
|
18347
|
+
const audit = unsupportedExts.length > 0 ? { unsupported_exts: unsupportedExts } : {};
|
|
18348
|
+
const symbols = rankSymbols([...new Set(collected)]);
|
|
18349
|
+
if (symbols.length === 0) {
|
|
18350
|
+
const everySupportedFileFoundNothing = unsupportedExts.length > 0;
|
|
18351
|
+
return {
|
|
18352
|
+
state: "absent",
|
|
18353
|
+
reason: everySupportedFileFoundNothing ? "unsupported-language" : "no-symbols",
|
|
18354
|
+
...audit
|
|
18355
|
+
};
|
|
18356
|
+
}
|
|
18357
|
+
const args = [
|
|
18358
|
+
"-n",
|
|
18359
|
+
"-w",
|
|
18360
|
+
"-F",
|
|
18361
|
+
"--no-heading",
|
|
18362
|
+
"--color",
|
|
18363
|
+
"never",
|
|
18364
|
+
// ⚠ NO `--sort path` — it single-threads rg, and on a large worktree that
|
|
18365
|
+
// is the difference between 17ms and a timeout. Determinism is restored by
|
|
18366
|
+
// sorting the hits in partitionSites instead.
|
|
18367
|
+
//
|
|
18368
|
+
// `-m 8` bounds output PER FILE (shared across all patterns), so a noisy
|
|
18369
|
+
// repo cannot blow the 4MB read buffer and turn the whole feature into
|
|
18370
|
+
// `absent/error`. Cost, accepted: the frequency gate sees per-file-capped
|
|
18371
|
+
// counts, so a symbol concentrated in a handful of files can slip a gate
|
|
18372
|
+
// a full count would have tripped — but the ≤3-sites-per-file cap already
|
|
18373
|
+
// bounds exactly that shape's damage; the gate exists for the many-file
|
|
18374
|
+
// 'init' shape, which 8-per-file still trips (>6 files ⇒ >50).
|
|
18375
|
+
"-m",
|
|
18376
|
+
"8",
|
|
18377
|
+
"--max-columns",
|
|
18378
|
+
"300",
|
|
18379
|
+
"--max-columns-preview",
|
|
18380
|
+
...symbols.flatMap((s) => ["-e", s]),
|
|
18381
|
+
"-g",
|
|
18382
|
+
"!**/{dist,build,out,vendor,node_modules,.git,coverage,target,__pycache__}/**",
|
|
18383
|
+
"./"
|
|
18384
|
+
];
|
|
18385
|
+
let res = null;
|
|
18386
|
+
for (const inv of rgInvocations()) {
|
|
18387
|
+
res = (0, import_node_child_process7.spawnSync)(inv.cmd, args, {
|
|
18388
|
+
...inv.argv0 ? { argv0: inv.argv0 } : {},
|
|
18389
|
+
cwd: input.cwd ?? process.cwd(),
|
|
18390
|
+
timeout: input.timeoutMs ?? RG_TIMEOUT_MS,
|
|
18391
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
18392
|
+
encoding: "utf8"
|
|
18393
|
+
});
|
|
18394
|
+
if (res.error?.code !== "ENOENT") break;
|
|
18395
|
+
}
|
|
18396
|
+
if (!res || res.error?.code === "ENOENT") {
|
|
18397
|
+
return { state: "absent", reason: "no-tool", symbols, ...audit };
|
|
18398
|
+
}
|
|
18399
|
+
if (res.error) {
|
|
18400
|
+
const code = res.error.code;
|
|
18401
|
+
if (code === "ETIMEDOUT") return { state: "absent", reason: "timeout", symbols, ...audit };
|
|
18402
|
+
return { state: "absent", reason: "error", symbols, ...audit };
|
|
18403
|
+
}
|
|
18404
|
+
if (res.signal) return { state: "absent", reason: "timeout", symbols, ...audit };
|
|
18405
|
+
if (res.status !== 0 && res.status !== 1) return { state: "absent", reason: "error", symbols, ...audit };
|
|
18406
|
+
const lines = (res.stdout ?? "").split("\n").map((l) => l.replace(/^\.\//, "")).filter(Boolean);
|
|
18407
|
+
const { callers, tests, dropped } = partitionSites(lines, symbols, {
|
|
18408
|
+
sentPaths: input.sentPaths,
|
|
18409
|
+
isExcluded: input.isExcluded
|
|
18410
|
+
});
|
|
18411
|
+
if (callers.length === 0 && tests.length === 0) {
|
|
18412
|
+
return {
|
|
18413
|
+
state: "absent",
|
|
18414
|
+
reason: "no-sites",
|
|
18415
|
+
symbols,
|
|
18416
|
+
...dropped.length > 0 ? { dropped_symbols: dropped } : {},
|
|
18417
|
+
...audit,
|
|
18418
|
+
elapsed_ms: Date.now() - started
|
|
18419
|
+
};
|
|
18420
|
+
}
|
|
18421
|
+
return {
|
|
18422
|
+
state: "ok",
|
|
18423
|
+
symbols,
|
|
18424
|
+
...dropped.length > 0 ? { dropped_symbols: dropped } : {},
|
|
18425
|
+
...audit,
|
|
18426
|
+
callers,
|
|
18427
|
+
tests,
|
|
18428
|
+
elapsed_ms: Date.now() - started
|
|
18429
|
+
};
|
|
18430
|
+
}
|
|
18431
|
+
var MAX_EXCERPTS = 12;
|
|
18432
|
+
var MAX_EXCERPTS_PER_FILE = 2;
|
|
18433
|
+
var EXCERPT_MAX_LINES = 30;
|
|
18434
|
+
var EXCERPT_MAX_CHARS = 2400;
|
|
18435
|
+
var EXCERPT_TOTAL_BYTES = 24576;
|
|
18436
|
+
var EXCERPT_DECL_SCAN = 40;
|
|
18437
|
+
function extractEnclosingExcerpt(content, siteLine, path) {
|
|
18438
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
18439
|
+
const rules = RULES_BY_EXT[ext] ?? [];
|
|
18440
|
+
const lines = content.split("\n");
|
|
18441
|
+
if (siteLine < 1 || siteLine > lines.length) return null;
|
|
18442
|
+
let declStart = null;
|
|
18443
|
+
const floor = Math.max(1, siteLine - EXCERPT_DECL_SCAN);
|
|
18444
|
+
for (let n = siteLine; n >= floor; n--) {
|
|
18445
|
+
if (declNameOn(lines[n - 1] ?? "", rules) !== null) {
|
|
18446
|
+
declStart = n;
|
|
18447
|
+
break;
|
|
18448
|
+
}
|
|
18449
|
+
}
|
|
18450
|
+
let start;
|
|
18451
|
+
if (declStart !== null && siteLine - declStart < EXCERPT_MAX_LINES) {
|
|
18452
|
+
start = declStart;
|
|
18453
|
+
} else {
|
|
18454
|
+
start = Math.max(1, siteLine - (EXCERPT_MAX_LINES - 6));
|
|
18455
|
+
}
|
|
18456
|
+
const end = Math.min(lines.length, start + EXCERPT_MAX_LINES - 1);
|
|
18457
|
+
const text = lines.slice(start - 1, end).join("\n").slice(0, EXCERPT_MAX_CHARS);
|
|
18458
|
+
return { start_line: start, text };
|
|
18459
|
+
}
|
|
18460
|
+
function upgradeToExcerpts(rc, opts) {
|
|
18461
|
+
if (rc.state !== "ok") return;
|
|
18462
|
+
const ranked = [
|
|
18463
|
+
...(rc.callers ?? []).filter((s) => s.kind === "contract"),
|
|
18464
|
+
...rc.tests ?? [],
|
|
18465
|
+
...(rc.callers ?? []).filter((s) => s.kind !== "contract")
|
|
18466
|
+
];
|
|
18467
|
+
const perFile = /* @__PURE__ */ new Map();
|
|
18468
|
+
const contentCache = /* @__PURE__ */ new Map();
|
|
18469
|
+
const excerpts = [];
|
|
18470
|
+
let totalBytes = 0;
|
|
18471
|
+
for (const site of ranked) {
|
|
18472
|
+
if (excerpts.length >= MAX_EXCERPTS) break;
|
|
18473
|
+
const used = perFile.get(site.file) ?? 0;
|
|
18474
|
+
if (used >= MAX_EXCERPTS_PER_FILE) continue;
|
|
18475
|
+
if (!contentCache.has(site.file)) contentCache.set(site.file, opts.readFile(site.file));
|
|
18476
|
+
const content = contentCache.get(site.file);
|
|
18477
|
+
if (content === null || content === void 0) continue;
|
|
18478
|
+
const ex = extractEnclosingExcerpt(content, site.line, site.file);
|
|
18479
|
+
if (!ex) continue;
|
|
18480
|
+
if (totalBytes + ex.text.length > EXCERPT_TOTAL_BYTES) break;
|
|
18481
|
+
excerpts.push({
|
|
18482
|
+
file: site.file,
|
|
18483
|
+
start_line: ex.start_line,
|
|
18484
|
+
symbol: site.symbol,
|
|
18485
|
+
kind: site.kind === "contract" ? "contract" : isTestPath(site.file) ? "test" : "caller",
|
|
18486
|
+
text: ex.text
|
|
18487
|
+
});
|
|
18488
|
+
totalBytes += ex.text.length;
|
|
18489
|
+
perFile.set(site.file, used + 1);
|
|
18490
|
+
}
|
|
18491
|
+
if (excerpts.length > 0) rc.excerpts = excerpts;
|
|
18492
|
+
}
|
|
18493
|
+
function describeRepoContext(rc) {
|
|
18494
|
+
if (rc.state !== "ok") {
|
|
18495
|
+
const exts = rc.unsupported_exts?.length ? ` \xB7 no rules for: ${rc.unsupported_exts.join(", ")}` : "";
|
|
18496
|
+
return `absent (${rc.reason ?? "unknown"})${exts}`;
|
|
18497
|
+
}
|
|
18498
|
+
const parts = [
|
|
18499
|
+
`${rc.symbols?.length ?? 0} symbol(s) \u2192 ${rc.callers?.length ?? 0} caller(s) \xB7 ${rc.tests?.length ?? 0} test(s)`
|
|
18500
|
+
];
|
|
18501
|
+
if (rc.excerpts?.length) parts.push(`${rc.excerpts.length} excerpt(s)`);
|
|
18502
|
+
if (rc.dropped_symbols?.length) parts.push(`dropped too-common: ${rc.dropped_symbols.join(", ")}`);
|
|
18503
|
+
if (rc.unsupported_exts?.length) parts.push(`no rules for: ${rc.unsupported_exts.join(", ")}`);
|
|
18504
|
+
if (typeof rc.elapsed_ms === "number") parts.push(`${rc.elapsed_ms}ms`);
|
|
18505
|
+
return parts.join(" \xB7 ");
|
|
17659
18506
|
}
|
|
17660
18507
|
|
|
17661
18508
|
// src/commands/analyze/evidence-log.ts
|
|
@@ -17696,6 +18543,7 @@ function formatRunEvidence(run2, startedAt) {
|
|
|
17696
18543
|
}
|
|
17697
18544
|
out += row("sent", `${sent.length} \xB7 ${list(sent)}`);
|
|
17698
18545
|
if (context.length > 0) out += row("context", `${context.length} \xB7 ${list(context)}`);
|
|
18546
|
+
if (run2.repoContext) out += row("repo", describeRepoContext(run2.repoContext));
|
|
17699
18547
|
const withheld = run2.reviewCoverage.notReviewed;
|
|
17700
18548
|
if (withheld.length > 0) {
|
|
17701
18549
|
const byReason = /* @__PURE__ */ new Map();
|
|
@@ -17777,9 +18625,9 @@ function installRunEvidence(run2) {
|
|
|
17777
18625
|
}
|
|
17778
18626
|
|
|
17779
18627
|
// src/lib/git-frame.ts
|
|
17780
|
-
var
|
|
17781
|
-
var
|
|
17782
|
-
var
|
|
18628
|
+
var import_node_child_process8 = require("node:child_process");
|
|
18629
|
+
var import_node_fs26 = require("node:fs");
|
|
18630
|
+
var import_node_os4 = require("node:os");
|
|
17783
18631
|
var import_node_path18 = require("node:path");
|
|
17784
18632
|
var import_node_path19 = require("node:path");
|
|
17785
18633
|
var VALUE_TOKEN = `(?:'[^']*'|"[^"]*"|\\S+)`;
|
|
@@ -17827,14 +18675,14 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
17827
18675
|
if (!m) continue;
|
|
17828
18676
|
named = true;
|
|
17829
18677
|
if (m[1] === void 0) {
|
|
17830
|
-
dir = (0,
|
|
18678
|
+
dir = (0, import_node_os4.homedir)();
|
|
17831
18679
|
continue;
|
|
17832
18680
|
}
|
|
17833
18681
|
const raw = unquote(m[1]);
|
|
17834
18682
|
if (SHELL_DYNAMIC.test(raw) || raw === "-") {
|
|
17835
18683
|
return { dir: null, named: true, unresolvable: `cd target not statically resolvable: ${raw}` };
|
|
17836
18684
|
}
|
|
17837
|
-
const expanded = raw === "~" ? (0,
|
|
18685
|
+
const expanded = raw === "~" ? (0, import_node_os4.homedir)() : raw.startsWith("~/") ? (0, import_node_path19.join)((0, import_node_os4.homedir)(), raw.slice(2)) : raw;
|
|
17838
18686
|
dir = (0, import_node_path18.isAbsolute)(expanded) ? expanded : (0, import_node_path18.resolve)(dir, expanded);
|
|
17839
18687
|
}
|
|
17840
18688
|
const seg = segments[segmentIndex];
|
|
@@ -17853,7 +18701,7 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
17853
18701
|
if (SHELL_DYNAMIC.test(raw)) {
|
|
17854
18702
|
return { dir: null, named: true, unresolvable: `-C target not statically resolvable: ${raw}` };
|
|
17855
18703
|
}
|
|
17856
|
-
const expanded = raw === "~" ? (0,
|
|
18704
|
+
const expanded = raw === "~" ? (0, import_node_os4.homedir)() : raw.startsWith("~/") ? (0, import_node_path19.join)((0, import_node_os4.homedir)(), raw.slice(2)) : raw;
|
|
17857
18705
|
dir = (0, import_node_path18.isAbsolute)(expanded) ? expanded : (0, import_node_path18.resolve)(dir, expanded);
|
|
17858
18706
|
}
|
|
17859
18707
|
}
|
|
@@ -17910,21 +18758,21 @@ function parsePushTarget(segment) {
|
|
|
17910
18758
|
}
|
|
17911
18759
|
function gitAt(dir, args) {
|
|
17912
18760
|
try {
|
|
17913
|
-
return (0,
|
|
18761
|
+
return (0, import_node_child_process8.execFileSync)("git", args, { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
17914
18762
|
} catch {
|
|
17915
18763
|
return "";
|
|
17916
18764
|
}
|
|
17917
18765
|
}
|
|
17918
18766
|
function realpathOr(p) {
|
|
17919
18767
|
try {
|
|
17920
|
-
return
|
|
18768
|
+
return import_node_fs26.realpathSync.native(p);
|
|
17921
18769
|
} catch {
|
|
17922
18770
|
return (0, import_node_path18.resolve)(p);
|
|
17923
18771
|
}
|
|
17924
18772
|
}
|
|
17925
18773
|
function resolveFrame(input) {
|
|
17926
18774
|
const found = findMomentSegment(input.command, input.on);
|
|
17927
|
-
const hookDirUsable = !!input.hookCwd && (0,
|
|
18775
|
+
const hookDirUsable = !!input.hookCwd && (0, import_node_fs26.existsSync)(input.hookCwd);
|
|
17928
18776
|
const baseDir = hookDirUsable ? input.hookCwd : process.cwd();
|
|
17929
18777
|
let anchor = hookDirUsable ? "hook-cwd" : "process-cwd";
|
|
17930
18778
|
const refuse = (refusal) => ({
|
|
@@ -17947,7 +18795,7 @@ function resolveFrame(input) {
|
|
|
17947
18795
|
if (dirs.size > 1) return refuse(`target:multiple ${found.moment} targets in one command`);
|
|
17948
18796
|
const targetDir = dirs.size === 1 ? [...dirs][0] : baseDir;
|
|
17949
18797
|
if (targetDir !== baseDir) {
|
|
17950
|
-
if (!(0,
|
|
18798
|
+
if (!(0, import_node_fs26.existsSync)(targetDir)) return refuse(`target:directory does not exist: ${targetDir}`);
|
|
17951
18799
|
dir = targetDir;
|
|
17952
18800
|
}
|
|
17953
18801
|
}
|
|
@@ -17986,7 +18834,7 @@ var SHA_RE2 = /^[0-9a-f]{40}$/;
|
|
|
17986
18834
|
function baselineShaAt(frame) {
|
|
17987
18835
|
if (!frame.worktreeRoot) return null;
|
|
17988
18836
|
try {
|
|
17989
|
-
const sha = (0,
|
|
18837
|
+
const sha = (0, import_node_fs26.readFileSync)((0, import_node_path19.join)(frame.worktreeRoot, BASELINE_SHA_FILE), "utf-8").trim();
|
|
17990
18838
|
if (!SHA_RE2.test(sha)) return null;
|
|
17991
18839
|
return refResolves(frame, sha) ? sha : null;
|
|
17992
18840
|
} catch {
|
|
@@ -18049,6 +18897,40 @@ function rangeFiles(frame, range) {
|
|
|
18049
18897
|
}
|
|
18050
18898
|
return out.split("\n").filter((l) => l.length > 0).filter((f) => !isVerityOwnedPath(f));
|
|
18051
18899
|
}
|
|
18900
|
+
function rangeChangeSignals(frame, range, paths) {
|
|
18901
|
+
const out = /* @__PURE__ */ new Map();
|
|
18902
|
+
if (range.kind === "nothing" || paths.length === 0) return out;
|
|
18903
|
+
const args = range.kind === "staged" ? ["diff", "--cached", "--unified=0"] : ["diff", "--unified=0", range.base, range.head === "INDEX" ? "HEAD" : range.head];
|
|
18904
|
+
const diff = frameGit(frame, [...args, "--", ...paths]);
|
|
18905
|
+
let current = null;
|
|
18906
|
+
let oldSide = null;
|
|
18907
|
+
let buf = [];
|
|
18908
|
+
const flush = () => {
|
|
18909
|
+
if (current !== null && buf.length > 0) out.set(current, parseDiffSignals(buf.join("\n")));
|
|
18910
|
+
buf = [];
|
|
18911
|
+
};
|
|
18912
|
+
for (const line of diff.split("\n")) {
|
|
18913
|
+
if (line.startsWith("diff --git ")) {
|
|
18914
|
+
flush();
|
|
18915
|
+
current = null;
|
|
18916
|
+
oldSide = null;
|
|
18917
|
+
continue;
|
|
18918
|
+
}
|
|
18919
|
+
const minusM = /^--- (?:a\/)?(.+)$/.exec(line);
|
|
18920
|
+
if (minusM) {
|
|
18921
|
+
oldSide = minusM[1] === "/dev/null" ? null : minusM[1];
|
|
18922
|
+
continue;
|
|
18923
|
+
}
|
|
18924
|
+
const plusM = /^\+\+\+ (?:b\/)?(.+)$/.exec(line);
|
|
18925
|
+
if (plusM) {
|
|
18926
|
+
current = plusM[1] === "/dev/null" ? oldSide : plusM[1];
|
|
18927
|
+
continue;
|
|
18928
|
+
}
|
|
18929
|
+
if (current !== null) buf.push(line);
|
|
18930
|
+
}
|
|
18931
|
+
flush();
|
|
18932
|
+
return out;
|
|
18933
|
+
}
|
|
18052
18934
|
function rangeMessages(frame, range) {
|
|
18053
18935
|
if (range.kind === "staged" || range.kind === "nothing" || !range.base) return "";
|
|
18054
18936
|
return frameGit(frame, ["log", `${range.base}..${range.head === "INDEX" ? "HEAD" : range.head}`, "--format=%B%x00"]).split("\0").map((s) => s.trim()).filter(Boolean).join("\n\n");
|
|
@@ -18099,7 +18981,7 @@ function truthy(v) {
|
|
|
18099
18981
|
}
|
|
18100
18982
|
|
|
18101
18983
|
// src/lib/transcript.ts
|
|
18102
|
-
var
|
|
18984
|
+
var import_node_fs27 = require("node:fs");
|
|
18103
18985
|
var MAX_READ_BYTES = 256 * 1024;
|
|
18104
18986
|
var SMALL_FILE_BYTES = 64 * 1024;
|
|
18105
18987
|
var MAX_FILES_LIST = 20;
|
|
@@ -18108,6 +18990,7 @@ var MAX_COMMANDS = 10;
|
|
|
18108
18990
|
var MAX_COMMAND_CHARS = 80;
|
|
18109
18991
|
var MAX_TOOL_BLOCKS = 200;
|
|
18110
18992
|
var MAX_SUMMARY_BYTES = 4096;
|
|
18993
|
+
var MAX_SEARCHES_DETAIL = 10;
|
|
18111
18994
|
var HOME = process.env.HOME ?? "";
|
|
18112
18995
|
var BASH_INPUT_RE = /^\s*<bash-input>([\s\S]*?)<\/bash-input>/;
|
|
18113
18996
|
var BASH_ECHO_RE = /^\s*<bash-(?:stdout|stderr)>/;
|
|
@@ -18125,7 +19008,7 @@ async function extractActionSummary(transcriptPath) {
|
|
|
18125
19008
|
function readTurnLines(transcriptPath) {
|
|
18126
19009
|
let size;
|
|
18127
19010
|
try {
|
|
18128
|
-
size = (0,
|
|
19011
|
+
size = (0, import_node_fs27.statSync)(transcriptPath).size;
|
|
18129
19012
|
} catch {
|
|
18130
19013
|
return null;
|
|
18131
19014
|
}
|
|
@@ -18133,7 +19016,7 @@ function readTurnLines(transcriptPath) {
|
|
|
18133
19016
|
let raw;
|
|
18134
19017
|
let windowed = false;
|
|
18135
19018
|
if (size <= SMALL_FILE_BYTES) {
|
|
18136
|
-
raw = (0,
|
|
19019
|
+
raw = (0, import_node_fs27.readFileSync)(transcriptPath, "utf-8");
|
|
18137
19020
|
} else {
|
|
18138
19021
|
windowed = true;
|
|
18139
19022
|
const buf = Buffer.alloc(Math.min(MAX_READ_BYTES, size));
|
|
@@ -18193,6 +19076,7 @@ function buildSummary(lines) {
|
|
|
18193
19076
|
let userCommandsTruncated = false;
|
|
18194
19077
|
let commandsTruncated = false;
|
|
18195
19078
|
let searches = 0;
|
|
19079
|
+
const searchesDetail = [];
|
|
18196
19080
|
let subagents = 0;
|
|
18197
19081
|
let webFetches = 0;
|
|
18198
19082
|
let totalToolCalls = 0;
|
|
@@ -18264,9 +19148,19 @@ function buildSummary(lines) {
|
|
|
18264
19148
|
break;
|
|
18265
19149
|
}
|
|
18266
19150
|
case "Grep":
|
|
18267
|
-
case "Glob":
|
|
19151
|
+
case "Glob": {
|
|
18268
19152
|
searches++;
|
|
19153
|
+
const pattern = typeof input.pattern === "string" ? input.pattern.slice(0, 120) : "";
|
|
19154
|
+
if (pattern && searchesDetail.length < MAX_SEARCHES_DETAIL) {
|
|
19155
|
+
const scopePath = typeof input.path === "string" ? input.path.slice(0, 200) : void 0;
|
|
19156
|
+
searchesDetail.push({
|
|
19157
|
+
tool: toolName,
|
|
19158
|
+
pattern,
|
|
19159
|
+
...scopePath ? { path: scopePath } : {}
|
|
19160
|
+
});
|
|
19161
|
+
}
|
|
18269
19162
|
break;
|
|
19163
|
+
}
|
|
18270
19164
|
case "Agent":
|
|
18271
19165
|
case "Task":
|
|
18272
19166
|
case "Workflow":
|
|
@@ -18301,6 +19195,7 @@ function buildSummary(lines) {
|
|
|
18301
19195
|
...cappedOut(filesCreated, MAX_CREATED_LIST)
|
|
18302
19196
|
],
|
|
18303
19197
|
searches,
|
|
19198
|
+
...searchesDetail.length > 0 ? { searches_detail: searchesDetail } : {},
|
|
18304
19199
|
commands,
|
|
18305
19200
|
...commandsTruncated ? { commands_truncated: true } : {},
|
|
18306
19201
|
user_commands: userCommands,
|
|
@@ -18311,6 +19206,9 @@ function buildSummary(lines) {
|
|
|
18311
19206
|
turn_messages: turnMessages,
|
|
18312
19207
|
turn_duration_ms: turnDurationMs
|
|
18313
19208
|
};
|
|
19209
|
+
if (JSON.stringify(summary).length > MAX_SUMMARY_BYTES) {
|
|
19210
|
+
delete summary.searches_detail;
|
|
19211
|
+
}
|
|
18314
19212
|
if (JSON.stringify(summary).length > MAX_SUMMARY_BYTES) {
|
|
18315
19213
|
summary.commands = [];
|
|
18316
19214
|
summary.commands_truncated = true;
|
|
@@ -18435,6 +19333,9 @@ async function bootstrap(run2) {
|
|
|
18435
19333
|
isTTY: process.stdout.isTTY === true
|
|
18436
19334
|
});
|
|
18437
19335
|
const { assistantMessage: assistantResponse, stopReason, transcriptPath, sessionId } = await readStopHookStdin();
|
|
19336
|
+
if (deferredToPlugin("analyze", sessionId ?? process.env.CLAUDE_SESSION_ID ?? null)) {
|
|
19337
|
+
process.exit(0);
|
|
19338
|
+
}
|
|
18438
19339
|
const actionSummary = transcriptPath ? await extractActionSummary(transcriptPath) : null;
|
|
18439
19340
|
const tokenResult = await resolveToken(globals.token);
|
|
18440
19341
|
const scopeToken = tokenResult.ok ? tokenResult.data.token : void 0;
|
|
@@ -18614,7 +19515,7 @@ function channelSilence(input) {
|
|
|
18614
19515
|
// src/lib/cli-version.ts
|
|
18615
19516
|
function cliVersion() {
|
|
18616
19517
|
try {
|
|
18617
|
-
return true ? "0.31.
|
|
19518
|
+
return true ? "0.31.2" : "dev";
|
|
18618
19519
|
} catch {
|
|
18619
19520
|
return "dev";
|
|
18620
19521
|
}
|
|
@@ -18654,8 +19555,8 @@ async function sendSkipBeacon(ctx, reason) {
|
|
|
18654
19555
|
}
|
|
18655
19556
|
|
|
18656
19557
|
// src/lib/static-analysis.ts
|
|
18657
|
-
var
|
|
18658
|
-
var
|
|
19558
|
+
var import_node_child_process9 = require("node:child_process");
|
|
19559
|
+
var import_node_fs28 = require("node:fs");
|
|
18659
19560
|
var SEVERITY_ORDER = {
|
|
18660
19561
|
Error: 0,
|
|
18661
19562
|
Critical: 0,
|
|
@@ -18667,7 +19568,7 @@ var SEVERITY_ORDER = {
|
|
|
18667
19568
|
};
|
|
18668
19569
|
function isCodacyAvailable() {
|
|
18669
19570
|
try {
|
|
18670
|
-
(0,
|
|
19571
|
+
(0, import_node_child_process9.execSync)("which codacy-analysis", { stdio: "pipe" });
|
|
18671
19572
|
return true;
|
|
18672
19573
|
} catch {
|
|
18673
19574
|
return false;
|
|
@@ -18703,13 +19604,13 @@ function runCodacyAnalysis(files) {
|
|
|
18703
19604
|
if (files.length === 0) return empty;
|
|
18704
19605
|
const existingFiles = files.filter((f) => {
|
|
18705
19606
|
try {
|
|
18706
|
-
return (0,
|
|
19607
|
+
return (0, import_node_fs28.existsSync)(f);
|
|
18707
19608
|
} catch {
|
|
18708
19609
|
return false;
|
|
18709
19610
|
}
|
|
18710
19611
|
});
|
|
18711
19612
|
if (existingFiles.length === 0) return empty;
|
|
18712
|
-
const proc = (0,
|
|
19613
|
+
const proc = (0, import_node_child_process9.spawnSync)("codacy-analysis", buildAnalyzerArgv(existingFiles), {
|
|
18713
19614
|
encoding: "utf-8",
|
|
18714
19615
|
maxBuffer: 10 * 1024 * 1024
|
|
18715
19616
|
});
|
|
@@ -18972,7 +19873,7 @@ async function scope(run2) {
|
|
|
18972
19873
|
}
|
|
18973
19874
|
|
|
18974
19875
|
// src/lib/specs.ts
|
|
18975
|
-
var
|
|
19876
|
+
var import_node_fs29 = require("node:fs");
|
|
18976
19877
|
var import_node_path20 = require("node:path");
|
|
18977
19878
|
var SPEC_CANDIDATES = [
|
|
18978
19879
|
"CLAUDE.md",
|
|
@@ -19004,16 +19905,16 @@ function discoverSpecs(consulted = []) {
|
|
|
19004
19905
|
const totalCap = relevant ? MAX_TOTAL_SPEC_BYTES : UNCONSULTED_TOTAL_BYTES;
|
|
19005
19906
|
if (totalBytes >= totalCap) return false;
|
|
19006
19907
|
if (seen.has(specPath)) return true;
|
|
19007
|
-
if (!(0,
|
|
19908
|
+
if (!(0, import_node_fs29.existsSync)(specPath)) return true;
|
|
19008
19909
|
seen.add(specPath);
|
|
19009
19910
|
const remaining = totalCap - totalBytes;
|
|
19010
19911
|
const fileCap = relevant ? MAX_SPEC_FILE_BYTES : UNCONSULTED_FILE_BYTES;
|
|
19011
19912
|
const readBytes = Math.min(fileCap, remaining);
|
|
19012
19913
|
try {
|
|
19013
19914
|
const buf = Buffer.alloc(readBytes);
|
|
19014
|
-
const fd = (0,
|
|
19015
|
-
const bytesRead = (0,
|
|
19016
|
-
(0,
|
|
19915
|
+
const fd = (0, import_node_fs29.openSync)(specPath, "r");
|
|
19916
|
+
const bytesRead = (0, import_node_fs29.readSync)(fd, buf, 0, readBytes, 0);
|
|
19917
|
+
(0, import_node_fs29.closeSync)(fd);
|
|
19017
19918
|
const content = buf.slice(0, bytesRead).toString("utf-8");
|
|
19018
19919
|
if (!content) return true;
|
|
19019
19920
|
result.push({ path: specPath, content });
|
|
@@ -19029,7 +19930,7 @@ function discoverSpecs(consulted = []) {
|
|
|
19029
19930
|
if (!addSpec(candidate)) break;
|
|
19030
19931
|
}
|
|
19031
19932
|
for (const dir of ["spec", "docs"]) {
|
|
19032
|
-
if (!(0,
|
|
19933
|
+
if (!(0, import_node_fs29.existsSync)(dir)) continue;
|
|
19033
19934
|
try {
|
|
19034
19935
|
const mdFiles = findMdFiles(dir, 2).sort();
|
|
19035
19936
|
for (const mdFile of mdFiles) {
|
|
@@ -19044,7 +19945,7 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
19044
19945
|
if (depth >= maxDepth) return [];
|
|
19045
19946
|
const result = [];
|
|
19046
19947
|
try {
|
|
19047
|
-
const entries = (0,
|
|
19948
|
+
const entries = (0, import_node_fs29.readdirSync)(dir, { withFileTypes: true });
|
|
19048
19949
|
for (const entry of entries) {
|
|
19049
19950
|
const fullPath = (0, import_node_path20.join)(dir, entry.name);
|
|
19050
19951
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -19063,14 +19964,14 @@ function discoverPlans() {
|
|
|
19063
19964
|
const candidates = [];
|
|
19064
19965
|
const seen = /* @__PURE__ */ new Set();
|
|
19065
19966
|
for (const plansDir of [localPlansDir, homePlansDir]) {
|
|
19066
|
-
if (!(0,
|
|
19967
|
+
if (!(0, import_node_fs29.existsSync)(plansDir)) continue;
|
|
19067
19968
|
try {
|
|
19068
|
-
for (const f of (0,
|
|
19969
|
+
for (const f of (0, import_node_fs29.readdirSync)(plansDir)) {
|
|
19069
19970
|
if (!f.endsWith(".md") || seen.has(f)) continue;
|
|
19070
19971
|
seen.add(f);
|
|
19071
19972
|
const fullPath = (0, import_node_path20.join)(plansDir, f);
|
|
19072
19973
|
try {
|
|
19073
|
-
const stat3 = (0,
|
|
19974
|
+
const stat3 = (0, import_node_fs29.statSync)(fullPath);
|
|
19074
19975
|
candidates.push({ name: f, path: fullPath, mtime: stat3.mtimeMs, size: stat3.size });
|
|
19075
19976
|
} catch {
|
|
19076
19977
|
}
|
|
@@ -19083,7 +19984,7 @@ function discoverPlans() {
|
|
|
19083
19984
|
for (const entry of candidates.slice(0, MAX_PLAN_FILES)) {
|
|
19084
19985
|
if (entry.size > MAX_PLAN_FILE_BYTES) continue;
|
|
19085
19986
|
try {
|
|
19086
|
-
const content = (0,
|
|
19987
|
+
const content = (0, import_node_fs29.readFileSync)(entry.path, "utf-8");
|
|
19087
19988
|
result.push({ name: entry.name, content });
|
|
19088
19989
|
} catch {
|
|
19089
19990
|
}
|
|
@@ -19098,12 +19999,12 @@ function discoverGuardDocs(rangeFiles2) {
|
|
|
19098
19999
|
if (result.length >= MAX_SPEC_FILES) break;
|
|
19099
20000
|
if (!GUARD_DOC_EXT.test(path)) continue;
|
|
19100
20001
|
if (path.startsWith("/") || path.includes("..")) continue;
|
|
19101
|
-
if (!(0,
|
|
20002
|
+
if (!(0, import_node_fs29.existsSync)(path)) continue;
|
|
19102
20003
|
try {
|
|
19103
|
-
const stat3 = (0,
|
|
20004
|
+
const stat3 = (0, import_node_fs29.statSync)(path);
|
|
19104
20005
|
if (stat3.size > MAX_PLAN_FILE_BYTES) continue;
|
|
19105
20006
|
if (totalBytes + stat3.size > MAX_TOTAL_SPEC_BYTES) continue;
|
|
19106
|
-
const content = (0,
|
|
20007
|
+
const content = (0, import_node_fs29.readFileSync)(path, "utf-8");
|
|
19107
20008
|
if (!content) continue;
|
|
19108
20009
|
result.push({ name: path, content });
|
|
19109
20010
|
totalBytes += content.length;
|
|
@@ -19214,7 +20115,6 @@ async function mode(run2) {
|
|
|
19214
20115
|
const { opts, globals } = run2;
|
|
19215
20116
|
const { actionSummary, allForReview, assistantResponse, baseline, conversation, memory, noFilesChanged, serviceUrl, sessionId, token, turnAuthoredCode } = run2;
|
|
19216
20117
|
const sessionIdForMemory = sessionId || process.env.CLAUDE_SESSION_ID || "";
|
|
19217
|
-
let contextFilePaths = [];
|
|
19218
20118
|
let predictedMode;
|
|
19219
20119
|
try {
|
|
19220
20120
|
const memoryPath2 = sessionIdForMemory ? `/memory?session_id=${encodeURIComponent(sessionIdForMemory)}` : "/memory";
|
|
@@ -19228,9 +20128,6 @@ async function mode(run2) {
|
|
|
19228
20128
|
cmd: "analyze_context"
|
|
19229
20129
|
});
|
|
19230
20130
|
if (memoryResult.ok) {
|
|
19231
|
-
if (Array.isArray(memoryResult.data.context_files)) {
|
|
19232
|
-
contextFilePaths = memoryResult.data.context_files;
|
|
19233
|
-
}
|
|
19234
20131
|
const rawMode = memoryResult.data.predicted_mode;
|
|
19235
20132
|
if (rawMode && ["standard", "plan", "debug", "skip"].includes(rawMode)) {
|
|
19236
20133
|
predictedMode = rawMode;
|
|
@@ -19279,11 +20176,11 @@ async function mode(run2) {
|
|
|
19279
20176
|
turnAuthoredCode ? "capacity" : void 0
|
|
19280
20177
|
);
|
|
19281
20178
|
}
|
|
19282
|
-
Object.assign(run2, { analysisMode,
|
|
20179
|
+
Object.assign(run2, { analysisMode, sessionAuthoredCode, sessionIdForMemory });
|
|
19283
20180
|
}
|
|
19284
20181
|
|
|
19285
20182
|
// src/lib/fold.ts
|
|
19286
|
-
var
|
|
20183
|
+
var import_node_fs30 = require("node:fs");
|
|
19287
20184
|
var import_node_path21 = require("node:path");
|
|
19288
20185
|
var KNOWN_RECORD_TYPES = /* @__PURE__ */ new Set([
|
|
19289
20186
|
"user",
|
|
@@ -19421,7 +20318,7 @@ function candidateRoots(repoRoot2) {
|
|
|
19421
20318
|
const norm = repoRoot2.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
19422
20319
|
const out = [norm];
|
|
19423
20320
|
try {
|
|
19424
|
-
const real =
|
|
20321
|
+
const real = import_node_fs30.realpathSync.native(norm).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
19425
20322
|
if (real !== norm) out.push(real);
|
|
19426
20323
|
} catch {
|
|
19427
20324
|
}
|
|
@@ -19509,8 +20406,8 @@ function fold(transcriptPath, opts = {}) {
|
|
|
19509
20406
|
}
|
|
19510
20407
|
};
|
|
19511
20408
|
try {
|
|
19512
|
-
if (!(0,
|
|
19513
|
-
ingest((0,
|
|
20409
|
+
if (!(0, import_node_fs30.existsSync)(transcriptPath)) return result;
|
|
20410
|
+
ingest((0, import_node_fs30.readFileSync)(transcriptPath, "utf8"), "agent");
|
|
19514
20411
|
result.coverage.complete = true;
|
|
19515
20412
|
} catch {
|
|
19516
20413
|
return result;
|
|
@@ -19521,19 +20418,19 @@ function fold(transcriptPath, opts = {}) {
|
|
|
19521
20418
|
(0, import_node_path21.basename)(transcriptPath).replace(/\.jsonl$/, ""),
|
|
19522
20419
|
"subagents"
|
|
19523
20420
|
);
|
|
19524
|
-
if ((0,
|
|
20421
|
+
if ((0, import_node_fs30.existsSync)(sidecarDir)) {
|
|
19525
20422
|
const maxFiles = opts.maxSidecars ?? 200;
|
|
19526
20423
|
const maxBytes = opts.maxSidecarBytes ?? 16 * 1024 * 1024;
|
|
19527
20424
|
const found = [];
|
|
19528
20425
|
const walk = (d, depth) => {
|
|
19529
20426
|
if (depth > 4) return;
|
|
19530
|
-
for (const e of (0,
|
|
20427
|
+
for (const e of (0, import_node_fs30.readdirSync)(d, { withFileTypes: true })) {
|
|
19531
20428
|
const p = (0, import_node_path21.join)(d, e.name);
|
|
19532
20429
|
if (e.isDirectory()) {
|
|
19533
20430
|
walk(p, depth + 1);
|
|
19534
20431
|
} else if (e.name.startsWith("agent-") && e.name.endsWith(".jsonl")) {
|
|
19535
20432
|
try {
|
|
19536
|
-
const st = (0,
|
|
20433
|
+
const st = (0, import_node_fs30.statSync)(p);
|
|
19537
20434
|
found.push({ path: p, size: st.size, mtimeMs: st.mtimeMs });
|
|
19538
20435
|
} catch {
|
|
19539
20436
|
result.coverage.malformed++;
|
|
@@ -19550,7 +20447,7 @@ function fold(transcriptPath, opts = {}) {
|
|
|
19550
20447
|
continue;
|
|
19551
20448
|
}
|
|
19552
20449
|
try {
|
|
19553
|
-
ingest((0,
|
|
20450
|
+
ingest((0, import_node_fs30.readFileSync)(f.path, "utf8"), "subagent");
|
|
19554
20451
|
bytes += f.size;
|
|
19555
20452
|
result.coverage.subagentFiles++;
|
|
19556
20453
|
} catch {
|
|
@@ -19585,7 +20482,7 @@ function fold(transcriptPath, opts = {}) {
|
|
|
19585
20482
|
}
|
|
19586
20483
|
function classifyUnobserved(path) {
|
|
19587
20484
|
try {
|
|
19588
|
-
const st = (0,
|
|
20485
|
+
const st = (0, import_node_fs30.statSync)(path);
|
|
19589
20486
|
if (!st.isFile()) return "unreadable";
|
|
19590
20487
|
} catch {
|
|
19591
20488
|
return "unreadable";
|
|
@@ -19889,20 +20786,20 @@ async function evidence(run2) {
|
|
|
19889
20786
|
}
|
|
19890
20787
|
|
|
19891
20788
|
// src/lib/cache-cleanup.ts
|
|
19892
|
-
var
|
|
20789
|
+
var import_node_fs31 = require("node:fs");
|
|
19893
20790
|
var import_node_path22 = require("node:path");
|
|
19894
20791
|
var CACHE_TTL_DAYS = 7;
|
|
19895
20792
|
function pruneStaleCache() {
|
|
19896
20793
|
try {
|
|
19897
20794
|
const dir = projectPath(CACHE_DIR);
|
|
19898
20795
|
const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
|
|
19899
|
-
for (const entry of (0,
|
|
20796
|
+
for (const entry of (0, import_node_fs31.readdirSync)(dir)) {
|
|
19900
20797
|
if (!entry.startsWith("pending-")) continue;
|
|
19901
20798
|
const path = (0, import_node_path22.join)(dir, entry);
|
|
19902
20799
|
try {
|
|
19903
|
-
const stat3 = (0,
|
|
20800
|
+
const stat3 = (0, import_node_fs31.statSync)(path);
|
|
19904
20801
|
if (stat3.mtimeMs < cutoff) {
|
|
19905
|
-
(0,
|
|
20802
|
+
(0, import_node_fs31.unlinkSync)(path);
|
|
19906
20803
|
logEvent("cache_entry_pruned", {
|
|
19907
20804
|
path: entry,
|
|
19908
20805
|
age_days: Math.round((Date.now() - stat3.mtimeMs) / 864e5)
|
|
@@ -19916,16 +20813,53 @@ function pruneStaleCache() {
|
|
|
19916
20813
|
}
|
|
19917
20814
|
|
|
19918
20815
|
// src/lib/context-files.ts
|
|
19919
|
-
var
|
|
20816
|
+
var import_node_fs32 = require("node:fs");
|
|
20817
|
+
var import_node_os5 = require("node:os");
|
|
19920
20818
|
var MAX_CONTEXT_FILES = 10;
|
|
19921
20819
|
var MAX_CONTEXT_FILE_BYTES = 10240;
|
|
19922
|
-
var MAX_CONTEXT_TOTAL_BYTES =
|
|
19923
|
-
function
|
|
20820
|
+
var MAX_CONTEXT_TOTAL_BYTES = 24576;
|
|
20821
|
+
function readSetContextPaths(summary, deltaFiles) {
|
|
20822
|
+
const reads = summary?.files_read ?? [];
|
|
20823
|
+
if (reads.length === 0) return [];
|
|
20824
|
+
const root = process.cwd().replace(/\/+$/, "");
|
|
20825
|
+
const home = (0, import_node_os5.homedir)();
|
|
20826
|
+
const toRepoRelative2 = (p) => {
|
|
20827
|
+
if (!p) return null;
|
|
20828
|
+
let abs;
|
|
20829
|
+
if (p.startsWith("/")) {
|
|
20830
|
+
abs = p;
|
|
20831
|
+
} else {
|
|
20832
|
+
const rebuilt = `${home}/${p}`;
|
|
20833
|
+
abs = rebuilt.startsWith(`${root}/`) ? rebuilt : `${root}/${p}`;
|
|
20834
|
+
}
|
|
20835
|
+
if (!abs.startsWith(`${root}/`)) return null;
|
|
20836
|
+
return abs.slice(root.length + 1);
|
|
20837
|
+
};
|
|
20838
|
+
const authored = /* @__PURE__ */ new Set();
|
|
20839
|
+
for (const p of [...summary?.files_edited ?? [], ...summary?.files_created ?? []]) {
|
|
20840
|
+
const rel = toRepoRelative2(p);
|
|
20841
|
+
if (rel) authored.add(rel);
|
|
20842
|
+
}
|
|
20843
|
+
for (const f of deltaFiles) authored.add(f.path);
|
|
20844
|
+
const out = [];
|
|
20845
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20846
|
+
for (const p of reads) {
|
|
20847
|
+
const rel = toRepoRelative2(p);
|
|
20848
|
+
if (!rel || seen.has(rel) || authored.has(rel)) continue;
|
|
20849
|
+
seen.add(rel);
|
|
20850
|
+
const ext = rel.split(".").pop()?.toLowerCase() ?? "";
|
|
20851
|
+
if (!ANALYZABLE_EXTENSIONS.has(ext) && !REVIEWABLE_EXTENSIONS.has(ext)) continue;
|
|
20852
|
+
out.push(rel);
|
|
20853
|
+
}
|
|
20854
|
+
return out;
|
|
20855
|
+
}
|
|
20856
|
+
function gatherContextFiles(contextPaths, deltaFiles, opts) {
|
|
20857
|
+
const fileCap = Math.max(0, Math.min(MAX_CONTEXT_FILES, opts?.maxFiles ?? MAX_CONTEXT_FILES));
|
|
19924
20858
|
const deltaPaths = new Set(deltaFiles.map((f) => f.path));
|
|
19925
20859
|
const result = [];
|
|
19926
20860
|
let totalBytes = 0;
|
|
19927
20861
|
for (const filePath of contextPaths) {
|
|
19928
|
-
if (result.length >=
|
|
20862
|
+
if (result.length >= fileCap) break;
|
|
19929
20863
|
if (deltaPaths.has(filePath)) continue;
|
|
19930
20864
|
if (isVerityOwnedPath(filePath)) {
|
|
19931
20865
|
logEvent("context_file_skipped", { path: filePath, reason: "verity_owned" });
|
|
@@ -19937,7 +20871,7 @@ function gatherContextFiles(contextPaths, deltaFiles) {
|
|
|
19937
20871
|
continue;
|
|
19938
20872
|
}
|
|
19939
20873
|
try {
|
|
19940
|
-
const content = (0,
|
|
20874
|
+
const content = (0, import_node_fs32.readFileSync)(safePath, "utf8");
|
|
19941
20875
|
const bytes = Buffer.byteLength(content);
|
|
19942
20876
|
if (bytes > MAX_CONTEXT_FILE_BYTES) {
|
|
19943
20877
|
logEvent("context_file_skipped", { path: filePath, reason: "too_large", bytes });
|
|
@@ -19983,9 +20917,14 @@ function gatherContextFiles(contextPaths, deltaFiles) {
|
|
|
19983
20917
|
|
|
19984
20918
|
// src/commands/analyze/phases/07-context-files.ts
|
|
19985
20919
|
async function contextFiles(run2) {
|
|
19986
|
-
const { codeDelta
|
|
19987
|
-
const
|
|
19988
|
-
const
|
|
20920
|
+
const { codeDelta } = run2;
|
|
20921
|
+
const readSet = readSetContextPaths(run2.actionSummary, codeDelta.files);
|
|
20922
|
+
const { kept: externalContext } = partitionVerityOwned(readSet);
|
|
20923
|
+
const ig = loadVerityIgnore();
|
|
20924
|
+
const unfenced = run2.verityIgnored.suspended ? externalContext : externalContext.filter((p) => !isIgnored(ig, p));
|
|
20925
|
+
const contextFiles2 = gatherContextFiles(unfenced, codeDelta.files, {
|
|
20926
|
+
maxFiles: MAX_FILES - codeDelta.files.length
|
|
20927
|
+
});
|
|
19989
20928
|
for (const f of codeDelta.files) {
|
|
19990
20929
|
f.role = "delta";
|
|
19991
20930
|
}
|
|
@@ -19997,9 +20936,33 @@ async function contextFiles(run2) {
|
|
|
19997
20936
|
});
|
|
19998
20937
|
}
|
|
19999
20938
|
|
|
20939
|
+
// src/commands/analyze/phases/07b-repo-context.ts
|
|
20940
|
+
async function repoContext(run2) {
|
|
20941
|
+
const { codeDelta, snapshotResult } = run2;
|
|
20942
|
+
const deltaFiles = codeDelta.files.filter((f) => f.role !== "context");
|
|
20943
|
+
const sentPaths = new Set(codeDelta.files.map((f) => f.path));
|
|
20944
|
+
const ig = loadVerityIgnore();
|
|
20945
|
+
const isExcluded = (p) => isVerityOwnedPath(p) || !run2.verityIgnored.suspended && isIgnored(ig, p);
|
|
20946
|
+
run2.repoContext = buildRepoContext({
|
|
20947
|
+
deltaFiles,
|
|
20948
|
+
diffs: snapshotResult.diffs,
|
|
20949
|
+
sentPaths,
|
|
20950
|
+
isExcluded
|
|
20951
|
+
});
|
|
20952
|
+
logEvent("repo_context", {
|
|
20953
|
+
state: run2.repoContext.state,
|
|
20954
|
+
reason: run2.repoContext.reason ?? null,
|
|
20955
|
+
symbols: run2.repoContext.symbols?.length ?? 0,
|
|
20956
|
+
dropped: run2.repoContext.dropped_symbols?.length ?? 0,
|
|
20957
|
+
callers: run2.repoContext.callers?.length ?? 0,
|
|
20958
|
+
tests: run2.repoContext.tests?.length ?? 0,
|
|
20959
|
+
elapsed_ms: run2.repoContext.elapsed_ms ?? null
|
|
20960
|
+
});
|
|
20961
|
+
}
|
|
20962
|
+
|
|
20000
20963
|
// src/lib/seed-runner.ts
|
|
20001
20964
|
var import_promises11 = require("node:fs/promises");
|
|
20002
|
-
var
|
|
20965
|
+
var import_node_fs33 = require("node:fs");
|
|
20003
20966
|
var import_node_path23 = require("node:path");
|
|
20004
20967
|
var import_yaml2 = __toESM(require_dist());
|
|
20005
20968
|
|
|
@@ -20239,7 +21202,7 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
|
|
|
20239
21202
|
return fm;
|
|
20240
21203
|
}
|
|
20241
21204
|
async function runSeed(opts) {
|
|
20242
|
-
if (!(0,
|
|
21205
|
+
if (!(0, import_node_fs33.existsSync)(STANDARD_FILE)) {
|
|
20243
21206
|
return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
20244
21207
|
}
|
|
20245
21208
|
let standardDoc;
|
|
@@ -20251,7 +21214,7 @@ async function runSeed(opts) {
|
|
|
20251
21214
|
}
|
|
20252
21215
|
const knowledgeSpec = standardDoc.knowledge_spec ?? {};
|
|
20253
21216
|
let readmeContent;
|
|
20254
|
-
if ((0,
|
|
21217
|
+
if ((0, import_node_fs33.existsSync)("README.md")) {
|
|
20255
21218
|
try {
|
|
20256
21219
|
readmeContent = await (0, import_promises11.readFile)("README.md", "utf-8");
|
|
20257
21220
|
} catch {
|
|
@@ -20259,7 +21222,7 @@ async function runSeed(opts) {
|
|
|
20259
21222
|
}
|
|
20260
21223
|
let claudeMdContent;
|
|
20261
21224
|
for (const p of ["CLAUDE.md", ".claude/CLAUDE.md"]) {
|
|
20262
|
-
if ((0,
|
|
21225
|
+
if ((0, import_node_fs33.existsSync)(p)) {
|
|
20263
21226
|
try {
|
|
20264
21227
|
claudeMdContent = await (0, import_promises11.readFile)(p, "utf-8");
|
|
20265
21228
|
break;
|
|
@@ -20283,7 +21246,7 @@ async function runSeed(opts) {
|
|
|
20283
21246
|
return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
|
|
20284
21247
|
}
|
|
20285
21248
|
const overviewPath = (0, import_node_path23.join)(MEMORY_DIR, "domain", "project-overview.md");
|
|
20286
|
-
if ((0,
|
|
21249
|
+
if ((0, import_node_fs33.existsSync)(overviewPath) && !opts.force) {
|
|
20287
21250
|
return { created: 0, failed: 0, skipped: "already_seeded", candidates };
|
|
20288
21251
|
}
|
|
20289
21252
|
if (opts.dryRun) {
|
|
@@ -20338,7 +21301,7 @@ async function runSeed(opts) {
|
|
|
20338
21301
|
}
|
|
20339
21302
|
|
|
20340
21303
|
// src/commands/analyze/phases/08-memory-manifest.ts
|
|
20341
|
-
var
|
|
21304
|
+
var import_node_fs34 = require("node:fs");
|
|
20342
21305
|
var import_node_path24 = require("node:path");
|
|
20343
21306
|
async function memoryManifest(run2) {
|
|
20344
21307
|
const { globals } = run2;
|
|
@@ -20350,8 +21313,8 @@ async function memoryManifest(run2) {
|
|
|
20350
21313
|
try {
|
|
20351
21314
|
await ensureMemoryDir();
|
|
20352
21315
|
const seedMarker = (0, import_node_path24.join)(VERITY_DIR, ".seeded");
|
|
20353
|
-
const hasStandard = (0,
|
|
20354
|
-
const alreadyTried = (0,
|
|
21316
|
+
const hasStandard = (0, import_node_fs34.existsSync)(STANDARD_FILE);
|
|
21317
|
+
const alreadyTried = (0, import_node_fs34.existsSync)(seedMarker);
|
|
20355
21318
|
if (hasStandard && !alreadyTried) {
|
|
20356
21319
|
const preManifest = await buildManifest();
|
|
20357
21320
|
if (preManifest.nodes.length === 0) {
|
|
@@ -20364,7 +21327,7 @@ async function memoryManifest(run2) {
|
|
|
20364
21327
|
dryRun: false
|
|
20365
21328
|
});
|
|
20366
21329
|
if (seedResult.created > 0) {
|
|
20367
|
-
(0,
|
|
21330
|
+
(0, import_node_fs34.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
|
|
20368
21331
|
`);
|
|
20369
21332
|
autoSeedNotice = `Seeded ${seedResult.created} knowledge node(s) from your existing Standard (one-time).`;
|
|
20370
21333
|
logEvent("auto_seed_ran", {
|
|
@@ -20372,7 +21335,7 @@ async function memoryManifest(run2) {
|
|
|
20372
21335
|
failed: seedResult.failed
|
|
20373
21336
|
});
|
|
20374
21337
|
} else if (seedResult.skipped === "already_seeded") {
|
|
20375
|
-
(0,
|
|
21338
|
+
(0, import_node_fs34.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
|
|
20376
21339
|
`);
|
|
20377
21340
|
} else {
|
|
20378
21341
|
logEvent("auto_seed_noop", {
|
|
@@ -20561,7 +21524,7 @@ async function workingMemory(run2) {
|
|
|
20561
21524
|
}
|
|
20562
21525
|
|
|
20563
21526
|
// src/lib/note-budget.ts
|
|
20564
|
-
var
|
|
21527
|
+
var import_node_fs35 = require("node:fs");
|
|
20565
21528
|
var ADVISORY_BUDGET = { PASS: 1, WARN: 2 };
|
|
20566
21529
|
var EPISODE_STALE_SECONDS = 30 * 60;
|
|
20567
21530
|
var FRESH = { delivered: 0, tasksCompleted: 0, ts: 0 };
|
|
@@ -20583,9 +21546,9 @@ function advisoryBudgetSpent(episode, rawDecision) {
|
|
|
20583
21546
|
}
|
|
20584
21547
|
function readAdvisoryEpisode(sessionId) {
|
|
20585
21548
|
const file = scopedFile(ADVISORY_EPISODE_FILE, sessionId);
|
|
20586
|
-
if (!(0,
|
|
21549
|
+
if (!(0, import_node_fs35.existsSync)(file)) return null;
|
|
20587
21550
|
try {
|
|
20588
|
-
const o = JSON.parse((0,
|
|
21551
|
+
const o = JSON.parse((0, import_node_fs35.readFileSync)(file, "utf-8")) ?? {};
|
|
20589
21552
|
const delivered = typeof o.delivered === "number" ? o.delivered : NaN;
|
|
20590
21553
|
if (isNaN(delivered)) return null;
|
|
20591
21554
|
return {
|
|
@@ -20599,8 +21562,8 @@ function readAdvisoryEpisode(sessionId) {
|
|
|
20599
21562
|
}
|
|
20600
21563
|
function writeAdvisoryEpisode(episode, sessionId) {
|
|
20601
21564
|
try {
|
|
20602
|
-
(0,
|
|
20603
|
-
(0,
|
|
21565
|
+
(0, import_node_fs35.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
21566
|
+
(0, import_node_fs35.writeFileSync)(
|
|
20604
21567
|
scopedFile(ADVISORY_EPISODE_FILE, sessionId),
|
|
20605
21568
|
JSON.stringify({ v: 1, ...episode })
|
|
20606
21569
|
);
|
|
@@ -20630,7 +21593,7 @@ function isExplicitlyAutonomous(env = process.env) {
|
|
|
20630
21593
|
}
|
|
20631
21594
|
|
|
20632
21595
|
// src/lib/task-context.ts
|
|
20633
|
-
var
|
|
21596
|
+
var import_node_child_process10 = require("node:child_process");
|
|
20634
21597
|
var CLOSING_RE = /\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?)\b[\s:]*#(\d+)/i;
|
|
20635
21598
|
var BRANCH_RE = /(?:^|[/_-])(?:issue|gh|fix)[-_/]?(\d+)\b/i;
|
|
20636
21599
|
function parseLinkedIssue(sources) {
|
|
@@ -20646,7 +21609,7 @@ function parseLinkedIssue(sources) {
|
|
|
20646
21609
|
}
|
|
20647
21610
|
function safeExec(cmd, timeout) {
|
|
20648
21611
|
try {
|
|
20649
|
-
return (0,
|
|
21612
|
+
return (0, import_node_child_process10.execSync)(cmd, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout }).trim();
|
|
20650
21613
|
} catch {
|
|
20651
21614
|
return "";
|
|
20652
21615
|
}
|
|
@@ -20853,6 +21816,9 @@ async function buildRequest(run2) {
|
|
|
20853
21816
|
if (snapshotResult.has_snapshots && snapshotResult.diffs.length > 0) {
|
|
20854
21817
|
requestBody.snapshot_diffs = snapshotResult.diffs;
|
|
20855
21818
|
}
|
|
21819
|
+
if (run2.repoContext) {
|
|
21820
|
+
requestBody.repo_context = run2.repoContext;
|
|
21821
|
+
}
|
|
20856
21822
|
const noHumanPrompt = (conversation?.prompts?.length ?? 0) === 0;
|
|
20857
21823
|
const w4Task = noHumanPrompt && isExplicitlyAutonomous() ? resolveTaskContext() : null;
|
|
20858
21824
|
const planApprovalActive = foldResult?.planApproval?.activeSinceLastPrompt === true;
|
|
@@ -20914,14 +21880,14 @@ async function buildRequest(run2) {
|
|
|
20914
21880
|
}
|
|
20915
21881
|
|
|
20916
21882
|
// src/lib/offline.ts
|
|
20917
|
-
var
|
|
21883
|
+
var import_node_fs36 = require("node:fs");
|
|
20918
21884
|
var import_node_crypto11 = require("node:crypto");
|
|
20919
21885
|
function cacheRequest(body) {
|
|
20920
21886
|
try {
|
|
20921
|
-
(0,
|
|
21887
|
+
(0, import_node_fs36.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
20922
21888
|
const suffix = (0, import_node_crypto11.randomBytes)(4).toString("hex");
|
|
20923
21889
|
const filename = `pending-${Math.floor(Date.now() / 1e3)}-${suffix}.json`;
|
|
20924
|
-
(0,
|
|
21890
|
+
(0, import_node_fs36.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(redactRequest(body)));
|
|
20925
21891
|
} catch {
|
|
20926
21892
|
}
|
|
20927
21893
|
}
|
|
@@ -21040,7 +22006,7 @@ async function transmit(run2) {
|
|
|
21040
22006
|
}
|
|
21041
22007
|
|
|
21042
22008
|
// src/commands/analyze/phases/13-reconcile.ts
|
|
21043
|
-
var
|
|
22009
|
+
var import_node_fs37 = require("node:fs");
|
|
21044
22010
|
var import_node_path26 = require("node:path");
|
|
21045
22011
|
async function reconcile(run2) {
|
|
21046
22012
|
const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run2;
|
|
@@ -21070,7 +22036,7 @@ async function reconcile(run2) {
|
|
|
21070
22036
|
const st = foldDossier(memorySession.d);
|
|
21071
22037
|
openElsewhere = openBlockingElsewhere(st.statements, sentPaths, (file, line) => {
|
|
21072
22038
|
try {
|
|
21073
|
-
const src = (0,
|
|
22039
|
+
const src = (0, import_node_fs37.readFileSync)((0, import_node_path26.join)(repoRoot(), file), "utf8").split("\n");
|
|
21074
22040
|
const at = src[line - 1];
|
|
21075
22041
|
return at === void 0 ? null : lineSha(at);
|
|
21076
22042
|
} catch {
|
|
@@ -21701,6 +22667,8 @@ var PIPELINE = [
|
|
|
21701
22667
|
// ← THE NARROWING. what gets sent, and why not the rest
|
|
21702
22668
|
["contextFiles", contextFiles],
|
|
21703
22669
|
// supporting files, merged INTO the delta array
|
|
22670
|
+
["repoContext", repoContext],
|
|
22671
|
+
// R1/R3 — call sites of changed symbols, one line each
|
|
21704
22672
|
["memoryManifest", memoryManifest],
|
|
21705
22673
|
// knowledge-graph manifest + one-time auto-seed
|
|
21706
22674
|
["foldTranscript", foldTranscript],
|
|
@@ -21717,7 +22685,7 @@ var PIPELINE = [
|
|
|
21717
22685
|
// say it — stderr, stdout, disk
|
|
21718
22686
|
];
|
|
21719
22687
|
function registerAnalyzeCommand(program2) {
|
|
21720
|
-
program2.command("analyze").description("Run Verity analysis on changed files (stop hook)").option("--debounce <seconds>", "Skip if last analysis was within N seconds",
|
|
22688
|
+
program2.command("analyze").description("Run Verity analysis on changed files (stop hook)").option("--debounce <seconds>", "Skip if last analysis was within N seconds", String(DEBOUNCE_SECONDS)).option("--max-iterations <n>", "Force PASS after N FAIL cycles", String(MAX_ITERATIONS)).option("--max-files <n>", "Max files to send for review", String(MAX_FILES)).option("--max-file-size <bytes>", "Skip files larger than N bytes", String(MAX_FILE_BYTES)).option("--max-total-size <bytes>", "Stop collecting files at N total bytes", String(MAX_DELTA_BYTES)).option("--skip-static", "Skip codacy-analysis").option("--mode <mode>", "Force analysis mode (standard|plan|debug|skip)").option("--json", "Output raw JSON response").action(async (opts) => {
|
|
21721
22689
|
const globals = program2.opts();
|
|
21722
22690
|
try {
|
|
21723
22691
|
await runAnalyze(opts, globals);
|
|
@@ -21750,7 +22718,7 @@ async function runAnalyze(opts, globals) {
|
|
|
21750
22718
|
}
|
|
21751
22719
|
|
|
21752
22720
|
// src/commands/baseline.ts
|
|
21753
|
-
var
|
|
22721
|
+
var import_node_fs38 = require("node:fs");
|
|
21754
22722
|
function registerBaselineCommands(program2) {
|
|
21755
22723
|
const baseline = program2.command("baseline").description("Manage the task-start working-tree baseline");
|
|
21756
22724
|
baseline.command("capture").description("Snapshot the working tree at task start (used by SessionStart hook)").option("--session-id <id>", "Session id (overrides any value from stdin)").option("--source <source>", "Lifecycle hint: startup|resume|clear|compact").action(async (opts) => {
|
|
@@ -21759,7 +22727,7 @@ function registerBaselineCommands(program2) {
|
|
|
21759
22727
|
process.chdir(repoRoot());
|
|
21760
22728
|
} catch {
|
|
21761
22729
|
}
|
|
21762
|
-
if (!(0,
|
|
22730
|
+
if (!(0, import_node_fs38.existsSync)(VERITY_DIR)) {
|
|
21763
22731
|
process.exit(0);
|
|
21764
22732
|
}
|
|
21765
22733
|
let sessionId = opts.sessionId;
|
|
@@ -21775,6 +22743,9 @@ function registerBaselineCommands(program2) {
|
|
|
21775
22743
|
}
|
|
21776
22744
|
}
|
|
21777
22745
|
}
|
|
22746
|
+
if (deferredToPlugin("baseline capture", sessionId ?? process.env.CLAUDE_SESSION_ID ?? null)) {
|
|
22747
|
+
process.exit(0);
|
|
22748
|
+
}
|
|
21778
22749
|
const authForScope = await resolveToken(program2.opts().token);
|
|
21779
22750
|
const scopeToken = authForScope.ok ? authForScope.data.token : void 0;
|
|
21780
22751
|
const scopeSession = sessionId || process.env.CLAUDE_SESSION_ID || void 0;
|
|
@@ -21799,7 +22770,7 @@ async function readStdin() {
|
|
|
21799
22770
|
}
|
|
21800
22771
|
|
|
21801
22772
|
// src/commands/review.ts
|
|
21802
|
-
var
|
|
22773
|
+
var import_node_fs39 = require("node:fs");
|
|
21803
22774
|
function registerReviewCommand(program2) {
|
|
21804
22775
|
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) => {
|
|
21805
22776
|
const globals = program2.opts();
|
|
@@ -21818,7 +22789,7 @@ async function runReview(opts, globals) {
|
|
|
21818
22789
|
const securityFiles = filterSecurity(allFiles);
|
|
21819
22790
|
let staticResults;
|
|
21820
22791
|
if (isCodacyAvailable()) {
|
|
21821
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0,
|
|
22792
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs39.existsSync)(f) || resolveFile(f) !== null);
|
|
21822
22793
|
staticResults = runCodacyAnalysis(scannable);
|
|
21823
22794
|
} else {
|
|
21824
22795
|
staticResults = {
|
|
@@ -21844,10 +22815,10 @@ async function runReview(opts, globals) {
|
|
|
21844
22815
|
const specPaths = opts.specs.split(",").map((f) => f.trim()).filter(Boolean);
|
|
21845
22816
|
specs = [];
|
|
21846
22817
|
for (const p of specPaths) {
|
|
21847
|
-
if (!(0,
|
|
22818
|
+
if (!(0, import_node_fs39.existsSync)(p)) continue;
|
|
21848
22819
|
try {
|
|
21849
|
-
const { readFileSync:
|
|
21850
|
-
const content =
|
|
22820
|
+
const { readFileSync: readFileSync27 } = await import("node:fs");
|
|
22821
|
+
const content = readFileSync27(p, "utf-8");
|
|
21851
22822
|
specs.push({ path: p, content: content.slice(0, 10240) });
|
|
21852
22823
|
} catch {
|
|
21853
22824
|
}
|
|
@@ -21904,7 +22875,7 @@ async function runReview(opts, globals) {
|
|
|
21904
22875
|
}
|
|
21905
22876
|
|
|
21906
22877
|
// src/commands/guard.ts
|
|
21907
|
-
var
|
|
22878
|
+
var import_node_fs40 = require("node:fs");
|
|
21908
22879
|
var import_node_path27 = require("node:path");
|
|
21909
22880
|
var GUARD_BLOCK_CAP = 2;
|
|
21910
22881
|
var GUARD_ITER_FILE = (0, import_node_path27.join)(VERITY_DIR, ".guard-iteration");
|
|
@@ -21952,7 +22923,7 @@ function readPreToolUseStdin() {
|
|
|
21952
22923
|
}
|
|
21953
22924
|
function readIterMap() {
|
|
21954
22925
|
try {
|
|
21955
|
-
const raw = JSON.parse((0,
|
|
22926
|
+
const raw = JSON.parse((0, import_node_fs40.readFileSync)(GUARD_ITER_FILE, "utf-8"));
|
|
21956
22927
|
if (raw && typeof raw === "object") {
|
|
21957
22928
|
if (typeof raw.moment === "string" && typeof raw.count === "number") {
|
|
21958
22929
|
return { [raw.moment]: raw.count };
|
|
@@ -21972,10 +22943,10 @@ function readIter(moment) {
|
|
|
21972
22943
|
}
|
|
21973
22944
|
function writeIter(moment, count) {
|
|
21974
22945
|
try {
|
|
21975
|
-
(0,
|
|
22946
|
+
(0, import_node_fs40.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
21976
22947
|
const map = readIterMap();
|
|
21977
22948
|
map[moment] = count;
|
|
21978
|
-
(0,
|
|
22949
|
+
(0, import_node_fs40.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
21979
22950
|
} catch {
|
|
21980
22951
|
}
|
|
21981
22952
|
}
|
|
@@ -21985,16 +22956,16 @@ function resetIter(moment) {
|
|
|
21985
22956
|
if (!(moment in map)) return;
|
|
21986
22957
|
delete map[moment];
|
|
21987
22958
|
if (Object.keys(map).length === 0) {
|
|
21988
|
-
if ((0,
|
|
22959
|
+
if ((0, import_node_fs40.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs40.unlinkSync)(GUARD_ITER_FILE);
|
|
21989
22960
|
} else {
|
|
21990
|
-
(0,
|
|
21991
|
-
(0,
|
|
22961
|
+
(0, import_node_fs40.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
22962
|
+
(0, import_node_fs40.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
21992
22963
|
}
|
|
21993
22964
|
} catch {
|
|
21994
22965
|
}
|
|
21995
22966
|
}
|
|
21996
22967
|
function registerGuardCommand(program2) {
|
|
21997
|
-
program2.command("guard").description("Git-moment gate: review staged/to-push changes before a commit/push (PreToolUse hook)").option("--on <moments>", "Which git moments to gate: commit,push
|
|
22968
|
+
program2.command("guard").description("Git-moment gate: review staged/to-push changes before a commit/push (PreToolUse hook)").option("--on <moments>", "Which git moments to gate: commit,push (default: the project config)").option("--json", "Output raw JSON response (debug)").action(async (opts) => {
|
|
21998
22969
|
const globals = program2.opts();
|
|
21999
22970
|
try {
|
|
22000
22971
|
await runGuard(opts, globals);
|
|
@@ -22059,7 +23030,7 @@ function buildGuardRequest(moment, files, codeDelta, iter, sessionId, statedInte
|
|
|
22059
23030
|
const securityFiles = filterSecurity(files);
|
|
22060
23031
|
let staticResults;
|
|
22061
23032
|
if (isCodacyAvailable()) {
|
|
22062
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0,
|
|
23033
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs40.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
|
|
22063
23034
|
staticResults = runCodacyAnalysis(scannable);
|
|
22064
23035
|
} else {
|
|
22065
23036
|
staticResults = { tool: "@codacy/analysis-cli", findings: [], summary: { total_findings: 0, by_severity: {}, tools_run: [] } };
|
|
@@ -22116,6 +23087,7 @@ function coverageBlock(c) {
|
|
|
22116
23087
|
const tree = c.root ? `${c.root}${c.linked ? " (linked worktree)" : ""}${c.branch ? ` \xB7 branch ${c.branch}` : ""}` : "(no tree resolved)";
|
|
22117
23088
|
lines.push(`Reviewed (${c.moment}): ${c.sent.length} file(s)${c.range ? ` @ ${c.range}` : ""}`);
|
|
22118
23089
|
lines.push(` Tree: ${tree}`);
|
|
23090
|
+
if (c.repoContext) lines.push(` Repo context: ${describeRepoContext(c.repoContext)}`);
|
|
22119
23091
|
for (const f of c.sent) lines.push(` - ${f}`);
|
|
22120
23092
|
if (c.excluded.length > 0) {
|
|
22121
23093
|
lines.push(` Excluded (${c.excluded.length}):`);
|
|
@@ -22131,8 +23103,10 @@ function emitAllowNotice(userMsg, agentMsg) {
|
|
|
22131
23103
|
process.exit(0);
|
|
22132
23104
|
}
|
|
22133
23105
|
async function runGuard(opts, globals) {
|
|
22134
|
-
const on = opts.on
|
|
23106
|
+
const on = resolveGuardMoments(opts.on);
|
|
23107
|
+
if (on.length === 0) process.exit(0);
|
|
22135
23108
|
const { command, cwd, sessionId } = await readPreToolUseStdin();
|
|
23109
|
+
if (deferredToPlugin("guard", sessionId)) process.exit(0);
|
|
22136
23110
|
const moment = classifyCommand(command, on);
|
|
22137
23111
|
if (!moment) process.exit(0);
|
|
22138
23112
|
const verb = moment === "pre-commit" ? "commit" : "push";
|
|
@@ -22182,6 +23156,39 @@ async function runGuard(opts, globals) {
|
|
|
22182
23156
|
statedIntent,
|
|
22183
23157
|
buildGuardCoverage(files, codeDelta, frame, range)
|
|
22184
23158
|
);
|
|
23159
|
+
try {
|
|
23160
|
+
const ig = loadVerityIgnore();
|
|
23161
|
+
const repoContext2 = buildRepoContext({
|
|
23162
|
+
deltaFiles: codeDelta.files,
|
|
23163
|
+
diffs: [],
|
|
23164
|
+
signalsByPath: rangeChangeSignals(frame, range, codeDelta.files.map((f) => f.path)),
|
|
23165
|
+
sentPaths: new Set(codeDelta.files.map((f) => f.path)),
|
|
23166
|
+
isExcluded: (p) => isVerityOwnedPath(p) || isIgnored(ig, p),
|
|
23167
|
+
cwd: frame.worktreeRoot ?? process.cwd()
|
|
23168
|
+
});
|
|
23169
|
+
upgradeToExcerpts(repoContext2, {
|
|
23170
|
+
readFile: (rel) => {
|
|
23171
|
+
try {
|
|
23172
|
+
return (0, import_node_fs40.readFileSync)((0, import_node_path27.join)(frame.worktreeRoot ?? process.cwd(), rel), "utf8");
|
|
23173
|
+
} catch {
|
|
23174
|
+
return null;
|
|
23175
|
+
}
|
|
23176
|
+
}
|
|
23177
|
+
});
|
|
23178
|
+
requestBody.repo_context = repoContext2;
|
|
23179
|
+
logEvent("repo_context", {
|
|
23180
|
+
moment,
|
|
23181
|
+
state: repoContext2.state,
|
|
23182
|
+
reason: repoContext2.reason ?? null,
|
|
23183
|
+
symbols: repoContext2.symbols?.length ?? 0,
|
|
23184
|
+
callers: repoContext2.callers?.length ?? 0,
|
|
23185
|
+
tests: repoContext2.tests?.length ?? 0,
|
|
23186
|
+
excerpts: repoContext2.excerpts?.length ?? 0,
|
|
23187
|
+
elapsed_ms: repoContext2.elapsed_ms ?? null
|
|
23188
|
+
});
|
|
23189
|
+
} catch (e) {
|
|
23190
|
+
logEvent("repo_context", { moment, state: "absent", reason: "exception", message: e.message });
|
|
23191
|
+
}
|
|
22185
23192
|
const coverage = {
|
|
22186
23193
|
moment,
|
|
22187
23194
|
root: frame.worktreeRoot,
|
|
@@ -22189,7 +23196,8 @@ async function runGuard(opts, globals) {
|
|
|
22189
23196
|
linked: frame.isLinkedWorktree,
|
|
22190
23197
|
range: describeRange(range),
|
|
22191
23198
|
sent: codeDelta.files.map((f) => f.path),
|
|
22192
|
-
excluded: codeDelta.excluded.map((e) => ({ path: e.path, reason: e.reason }))
|
|
23199
|
+
excluded: codeDelta.excluded.map((e) => ({ path: e.path, reason: e.reason })),
|
|
23200
|
+
...requestBody.repo_context ? { repoContext: requestBody.repo_context } : {}
|
|
22193
23201
|
};
|
|
22194
23202
|
logToFileOnly(coverageBlock(coverage));
|
|
22195
23203
|
const reviewStart = Date.now();
|
|
@@ -22382,7 +23390,7 @@ function registerIgnoreCommand(program2) {
|
|
|
22382
23390
|
|
|
22383
23391
|
// src/commands/waive.ts
|
|
22384
23392
|
var import_node_crypto12 = require("node:crypto");
|
|
22385
|
-
var
|
|
23393
|
+
var import_node_fs41 = require("node:fs");
|
|
22386
23394
|
function registerWaiveCommand(program2) {
|
|
22387
23395
|
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) => {
|
|
22388
23396
|
const globals = program2.opts();
|
|
@@ -22411,7 +23419,7 @@ function registerWaiveCommand(program2) {
|
|
|
22411
23419
|
if (opts.file) {
|
|
22412
23420
|
body.file = opts.file;
|
|
22413
23421
|
try {
|
|
22414
|
-
body.file_sha256 = (0, import_node_crypto12.createHash)("sha256").update((0,
|
|
23422
|
+
body.file_sha256 = (0, import_node_crypto12.createHash)("sha256").update((0, import_node_fs41.readFileSync)(opts.file)).digest("hex");
|
|
22415
23423
|
} catch {
|
|
22416
23424
|
printError(`Cannot read ${opts.file} \u2014 run from the repo root, or omit --file to waive by pattern.`);
|
|
22417
23425
|
process.exit(1);
|
|
@@ -22436,10 +23444,10 @@ function registerWaiveCommand(program2) {
|
|
|
22436
23444
|
}
|
|
22437
23445
|
|
|
22438
23446
|
// src/commands/init.ts
|
|
22439
|
-
var
|
|
23447
|
+
var import_node_fs46 = require("node:fs");
|
|
22440
23448
|
var import_promises14 = require("node:fs/promises");
|
|
22441
23449
|
var import_node_path29 = require("node:path");
|
|
22442
|
-
var
|
|
23450
|
+
var import_node_child_process14 = require("node:child_process");
|
|
22443
23451
|
|
|
22444
23452
|
// src/lib/banner.ts
|
|
22445
23453
|
var WORDMARK = [
|
|
@@ -22517,14 +23525,14 @@ function printPhase(n, of, title, subtitle) {
|
|
|
22517
23525
|
}
|
|
22518
23526
|
|
|
22519
23527
|
// src/commands/doctor.ts
|
|
22520
|
-
var
|
|
23528
|
+
var import_node_fs44 = require("node:fs");
|
|
22521
23529
|
|
|
22522
23530
|
// src/lib/prereqs.ts
|
|
22523
|
-
var
|
|
23531
|
+
var import_node_child_process11 = require("node:child_process");
|
|
22524
23532
|
var MIN_NODE_MAJOR = 20;
|
|
22525
23533
|
function which(bin) {
|
|
22526
23534
|
try {
|
|
22527
|
-
const out = (0,
|
|
23535
|
+
const out = (0, import_node_child_process11.execSync)(`command -v ${bin}`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
22528
23536
|
return out || null;
|
|
22529
23537
|
} catch {
|
|
22530
23538
|
return null;
|
|
@@ -22546,7 +23554,7 @@ function checkNode() {
|
|
|
22546
23554
|
function checkGit() {
|
|
22547
23555
|
let detail = "";
|
|
22548
23556
|
try {
|
|
22549
|
-
detail = (0,
|
|
23557
|
+
detail = (0, import_node_child_process11.execSync)("git --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
22550
23558
|
} catch {
|
|
22551
23559
|
return {
|
|
22552
23560
|
id: "git",
|
|
@@ -22584,7 +23592,7 @@ function checkAnalysisCli() {
|
|
|
22584
23592
|
var INSTALL_TIMEOUT_MS = 12e4;
|
|
22585
23593
|
function run(command, args, opts = {}) {
|
|
22586
23594
|
return new Promise((resolve4) => {
|
|
22587
|
-
const child = (0,
|
|
23595
|
+
const child = (0, import_node_child_process11.spawn)(command, args, {
|
|
22588
23596
|
stdio: opts.inherit ? "inherit" : "pipe",
|
|
22589
23597
|
timeout: INSTALL_TIMEOUT_MS
|
|
22590
23598
|
});
|
|
@@ -22636,8 +23644,8 @@ async function checkPrereqs(opts = {}) {
|
|
|
22636
23644
|
var import_promises12 = require("node:fs/promises");
|
|
22637
23645
|
|
|
22638
23646
|
// src/lib/gitignore.ts
|
|
22639
|
-
var
|
|
22640
|
-
var
|
|
23647
|
+
var import_node_child_process12 = require("node:child_process");
|
|
23648
|
+
var import_node_fs42 = require("node:fs");
|
|
22641
23649
|
var VERITY_GITIGNORE_MARKER = "# Verity \u2014 machine-local state.";
|
|
22642
23650
|
var SETTINGS_LOCAL_IGNORE_ENTRY = ".claude/settings.local.json";
|
|
22643
23651
|
var VERITY_GITIGNORE_BLOCK = [
|
|
@@ -22653,7 +23661,7 @@ var VERITY_GITIGNORE_BLOCK = [
|
|
|
22653
23661
|
var BREAKING_ENTRIES = /* @__PURE__ */ new Set([".verity/", ".verity"]);
|
|
22654
23662
|
function isIgnored2(path) {
|
|
22655
23663
|
try {
|
|
22656
|
-
(0,
|
|
23664
|
+
(0, import_node_child_process12.execSync)(`git check-ignore -q -- "${path}"`, { stdio: "pipe" });
|
|
22657
23665
|
return true;
|
|
22658
23666
|
} catch (err) {
|
|
22659
23667
|
return err.status === 1 ? false : null;
|
|
@@ -22670,7 +23678,7 @@ function semanticsHold() {
|
|
|
22670
23678
|
function ensureVerityGitignore() {
|
|
22671
23679
|
let content = "";
|
|
22672
23680
|
try {
|
|
22673
|
-
content = (0,
|
|
23681
|
+
content = (0, import_node_fs42.readFileSync)(".gitignore", "utf-8");
|
|
22674
23682
|
} catch {
|
|
22675
23683
|
}
|
|
22676
23684
|
const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
|
|
@@ -22691,7 +23699,7 @@ function ensureVerityGitignore() {
|
|
|
22691
23699
|
const sep2 = next === "" ? "" : next.endsWith("\n") ? "\n" : "\n\n";
|
|
22692
23700
|
next = next + sep2 + VERITY_GITIGNORE_BLOCK;
|
|
22693
23701
|
}
|
|
22694
|
-
(0,
|
|
23702
|
+
(0, import_node_fs42.writeFileSync)(".gitignore", next);
|
|
22695
23703
|
return verified(needsRepair ? "repaired" : "added");
|
|
22696
23704
|
} catch {
|
|
22697
23705
|
return "failed";
|
|
@@ -22700,7 +23708,7 @@ function ensureVerityGitignore() {
|
|
|
22700
23708
|
function committedVerityState() {
|
|
22701
23709
|
let out = "";
|
|
22702
23710
|
try {
|
|
22703
|
-
out = (0,
|
|
23711
|
+
out = (0, import_node_child_process12.execSync)("git ls-files -z -- .verity", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
22704
23712
|
} catch {
|
|
22705
23713
|
return [];
|
|
22706
23714
|
}
|
|
@@ -22710,10 +23718,10 @@ function untrackVerityState() {
|
|
|
22710
23718
|
const tracked = committedVerityState();
|
|
22711
23719
|
if (tracked.length === 0) return "none";
|
|
22712
23720
|
try {
|
|
22713
|
-
(0,
|
|
23721
|
+
(0, import_node_child_process12.execSync)("git rm -r --cached --quiet -- .verity", { stdio: "pipe" });
|
|
22714
23722
|
for (const keep of [".verity/standard.yaml", ".verity/memory"]) {
|
|
22715
23723
|
try {
|
|
22716
|
-
(0,
|
|
23724
|
+
(0, import_node_child_process12.execSync)(`git add -- "${keep}"`, { stdio: "pipe" });
|
|
22717
23725
|
} catch {
|
|
22718
23726
|
}
|
|
22719
23727
|
}
|
|
@@ -22814,11 +23822,11 @@ async function uninstallTelemetry() {
|
|
|
22814
23822
|
|
|
22815
23823
|
// src/lib/setup-state.ts
|
|
22816
23824
|
var import_promises13 = require("node:fs/promises");
|
|
22817
|
-
var
|
|
23825
|
+
var import_node_fs43 = require("node:fs");
|
|
22818
23826
|
var SETUP_STATE_FILE = `${VERITY_DIR}/setup.json`;
|
|
22819
23827
|
async function readSetupState() {
|
|
22820
23828
|
const path = projectPath(SETUP_STATE_FILE);
|
|
22821
|
-
if (!(0,
|
|
23829
|
+
if (!(0, import_node_fs43.existsSync)(path)) return null;
|
|
22822
23830
|
try {
|
|
22823
23831
|
const parsed = JSON.parse(await (0, import_promises13.readFile)(path, "utf-8"));
|
|
22824
23832
|
return parsed && typeof parsed === "object" ? parsed : null;
|
|
@@ -22840,9 +23848,9 @@ async function buildReport() {
|
|
|
22840
23848
|
const hooks = await checkAllVerityHooks();
|
|
22841
23849
|
const telemetry = await checkTelemetry();
|
|
22842
23850
|
const artifacts = {
|
|
22843
|
-
standard: (0,
|
|
22844
|
-
analysisConfig: (0,
|
|
22845
|
-
verityMd: (0,
|
|
23851
|
+
standard: (0, import_node_fs44.existsSync)(projectPath(STANDARD_FILE)),
|
|
23852
|
+
analysisConfig: (0, import_node_fs44.existsSync)(projectPath(CODACY_CONFIG_FILE)),
|
|
23853
|
+
verityMd: (0, import_node_fs44.existsSync)(projectPath(VERITY_MD_FILE))
|
|
22846
23854
|
};
|
|
22847
23855
|
const next = [];
|
|
22848
23856
|
for (const c of prereqs.checks) {
|
|
@@ -22915,16 +23923,16 @@ function registerDoctorCommand(program2) {
|
|
|
22915
23923
|
}
|
|
22916
23924
|
|
|
22917
23925
|
// src/commands/migrate.ts
|
|
22918
|
-
var
|
|
23926
|
+
var import_node_fs45 = require("node:fs");
|
|
22919
23927
|
var import_node_path28 = require("node:path");
|
|
22920
|
-
var
|
|
23928
|
+
var import_node_child_process13 = require("node:child_process");
|
|
22921
23929
|
var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
|
|
22922
23930
|
function defaultNpmRemover(pkg) {
|
|
22923
|
-
(0,
|
|
23931
|
+
(0, import_node_child_process13.execSync)(`npm rm -g ${pkg}`, { stdio: "pipe", timeout: 12e4 });
|
|
22924
23932
|
}
|
|
22925
23933
|
function isGitTracked(cwd, relPath) {
|
|
22926
23934
|
try {
|
|
22927
|
-
(0,
|
|
23935
|
+
(0, import_node_child_process13.execSync)(`git ls-files --error-unmatch ${relPath}`, { cwd, stdio: "pipe" });
|
|
22928
23936
|
return true;
|
|
22929
23937
|
} catch {
|
|
22930
23938
|
return false;
|
|
@@ -22932,7 +23940,7 @@ function isGitTracked(cwd, relPath) {
|
|
|
22932
23940
|
}
|
|
22933
23941
|
function isGitRepo(cwd) {
|
|
22934
23942
|
try {
|
|
22935
|
-
(0,
|
|
23943
|
+
(0, import_node_child_process13.execSync)("git rev-parse --is-inside-work-tree", { cwd, stdio: "pipe" });
|
|
22936
23944
|
return true;
|
|
22937
23945
|
} catch {
|
|
22938
23946
|
return false;
|
|
@@ -22955,10 +23963,10 @@ async function runMigration(opts = {}) {
|
|
|
22955
23963
|
function migrateProjectDir(root, actions) {
|
|
22956
23964
|
const gateDir = (0, import_node_path28.join)(root, ".gate");
|
|
22957
23965
|
const verityDir = (0, import_node_path28.join)(root, ".verity");
|
|
22958
|
-
if ((0,
|
|
23966
|
+
if ((0, import_node_fs45.existsSync)(gateDir) && !(0, import_node_fs45.existsSync)(verityDir)) {
|
|
22959
23967
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
22960
23968
|
}
|
|
22961
|
-
if ((0,
|
|
23969
|
+
if ((0, import_node_fs45.existsSync)(gateDir) && (0, import_node_fs45.existsSync)(verityDir)) {
|
|
22962
23970
|
return migrateProjectDirCarry(gateDir, verityDir, actions);
|
|
22963
23971
|
}
|
|
22964
23972
|
return false;
|
|
@@ -22972,20 +23980,20 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
|
|
|
22972
23980
|
);
|
|
22973
23981
|
}
|
|
22974
23982
|
try {
|
|
22975
|
-
(0,
|
|
23983
|
+
(0, import_node_child_process13.execSync)("git mv .gate .verity", { cwd: root, stdio: "pipe" });
|
|
22976
23984
|
actions.push("Moved .gate/ \u2192 .verity/ (git mv, staged)");
|
|
22977
23985
|
moved = true;
|
|
22978
23986
|
} catch {
|
|
22979
23987
|
}
|
|
22980
23988
|
}
|
|
22981
23989
|
if (moved) {
|
|
22982
|
-
if ((0,
|
|
23990
|
+
if ((0, import_node_fs45.existsSync)(gateDir)) {
|
|
22983
23991
|
const carried = carryLegacyContents(gateDir, verityDir);
|
|
22984
23992
|
if (carried > 0) {
|
|
22985
23993
|
actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
|
|
22986
23994
|
}
|
|
22987
23995
|
try {
|
|
22988
|
-
(0,
|
|
23996
|
+
(0, import_node_fs45.rmSync)(gateDir, { recursive: true, force: true });
|
|
22989
23997
|
} catch {
|
|
22990
23998
|
}
|
|
22991
23999
|
}
|
|
@@ -23001,7 +24009,7 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
23001
24009
|
actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
|
|
23002
24010
|
}
|
|
23003
24011
|
try {
|
|
23004
|
-
(0,
|
|
24012
|
+
(0, import_node_fs45.rmSync)(gateDir, { recursive: true, force: true });
|
|
23005
24013
|
} catch {
|
|
23006
24014
|
}
|
|
23007
24015
|
return carried > 0;
|
|
@@ -23010,9 +24018,9 @@ function migrateGlobalCredentials(home, actions) {
|
|
|
23010
24018
|
if (!home) return;
|
|
23011
24019
|
const gateCreds = (0, import_node_path28.join)(home, ".gate", "credentials");
|
|
23012
24020
|
const verityCreds = (0, import_node_path28.join)(home, ".verity", "credentials");
|
|
23013
|
-
if (!(0,
|
|
23014
|
-
if (!(0,
|
|
23015
|
-
(0,
|
|
24021
|
+
if (!(0, import_node_fs45.existsSync)(gateCreds)) return;
|
|
24022
|
+
if (!(0, import_node_fs45.existsSync)(verityCreds)) {
|
|
24023
|
+
(0, import_node_fs45.mkdirSync)((0, import_node_path28.join)(home, ".verity"), { recursive: true });
|
|
23016
24024
|
moveFile(gateCreds, verityCreds);
|
|
23017
24025
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
23018
24026
|
return;
|
|
@@ -23035,7 +24043,7 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
23035
24043
|
}
|
|
23036
24044
|
async function migrateClaudeMd(root, actions) {
|
|
23037
24045
|
const claudeMd = (0, import_node_path28.join)(root, "CLAUDE.md");
|
|
23038
|
-
const hadLegacyBlock = (0,
|
|
24046
|
+
const hadLegacyBlock = (0, import_node_fs45.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
|
|
23039
24047
|
if (!hadLegacyBlock) return;
|
|
23040
24048
|
try {
|
|
23041
24049
|
await ensureClaudeMdPointer(root);
|
|
@@ -23047,11 +24055,11 @@ async function migrateClaudeMd(root, actions) {
|
|
|
23047
24055
|
function migrateStandardFile(root, actions) {
|
|
23048
24056
|
const gateMd = (0, import_node_path28.join)(root, "GATE.md");
|
|
23049
24057
|
const verityMd = (0, import_node_path28.join)(root, "VERITY.md");
|
|
23050
|
-
if (!(0,
|
|
24058
|
+
if (!(0, import_node_fs45.existsSync)(gateMd) || (0, import_node_fs45.existsSync)(verityMd)) return;
|
|
23051
24059
|
let moved = false;
|
|
23052
24060
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
23053
24061
|
try {
|
|
23054
|
-
(0,
|
|
24062
|
+
(0, import_node_child_process13.execSync)("git mv GATE.md VERITY.md", { cwd: root, stdio: "pipe" });
|
|
23055
24063
|
moved = true;
|
|
23056
24064
|
} catch {
|
|
23057
24065
|
}
|
|
@@ -23059,12 +24067,12 @@ function migrateStandardFile(root, actions) {
|
|
|
23059
24067
|
if (!moved) moveFile(gateMd, verityMd);
|
|
23060
24068
|
const content = readFileSyncSafe(verityMd);
|
|
23061
24069
|
const refreshed = content.split("GATE.md").join("VERITY.md");
|
|
23062
|
-
if (refreshed !== content) (0,
|
|
24070
|
+
if (refreshed !== content) (0, import_node_fs45.writeFileSync)(verityMd, refreshed);
|
|
23063
24071
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
23064
24072
|
}
|
|
23065
24073
|
async function migrateTelemetryHeaders(root, actions) {
|
|
23066
24074
|
const file = (0, import_node_path28.join)(root, ".claude", "settings.local.json");
|
|
23067
|
-
if (!(0,
|
|
24075
|
+
if (!(0, import_node_fs45.existsSync)(file)) return;
|
|
23068
24076
|
let settings;
|
|
23069
24077
|
try {
|
|
23070
24078
|
settings = JSON.parse(readFileSyncSafe(file) || "{}");
|
|
@@ -23112,21 +24120,21 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
23112
24120
|
}
|
|
23113
24121
|
if (toAppend.length > 0) {
|
|
23114
24122
|
const sep2 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
23115
|
-
(0,
|
|
24123
|
+
(0, import_node_fs45.writeFileSync)(verityCreds, verityContent + sep2 + toAppend.join("\n") + "\n");
|
|
23116
24124
|
}
|
|
23117
|
-
(0,
|
|
24125
|
+
(0, import_node_fs45.rmSync)(gateCreds, { force: true });
|
|
23118
24126
|
return toAppend.length;
|
|
23119
24127
|
}
|
|
23120
24128
|
function readFileSyncSafe(path) {
|
|
23121
24129
|
try {
|
|
23122
|
-
return (0,
|
|
24130
|
+
return (0, import_node_fs45.readFileSync)(path, "utf-8");
|
|
23123
24131
|
} catch {
|
|
23124
24132
|
return "";
|
|
23125
24133
|
}
|
|
23126
24134
|
}
|
|
23127
24135
|
function hasStagedChanges(root) {
|
|
23128
24136
|
try {
|
|
23129
|
-
(0,
|
|
24137
|
+
(0, import_node_child_process13.execSync)("git diff --cached --quiet", { cwd: root, stdio: "pipe" });
|
|
23130
24138
|
return false;
|
|
23131
24139
|
} catch {
|
|
23132
24140
|
return true;
|
|
@@ -23134,35 +24142,35 @@ function hasStagedChanges(root) {
|
|
|
23134
24142
|
}
|
|
23135
24143
|
function moveDir(from, to) {
|
|
23136
24144
|
try {
|
|
23137
|
-
(0,
|
|
24145
|
+
(0, import_node_fs45.renameSync)(from, to);
|
|
23138
24146
|
} catch (err) {
|
|
23139
24147
|
if (err.code !== "EXDEV") throw err;
|
|
23140
|
-
(0,
|
|
23141
|
-
(0,
|
|
24148
|
+
(0, import_node_fs45.cpSync)(from, to, { recursive: true });
|
|
24149
|
+
(0, import_node_fs45.rmSync)(from, { recursive: true, force: true });
|
|
23142
24150
|
}
|
|
23143
24151
|
}
|
|
23144
24152
|
function moveFile(from, to) {
|
|
23145
24153
|
try {
|
|
23146
|
-
(0,
|
|
24154
|
+
(0, import_node_fs45.renameSync)(from, to);
|
|
23147
24155
|
} catch (err) {
|
|
23148
24156
|
if (err.code !== "EXDEV") throw err;
|
|
23149
|
-
(0,
|
|
23150
|
-
(0,
|
|
24157
|
+
(0, import_node_fs45.cpSync)(from, to);
|
|
24158
|
+
(0, import_node_fs45.rmSync)(from, { force: true });
|
|
23151
24159
|
}
|
|
23152
24160
|
}
|
|
23153
24161
|
function carryLegacyContents(gateDir, verityDir) {
|
|
23154
24162
|
let copied = 0;
|
|
23155
24163
|
const walk = (relDir) => {
|
|
23156
24164
|
const srcDir = (0, import_node_path28.join)(gateDir, relDir);
|
|
23157
|
-
for (const entry of (0,
|
|
24165
|
+
for (const entry of (0, import_node_fs45.readdirSync)(srcDir)) {
|
|
23158
24166
|
const rel = relDir ? (0, import_node_path28.join)(relDir, entry) : entry;
|
|
23159
24167
|
const src = (0, import_node_path28.join)(gateDir, rel);
|
|
23160
24168
|
const dest = (0, import_node_path28.join)(verityDir, rel);
|
|
23161
|
-
if ((0,
|
|
24169
|
+
if ((0, import_node_fs45.statSync)(src).isDirectory()) {
|
|
23162
24170
|
walk(rel);
|
|
23163
|
-
} else if (!(0,
|
|
23164
|
-
(0,
|
|
23165
|
-
(0,
|
|
24171
|
+
} else if (!(0, import_node_fs45.existsSync)(dest)) {
|
|
24172
|
+
(0, import_node_fs45.mkdirSync)((0, import_node_path28.dirname)(dest), { recursive: true });
|
|
24173
|
+
(0, import_node_fs45.cpSync)(src, dest);
|
|
23166
24174
|
copied++;
|
|
23167
24175
|
}
|
|
23168
24176
|
}
|
|
@@ -23173,20 +24181,20 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
23173
24181
|
async function needsMigration(root = repoRoot()) {
|
|
23174
24182
|
const gateDir = (0, import_node_path28.join)(root, ".gate");
|
|
23175
24183
|
const verityDir = (0, import_node_path28.join)(root, ".verity");
|
|
23176
|
-
if ((0,
|
|
23177
|
-
if ((0,
|
|
23178
|
-
if ((0,
|
|
24184
|
+
if ((0, import_node_fs45.existsSync)(gateDir) && !(0, import_node_fs45.existsSync)(verityDir)) return true;
|
|
24185
|
+
if ((0, import_node_fs45.existsSync)(gateDir) && (0, import_node_fs45.existsSync)(verityDir)) {
|
|
24186
|
+
if ((0, import_node_fs45.existsSync)((0, import_node_path28.join)(gateDir, "credentials")) && !(0, import_node_fs45.existsSync)((0, import_node_path28.join)(verityDir, "credentials"))) {
|
|
23179
24187
|
return true;
|
|
23180
24188
|
}
|
|
23181
|
-
if ((0,
|
|
24189
|
+
if ((0, import_node_fs45.existsSync)((0, import_node_path28.join)(gateDir, "memory")) && !(0, import_node_fs45.existsSync)((0, import_node_path28.join)(verityDir, "memory"))) {
|
|
23182
24190
|
return true;
|
|
23183
24191
|
}
|
|
23184
24192
|
}
|
|
23185
24193
|
const claudeMd = (0, import_node_path28.join)(root, "CLAUDE.md");
|
|
23186
|
-
if ((0,
|
|
24194
|
+
if ((0, import_node_fs45.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
23187
24195
|
return true;
|
|
23188
24196
|
}
|
|
23189
|
-
if ((0,
|
|
24197
|
+
if ((0, import_node_fs45.existsSync)((0, import_node_path28.join)(root, "GATE.md")) && !(0, import_node_fs45.existsSync)((0, import_node_path28.join)(root, "VERITY.md"))) {
|
|
23190
24198
|
return true;
|
|
23191
24199
|
}
|
|
23192
24200
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -23358,7 +24366,7 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
23358
24366
|
}
|
|
23359
24367
|
let remote = "";
|
|
23360
24368
|
try {
|
|
23361
|
-
remote = (0,
|
|
24369
|
+
remote = (0, import_node_child_process14.execSync)("git remote get-url origin", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
23362
24370
|
} catch {
|
|
23363
24371
|
}
|
|
23364
24372
|
if (!healed) {
|
|
@@ -23412,7 +24420,7 @@ function resolveDataDir() {
|
|
|
23412
24420
|
// local dev: running from repo root
|
|
23413
24421
|
];
|
|
23414
24422
|
for (const candidate of candidates) {
|
|
23415
|
-
if ((0,
|
|
24423
|
+
if ((0, import_node_fs46.existsSync)((0, import_node_path29.join)(candidate, "skills"))) {
|
|
23416
24424
|
return candidate;
|
|
23417
24425
|
}
|
|
23418
24426
|
}
|
|
@@ -23428,7 +24436,7 @@ async function skillIsCurrent(src, dest) {
|
|
|
23428
24436
|
const list2 = (dir) => {
|
|
23429
24437
|
const out = [];
|
|
23430
24438
|
const walk = (d, prefix) => {
|
|
23431
|
-
for (const e of (0,
|
|
24439
|
+
for (const e of (0, import_node_fs46.readdirSync)(d, { withFileTypes: true })) {
|
|
23432
24440
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
23433
24441
|
if (e.isDirectory()) walk((0, import_node_path29.join)(d, e.name), rel);
|
|
23434
24442
|
else if (e.isFile()) out.push(rel);
|
|
@@ -23578,20 +24586,76 @@ async function handoffToSetup(enabled, claudeInstalled) {
|
|
|
23578
24586
|
console.log(" Usually a minute or two. Quit any time \u2014 re-running /verity-setup resumes.");
|
|
23579
24587
|
console.log("");
|
|
23580
24588
|
const startedAt = Date.now();
|
|
23581
|
-
const run2 = (0,
|
|
24589
|
+
const run2 = (0, import_node_child_process14.spawnSync)("claude", ["/verity-setup"], { stdio: "inherit" });
|
|
23582
24590
|
if (run2.error) {
|
|
23583
24591
|
printWarn(`Could not start Claude Code: ${run2.error.message}`);
|
|
23584
24592
|
return instruct("start it yourself and run the skill there");
|
|
23585
24593
|
}
|
|
23586
24594
|
await reportPhaseTwo(startedAt);
|
|
23587
24595
|
}
|
|
24596
|
+
async function installSkills(force, step) {
|
|
24597
|
+
step("Installing skills");
|
|
24598
|
+
const dataDir = resolveDataDir();
|
|
24599
|
+
const skillsSource = (0, import_node_path29.join)(dataDir, "skills");
|
|
24600
|
+
const skillsDest = ".claude/skills";
|
|
24601
|
+
let skillsInstalled = 0;
|
|
24602
|
+
for (const skill of SKILLS) {
|
|
24603
|
+
const src = (0, import_node_path29.join)(skillsSource, skill);
|
|
24604
|
+
const dest = (0, import_node_path29.join)(skillsDest, skill);
|
|
24605
|
+
if (!(0, import_node_fs46.existsSync)(src)) {
|
|
24606
|
+
printWarn(` Skill data not found: ${skill}`);
|
|
24607
|
+
continue;
|
|
24608
|
+
}
|
|
24609
|
+
if ((0, import_node_fs46.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) {
|
|
24610
|
+
skillsInstalled++;
|
|
24611
|
+
continue;
|
|
24612
|
+
}
|
|
24613
|
+
await copyDir(src, dest);
|
|
24614
|
+
skillsInstalled++;
|
|
24615
|
+
}
|
|
24616
|
+
printInfo(` ${skillsInstalled}/${SKILLS.length} skills installed to .claude/skills/ \u2713`);
|
|
24617
|
+
}
|
|
24618
|
+
async function adoptPluginWiring(gitMoments, moments) {
|
|
24619
|
+
const settings = await readSettings();
|
|
24620
|
+
const stripped = removeVerityHooks(settings);
|
|
24621
|
+
const hadAny = JSON.stringify(settings.hooks ?? {}) !== JSON.stringify(stripped.hooks ?? {});
|
|
24622
|
+
if (hadAny) {
|
|
24623
|
+
await writeSettings(stripped);
|
|
24624
|
+
printInfo(" Removed this project's Verity hooks from .claude/settings.json \u2713");
|
|
24625
|
+
printInfo(" The plugin wires them now, so each turn is reviewed once.");
|
|
24626
|
+
} else {
|
|
24627
|
+
printInfo(" Wired by the Verity plugin \u2014 nothing to reconcile here \u2713");
|
|
24628
|
+
}
|
|
24629
|
+
printInfo(` Pre-commit gate: ${gitMoments.includes("commit") ? "on" : "off"}`);
|
|
24630
|
+
printInfo(` Pre-push/PR gate: ${gitMoments.includes("push") ? "on" : "off"}`);
|
|
24631
|
+
printInfo(" Stop + intent + baseline + compact + session-end: always on \u2713");
|
|
24632
|
+
if (!moments.includes("stop")) {
|
|
24633
|
+
printWarn(" Turning the Stop review off is not yet supported under the plugin \u2014 it stays on.");
|
|
24634
|
+
}
|
|
24635
|
+
}
|
|
24636
|
+
async function reconcileOwnWiring(moments) {
|
|
24637
|
+
await applyMomentSelection(moments);
|
|
24638
|
+
const hookStatus = await checkAllVerityHooks();
|
|
24639
|
+
printInfo(` Stop (verity analyze): ${hookStatus.stop ? "on" : "off"}`);
|
|
24640
|
+
printInfo(` Pre-commit gate: ${hookStatus.guardOn.includes("commit") ? "on" : "off"}`);
|
|
24641
|
+
printInfo(` Pre-push/PR gate: ${hookStatus.guardOn.includes("push") ? "on" : "off"}`);
|
|
24642
|
+
printInfo(" Intent + baseline + compact + session-end: always on \u2713");
|
|
24643
|
+
if (!hookStatus.stop && hookStatus.guardOn.length === 0) {
|
|
24644
|
+
printWarn(" No analysis moment is active \u2014 code changes will NOT be reviewed.");
|
|
24645
|
+
printWarn(" Enable one: verity hooks install --moments stop");
|
|
24646
|
+
}
|
|
24647
|
+
}
|
|
23588
24648
|
function registerInitCommand(program2) {
|
|
23589
|
-
program2.command("init").alias("setup").description("Set up Verity in the current project (asks the setup questions, then hands off to /verity-setup)").option("--force", "Reinstall the skills even when they are already up to date (hooks are always reconciled)").option("-y, --yes", "Take the recommended answer for every question (no prompts)").option("--no-setup", "Skip the /verity-setup handoff at the end").
|
|
24649
|
+
program2.command("init").alias("setup").description("Set up Verity in the current project (asks the setup questions, then hands off to /verity-setup)").option("--force", "Reinstall the skills even when they are already up to date (hooks are always reconciled)").option("-y, --yes", "Take the recommended answer for every question (no prompts)").option("--no-setup", "Skip the /verity-setup handoff at the end").option(
|
|
24650
|
+
"--plugin-mode",
|
|
24651
|
+
"The Claude Code plugin owns the skills and hooks: install neither, and remove any this project already has"
|
|
24652
|
+
).action(async (opts) => {
|
|
23590
24653
|
const force = opts.force ?? false;
|
|
23591
24654
|
const wantsHandoff = opts.setup !== false;
|
|
23592
24655
|
const defaultsOnly = (opts.yes ?? false) || !interactive();
|
|
24656
|
+
const pluginMode = opts.pluginMode ?? pluginActiveHere();
|
|
23593
24657
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
23594
|
-
const isProject = projectMarkers.some((m) => (0,
|
|
24658
|
+
const isProject = projectMarkers.some((m) => (0, import_node_fs46.existsSync)(m));
|
|
23595
24659
|
if (!isProject) {
|
|
23596
24660
|
printError("No project detected in the current directory.");
|
|
23597
24661
|
printInfo('Run "verity init" from your project root.');
|
|
@@ -23639,26 +24703,11 @@ function registerInitCommand(program2) {
|
|
|
23639
24703
|
}
|
|
23640
24704
|
const claudeInstalled = prereqs.checks.some((c) => c.id === "claude" && c.status === "ok");
|
|
23641
24705
|
console.log("");
|
|
23642
|
-
|
|
23643
|
-
|
|
23644
|
-
|
|
23645
|
-
|
|
23646
|
-
let skillsInstalled = 0;
|
|
23647
|
-
for (const skill of SKILLS) {
|
|
23648
|
-
const src = (0, import_node_path29.join)(skillsSource, skill);
|
|
23649
|
-
const dest = (0, import_node_path29.join)(skillsDest, skill);
|
|
23650
|
-
if (!(0, import_node_fs44.existsSync)(src)) {
|
|
23651
|
-
printWarn(` Skill data not found: ${skill}`);
|
|
23652
|
-
continue;
|
|
23653
|
-
}
|
|
23654
|
-
if ((0, import_node_fs44.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) {
|
|
23655
|
-
skillsInstalled++;
|
|
23656
|
-
continue;
|
|
23657
|
-
}
|
|
23658
|
-
await copyDir(src, dest);
|
|
23659
|
-
skillsInstalled++;
|
|
24706
|
+
if (pluginMode) {
|
|
24707
|
+
printInfo("Skipping skills \u2014 the Verity plugin provides them, namespaced as /verity:<name>.");
|
|
24708
|
+
} else {
|
|
24709
|
+
await installSkills(force, step);
|
|
23660
24710
|
}
|
|
23661
|
-
printInfo(` ${skillsInstalled}/${SKILLS.length} skills installed to .claude/skills/ \u2713`);
|
|
23662
24711
|
step(defaultsOnly ? "Setup answers (defaults)" : "Your setup answers");
|
|
23663
24712
|
const previous = await readSetupState();
|
|
23664
24713
|
const answers = await askSetupQuestions(defaultsOnly, previous);
|
|
@@ -23705,15 +24754,15 @@ function registerInitCommand(program2) {
|
|
|
23705
24754
|
await (0, import_promises14.mkdir)(globalVerityDir, { recursive: true });
|
|
23706
24755
|
console.log("");
|
|
23707
24756
|
step("Wiring Claude Code hooks");
|
|
23708
|
-
|
|
23709
|
-
|
|
23710
|
-
|
|
23711
|
-
|
|
23712
|
-
|
|
23713
|
-
|
|
23714
|
-
|
|
23715
|
-
|
|
23716
|
-
|
|
24757
|
+
const gitMoments = [
|
|
24758
|
+
...moments.includes("pre-commit") ? ["commit"] : [],
|
|
24759
|
+
...moments.includes("pre-push") ? ["push"] : []
|
|
24760
|
+
];
|
|
24761
|
+
writeProjectConfig({ git_moments: gitMoments });
|
|
24762
|
+
if (pluginMode) {
|
|
24763
|
+
await adoptPluginWiring(gitMoments, moments);
|
|
24764
|
+
} else {
|
|
24765
|
+
await reconcileOwnWiring(moments);
|
|
23717
24766
|
}
|
|
23718
24767
|
console.log("");
|
|
23719
24768
|
step("Sign in to Verity (optional)");
|
|
@@ -23762,7 +24811,7 @@ function registerInitCommand(program2) {
|
|
|
23762
24811
|
...telemetryChoice ? { telemetry: telemetryChoice } : {},
|
|
23763
24812
|
init: {
|
|
23764
24813
|
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23765
|
-
cli_version: true ? "0.31.
|
|
24814
|
+
cli_version: true ? "0.31.2" : "dev"
|
|
23766
24815
|
}
|
|
23767
24816
|
});
|
|
23768
24817
|
} catch (err) {
|
|
@@ -23771,9 +24820,13 @@ function registerInitCommand(program2) {
|
|
|
23771
24820
|
console.log("");
|
|
23772
24821
|
printInfo("This machine is set up.");
|
|
23773
24822
|
console.log("");
|
|
23774
|
-
|
|
23775
|
-
|
|
23776
|
-
|
|
24823
|
+
if (pluginMode) {
|
|
24824
|
+
console.log(" (skills and hooks come from the Verity plugin, not this project)");
|
|
24825
|
+
} else {
|
|
24826
|
+
console.log(" .claude/skills/verity-*/ 8 skills (setup, analyze, status, feedback,");
|
|
24827
|
+
console.log(" learn, memory, insights, reflect)");
|
|
24828
|
+
console.log(" .claude/settings.json hooks, reconciled to your chosen moments");
|
|
24829
|
+
}
|
|
23777
24830
|
console.log(" .verity/memory/ knowledge base (commit to git)");
|
|
23778
24831
|
console.log(" .verity/setup.json your answers, read by /verity-setup");
|
|
23779
24832
|
console.log(" .gitignore Verity block (whitelist form)");
|
|
@@ -23786,7 +24839,7 @@ function registerInitCommand(program2) {
|
|
|
23786
24839
|
}
|
|
23787
24840
|
|
|
23788
24841
|
// src/commands/uninstall.ts
|
|
23789
|
-
var
|
|
24842
|
+
var import_node_fs47 = require("node:fs");
|
|
23790
24843
|
var import_node_path30 = require("node:path");
|
|
23791
24844
|
var SKILL_NAMES = [
|
|
23792
24845
|
"verity-setup",
|
|
@@ -23807,10 +24860,10 @@ function registerUninstallCommand(program2) {
|
|
|
23807
24860
|
const skillsRoot = projectPath(".claude/skills");
|
|
23808
24861
|
for (const name of SKILL_NAMES) {
|
|
23809
24862
|
const dir = (0, import_node_path30.join)(skillsRoot, name);
|
|
23810
|
-
if ((0,
|
|
24863
|
+
if ((0, import_node_fs47.existsSync)(dir)) {
|
|
23811
24864
|
actions.push({
|
|
23812
24865
|
label: `Remove .claude/skills/${name}/`,
|
|
23813
|
-
apply: () => (0,
|
|
24866
|
+
apply: () => (0, import_node_fs47.rmSync)(dir, { recursive: true, force: true })
|
|
23814
24867
|
});
|
|
23815
24868
|
}
|
|
23816
24869
|
}
|
|
@@ -23824,24 +24877,24 @@ function registerUninstallCommand(program2) {
|
|
|
23824
24877
|
});
|
|
23825
24878
|
}
|
|
23826
24879
|
const verityDir = projectPath(VERITY_DIR);
|
|
23827
|
-
if ((0,
|
|
24880
|
+
if ((0, import_node_fs47.existsSync)(verityDir)) {
|
|
23828
24881
|
actions.push({
|
|
23829
24882
|
label: `Remove ${VERITY_DIR}/`,
|
|
23830
|
-
apply: () => (0,
|
|
24883
|
+
apply: () => (0, import_node_fs47.rmSync)(verityDir, { recursive: true, force: true })
|
|
23831
24884
|
});
|
|
23832
24885
|
}
|
|
23833
24886
|
if (!keepVerityMd) {
|
|
23834
24887
|
const verityMd = projectPath(VERITY_MD_FILE);
|
|
23835
|
-
if ((0,
|
|
24888
|
+
if ((0, import_node_fs47.existsSync)(verityMd)) {
|
|
23836
24889
|
actions.push({
|
|
23837
24890
|
label: `Remove ${VERITY_MD_FILE}`,
|
|
23838
|
-
apply: () => (0,
|
|
24891
|
+
apply: () => (0, import_node_fs47.rmSync)(verityMd, { force: true })
|
|
23839
24892
|
});
|
|
23840
24893
|
}
|
|
23841
24894
|
}
|
|
23842
24895
|
const cleanupEmptyDir = (path) => {
|
|
23843
|
-
if ((0,
|
|
23844
|
-
(0,
|
|
24896
|
+
if ((0, import_node_fs47.existsSync)(path) && (0, import_node_fs47.statSync)(path).isDirectory() && (0, import_node_fs47.readdirSync)(path).length === 0) {
|
|
24897
|
+
(0, import_node_fs47.rmdirSync)(path);
|
|
23845
24898
|
}
|
|
23846
24899
|
};
|
|
23847
24900
|
actions.push({
|
|
@@ -23853,10 +24906,10 @@ function registerUninstallCommand(program2) {
|
|
|
23853
24906
|
});
|
|
23854
24907
|
const home = process.env.HOME ?? "";
|
|
23855
24908
|
const globalVerityDir = (0, import_node_path30.join)(home, ".verity");
|
|
23856
|
-
if (purgeGlobal && (0,
|
|
24909
|
+
if (purgeGlobal && (0, import_node_fs47.existsSync)(globalVerityDir)) {
|
|
23857
24910
|
actions.push({
|
|
23858
24911
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
23859
|
-
apply: () => (0,
|
|
24912
|
+
apply: () => (0, import_node_fs47.rmSync)(globalVerityDir, { recursive: true, force: true })
|
|
23860
24913
|
});
|
|
23861
24914
|
}
|
|
23862
24915
|
if (actions.length === 0) {
|
|
@@ -24050,7 +25103,7 @@ function registerTaskCommands(program2) {
|
|
|
24050
25103
|
}
|
|
24051
25104
|
|
|
24052
25105
|
// src/commands/reset.ts
|
|
24053
|
-
var
|
|
25106
|
+
var import_node_fs48 = require("node:fs");
|
|
24054
25107
|
var import_node_path31 = require("node:path");
|
|
24055
25108
|
function registerResetCommand(program2) {
|
|
24056
25109
|
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) => {
|
|
@@ -24088,11 +25141,11 @@ function registerResetCommand(program2) {
|
|
|
24088
25141
|
}
|
|
24089
25142
|
const cacheDir = projectPath(CACHE_DIR);
|
|
24090
25143
|
let purged = 0;
|
|
24091
|
-
if ((0,
|
|
24092
|
-
for (const entry of (0,
|
|
25144
|
+
if ((0, import_node_fs48.existsSync)(cacheDir)) {
|
|
25145
|
+
for (const entry of (0, import_node_fs48.readdirSync)(cacheDir)) {
|
|
24093
25146
|
if (entry.startsWith("pending-")) {
|
|
24094
25147
|
try {
|
|
24095
|
-
(0,
|
|
25148
|
+
(0, import_node_fs48.unlinkSync)((0, import_node_path31.join)(cacheDir, entry));
|
|
24096
25149
|
purged++;
|
|
24097
25150
|
} catch {
|
|
24098
25151
|
}
|
|
@@ -24107,19 +25160,19 @@ function registerResetCommand(program2) {
|
|
|
24107
25160
|
projectPath(`${VERITY_DIR}/.last-analysis`)
|
|
24108
25161
|
];
|
|
24109
25162
|
for (const file of filesToClear) {
|
|
24110
|
-
if ((0,
|
|
25163
|
+
if ((0, import_node_fs48.existsSync)(file)) {
|
|
24111
25164
|
try {
|
|
24112
|
-
(0,
|
|
25165
|
+
(0, import_node_fs48.writeFileSync)(file, "");
|
|
24113
25166
|
} catch {
|
|
24114
25167
|
}
|
|
24115
25168
|
}
|
|
24116
25169
|
}
|
|
24117
25170
|
if (opts.all) {
|
|
24118
25171
|
const logsDir = projectPath(`${VERITY_DIR}/.logs`);
|
|
24119
|
-
if ((0,
|
|
24120
|
-
for (const entry of (0,
|
|
25172
|
+
if ((0, import_node_fs48.existsSync)(logsDir)) {
|
|
25173
|
+
for (const entry of (0, import_node_fs48.readdirSync)(logsDir)) {
|
|
24121
25174
|
try {
|
|
24122
|
-
(0,
|
|
25175
|
+
(0, import_node_fs48.unlinkSync)((0, import_node_path31.join)(logsDir, entry));
|
|
24123
25176
|
} catch {
|
|
24124
25177
|
}
|
|
24125
25178
|
}
|
|
@@ -24427,8 +25480,8 @@ function registerTelemetryCommands(program2) {
|
|
|
24427
25480
|
}
|
|
24428
25481
|
|
|
24429
25482
|
// src/cli.ts
|
|
24430
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.31.
|
|
24431
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.31.
|
|
25483
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.31.2").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) => {
|
|
25484
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.31.2");
|
|
24432
25485
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
24433
25486
|
try {
|
|
24434
25487
|
await foldLegacyLocalCredential();
|